1 #include "../../include/nntp/nntpconnection.h"
\r
2 #include "../../include/nntp/uwildmat.h"
\r
3 #include "../../include/stringfunctions.h"
\r
4 #include "../../include/boardlist.h"
\r
5 #include "../../include/message.h"
\r
6 #include "../../include/messagelist.h"
\r
7 #include "../../include/option.h"
\r
8 #include "../../include/nntp/extensiontrust.h"
\r
9 #include "../../include/threadwrapper/cancelablethread.h"
\r
11 #include <algorithm>
\r
12 #include <Poco/DateTime.h>
\r
13 #include <Poco/DateTimeFormatter.h>
\r
14 #include <Poco/Timestamp.h>
\r
20 NNTPConnection::NNTPConnection(SOCKET sock):m_socket(sock)
\r
22 std::string tempval("");
\r
24 m_tempbuffer.resize(32768);
\r
26 m_status.m_isposting=false;
\r
27 m_status.m_allowpost=false;
\r
28 m_status.m_boardid=-1;
\r
29 m_status.m_messageid=-1;
\r
30 m_status.m_mode=MODE_NONE;
\r
31 m_status.m_authenticated=false;
\r
33 Option::Instance()->Get("NNTPAllowPost",tempval);
\r
36 m_status.m_allowpost=true;
\r
41 NNTPConnection::~NNTPConnection()
\r
46 void NNTPConnection::Disconnect()
\r
48 if(m_socket!=INVALID_SOCKET)
\r
51 closesocket(m_socket);
\r
55 m_socket=INVALID_SOCKET;
\r
59 std::vector<char>::iterator NNTPConnection::Find(std::vector<char> &buffer, const std::string &val)
\r
61 return std::search(buffer.begin(),buffer.end(),val.begin(),val.end());
\r
64 const bool NNTPConnection::HandleArticleCommand(const NNTPCommand &command)
\r
67 SendArticleParts(command);
\r
72 const bool NNTPConnection::HandleAuthInfoCommand(const NNTPCommand &command)
\r
74 if(command.m_arguments.size()<2)
\r
76 SendBufferedLine("501 Syntax error");
\r
78 else if(m_status.m_authenticated==true)
\r
80 SendBufferedLine("502 Command unavailable"); // not available when already authenticated
\r
84 std::string arg=command.m_arguments[0];
\r
85 StringFunctions::UpperCase(arg,arg);
\r
86 std::string name="";
\r
87 // get remaining args as part of the name since a name might have a space and the args are split on spaces
\r
88 for(std::vector<std::string>::const_iterator i=command.m_arguments.begin()+1; i!=command.m_arguments.end(); i++)
\r
90 // we split on the space, so add it back
\r
91 if(i!=command.m_arguments.begin()+1)
\r
99 LocalIdentity localid;
\r
100 if(localid.Load(name))
\r
102 m_status.m_authuser=localid;
\r
103 m_status.m_authenticated=true;
\r
104 SendBufferedLine("281 Authentication accepted");
\r
108 SendBufferedLine("481 Authentication failed");
\r
111 else if(arg=="PASS")
\r
113 SendBufferedLine("482 Authentication commands issued out of sequence"); // only require username
\r
117 SendBufferedLine("501 Syntax error");
\r
124 const bool NNTPConnection::HandleBodyCommand(const NNTPCommand &command)
\r
126 SendArticleParts(command);
\r
131 const bool NNTPConnection::HandleCapabilitiesCommand(const NNTPCommand &command)
\r
134 SendBufferedLine("101 Capability list :");
\r
135 SendBufferedLine("VERSION 2");
\r
136 if(m_status.m_authenticated==false) // RFC 4643 2.2 0 - don't advertise MODE-READER after authentication
\r
138 SendBufferedLine("MODE-READER");
\r
140 SendBufferedLine("READER");
\r
141 SendBufferedLine("LIST OVERVIEW.FMT");
\r
142 SendBufferedLine("OVER MSGID");
\r
143 if(m_status.m_allowpost==true)
\r
145 SendBufferedLine("POST");
\r
147 if(m_status.m_authenticated==false)
\r
149 SendBufferedLine("AUTHINFO USER");
\r
151 SendBufferedLine("XFMSTRUST");
\r
152 SendBufferedLine(".");
\r
157 const bool NNTPConnection::HandleCommand(const NNTPCommand &command)
\r
159 if(command.m_command=="QUIT")
\r
161 return HandleQuitCommand(command);
\r
163 if(command.m_command=="MODE")
\r
165 return HandleModeCommand(command);
\r
167 if(command.m_command=="CAPABILITIES")
\r
169 return HandleCapabilitiesCommand(command);
\r
171 if(command.m_command=="HELP")
\r
173 return HandleHelpCommand(command);
\r
175 if(command.m_command=="DATE")
\r
177 return HandleDateCommand(command);
\r
179 if(command.m_command=="LIST")
\r
181 return HandleListCommand(command);
\r
183 if(command.m_command=="GROUP")
\r
185 return HandleGroupCommand(command);
\r
187 if(command.m_command=="LISTGROUP")
\r
189 return HandleListGroupCommand(command);
\r
191 if(command.m_command=="LAST")
\r
193 return HandleLastCommand(command);
\r
195 if(command.m_command=="NEXT")
\r
197 return HandleNextCommand(command);
\r
199 if(command.m_command=="ARTICLE")
\r
201 return HandleArticleCommand(command);
\r
203 if(command.m_command=="HEAD")
\r
205 return HandleHeadCommand(command);
\r
207 if(command.m_command=="BODY")
\r
209 return HandleBodyCommand(command);
\r
211 if(command.m_command=="STAT")
\r
213 return HandleStatCommand(command);
\r
215 if(command.m_command=="NEWGROUPS")
\r
217 return HandleNewGroupsCommand(command);
\r
219 if(command.m_command=="POST")
\r
221 return HandlePostCommand(command);
\r
223 if(command.m_command=="OVER" || command.m_command=="XOVER")
\r
225 return HandleOverCommand(command);
\r
227 if(command.m_command=="AUTHINFO")
\r
229 return HandleAuthInfoCommand(command);
\r
231 if(command.m_command=="XGETTRUST")
\r
233 return HandleGetTrustCommand(command);
\r
235 if(command.m_command=="XSETTRUST")
\r
237 return HandleSetTrustCommand(command);
\r
239 if(command.m_command=="XGETTRUSTLIST")
\r
241 return HandleGetTrustListCommand(command);
\r
247 const bool NNTPConnection::HandleDateCommand(const NNTPCommand &command)
\r
249 Poco::DateTime now;
\r
250 SendBufferedLine("111 "+Poco::DateTimeFormatter::format(now,"%Y%m%d%H%M%S"));
\r
254 const bool NNTPConnection::HandleGetTrustCommand(const NNTPCommand &command)
\r
256 if(command.m_arguments.size()>=2)
\r
258 std::string type=command.m_arguments[0];
\r
259 StringFunctions::UpperCase(type,type);
\r
260 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="PEERMESSAGE" || type=="PEERTRUSTLIST")
\r
262 if(m_status.m_authenticated)
\r
266 std::string nntpname="";
\r
267 for(int i=1; i<command.m_arguments.size(); i++)
\r
273 nntpname+=command.m_arguments[i];
\r
276 TrustExtension tr(m_status.m_authuser.GetID());
\r
278 if(type=="MESSAGE")
\r
280 if(tr.GetMessageTrust(nntpname,trust))
\r
285 else if(type=="TRUSTLIST")
\r
287 if(tr.GetTrustListTrust(nntpname,trust))
\r
292 else if(type=="PEERMESSAGE")
\r
294 if(tr.GetPeerMessageTrust(nntpname,trust))
\r
299 else if(type=="PEERTRUSTLIST")
\r
301 if(tr.GetPeerTrustListTrust(nntpname,trust))
\r
307 if(trust>=0 && found)
\r
309 std::string truststr="";
\r
310 StringFunctions::Convert(trust,truststr);
\r
311 SendBufferedLine("280 "+truststr);
\r
315 SendBufferedLine("281 null");
\r
319 SendBufferedLine("480 Identity not found");
\r
325 SendBufferedLine("480 User not authenticated");
\r
330 SendBufferedLine("501 Syntax error");
\r
335 SendBufferedLine("501 Syntax error");
\r
340 const bool NNTPConnection::HandleGetTrustListCommand(const NNTPCommand &command)
\r
342 if(m_status.m_authenticated)
\r
344 TrustExtension tr(m_status.m_authuser.GetID());
\r
345 std::map<std::string,TrustExtension::trust> trustlist;
\r
346 if(tr.GetTrustList(trustlist))
\r
348 SendBufferedLine("280 Trust list follows");
\r
349 for(std::map<std::string,TrustExtension::trust>::iterator i=trustlist.begin(); i!=trustlist.end(); i++)
\r
351 std::ostringstream tempstr;
\r
352 tempstr << (*i).first << "\t";
\r
353 if((*i).second.m_localmessagetrust>-1)
\r
355 tempstr << (*i).second.m_localmessagetrust;
\r
362 if((*i).second.m_localtrustlisttrust>-1)
\r
364 tempstr << (*i).second.m_localtrustlisttrust;
\r
371 if((*i).second.m_peermessagetrust>-1)
\r
373 tempstr << (*i).second.m_peermessagetrust;
\r
380 if((*i).second.m_peertrustlisttrust>-1)
\r
382 tempstr << (*i).second.m_peertrustlisttrust;
\r
389 tempstr << (*i).second.m_messagetrustcomment;
\r
391 tempstr << (*i).second.m_trustlisttrustcomment;
\r
393 SendBufferedLine(tempstr.str());
\r
395 SendBufferedLine(".");
\r
399 SendBufferedLine("501 Syntax error");
\r
404 SendBufferedLine("480 User not authenticated");
\r
409 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
411 if(command.m_arguments.size()==1)
\r
414 if(board.Load(command.m_arguments[0])==true)
\r
416 std::ostringstream tempstr;
\r
418 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
420 SendBufferedLine(tempstr.str());
\r
422 // set the current boardid to this one
\r
423 m_status.m_boardid=board.GetBoardID();
\r
424 //set the first message id, -1 if there are no messages
\r
425 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
430 SendBufferedLine("411 No such newsgroup");
\r
435 SendBufferedLine("501 Syntax error");
\r
436 m_log->debug("NNTPConnection::HandleGroupCommand syntax error");
\r
442 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
445 SendArticleParts(command);
\r
450 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
452 SendBufferedLine("100 Help text follows");
\r
453 SendBufferedLine("There is no help text");
\r
454 SendBufferedLine(".");
\r
459 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
461 if(m_status.m_boardid!=-1)
\r
463 if(m_status.m_messageid!=-1)
\r
467 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
469 std::ostringstream tempstr;
\r
471 m_status.m_messageid=mess.GetMessageID();
\r
473 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
475 SendBufferedLine(tempstr.str());
\r
480 SendBufferedLine("422 No previous article in this group");
\r
485 SendBufferedLine("420 Current article number is invalid");
\r
490 SendBufferedLine("412 No newsgroup selected");
\r
496 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
499 int type=1; // default LIST type is active
\r
500 std::string arg1="";
\r
501 std::string arg2="";
\r
504 if(command.m_arguments.size()>0)
\r
506 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
511 else if(arg1=="NEWSGROUPS")
\r
515 else if(arg1=="OVERVIEW.FMT")
\r
525 if(command.m_arguments.size()>1)
\r
527 arg2=command.m_arguments[1];
\r
530 // LIST ACTIVE [wildmat]
\r
534 std::ostringstream tempstr;
\r
538 SendBufferedLine("215 list of newsgroups follows");
\r
540 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
545 // check wilmat match
\r
548 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
551 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
553 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
554 SendBufferedLine(tempstr.str());
\r
558 SendBufferedLine(".");
\r
565 std::ostringstream tempstr;
\r
569 SendBufferedLine("215 list of newsgroups follows");
\r
571 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
576 // check wilmat match
\r
579 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
582 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
584 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
585 SendBufferedLine(tempstr.str());
\r
589 SendBufferedLine(".");
\r
592 // LIST OVERVIEW.FMT
\r
595 SendBufferedLine("215 Order of fields in overview database.");
\r
596 SendBufferedLine("Subject:");
\r
597 SendBufferedLine("From:");
\r
598 SendBufferedLine("Date:");
\r
599 SendBufferedLine("Message-ID:");
\r
600 SendBufferedLine("References:");
\r
601 SendBufferedLine(":bytes");
\r
602 SendBufferedLine(":lines");
\r
603 SendBufferedLine(".");
\r
608 SendBufferedLine("501 Syntax error");
\r
609 m_log->debug("NNTPConnection::HandleListCommand unhandled LIST variant");
\r
615 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
618 std::ostringstream tempstr;
\r
620 bool validgroup=false;
\r
624 // no args and invalid boardid
\r
625 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
627 SendBufferedLine("412 No newsgroup selected");
\r
629 else if(command.m_arguments.size()==0)
\r
631 validgroup=board.Load(m_status.m_boardid);
\r
633 else if(command.m_arguments.size()==1)
\r
635 validgroup=board.Load(command.m_arguments[0]);
\r
638 lownum=board.GetLowMessageID();
\r
639 highnum=board.GetHighMessageID();
\r
643 SendBufferedLine("411 No such newsgroup");
\r
646 else if(command.m_arguments.size()==2)
\r
648 validgroup=board.Load(command.m_arguments[0]);
\r
649 std::vector<std::string> rangeparts;
\r
650 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
652 if(rangeparts.size()>0)
\r
654 StringFunctions::Convert(rangeparts[0],lownum);
\r
656 if(rangeparts.size()>1)
\r
658 StringFunctions::Convert(rangeparts[1],highnum);
\r
665 SendBufferedLine("501 Syntax error");
\r
666 m_log->debug("NNTPConnection::HandleListGroupCommand unknown arguments");
\r
672 // set boardid and messageid
\r
673 m_status.m_boardid=board.GetBoardID();
\r
674 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
678 lownum=board.GetLowMessageID();
\r
682 highnum=board.GetHighMessageID();
\r
685 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
686 SendBufferedLine(tempstr.str());
\r
689 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
691 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
694 tempstr << (*i).GetMessageID();
\r
696 SendBufferedLine(tempstr.str());
\r
699 // end of multi-line response
\r
700 SendBufferedLine(".");
\r
707 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
709 if(command.m_arguments.size()>0)
\r
711 std::string arg=command.m_arguments[0];
\r
712 StringFunctions::UpperCase(arg,arg);
\r
715 m_status.m_mode=MODE_READER;
\r
716 if(m_status.m_allowpost==true)
\r
718 SendBufferedLine("200 Posting allowed");
\r
722 SendBufferedLine("201 Posting prohibited");
\r
725 m_log->debug("NNTPConnection::HandleModeCommand set mode to reader");
\r
729 SendBufferedLine("501 Syntax error");
\r
730 m_log->debug("NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
735 SendBufferedLine("501 Syntax error");
\r
736 m_log->debug("NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
742 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
744 if(command.m_arguments.size()>=2)
\r
746 Poco::DateTime date;
\r
750 if(command.m_arguments[0].size()==8)
\r
752 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempyear);
\r
753 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempmonth);
\r
754 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempday);
\r
757 date.assign(tempyear,tempmonth,tempday,date.hour(),date.minute(),date.second());
\r
761 m_log->fatal("NNTPConnection::HandleNewGroupsCommand error assigning date");
\r
768 If the first two digits of the year are not specified
\r
769 (this is supported only for backward compatibility), the year is to
\r
770 be taken from the current century if yy is smaller than or equal to
\r
771 the current year, and the previous century otherwise.
\r
774 Poco::DateTime now;
\r
775 century=now.year()-(now.year()%100);
\r
777 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempyear);
\r
778 tempyear<=now.year()-century ? tempyear+=century : tempyear+=(century-100);
\r
780 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
782 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempmonth);
\r
783 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempday);
\r
786 date.assign(tempyear,tempmonth,tempday);
\r
790 m_log->fatal("NNTPConnection::HandleNewGroupsCommand error assigning date");
\r
796 bl.LoadNew(Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));
\r
798 SendBufferedLine("231 List of new newsgroups follows");
\r
800 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
802 if((*i).GetSaveReceivedMessages()==true)
\r
804 std::ostringstream tempstr;
\r
805 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << m_status.m_allowpost ? "y" : "n";
\r
806 SendBufferedLine(tempstr.str());
\r
810 SendBufferedLine(".");
\r
815 SendBufferedLine("501 Syntax error");
\r
816 m_log->debug("NNTPConnection::HandleNewGroupsCommand syntax error");
\r
823 const bool NNTPConnection::HandleNextCommand(const NNTPCommand &command)
\r
825 if(m_status.m_boardid!=-1)
\r
827 if(m_status.m_messageid!=-1)
\r
831 if(mess.LoadNext(m_status.m_messageid,m_status.m_boardid))
\r
833 std::ostringstream tempstr;
\r
835 m_status.m_messageid=mess.GetMessageID();
\r
837 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
839 SendBufferedLine(tempstr.str());
\r
844 SendBufferedLine("421 No next article in this group");
\r
849 SendBufferedLine("420 Current article number is invalid");
\r
854 SendBufferedLine("412 No newsgroup selected");
\r
861 const bool NNTPConnection::HandleOverCommand(const NNTPCommand &command)
\r
863 long lowmessageid,highmessageid;
\r
864 std::string messageuuid="";
\r
866 lowmessageid=highmessageid=-2;
\r
868 if(command.m_arguments.size()==0)
\r
870 lowmessageid=m_status.m_messageid;
\r
871 highmessageid=m_status.m_messageid;
\r
876 if(command.m_arguments.size()>0 && command.m_arguments[0].find("<")==0 && command.m_arguments[0].find(">")>0)
\r
878 messageuuid=command.m_arguments[0];
\r
879 messageuuid=StringFunctions::Replace(messageuuid,"<","");
\r
880 messageuuid=StringFunctions::Replace(messageuuid,">","");
\r
882 // get rid of @ and everything after
\r
883 if(messageuuid.find("@")!=std::string::npos)
\r
885 messageuuid.erase(messageuuid.find("@"));
\r
889 // single article or range
\r
893 if(command.m_arguments[0].find("-")!=std::string::npos)
\r
895 std::vector<std::string> rangeparts;
\r
896 StringFunctions::Split(command.m_arguments[0],"-",rangeparts);
\r
898 if(rangeparts.size()>0)
\r
900 StringFunctions::Convert(rangeparts[0],lowmessageid);
\r
904 else if(rangeparts.size()>1)
\r
906 StringFunctions::Convert(rangeparts[1],highmessageid);
\r
912 StringFunctions::Convert(command.m_arguments[0],lowmessageid);
\r
917 if(messageuuid!="")
\r
920 if(mess.Load(messageuuid))
\r
922 SendBufferedLine("224 Overview information follows");
\r
923 SendArticleOverInfo(mess);
\r
924 SendBufferedLine(".");
\r
928 SendBufferedLine("423 No such article");
\r
934 if(m_status.m_boardid!=-1 && bd.Load(m_status.m_boardid))
\r
937 if(highmessageid==-2)
\r
940 if(mess.Load(lowmessageid,m_status.m_boardid))
\r
942 SendBufferedLine("224 Overview information follows");
\r
943 SendArticleOverInfo(mess);
\r
944 SendBufferedLine(".");
\r
948 SendBufferedLine("423 No such article in this group");
\r
951 // range with no upper bound
\r
952 else if(highmessageid==-1)
\r
955 ml.LoadRange(lowmessageid,bd.GetHighMessageID(),m_status.m_boardid);
\r
958 SendBufferedLine("224 Overview information follows");
\r
959 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
961 SendArticleOverInfo((*i));
\r
963 SendBufferedLine(".");
\r
967 SendBufferedLine("423 Empty range");
\r
970 // range with upper and lower bound
\r
971 else if(highmessageid>=lowmessageid)
\r
974 ml.LoadRange(lowmessageid,highmessageid,m_status.m_boardid);
\r
977 SendBufferedLine("224 Overview information follows");
\r
978 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
980 SendArticleOverInfo((*i));
\r
982 SendBufferedLine(".");
\r
986 SendBufferedLine("423 Empty range");
\r
992 SendBufferedLine("423 Empty range");
\r
997 SendBufferedLine("423 No newsgroup selected");
\r
1005 const bool NNTPConnection::HandlePostCommand(const NNTPCommand &command)
\r
1007 if(m_status.m_allowpost==true)
\r
1009 SendBufferedLine("340 Send article to be posted");
\r
1010 m_status.m_isposting=true;
\r
1014 SendBufferedLine("440 Posting not permitted");
\r
1020 void NNTPConnection::HandlePostedMessage(const std::string &message)
\r
1024 if(mess.ParseNNTPMessage(message))
\r
1026 // if we authenticated, set the username to the authenticated user
\r
1027 if(m_status.m_authenticated)
\r
1029 mess.SetFromName(m_status.m_authuser.GetName());
\r
1031 // handle a messages posted to an adminboard
\r
1032 if(mess.PostedToAdministrationBoard()==true)
\r
1034 mess.HandleAdministrationMessage();
\r
1036 if(mess.StartFreenetInsert())
\r
1038 SendBufferedLine("240 Article received OK");
\r
1042 SendBufferedLine("441 Posting failed. Make sure the identity you are sending with exists!");
\r
1047 SendBufferedLine("441 Posting failed");
\r
1051 void NNTPConnection::HandleReceivedData()
\r
1053 if(m_status.m_isposting==false)
\r
1055 // get end of command line
\r
1056 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n");
\r
1058 // we got a command
\r
1059 if(endpos!=m_receivebuffer.end())
\r
1061 NNTPCommand command;
\r
1062 std::string commandline(m_receivebuffer.begin(),endpos);
\r
1064 // remove command from receive buffer
\r
1065 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+2);
\r
1067 // remove any leading/trailing whitespace
\r
1068 commandline=StringFunctions::TrimWhitespace(commandline);
\r
1070 // split out command and arguments separated by space or tab
\r
1071 StringFunctions::SplitMultiple(commandline," \t",command.m_arguments);
\r
1073 // command is first element in argument vector
\r
1074 command.m_command=command.m_arguments[0];
\r
1075 // erase command from argument vector and make it upper case
\r
1076 command.m_arguments.erase(command.m_arguments.begin());
\r
1077 StringFunctions::UpperCase(command.m_command,command.m_command);
\r
1079 if(HandleCommand(command)==true)
\r
1085 SendBufferedLine("500 Unknown command");
\r
1087 m_log->debug("NNTPConnection::HandleReceivedData received unhandled NNTP command : "+commandline);
\r
1095 // check for end of post
\r
1096 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n.\r\n");
\r
1098 if(endpos!=m_receivebuffer.end())
\r
1100 // get the message
\r
1101 std::string message(m_receivebuffer.begin(),endpos);
\r
1102 // remove from receive buffer
\r
1103 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+5);
\r
1105 // get rid of dot stuffing ( 2 dots on start of a line - used to prevent premature message end in NNTP)
\r
1106 message=StringFunctions::Replace(message,"\r\n..","\r\n.");
\r
1108 HandlePostedMessage(message);
\r
1110 // message was received, so posting is completed
\r
1111 m_status.m_isposting=false;
\r
1117 const bool NNTPConnection::HandleSetTrustCommand(const NNTPCommand &command)
\r
1119 if(command.m_arguments.size()>=3)
\r
1121 std::string type=command.m_arguments[0];
\r
1122 StringFunctions::UpperCase(type,type);
\r
1123 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="MESSAGECOMMENT" || type=="TRUSTLISTCOMMENT")
\r
1125 if(m_status.m_authenticated)
\r
1130 std::string comment="";
\r
1131 std::string nntpname="";
\r
1133 if(type=="MESSAGE" || type=="TRUSTLIST")
\r
1135 for(int i=1; i<command.m_arguments.size()-1; i++)
\r
1141 nntpname+=command.m_arguments[i];
\r
1144 if(command.m_arguments[command.m_arguments.size()-1]!="null")
\r
1146 StringFunctions::Convert(command.m_arguments[command.m_arguments.size()-1],trust);
\r
1149 if(trust>=-1 && trust<=100)
\r
1158 for(int i=1; i<command.m_arguments.size() && startpos==-1; i++)
\r
1160 if(command.m_arguments[i].size()>0 && command.m_arguments[i][0]!='\"')
\r
1166 nntpname+=command.m_arguments[i];
\r
1175 for(int i=startpos; i<command.m_arguments.size(); i++)
\r
1181 comment+=command.m_arguments[i];
\r
1183 // strip " from comment beginning and end
\r
1184 if(comment.size()>0 && comment[0]=='\"')
\r
1186 comment.erase(0,1);
\r
1188 if(comment.size()>0 && comment[comment.size()-1]=='\"')
\r
1190 comment.erase(comment.size()-1);
\r
1196 TrustExtension tr(m_status.m_authuser.GetID());
\r
1198 if(type=="MESSAGE")
\r
1200 if(tr.SetMessageTrust(nntpname,trust))
\r
1205 if(type=="TRUSTLIST")
\r
1207 if(tr.SetTrustListTrust(nntpname,trust))
\r
1212 if(type=="MESSAGECOMMENT")
\r
1214 if(tr.SetMessageTrustComment(nntpname,comment))
\r
1219 if(type=="TRUSTLISTCOMMENT")
\r
1221 if(tr.SetTrustListTrustComment(nntpname,comment))
\r
1227 if(found && valid)
\r
1229 SendBufferedLine("280 Trust Set");
\r
1231 else if(found==false)
\r
1233 SendBufferedLine("480 Identity not found");
\r
1237 SendBufferedLine("501 Syntax error");
\r
1243 SendBufferedLine("480 User not authenticated");
\r
1248 SendBufferedLine("501 Syntax error");
\r
1253 SendBufferedLine("501 Syntax error");
\r
1258 const bool NNTPConnection::HandleStatCommand(const NNTPCommand &command)
\r
1260 SendArticleParts(command);
\r
1265 const bool NNTPConnection::HandleQuitCommand(const NNTPCommand &command)
\r
1267 SendBufferedLine("205 Connection Closing");
\r
1270 m_log->information("NNTPConnection::HandleQuitCommand client closed connection");
\r
1274 void NNTPConnection::run()
\r
1276 struct timeval tv;
\r
1277 fd_set writefs,readfs;
\r
1280 // seed random number generater for this thread
\r
1281 srand(time(NULL));
\r
1283 if(m_status.m_allowpost==true)
\r
1285 SendBufferedLine("200 Service available, posting allowed");
\r
1289 SendBufferedLine("201 Service available, posting prohibited");
\r
1295 FD_ZERO(&writefs);
\r
1297 FD_SET(m_socket,&readfs);
\r
1298 if(m_sendbuffer.size()>0)
\r
1300 FD_SET(m_socket,&writefs);
\r
1306 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
1310 if(FD_ISSET(m_socket,&readfs))
\r
1313 HandleReceivedData();
\r
1315 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1320 else if(rval==SOCKET_ERROR)
\r
1322 m_log->error("NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1325 //process all remaining commands in buffer
\r
1326 std::vector<char>::size_type rbs=0;
\r
1327 while(rbs!=m_receivebuffer.size())
\r
1329 rbs=m_receivebuffer.size();
\r
1330 HandleReceivedData();
\r
1333 }while(!Disconnected() && !IsCancelled());
\r
1339 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1341 std::string tempval;
\r
1343 std::map<long,std::string> references;
\r
1345 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1346 line=tempval+"\t";
\r
1347 line+=message.GetSubject()+"\t";
\r
1348 line+=message.GetFromName()+"\t";
\r
1349 line+=Poco::DateTimeFormatter::format(message.GetDateTime(),"%w, %d %b %y %H:%M:%S -0000")+"\t";
\r
1350 line+=message.GetNNTPArticleID()+"\t";
\r
1351 references=message.GetInReplyTo();
\r
1352 if(references.size()>0)
\r
1354 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1356 if(i!=references.rbegin())
\r
1360 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1370 SendBufferedLine(line);
\r
1373 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1375 bool sendheaders,sendbody;
\r
1376 std::string successcode;
\r
1378 if(command.m_command=="ARTICLE")
\r
1382 successcode="220";
\r
1384 else if(command.m_command=="HEAD")
\r
1388 successcode="221";
\r
1390 else if(command.m_command=="BODY")
\r
1392 sendheaders=false;
\r
1394 successcode="222";
\r
1396 else if(command.m_command=="STAT")
\r
1398 sendheaders=false;
\r
1400 successcode="223";
\r
1404 int messageid=m_status.m_messageid;
\r
1405 std::string articleid="";
\r
1406 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1408 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1410 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1412 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1413 message.Load(messageid,m_status.m_boardid);
\r
1414 m_status.m_messageid=message.GetMessageID();
\r
1419 articleid=command.m_arguments[0];
\r
1420 //strip off < and > and everthing after @
\r
1421 if(articleid.size()>0 && articleid[0]=='<')
\r
1423 articleid.erase(0,1);
\r
1425 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1427 articleid.erase(articleid.size()-1);
\r
1430 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1432 articleid.erase(articleid.find('@'));
\r
1435 message.Load(articleid);
\r
1441 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1447 if(m_status.m_boardid!=-1)
\r
1449 if(m_status.m_messageid!=-1)
\r
1451 std::ostringstream tempstr;
\r
1452 std::string article;
\r
1453 if(sendheaders&&sendbody)
\r
1455 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1457 else if(sendheaders && !sendbody)
\r
1459 article=message.GetNNTPHeaders();
\r
1460 // strip off final \r\n from headers
\r
1461 if(article.rfind("\r\n")==article.size()-2)
\r
1463 article.erase(article.size()-2);
\r
1468 article=message.GetNNTPBody();
\r
1470 // dot stuff article
\r
1471 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1473 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1475 SendBufferedLine(tempstr.str());
\r
1476 if(sendheaders || sendbody)
\r
1478 SendBufferedLine(article);
\r
1479 SendBufferedLine(".");
\r
1485 SendBufferedLine("420 Current article number is invalid");
\r
1490 SendBufferedLine("412 No newsgroup selected");
\r
1494 if(m_status.m_boardid!=-1)
\r
1496 if(message.GetMessageID()!=-1)
\r
1498 std::ostringstream tempstr;
\r
1499 std::string article;
\r
1500 if(sendheaders&&sendbody)
\r
1502 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1504 else if(sendheaders && !sendbody)
\r
1506 article=message.GetNNTPHeaders();
\r
1507 // strip off final \r\n from headers
\r
1508 if(article.rfind("\r\n")==article.size()-2)
\r
1510 article.erase(article.size()-2);
\r
1515 article=message.GetNNTPBody();
\r
1517 // dot stuff article
\r
1518 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1520 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1522 SendBufferedLine(tempstr.str());
\r
1523 if(sendheaders || sendbody)
\r
1525 SendBufferedLine(article);
\r
1526 SendBufferedLine(".");
\r
1531 SendBufferedLine("423 No article with that number");
\r
1536 SendBufferedLine("412 No newsgroup selected");
\r
1540 if(message.GetMessageID()!=-1)
\r
1542 std::string article;
\r
1543 if(sendheaders&&sendbody)
\r
1545 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1547 else if(sendheaders && !sendbody)
\r
1549 article=message.GetNNTPHeaders();
\r
1550 // strip off final \r\n from headers
\r
1551 if(article.rfind("\r\n")==article.size()-2)
\r
1553 article.erase(article.size()-2);
\r
1558 article=message.GetNNTPBody();
\r
1560 // dot stuff article
\r
1561 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1563 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1564 if(sendheaders || sendbody)
\r
1566 SendBufferedLine(article);
\r
1567 SendBufferedLine(".");
\r
1572 SendBufferedLine("430 No article with that message-id");
\r
1579 void NNTPConnection::SendBuffered(const std::string &data)
\r
1581 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1584 void NNTPConnection::SocketReceive()
\r
1586 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1589 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1594 m_log->information("NNTPConnection::SocketReceive remote host closed connection");
\r
1598 std::string errnostr;
\r
1599 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1600 // error on receive - close the connection
\r
1602 m_log->error("NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1606 void NNTPConnection::SocketSend()
\r
1608 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1610 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1613 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1617 std::string errnostr;
\r
1618 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1619 m_log->error("NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r