1 #include "../../include/nntp/nntpconnection.h"
\r
2 #include "../../include/nntp/uwildmat.h"
\r
3 #include "../../include/stringfunctions.h"
\r
4 #include "../../include/datetime.h"
\r
5 #include "../../include/boardlist.h"
\r
6 #include "../../include/message.h"
\r
7 #include "../../include/messagelist.h"
\r
8 #include "../../include/option.h"
\r
9 #include "../../include/nntp/extensiontrust.h"
\r
11 #include <algorithm>
\r
13 //#include <zthread/Thread.h>
\r
14 #include "../../include/pthreadwrapper/thread.h"
\r
20 NNTPConnection::NNTPConnection(SOCKET sock)
\r
22 std::string tempval;
\r
25 m_tempbuffer.resize(32768);
\r
27 m_status.m_isposting=false;
\r
28 m_status.m_allowpost=false;
\r
29 m_status.m_boardid=-1;
\r
30 m_status.m_messageid=-1;
\r
31 m_status.m_mode=MODE_NONE;
\r
32 m_status.m_authenticated=false;
\r
34 Option::Instance()->Get("NNTPAllowPost",tempval);
\r
37 m_status.m_allowpost=true;
\r
42 NNTPConnection::~NNTPConnection()
\r
47 void NNTPConnection::Disconnect()
\r
49 if(m_socket!=INVALID_SOCKET)
\r
52 closesocket(m_socket);
\r
56 m_socket=INVALID_SOCKET;
\r
60 std::vector<char>::iterator NNTPConnection::Find(std::vector<char> &buffer, const std::string &val)
\r
62 return std::search(buffer.begin(),buffer.end(),val.begin(),val.end());
\r
65 const bool NNTPConnection::HandleArticleCommand(const NNTPCommand &command)
\r
68 SendArticleParts(command);
\r
73 const bool NNTPConnection::HandleAuthInfoCommand(const NNTPCommand &command)
\r
75 if(command.m_arguments.size()<2)
\r
77 SendBufferedLine("501 Syntax error");
\r
79 else if(m_status.m_authenticated==true)
\r
81 SendBufferedLine("502 Command unavailable"); // not available when already authenticated
\r
85 std::string arg=command.m_arguments[0];
\r
86 StringFunctions::UpperCase(arg,arg);
\r
87 std::string name="";
\r
88 // get remaining args as part of the name since a name might have a space and the args are split on spaces
\r
89 for(std::vector<std::string>::const_iterator i=command.m_arguments.begin()+1; i!=command.m_arguments.end(); i++)
\r
91 // we split on the space, so add it back
\r
92 if(i!=command.m_arguments.begin()+1)
\r
100 LocalIdentity localid;
\r
101 if(localid.Load(name))
\r
103 m_status.m_authuser=localid;
\r
104 m_status.m_authenticated=true;
\r
105 SendBufferedLine("281 Authentication accepted");
\r
109 SendBufferedLine("481 Authentication failed");
\r
112 else if(arg=="PASS")
\r
114 SendBufferedLine("482 Authentication commands issued out of sequence"); // only require username
\r
118 SendBufferedLine("501 Syntax error");
\r
125 const bool NNTPConnection::HandleBodyCommand(const NNTPCommand &command)
\r
127 SendArticleParts(command);
\r
132 const bool NNTPConnection::HandleCapabilitiesCommand(const NNTPCommand &command)
\r
135 SendBufferedLine("101 Capability list :");
\r
136 SendBufferedLine("VERSION 2");
\r
137 if(m_status.m_authenticated==false) // RFC 4643 2.2 0 - don't advertise MODE-READER after authentication
\r
139 SendBufferedLine("MODE-READER");
\r
141 SendBufferedLine("READER");
\r
142 SendBufferedLine("LIST OVERVIEW.FMT");
\r
143 SendBufferedLine("OVER MSGID");
\r
144 if(m_status.m_allowpost==true)
\r
146 SendBufferedLine("POST");
\r
148 if(m_status.m_authenticated==false)
\r
150 SendBufferedLine("AUTHINFO USER");
\r
152 SendBufferedLine("XFMSTRUST");
\r
153 SendBufferedLine(".");
\r
158 const bool NNTPConnection::HandleCommand(const NNTPCommand &command)
\r
160 if(command.m_command=="QUIT")
\r
162 return HandleQuitCommand(command);
\r
164 if(command.m_command=="MODE")
\r
166 return HandleModeCommand(command);
\r
168 if(command.m_command=="CAPABILITIES")
\r
170 return HandleCapabilitiesCommand(command);
\r
172 if(command.m_command=="HELP")
\r
174 return HandleHelpCommand(command);
\r
176 if(command.m_command=="DATE")
\r
178 return HandleDateCommand(command);
\r
180 if(command.m_command=="LIST")
\r
182 return HandleListCommand(command);
\r
184 if(command.m_command=="GROUP")
\r
186 return HandleGroupCommand(command);
\r
188 if(command.m_command=="LISTGROUP")
\r
190 return HandleListGroupCommand(command);
\r
192 if(command.m_command=="LAST")
\r
194 return HandleLastCommand(command);
\r
196 if(command.m_command=="NEXT")
\r
198 return HandleNextCommand(command);
\r
200 if(command.m_command=="ARTICLE")
\r
202 return HandleArticleCommand(command);
\r
204 if(command.m_command=="HEAD")
\r
206 return HandleHeadCommand(command);
\r
208 if(command.m_command=="BODY")
\r
210 return HandleBodyCommand(command);
\r
212 if(command.m_command=="STAT")
\r
214 return HandleStatCommand(command);
\r
216 if(command.m_command=="NEWGROUPS")
\r
218 return HandleNewGroupsCommand(command);
\r
220 if(command.m_command=="POST")
\r
222 return HandlePostCommand(command);
\r
224 if(command.m_command=="OVER" || command.m_command=="XOVER")
\r
226 return HandleOverCommand(command);
\r
228 if(command.m_command=="AUTHINFO")
\r
230 return HandleAuthInfoCommand(command);
\r
232 if(command.m_command=="XGETTRUST")
\r
234 return HandleGetTrustCommand(command);
\r
236 if(command.m_command=="XSETTRUST")
\r
238 return HandleSetTrustCommand(command);
\r
240 if(command.m_command=="XGETTRUSTLIST")
\r
242 return HandleGetTrustListCommand(command);
\r
248 const bool NNTPConnection::HandleDateCommand(const NNTPCommand &command)
\r
252 SendBufferedLine("111 "+now.Format("%Y%m%d%H%M%S"));
\r
256 const bool NNTPConnection::HandleGetTrustCommand(const NNTPCommand &command)
\r
258 if(command.m_arguments.size()>=2)
\r
260 std::string type=command.m_arguments[0];
\r
261 StringFunctions::UpperCase(type,type);
\r
262 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="PEERMESSAGE" || type=="PEERTRUSTLIST")
\r
264 if(m_status.m_authenticated)
\r
268 std::string nntpname="";
\r
269 for(int i=1; i<command.m_arguments.size(); i++)
\r
271 nntpname+=command.m_arguments[i];
\r
274 TrustExtension tr(m_status.m_authuser.GetID());
\r
276 if(type=="MESSAGE")
\r
278 if(tr.GetMessageTrust(nntpname,trust))
\r
283 else if(type=="TRUSTLIST")
\r
285 if(tr.GetTrustListTrust(nntpname,trust))
\r
290 else if(type=="PEERMESSAGE")
\r
292 if(tr.GetPeerMessageTrust(nntpname,trust))
\r
297 else if(type=="PEERTRUSTLIST")
\r
299 if(tr.GetPeerTrustListTrust(nntpname,trust))
\r
305 if(trust>=0 && found)
\r
307 std::string truststr="";
\r
308 StringFunctions::Convert(trust,truststr);
\r
309 SendBufferedLine("280 "+truststr);
\r
313 SendBufferedLine("281 null");
\r
317 SendBufferedLine("480 Identity not found");
\r
323 SendBufferedLine("480 User not authenticated");
\r
328 SendBufferedLine("501 Syntax error");
\r
333 SendBufferedLine("501 Syntax error");
\r
338 const bool NNTPConnection::HandleGetTrustListCommand(const NNTPCommand &command)
\r
340 if(m_status.m_authenticated)
\r
342 TrustExtension tr(m_status.m_authuser.GetID());
\r
343 std::map<std::string,std::pair<int,int> > trustlist;
\r
344 if(tr.GetTrustList(trustlist))
\r
346 SendBufferedLine("280 Trust list follows");
\r
347 for(std::map<std::string,std::pair<int,int> >::iterator i=trustlist.begin(); i!=trustlist.end(); i++)
\r
349 std::ostringstream tempstr;
\r
350 tempstr << (*i).first << "\t";
\r
351 if((*i).second.first>-1)
\r
353 tempstr << (*i).second.first;
\r
360 if((*i).second.second>-1)
\r
362 tempstr << (*i).second.second;
\r
368 SendBufferedLine(tempstr.str());
\r
370 SendBufferedLine(".");
\r
374 SendBufferedLine("501 Syntax error");
\r
379 SendBufferedLine("480 User not authenticated");
\r
384 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
386 if(command.m_arguments.size()==1)
\r
389 if(board.Load(command.m_arguments[0])==true)
\r
391 std::ostringstream tempstr;
\r
393 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
395 SendBufferedLine(tempstr.str());
\r
397 // set the current boardid to this one
\r
398 m_status.m_boardid=board.GetBoardID();
\r
399 //set the first message id, -1 if there are no messages
\r
400 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
405 SendBufferedLine("411 No such newsgroup");
\r
410 SendBufferedLine("501 Syntax error");
\r
411 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleGroupCommand syntax error");
\r
417 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
420 SendArticleParts(command);
\r
425 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
427 SendBufferedLine("100 Help text follows");
\r
428 SendBufferedLine("There is no help text");
\r
429 SendBufferedLine(".");
\r
434 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
436 if(m_status.m_boardid!=-1)
\r
438 if(m_status.m_messageid!=-1)
\r
442 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
444 std::ostringstream tempstr;
\r
446 m_status.m_messageid=mess.GetMessageID();
\r
448 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
450 SendBufferedLine(tempstr.str());
\r
455 SendBufferedLine("422 No previous article in this group");
\r
460 SendBufferedLine("420 Current article number is invalid");
\r
465 SendBufferedLine("412 No newsgroup selected");
\r
471 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
474 int type=1; // default LIST type is active
\r
475 std::string arg1="";
\r
476 std::string arg2="";
\r
479 if(command.m_arguments.size()>0)
\r
481 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
486 else if(arg1=="NEWSGROUPS")
\r
490 else if(arg1=="OVERVIEW.FMT")
\r
500 if(command.m_arguments.size()>1)
\r
502 arg2=command.m_arguments[1];
\r
505 // LIST ACTIVE [wildmat]
\r
509 std::ostringstream tempstr;
\r
513 SendBufferedLine("215 list of newsgroups follows");
\r
515 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
520 // check wilmat match
\r
523 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
526 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
528 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
529 SendBufferedLine(tempstr.str());
\r
533 SendBufferedLine(".");
\r
540 std::ostringstream tempstr;
\r
544 SendBufferedLine("215 list of newsgroups follows");
\r
546 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
551 // check wilmat match
\r
554 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
557 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
559 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
560 SendBufferedLine(tempstr.str());
\r
564 SendBufferedLine(".");
\r
567 // LIST OVERVIEW.FMT
\r
570 SendBufferedLine("215 Order of fields in overview database.");
\r
571 SendBufferedLine("Subject:");
\r
572 SendBufferedLine("From:");
\r
573 SendBufferedLine("Date:");
\r
574 SendBufferedLine("Message-ID:");
\r
575 SendBufferedLine("References:");
\r
576 SendBufferedLine(":bytes");
\r
577 SendBufferedLine(":lines");
\r
578 SendBufferedLine(".");
\r
583 SendBufferedLine("501 Syntax error");
\r
584 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListCommand unhandled LIST variant");
\r
590 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
593 std::ostringstream tempstr;
\r
595 bool validgroup=false;
\r
599 // no args and invalid boardid
\r
600 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
602 SendBufferedLine("412 No newsgroup selected");
\r
604 else if(command.m_arguments.size()==0)
\r
606 validgroup=board.Load(m_status.m_boardid);
\r
608 else if(command.m_arguments.size()==1)
\r
610 validgroup=board.Load(command.m_arguments[0]);
\r
613 lownum=board.GetLowMessageID();
\r
614 highnum=board.GetHighMessageID();
\r
618 SendBufferedLine("411 No such newsgroup");
\r
621 else if(command.m_arguments.size()==2)
\r
623 validgroup=board.Load(command.m_arguments[0]);
\r
624 std::vector<std::string> rangeparts;
\r
625 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
627 if(rangeparts.size()>0)
\r
629 StringFunctions::Convert(rangeparts[0],lownum);
\r
631 if(rangeparts.size()>1)
\r
633 StringFunctions::Convert(rangeparts[1],highnum);
\r
640 SendBufferedLine("501 Syntax error");
\r
641 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListGroupCommand unknown arguments");
\r
647 // set boardid and messageid
\r
648 m_status.m_boardid=board.GetBoardID();
\r
649 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
653 lownum=board.GetLowMessageID();
\r
657 highnum=board.GetHighMessageID();
\r
660 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
661 SendBufferedLine(tempstr.str());
\r
664 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
666 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
669 tempstr << (*i).GetMessageID();
\r
671 SendBufferedLine(tempstr.str());
\r
674 // end of multi-line response
\r
675 SendBufferedLine(".");
\r
682 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
684 if(command.m_arguments.size()>0)
\r
686 std::string arg=command.m_arguments[0];
\r
687 StringFunctions::UpperCase(arg,arg);
\r
690 m_status.m_mode=MODE_READER;
\r
691 if(m_status.m_allowpost==true)
\r
693 SendBufferedLine("200 Posting allowed");
\r
697 SendBufferedLine("201 Posting prohibited");
\r
700 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand set mode to reader");
\r
704 SendBufferedLine("501 Syntax error");
\r
705 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
710 SendBufferedLine("501 Syntax error");
\r
711 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
717 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
719 if(command.m_arguments.size()>=2)
\r
723 if(command.m_arguments[0].size()==8)
\r
725 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempint);
\r
726 date.SetYear(tempint);
\r
727 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
728 date.SetMonth(tempint);
\r
729 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempint);
\r
730 date.SetDay(tempint);
\r
736 If the first two digits of the year are not specified
\r
737 (this is supported only for backward compatibility), the year is to
\r
738 be taken from the current century if yy is smaller than or equal to
\r
739 the current year, and the previous century otherwise.
\r
744 century=now.GetYear()-(now.GetYear()%100);
\r
746 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempint);
\r
747 tempint<=now.GetYear()-century ? tempint+=century : tempint+=(century-100);
\r
749 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
751 date.SetYear(tempint);
\r
752 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempint);
\r
753 date.SetMonth(tempint);
\r
754 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
755 date.SetDay(tempint);
\r
762 bl.LoadNew(date.Format("%Y-%m-%d %H:%M:%S"));
\r
764 SendBufferedLine("231 List of new newsgroups follows");
\r
766 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
768 if((*i).GetSaveReceivedMessages()==true)
\r
770 std::ostringstream tempstr;
\r
771 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << m_status.m_allowpost ? "y" : "n";
\r
772 SendBufferedLine(tempstr.str());
\r
776 SendBufferedLine(".");
\r
781 SendBufferedLine("501 Syntax error");
\r
782 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleNewGroupsCommand syntax error");
\r
789 const bool NNTPConnection::HandleNextCommand(const NNTPCommand &command)
\r
791 if(m_status.m_boardid!=-1)
\r
793 if(m_status.m_messageid!=-1)
\r
797 if(mess.LoadNext(m_status.m_messageid,m_status.m_boardid))
\r
799 std::ostringstream tempstr;
\r
801 m_status.m_messageid=mess.GetMessageID();
\r
803 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
805 SendBufferedLine(tempstr.str());
\r
810 SendBufferedLine("421 No next article in this group");
\r
815 SendBufferedLine("420 Current article number is invalid");
\r
820 SendBufferedLine("412 No newsgroup selected");
\r
827 const bool NNTPConnection::HandleOverCommand(const NNTPCommand &command)
\r
829 long lowmessageid,highmessageid;
\r
830 std::string messageuuid="";
\r
832 lowmessageid=highmessageid=-2;
\r
834 if(command.m_arguments.size()==0)
\r
836 lowmessageid=m_status.m_messageid;
\r
837 highmessageid=m_status.m_messageid;
\r
842 if(command.m_arguments.size()>0 && command.m_arguments[0].find("<")==0 && command.m_arguments[0].find(">")>0)
\r
844 messageuuid=command.m_arguments[0];
\r
845 messageuuid=StringFunctions::Replace(messageuuid,"<","");
\r
846 messageuuid=StringFunctions::Replace(messageuuid,">","");
\r
848 // get rid of @ and everything after
\r
849 if(messageuuid.find("@")!=std::string::npos)
\r
851 messageuuid.erase(messageuuid.find("@"));
\r
855 // single article or range
\r
859 if(command.m_arguments[0].find("-")!=std::string::npos)
\r
861 std::vector<std::string> rangeparts;
\r
862 StringFunctions::Split(command.m_arguments[0],"-",rangeparts);
\r
864 if(rangeparts.size()>0)
\r
866 StringFunctions::Convert(rangeparts[0],lowmessageid);
\r
870 else if(rangeparts.size()>1)
\r
872 StringFunctions::Convert(rangeparts[1],highmessageid);
\r
878 StringFunctions::Convert(command.m_arguments[0],lowmessageid);
\r
883 if(messageuuid!="")
\r
886 if(mess.Load(messageuuid))
\r
888 SendBufferedLine("224 Overview information follows");
\r
889 SendArticleOverInfo(mess);
\r
890 SendBufferedLine(".");
\r
894 SendBufferedLine("423 No such article");
\r
900 if(m_status.m_boardid!=-1 && bd.Load(m_status.m_boardid))
\r
903 if(highmessageid==-2)
\r
906 if(mess.Load(lowmessageid,m_status.m_boardid))
\r
908 SendBufferedLine("224 Overview information follows");
\r
909 SendArticleOverInfo(mess);
\r
910 SendBufferedLine(".");
\r
914 SendBufferedLine("423 No such article in this group");
\r
917 // range with no upper bound
\r
918 else if(highmessageid==-1)
\r
921 ml.LoadRange(lowmessageid,bd.GetHighMessageID(),m_status.m_boardid);
\r
924 SendBufferedLine("224 Overview information follows");
\r
925 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
927 SendArticleOverInfo((*i));
\r
929 SendBufferedLine(".");
\r
933 SendBufferedLine("423 Empty range");
\r
936 // range with upper and lower bound
\r
937 else if(highmessageid>=lowmessageid)
\r
940 ml.LoadRange(lowmessageid,highmessageid,m_status.m_boardid);
\r
943 SendBufferedLine("224 Overview information follows");
\r
944 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
946 SendArticleOverInfo((*i));
\r
948 SendBufferedLine(".");
\r
952 SendBufferedLine("423 Empty range");
\r
958 SendBufferedLine("423 Empty range");
\r
963 SendBufferedLine("423 No newsgroup selected");
\r
971 const bool NNTPConnection::HandlePostCommand(const NNTPCommand &command)
\r
973 if(m_status.m_allowpost==true)
\r
975 SendBufferedLine("340 Send article to be posted");
\r
976 m_status.m_isposting=true;
\r
980 SendBufferedLine("440 Posting not permitted");
\r
986 void NNTPConnection::HandlePostedMessage(const std::string &message)
\r
990 if(mess.ParseNNTPMessage(message))
\r
992 // if we authenticated, set the username to the authenticated user
\r
993 if(m_status.m_authenticated)
\r
995 mess.SetFromName(m_status.m_authuser.GetName());
\r
997 // handle a messages posted to an adminboard
\r
998 if(mess.PostedToAdministrationBoard()==true)
\r
1000 mess.HandleAdministrationMessage();
\r
1002 if(mess.StartFreenetInsert())
\r
1004 SendBufferedLine("240 Article received OK");
\r
1008 SendBufferedLine("441 Posting failed. Make sure the identity you are sending with exists!");
\r
1013 SendBufferedLine("441 Posting failed");
\r
1017 void NNTPConnection::HandleReceivedData()
\r
1019 if(m_status.m_isposting==false)
\r
1021 // get end of command line
\r
1022 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n");
\r
1024 // we got a command
\r
1025 if(endpos!=m_receivebuffer.end())
\r
1027 NNTPCommand command;
\r
1028 std::string commandline(m_receivebuffer.begin(),endpos);
\r
1030 // remove command from receive buffer
\r
1031 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+2);
\r
1033 // remove any leading/trailing whitespace
\r
1034 commandline=StringFunctions::TrimWhitespace(commandline);
\r
1036 // split out command and arguments separated by space or tab
\r
1037 StringFunctions::SplitMultiple(commandline," \t",command.m_arguments);
\r
1039 // command is first element in argument vector
\r
1040 command.m_command=command.m_arguments[0];
\r
1041 // erase command from argument vector and make it upper case
\r
1042 command.m_arguments.erase(command.m_arguments.begin());
\r
1043 StringFunctions::UpperCase(command.m_command,command.m_command);
\r
1045 if(HandleCommand(command)==true)
\r
1051 SendBufferedLine("500 Unknown command");
\r
1053 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleReceivedData received unhandled NNTP command : "+commandline);
\r
1061 // check for end of post
\r
1062 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n.\r\n");
\r
1064 if(endpos!=m_receivebuffer.end())
\r
1066 // get the message
\r
1067 std::string message(m_receivebuffer.begin(),endpos);
\r
1068 // remove from receive buffer
\r
1069 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+5);
\r
1071 // get rid of dot stuffing ( 2 dots on start of a line - used to prevent premature message end in NNTP)
\r
1072 message=StringFunctions::Replace(message,"\r\n..","\r\n.");
\r
1074 HandlePostedMessage(message);
\r
1076 // message was received, so posting is completed
\r
1077 m_status.m_isposting=false;
\r
1083 const bool NNTPConnection::HandleSetTrustCommand(const NNTPCommand &command)
\r
1085 if(command.m_arguments.size()>=3)
\r
1087 std::string type=command.m_arguments[0];
\r
1088 StringFunctions::UpperCase(type,type);
\r
1089 if(type=="MESSAGE" || type=="TRUSTLIST")
\r
1091 if(m_status.m_authenticated)
\r
1096 std::string nntpname="";
\r
1097 for(int i=1; i<command.m_arguments.size()-1; i++)
\r
1099 nntpname+=command.m_arguments[i];
\r
1102 if(command.m_arguments[command.m_arguments.size()-1]!="null")
\r
1104 StringFunctions::Convert(command.m_arguments[command.m_arguments.size()-1],trust);
\r
1107 if(trust>=-1 && trust<=100)
\r
1112 TrustExtension tr(m_status.m_authuser.GetID());
\r
1114 if(type=="MESSAGE")
\r
1116 if(tr.SetMessageTrust(nntpname,trust))
\r
1121 if(type=="TRUSTLIST")
\r
1123 if(tr.SetTrustListTrust(nntpname,trust))
\r
1129 if(found && valid)
\r
1131 SendBufferedLine("280 Trust Set");
\r
1133 else if(found==false)
\r
1135 SendBufferedLine("480 Identity not found");
\r
1139 SendBufferedLine("501 Syntax error");
\r
1145 SendBufferedLine("480 User not authenticated");
\r
1150 SendBufferedLine("501 Syntax error");
\r
1155 SendBufferedLine("501 Syntax error");
\r
1160 const bool NNTPConnection::HandleStatCommand(const NNTPCommand &command)
\r
1162 SendArticleParts(command);
\r
1167 const bool NNTPConnection::HandleQuitCommand(const NNTPCommand &command)
\r
1169 SendBufferedLine("205 Connection Closing");
\r
1172 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::HandleQuitCommand client closed connection");
\r
1176 void NNTPConnection::Run()
\r
1178 struct timeval tv;
\r
1179 fd_set writefs,readfs;
\r
1182 // seed random number generater for this thread
\r
1183 srand(time(NULL));
\r
1185 if(m_status.m_allowpost==true)
\r
1187 SendBufferedLine("200 Service available, posting allowed");
\r
1191 SendBufferedLine("201 Service available, posting prohibited");
\r
1197 FD_ZERO(&writefs);
\r
1199 FD_SET(m_socket,&readfs);
\r
1200 if(m_sendbuffer.size()>0)
\r
1202 FD_SET(m_socket,&writefs);
\r
1208 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
1212 if(FD_ISSET(m_socket,&readfs))
\r
1215 HandleReceivedData();
\r
1217 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1222 else if(rval==SOCKET_ERROR)
\r
1224 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1227 // }while(!Disconnected() && !ZThread::Thread::interrupted());
\r
1228 }while(!Disconnected() && !IsCancelled());
\r
1234 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1236 std::string tempval;
\r
1238 std::map<long,std::string> references;
\r
1240 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1241 line=tempval+"\t";
\r
1242 line+=message.GetSubject()+"\t";
\r
1243 line+=message.GetFromName()+"\t";
\r
1244 line+=message.GetDateTime().Format("%a, %d %b %y %H:%M:%S -0000")+"\t";
\r
1245 line+=message.GetNNTPArticleID()+"\t";
\r
1246 references=message.GetInReplyTo();
\r
1247 if(references.size()>0)
\r
1249 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1251 if(i!=references.rbegin())
\r
1255 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1265 SendBufferedLine(line);
\r
1268 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1270 bool sendheaders,sendbody;
\r
1271 std::string successcode;
\r
1273 if(command.m_command=="ARTICLE")
\r
1277 successcode="220";
\r
1279 else if(command.m_command=="HEAD")
\r
1283 successcode="221";
\r
1285 else if(command.m_command=="BODY")
\r
1287 sendheaders=false;
\r
1289 successcode="222";
\r
1291 else if(command.m_command=="STAT")
\r
1293 sendheaders=false;
\r
1295 successcode="223";
\r
1299 int messageid=m_status.m_messageid;
\r
1300 std::string articleid="";
\r
1301 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1303 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1305 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1307 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1308 message.Load(messageid,m_status.m_boardid);
\r
1309 m_status.m_messageid=message.GetMessageID();
\r
1314 articleid=command.m_arguments[0];
\r
1315 //strip off < and > and everthing after @
\r
1316 if(articleid.size()>0 && articleid[0]=='<')
\r
1318 articleid.erase(0,1);
\r
1320 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1322 articleid.erase(articleid.size()-1);
\r
1325 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1327 articleid.erase(articleid.find('@'));
\r
1330 message.Load(articleid);
\r
1336 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1342 if(m_status.m_boardid!=-1)
\r
1344 if(m_status.m_messageid!=-1)
\r
1346 std::ostringstream tempstr;
\r
1347 std::string article;
\r
1348 if(sendheaders&&sendbody)
\r
1350 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1352 else if(sendheaders && !sendbody)
\r
1354 article=message.GetNNTPHeaders();
\r
1355 // strip off final \r\n from headers
\r
1356 if(article.rfind("\r\n")==article.size()-2)
\r
1358 article.erase(article.size()-2);
\r
1363 article=message.GetNNTPBody();
\r
1365 // dot stuff article
\r
1366 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1368 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1370 SendBufferedLine(tempstr.str());
\r
1371 if(sendheaders || sendbody)
\r
1373 SendBufferedLine(article);
\r
1374 SendBufferedLine(".");
\r
1380 SendBufferedLine("420 Current article number is invalid");
\r
1385 SendBufferedLine("412 No newsgroup selected");
\r
1389 if(m_status.m_boardid!=-1)
\r
1391 if(message.GetMessageID()!=-1)
\r
1393 std::ostringstream tempstr;
\r
1394 std::string article;
\r
1395 if(sendheaders&&sendbody)
\r
1397 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1399 else if(sendheaders && !sendbody)
\r
1401 article=message.GetNNTPHeaders();
\r
1402 // strip off final \r\n from headers
\r
1403 if(article.rfind("\r\n")==article.size()-2)
\r
1405 article.erase(article.size()-2);
\r
1410 article=message.GetNNTPBody();
\r
1412 // dot stuff article
\r
1413 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1415 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1417 SendBufferedLine(tempstr.str());
\r
1418 if(sendheaders || sendbody)
\r
1420 SendBufferedLine(article);
\r
1421 SendBufferedLine(".");
\r
1426 SendBufferedLine("423 No article with that number");
\r
1431 SendBufferedLine("412 No newsgroup selected");
\r
1435 if(message.GetMessageID()!=-1)
\r
1437 std::string article;
\r
1438 if(sendheaders&&sendbody)
\r
1440 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1442 else if(sendheaders && !sendbody)
\r
1444 article=message.GetNNTPHeaders();
\r
1445 // strip off final \r\n from headers
\r
1446 if(article.rfind("\r\n")==article.size()-2)
\r
1448 article.erase(article.size()-2);
\r
1453 article=message.GetNNTPBody();
\r
1455 // dot stuff article
\r
1456 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1458 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1459 if(sendheaders || sendbody)
\r
1461 SendBufferedLine(article);
\r
1462 SendBufferedLine(".");
\r
1467 SendBufferedLine("430 No article with that message-id");
\r
1474 void NNTPConnection::SendBuffered(const std::string &data)
\r
1476 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1479 void NNTPConnection::SocketReceive()
\r
1481 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1484 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1489 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::SocketReceive remote host closed connection");
\r
1493 std::string errnostr;
\r
1494 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1495 // error on receive - close the connection
\r
1497 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1501 void NNTPConnection::SocketSend()
\r
1503 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1505 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1508 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1512 std::string errnostr;
\r
1513 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1514 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r