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")
\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 if(type=="TRUSTLIST")
\r
285 if(tr.GetTrustListTrust(nntpname,trust))
\r
291 if(trust>=0 && found)
\r
293 std::string truststr="";
\r
294 StringFunctions::Convert(trust,truststr);
\r
295 SendBufferedLine("280 "+truststr);
\r
299 SendBufferedLine("281 null");
\r
303 SendBufferedLine("480 Identity not found");
\r
309 SendBufferedLine("480 User not authenticated");
\r
314 SendBufferedLine("501 Syntax error");
\r
319 SendBufferedLine("501 Syntax error");
\r
324 const bool NNTPConnection::HandleGetTrustListCommand(const NNTPCommand &command)
\r
326 if(m_status.m_authenticated)
\r
328 TrustExtension tr(m_status.m_authuser.GetID());
\r
329 std::map<std::string,std::pair<int,int> > trustlist;
\r
330 if(tr.GetTrustList(trustlist))
\r
332 SendBufferedLine("280 Trust list follows");
\r
333 for(std::map<std::string,std::pair<int,int> >::iterator i=trustlist.begin(); i!=trustlist.end(); i++)
\r
335 std::ostringstream tempstr;
\r
336 tempstr << (*i).first << "\t";
\r
337 if((*i).second.first>-1)
\r
339 tempstr << (*i).second.first;
\r
346 if((*i).second.second>-1)
\r
348 tempstr << (*i).second.second;
\r
354 SendBufferedLine(tempstr.str());
\r
356 SendBufferedLine(".");
\r
360 SendBufferedLine("501 Syntax error");
\r
365 SendBufferedLine("480 User not authenticated");
\r
370 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
372 if(command.m_arguments.size()==1)
\r
375 if(board.Load(command.m_arguments[0])==true)
\r
377 std::ostringstream tempstr;
\r
379 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
381 SendBufferedLine(tempstr.str());
\r
383 // set the current boardid to this one
\r
384 m_status.m_boardid=board.GetBoardID();
\r
385 //set the first message id, -1 if there are no messages
\r
386 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
391 SendBufferedLine("411 No such newsgroup");
\r
396 SendBufferedLine("501 Syntax error");
\r
397 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleGroupCommand syntax error");
\r
403 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
406 SendArticleParts(command);
\r
411 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
413 SendBufferedLine("100 Help text follows");
\r
414 SendBufferedLine("There is no help text");
\r
415 SendBufferedLine(".");
\r
420 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
422 if(m_status.m_boardid!=-1)
\r
424 if(m_status.m_messageid!=-1)
\r
428 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
430 std::ostringstream tempstr;
\r
432 m_status.m_messageid=mess.GetMessageID();
\r
434 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
436 SendBufferedLine(tempstr.str());
\r
441 SendBufferedLine("422 No previous article in this group");
\r
446 SendBufferedLine("420 Current article number is invalid");
\r
451 SendBufferedLine("412 No newsgroup selected");
\r
457 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
460 int type=1; // default LIST type is active
\r
461 std::string arg1="";
\r
462 std::string arg2="";
\r
465 if(command.m_arguments.size()>0)
\r
467 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
472 else if(arg1=="NEWSGROUPS")
\r
476 else if(arg1=="OVERVIEW.FMT")
\r
486 if(command.m_arguments.size()>1)
\r
488 arg2=command.m_arguments[1];
\r
491 // LIST ACTIVE [wildmat]
\r
495 std::ostringstream tempstr;
\r
499 SendBufferedLine("215 list of newsgroups follows");
\r
501 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
506 // check wilmat match
\r
509 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
512 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
514 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
515 SendBufferedLine(tempstr.str());
\r
519 SendBufferedLine(".");
\r
526 std::ostringstream tempstr;
\r
530 SendBufferedLine("215 list of newsgroups follows");
\r
532 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
537 // check wilmat match
\r
540 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
543 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
545 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
546 SendBufferedLine(tempstr.str());
\r
550 SendBufferedLine(".");
\r
553 // LIST OVERVIEW.FMT
\r
556 SendBufferedLine("215 Order of fields in overview database.");
\r
557 SendBufferedLine("Subject:");
\r
558 SendBufferedLine("From:");
\r
559 SendBufferedLine("Date:");
\r
560 SendBufferedLine("Message-ID:");
\r
561 SendBufferedLine("References:");
\r
562 SendBufferedLine(":bytes");
\r
563 SendBufferedLine(":lines");
\r
564 SendBufferedLine(".");
\r
569 SendBufferedLine("501 Syntax error");
\r
570 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListCommand unhandled LIST variant");
\r
576 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
579 std::ostringstream tempstr;
\r
581 bool validgroup=false;
\r
585 // no args and invalid boardid
\r
586 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
588 SendBufferedLine("412 No newsgroup selected");
\r
590 else if(command.m_arguments.size()==0)
\r
592 validgroup=board.Load(m_status.m_boardid);
\r
594 else if(command.m_arguments.size()==1)
\r
596 validgroup=board.Load(command.m_arguments[0]);
\r
599 lownum=board.GetLowMessageID();
\r
600 highnum=board.GetHighMessageID();
\r
604 SendBufferedLine("411 No such newsgroup");
\r
607 else if(command.m_arguments.size()==2)
\r
609 validgroup=board.Load(command.m_arguments[0]);
\r
610 std::vector<std::string> rangeparts;
\r
611 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
613 if(rangeparts.size()>0)
\r
615 StringFunctions::Convert(rangeparts[0],lownum);
\r
617 if(rangeparts.size()>1)
\r
619 StringFunctions::Convert(rangeparts[1],highnum);
\r
626 SendBufferedLine("501 Syntax error");
\r
627 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListGroupCommand unknown arguments");
\r
633 // set boardid and messageid
\r
634 m_status.m_boardid=board.GetBoardID();
\r
635 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
639 lownum=board.GetLowMessageID();
\r
643 highnum=board.GetHighMessageID();
\r
646 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
647 SendBufferedLine(tempstr.str());
\r
650 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
652 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
655 tempstr << (*i).GetMessageID();
\r
657 SendBufferedLine(tempstr.str());
\r
660 // end of multi-line response
\r
661 SendBufferedLine(".");
\r
668 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
670 if(command.m_arguments.size()>0)
\r
672 std::string arg=command.m_arguments[0];
\r
673 StringFunctions::UpperCase(arg,arg);
\r
676 m_status.m_mode=MODE_READER;
\r
677 if(m_status.m_allowpost==true)
\r
679 SendBufferedLine("200 Posting allowed");
\r
683 SendBufferedLine("201 Posting prohibited");
\r
686 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand set mode to reader");
\r
690 SendBufferedLine("501 Syntax error");
\r
691 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
696 SendBufferedLine("501 Syntax error");
\r
697 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
703 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
705 if(command.m_arguments.size()>=2)
\r
709 if(command.m_arguments[0].size()==8)
\r
711 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempint);
\r
712 date.SetYear(tempint);
\r
713 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
714 date.SetMonth(tempint);
\r
715 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempint);
\r
716 date.SetDay(tempint);
\r
722 If the first two digits of the year are not specified
\r
723 (this is supported only for backward compatibility), the year is to
\r
724 be taken from the current century if yy is smaller than or equal to
\r
725 the current year, and the previous century otherwise.
\r
730 century=now.GetYear()-(now.GetYear()%100);
\r
732 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempint);
\r
733 tempint<=now.GetYear()-century ? tempint+=century : tempint+=(century-100);
\r
735 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
737 date.SetYear(tempint);
\r
738 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempint);
\r
739 date.SetMonth(tempint);
\r
740 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
741 date.SetDay(tempint);
\r
748 bl.LoadNew(date.Format("%Y-%m-%d %H:%M:%S"));
\r
750 SendBufferedLine("231 List of new newsgroups follows");
\r
752 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
754 if((*i).GetSaveReceivedMessages()==true)
\r
756 std::ostringstream tempstr;
\r
757 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << m_status.m_allowpost ? "y" : "n";
\r
758 SendBufferedLine(tempstr.str());
\r
762 SendBufferedLine(".");
\r
767 SendBufferedLine("501 Syntax error");
\r
768 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleNewGroupsCommand syntax error");
\r
775 const bool NNTPConnection::HandleNextCommand(const NNTPCommand &command)
\r
777 if(m_status.m_boardid!=-1)
\r
779 if(m_status.m_messageid!=-1)
\r
783 if(mess.LoadNext(m_status.m_messageid,m_status.m_boardid))
\r
785 std::ostringstream tempstr;
\r
787 m_status.m_messageid=mess.GetMessageID();
\r
789 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
791 SendBufferedLine(tempstr.str());
\r
796 SendBufferedLine("421 No next article in this group");
\r
801 SendBufferedLine("420 Current article number is invalid");
\r
806 SendBufferedLine("412 No newsgroup selected");
\r
813 const bool NNTPConnection::HandleOverCommand(const NNTPCommand &command)
\r
815 long lowmessageid,highmessageid;
\r
816 std::string messageuuid="";
\r
818 lowmessageid=highmessageid=-2;
\r
820 if(command.m_arguments.size()==0)
\r
822 lowmessageid=m_status.m_messageid;
\r
823 highmessageid=m_status.m_messageid;
\r
828 if(command.m_arguments.size()>0 && command.m_arguments[0].find("<")==0 && command.m_arguments[0].find(">")>0)
\r
830 messageuuid=command.m_arguments[0];
\r
831 messageuuid=StringFunctions::Replace(messageuuid,"<","");
\r
832 messageuuid=StringFunctions::Replace(messageuuid,">","");
\r
834 // get rid of @ and everything after
\r
835 if(messageuuid.find("@")!=std::string::npos)
\r
837 messageuuid.erase(messageuuid.find("@"));
\r
841 // single article or range
\r
845 if(command.m_arguments[0].find("-")!=std::string::npos)
\r
847 std::vector<std::string> rangeparts;
\r
848 StringFunctions::Split(command.m_arguments[0],"-",rangeparts);
\r
850 if(rangeparts.size()>0)
\r
852 StringFunctions::Convert(rangeparts[0],lowmessageid);
\r
856 else if(rangeparts.size()>1)
\r
858 StringFunctions::Convert(rangeparts[1],highmessageid);
\r
864 StringFunctions::Convert(command.m_arguments[0],lowmessageid);
\r
869 if(messageuuid!="")
\r
872 if(mess.Load(messageuuid))
\r
874 SendBufferedLine("224 Overview information follows");
\r
875 SendArticleOverInfo(mess);
\r
876 SendBufferedLine(".");
\r
880 SendBufferedLine("423 No such article");
\r
886 if(m_status.m_boardid!=-1 && bd.Load(m_status.m_boardid))
\r
889 if(highmessageid==-2)
\r
892 if(mess.Load(lowmessageid,m_status.m_boardid))
\r
894 SendBufferedLine("224 Overview information follows");
\r
895 SendArticleOverInfo(mess);
\r
896 SendBufferedLine(".");
\r
900 SendBufferedLine("423 No such article in this group");
\r
903 // range with no upper bound
\r
904 else if(highmessageid==-1)
\r
907 ml.LoadRange(lowmessageid,bd.GetHighMessageID(),m_status.m_boardid);
\r
910 SendBufferedLine("224 Overview information follows");
\r
911 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
913 SendArticleOverInfo((*i));
\r
915 SendBufferedLine(".");
\r
919 SendBufferedLine("423 Empty range");
\r
922 // range with upper and lower bound
\r
923 else if(highmessageid>=lowmessageid)
\r
926 ml.LoadRange(lowmessageid,highmessageid,m_status.m_boardid);
\r
929 SendBufferedLine("224 Overview information follows");
\r
930 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
932 SendArticleOverInfo((*i));
\r
934 SendBufferedLine(".");
\r
938 SendBufferedLine("423 Empty range");
\r
944 SendBufferedLine("423 Empty range");
\r
949 SendBufferedLine("423 No newsgroup selected");
\r
957 const bool NNTPConnection::HandlePostCommand(const NNTPCommand &command)
\r
959 if(m_status.m_allowpost==true)
\r
961 SendBufferedLine("340 Send article to be posted");
\r
962 m_status.m_isposting=true;
\r
966 SendBufferedLine("440 Posting not permitted");
\r
972 void NNTPConnection::HandlePostedMessage(const std::string &message)
\r
976 if(mess.ParseNNTPMessage(message))
\r
978 // if we authenticated, set the username to the authenticated user
\r
979 if(m_status.m_authenticated)
\r
981 mess.SetFromName(m_status.m_authuser.GetName());
\r
983 // handle a messages posted to an adminboard
\r
984 if(mess.PostedToAdministrationBoard()==true)
\r
986 mess.HandleAdministrationMessage();
\r
988 if(mess.StartFreenetInsert())
\r
990 SendBufferedLine("240 Article received OK");
\r
994 SendBufferedLine("441 Posting failed. Make sure the identity you are sending with exists!");
\r
999 SendBufferedLine("441 Posting failed");
\r
1003 void NNTPConnection::HandleReceivedData()
\r
1005 if(m_status.m_isposting==false)
\r
1007 // get end of command line
\r
1008 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n");
\r
1010 // we got a command
\r
1011 if(endpos!=m_receivebuffer.end())
\r
1013 NNTPCommand command;
\r
1014 std::string commandline(m_receivebuffer.begin(),endpos);
\r
1016 // remove command from receive buffer
\r
1017 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+2);
\r
1019 // remove any leading/trailing whitespace
\r
1020 commandline=StringFunctions::TrimWhitespace(commandline);
\r
1022 // split out command and arguments separated by space or tab
\r
1023 StringFunctions::SplitMultiple(commandline," \t",command.m_arguments);
\r
1025 // command is first element in argument vector
\r
1026 command.m_command=command.m_arguments[0];
\r
1027 // erase command from argument vector and make it upper case
\r
1028 command.m_arguments.erase(command.m_arguments.begin());
\r
1029 StringFunctions::UpperCase(command.m_command,command.m_command);
\r
1031 if(HandleCommand(command)==true)
\r
1037 SendBufferedLine("500 Unknown command");
\r
1039 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleReceivedData received unhandled NNTP command : "+commandline);
\r
1047 // check for end of post
\r
1048 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n.\r\n");
\r
1050 if(endpos!=m_receivebuffer.end())
\r
1052 // get the message
\r
1053 std::string message(m_receivebuffer.begin(),endpos);
\r
1054 // remove from receive buffer
\r
1055 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+5);
\r
1057 // get rid of dot stuffing ( 2 dots on start of a line - used to prevent premature message end in NNTP)
\r
1058 message=StringFunctions::Replace(message,"\r\n..","\r\n.");
\r
1060 HandlePostedMessage(message);
\r
1062 // message was received, so posting is completed
\r
1063 m_status.m_isposting=false;
\r
1069 const bool NNTPConnection::HandleSetTrustCommand(const NNTPCommand &command)
\r
1071 if(command.m_arguments.size()>=3)
\r
1073 std::string type=command.m_arguments[0];
\r
1074 StringFunctions::UpperCase(type,type);
\r
1075 if(type=="MESSAGE" || type=="TRUSTLIST")
\r
1077 if(m_status.m_authenticated)
\r
1082 std::string nntpname="";
\r
1083 for(int i=1; i<command.m_arguments.size()-1; i++)
\r
1085 nntpname+=command.m_arguments[i];
\r
1088 if(command.m_arguments[command.m_arguments.size()-1]!="null")
\r
1090 StringFunctions::Convert(command.m_arguments[command.m_arguments.size()-1],trust);
\r
1093 if(trust>=-1 && trust<=100)
\r
1098 TrustExtension tr(m_status.m_authuser.GetID());
\r
1100 if(type=="MESSAGE")
\r
1102 if(tr.SetMessageTrust(nntpname,trust))
\r
1107 if(type=="TRUSTLIST")
\r
1109 if(tr.SetTrustListTrust(nntpname,trust))
\r
1115 if(found && valid)
\r
1117 SendBufferedLine("280 Trust Set");
\r
1119 else if(found==false)
\r
1121 SendBufferedLine("480 Identity not found");
\r
1125 SendBufferedLine("501 Syntax error");
\r
1131 SendBufferedLine("480 User not authenticated");
\r
1136 SendBufferedLine("501 Syntax error");
\r
1141 SendBufferedLine("501 Syntax error");
\r
1146 const bool NNTPConnection::HandleStatCommand(const NNTPCommand &command)
\r
1148 SendArticleParts(command);
\r
1153 const bool NNTPConnection::HandleQuitCommand(const NNTPCommand &command)
\r
1155 SendBufferedLine("205 Connection Closing");
\r
1158 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::HandleQuitCommand client closed connection");
\r
1162 void NNTPConnection::Run()
\r
1164 struct timeval tv;
\r
1165 fd_set writefs,readfs;
\r
1168 // seed random number generater for this thread
\r
1169 srand(time(NULL));
\r
1171 if(m_status.m_allowpost==true)
\r
1173 SendBufferedLine("200 Service available, posting allowed");
\r
1177 SendBufferedLine("201 Service available, posting prohibited");
\r
1183 FD_ZERO(&writefs);
\r
1185 FD_SET(m_socket,&readfs);
\r
1186 if(m_sendbuffer.size()>0)
\r
1188 FD_SET(m_socket,&writefs);
\r
1194 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
1198 if(FD_ISSET(m_socket,&readfs))
\r
1201 HandleReceivedData();
\r
1203 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1208 else if(rval==SOCKET_ERROR)
\r
1210 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1213 // }while(!Disconnected() && !ZThread::Thread::interrupted());
\r
1214 }while(!Disconnected() && !IsCancelled());
\r
1220 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1222 std::string tempval;
\r
1224 std::map<long,std::string> references;
\r
1226 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1227 line=tempval+"\t";
\r
1228 line+=message.GetSubject()+"\t";
\r
1229 line+=message.GetFromName()+"\t";
\r
1230 line+=message.GetDateTime().Format("%a, %d %b %y %H:%M:%S -0000")+"\t";
\r
1231 line+=message.GetNNTPArticleID()+"\t";
\r
1232 references=message.GetInReplyTo();
\r
1233 if(references.size()>0)
\r
1235 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1237 if(i!=references.rbegin())
\r
1241 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1251 SendBufferedLine(line);
\r
1254 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1256 bool sendheaders,sendbody;
\r
1257 std::string successcode;
\r
1259 if(command.m_command=="ARTICLE")
\r
1263 successcode="220";
\r
1265 else if(command.m_command=="HEAD")
\r
1269 successcode="221";
\r
1271 else if(command.m_command=="BODY")
\r
1273 sendheaders=false;
\r
1275 successcode="222";
\r
1277 else if(command.m_command=="STAT")
\r
1279 sendheaders=false;
\r
1281 successcode="223";
\r
1285 int messageid=m_status.m_messageid;
\r
1286 std::string articleid="";
\r
1287 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1289 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1291 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1293 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1294 message.Load(messageid,m_status.m_boardid);
\r
1295 m_status.m_messageid=message.GetMessageID();
\r
1300 articleid=command.m_arguments[0];
\r
1301 //strip off < and > and everthing after @
\r
1302 if(articleid.size()>0 && articleid[0]=='<')
\r
1304 articleid.erase(0,1);
\r
1306 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1308 articleid.erase(articleid.size()-1);
\r
1311 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1313 articleid.erase(articleid.find('@'));
\r
1316 message.Load(articleid);
\r
1322 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1328 if(m_status.m_boardid!=-1)
\r
1330 if(m_status.m_messageid!=-1)
\r
1332 std::ostringstream tempstr;
\r
1333 std::string article;
\r
1334 if(sendheaders&&sendbody)
\r
1336 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1338 else if(sendheaders && !sendbody)
\r
1340 article=message.GetNNTPHeaders();
\r
1341 // strip off final \r\n from headers
\r
1342 if(article.rfind("\r\n")==article.size()-2)
\r
1344 article.erase(article.size()-2);
\r
1349 article=message.GetNNTPBody();
\r
1351 // dot stuff article
\r
1352 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1354 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1356 SendBufferedLine(tempstr.str());
\r
1357 if(sendheaders || sendbody)
\r
1359 SendBufferedLine(article);
\r
1360 SendBufferedLine(".");
\r
1366 SendBufferedLine("420 Current article number is invalid");
\r
1371 SendBufferedLine("412 No newsgroup selected");
\r
1375 if(m_status.m_boardid!=-1)
\r
1377 if(message.GetMessageID()!=-1)
\r
1379 std::ostringstream tempstr;
\r
1380 std::string article;
\r
1381 if(sendheaders&&sendbody)
\r
1383 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1385 else if(sendheaders && !sendbody)
\r
1387 article=message.GetNNTPHeaders();
\r
1388 // strip off final \r\n from headers
\r
1389 if(article.rfind("\r\n")==article.size()-2)
\r
1391 article.erase(article.size()-2);
\r
1396 article=message.GetNNTPBody();
\r
1398 // dot stuff article
\r
1399 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1401 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1403 SendBufferedLine(tempstr.str());
\r
1404 if(sendheaders || sendbody)
\r
1406 SendBufferedLine(article);
\r
1407 SendBufferedLine(".");
\r
1412 SendBufferedLine("423 No article with that number");
\r
1417 SendBufferedLine("412 No newsgroup selected");
\r
1421 if(message.GetMessageID()!=-1)
\r
1423 std::string article;
\r
1424 if(sendheaders&&sendbody)
\r
1426 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1428 else if(sendheaders && !sendbody)
\r
1430 article=message.GetNNTPHeaders();
\r
1431 // strip off final \r\n from headers
\r
1432 if(article.rfind("\r\n")==article.size()-2)
\r
1434 article.erase(article.size()-2);
\r
1439 article=message.GetNNTPBody();
\r
1441 // dot stuff article
\r
1442 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1444 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1445 if(sendheaders || sendbody)
\r
1447 SendBufferedLine(article);
\r
1448 SendBufferedLine(".");
\r
1453 SendBufferedLine("430 No article with that message-id");
\r
1460 void NNTPConnection::SendBuffered(const std::string &data)
\r
1462 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1465 void NNTPConnection::SocketReceive()
\r
1467 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1470 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1475 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::SocketReceive remote host closed connection");
\r
1479 std::string errnostr;
\r
1480 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1481 // error on receive - close the connection
\r
1483 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1487 void NNTPConnection::SocketSend()
\r
1489 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1491 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1494 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1498 std::string errnostr;
\r
1499 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1500 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r