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),m_status(0)
\r
23 m_tempbuffer.resize(32768);
\r
25 m_status.m_isposting=false;
\r
26 m_status.m_allowpost=false;
\r
27 m_status.m_boardid=-1;
\r
28 m_status.m_messageid=-1;
\r
29 m_status.m_mode=MODE_NONE;
\r
30 m_status.m_authenticated=false;
\r
34 NNTPConnection::~NNTPConnection()
\r
39 void NNTPConnection::Disconnect()
\r
41 if(m_socket!=INVALID_SOCKET)
\r
44 closesocket(m_socket);
\r
48 m_socket=INVALID_SOCKET;
\r
52 std::vector<char>::iterator NNTPConnection::Find(std::vector<char> &buffer, const std::string &val)
\r
54 return std::search(buffer.begin(),buffer.end(),val.begin(),val.end());
\r
57 const bool NNTPConnection::HandleArticleCommand(const NNTPCommand &command)
\r
60 SendArticleParts(command);
\r
65 const bool NNTPConnection::HandleAuthInfoCommand(const NNTPCommand &command)
\r
67 if(command.m_arguments.size()<2)
\r
69 SendBufferedLine("501 Syntax error");
\r
71 else if(m_status.m_authenticated==true)
\r
73 SendBufferedLine("502 Command unavailable"); // not available when already authenticated
\r
77 std::string arg=command.m_arguments[0];
\r
78 StringFunctions::UpperCase(arg,arg);
\r
79 std::string name="";
\r
80 // get remaining args as part of the name since a name might have a space and the args are split on spaces
\r
81 for(std::vector<std::string>::const_iterator i=command.m_arguments.begin()+1; i!=command.m_arguments.end(); i++)
\r
83 // we split on the space, so add it back
\r
84 if(i!=command.m_arguments.begin()+1)
\r
92 LocalIdentity localid(m_db);
\r
93 if(localid.Load(name))
\r
95 m_status.m_authuser=localid;
\r
96 m_status.m_authenticated=true;
\r
97 SendBufferedLine("281 Authentication accepted");
\r
101 SendBufferedLine("481 Authentication failed");
\r
104 else if(arg=="PASS")
\r
106 SendBufferedLine("482 Authentication commands issued out of sequence"); // only require username
\r
110 SendBufferedLine("501 Syntax error");
\r
117 const bool NNTPConnection::HandleBodyCommand(const NNTPCommand &command)
\r
119 SendArticleParts(command);
\r
124 const bool NNTPConnection::HandleCapabilitiesCommand(const NNTPCommand &command)
\r
127 SendBufferedLine("101 Capability list :");
\r
128 SendBufferedLine("VERSION 2");
\r
129 if(m_status.m_authenticated==false) // RFC 4643 2.2 0 - don't advertise MODE-READER after authentication
\r
131 SendBufferedLine("MODE-READER");
\r
133 SendBufferedLine("READER");
\r
134 SendBufferedLine("LIST OVERVIEW.FMT");
\r
135 SendBufferedLine("OVER MSGID");
\r
136 if(m_status.m_allowpost==true)
\r
138 SendBufferedLine("POST");
\r
140 if(m_status.m_authenticated==false)
\r
142 SendBufferedLine("AUTHINFO USER");
\r
144 SendBufferedLine("XFMSTRUST");
\r
145 SendBufferedLine(".");
\r
150 const bool NNTPConnection::HandleCommand(const NNTPCommand &command)
\r
152 if(command.m_command=="QUIT")
\r
154 return HandleQuitCommand(command);
\r
156 if(command.m_command=="MODE")
\r
158 return HandleModeCommand(command);
\r
160 if(command.m_command=="CAPABILITIES")
\r
162 return HandleCapabilitiesCommand(command);
\r
164 if(command.m_command=="HELP")
\r
166 return HandleHelpCommand(command);
\r
168 if(command.m_command=="DATE")
\r
170 return HandleDateCommand(command);
\r
172 if(command.m_command=="LIST")
\r
174 return HandleListCommand(command);
\r
176 if(command.m_command=="GROUP")
\r
178 return HandleGroupCommand(command);
\r
180 if(command.m_command=="LISTGROUP")
\r
182 return HandleListGroupCommand(command);
\r
184 if(command.m_command=="LAST")
\r
186 return HandleLastCommand(command);
\r
188 if(command.m_command=="NEXT")
\r
190 return HandleNextCommand(command);
\r
192 if(command.m_command=="ARTICLE")
\r
194 return HandleArticleCommand(command);
\r
196 if(command.m_command=="HEAD")
\r
198 return HandleHeadCommand(command);
\r
200 if(command.m_command=="BODY")
\r
202 return HandleBodyCommand(command);
\r
204 if(command.m_command=="STAT")
\r
206 return HandleStatCommand(command);
\r
208 if(command.m_command=="NEWGROUPS")
\r
210 return HandleNewGroupsCommand(command);
\r
212 if(command.m_command=="POST")
\r
214 return HandlePostCommand(command);
\r
216 if(command.m_command=="OVER" || command.m_command=="XOVER")
\r
218 return HandleOverCommand(command);
\r
220 if(command.m_command=="AUTHINFO")
\r
222 return HandleAuthInfoCommand(command);
\r
224 if(command.m_command=="XGETTRUST")
\r
226 return HandleGetTrustCommand(command);
\r
228 if(command.m_command=="XSETTRUST")
\r
230 return HandleSetTrustCommand(command);
\r
232 if(command.m_command=="XGETTRUSTLIST")
\r
234 return HandleGetTrustListCommand(command);
\r
240 const bool NNTPConnection::HandleDateCommand(const NNTPCommand &command)
\r
242 Poco::DateTime now;
\r
243 SendBufferedLine("111 "+Poco::DateTimeFormatter::format(now,"%Y%m%d%H%M%S"));
\r
247 const bool NNTPConnection::HandleGetTrustCommand(const NNTPCommand &command)
\r
249 if(command.m_arguments.size()>=2)
\r
251 std::string type=command.m_arguments[0];
\r
252 StringFunctions::UpperCase(type,type);
\r
253 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="PEERMESSAGE" || type=="PEERTRUSTLIST")
\r
255 if(m_status.m_authenticated)
\r
259 std::string nntpname="";
\r
260 for(int i=1; i<command.m_arguments.size(); i++)
\r
266 nntpname+=command.m_arguments[i];
\r
269 TrustExtension tr(m_db,m_status.m_authuser.GetID());
\r
271 if(type=="MESSAGE")
\r
273 if(tr.GetMessageTrust(nntpname,trust))
\r
278 else if(type=="TRUSTLIST")
\r
280 if(tr.GetTrustListTrust(nntpname,trust))
\r
285 else if(type=="PEERMESSAGE")
\r
287 if(tr.GetPeerMessageTrust(nntpname,trust))
\r
292 else if(type=="PEERTRUSTLIST")
\r
294 if(tr.GetPeerTrustListTrust(nntpname,trust))
\r
300 if(trust>=0 && found)
\r
302 std::string truststr="";
\r
303 StringFunctions::Convert(trust,truststr);
\r
304 SendBufferedLine("280 "+truststr);
\r
308 SendBufferedLine("281 null");
\r
312 SendBufferedLine("480 Identity not found");
\r
318 SendBufferedLine("480 User not authenticated");
\r
323 SendBufferedLine("501 Syntax error");
\r
328 SendBufferedLine("501 Syntax error");
\r
333 const bool NNTPConnection::HandleGetTrustListCommand(const NNTPCommand &command)
\r
335 if(m_status.m_authenticated)
\r
337 TrustExtension tr(m_db,m_status.m_authuser.GetID());
\r
338 std::map<std::string,TrustExtension::trust> trustlist;
\r
339 if(tr.GetTrustList(trustlist))
\r
341 SendBufferedLine("280 Trust list follows");
\r
342 for(std::map<std::string,TrustExtension::trust>::iterator i=trustlist.begin(); i!=trustlist.end(); i++)
\r
344 std::ostringstream tempstr;
\r
345 tempstr << (*i).first << "\t";
\r
346 if((*i).second.m_localmessagetrust>-1)
\r
348 tempstr << (*i).second.m_localmessagetrust;
\r
355 if((*i).second.m_localtrustlisttrust>-1)
\r
357 tempstr << (*i).second.m_localtrustlisttrust;
\r
364 if((*i).second.m_peermessagetrust>-1)
\r
366 tempstr << (*i).second.m_peermessagetrust;
\r
373 if((*i).second.m_peertrustlisttrust>-1)
\r
375 tempstr << (*i).second.m_peertrustlisttrust;
\r
382 tempstr << (*i).second.m_messagetrustcomment;
\r
384 tempstr << (*i).second.m_trustlisttrustcomment;
\r
386 SendBufferedLine(tempstr.str());
\r
388 SendBufferedLine(".");
\r
392 SendBufferedLine("501 Syntax error");
\r
397 SendBufferedLine("480 User not authenticated");
\r
402 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
404 if(command.m_arguments.size()==1)
\r
407 if(board.Load(command.m_arguments[0])==true)
\r
409 std::ostringstream tempstr;
\r
411 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
413 SendBufferedLine(tempstr.str());
\r
415 // set the current boardid to this one
\r
416 m_status.m_boardid=board.GetBoardID();
\r
417 //set the first message id, -1 if there are no messages
\r
418 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
423 SendBufferedLine("411 No such newsgroup");
\r
428 SendBufferedLine("501 Syntax error");
\r
429 m_log->debug("NNTPConnection::HandleGroupCommand syntax error");
\r
435 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
438 SendArticleParts(command);
\r
443 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
445 SendBufferedLine("100 Help text follows");
\r
446 SendBufferedLine("There is no help text");
\r
447 SendBufferedLine(".");
\r
452 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
454 if(m_status.m_boardid!=-1)
\r
456 if(m_status.m_messageid!=-1)
\r
458 Message mess(m_db);
\r
460 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
462 std::ostringstream tempstr;
\r
464 m_status.m_messageid=mess.GetMessageID();
\r
466 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
468 SendBufferedLine(tempstr.str());
\r
473 SendBufferedLine("422 No previous article in this group");
\r
478 SendBufferedLine("420 Current article number is invalid");
\r
483 SendBufferedLine("412 No newsgroup selected");
\r
489 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
492 int type=1; // default LIST type is active
\r
493 std::string arg1="";
\r
494 std::string arg2="";
\r
497 if(command.m_arguments.size()>0)
\r
499 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
504 else if(arg1=="NEWSGROUPS")
\r
508 else if(arg1=="OVERVIEW.FMT")
\r
518 if(command.m_arguments.size()>1)
\r
520 arg2=command.m_arguments[1];
\r
523 // LIST ACTIVE [wildmat]
\r
527 std::ostringstream tempstr;
\r
528 BoardList bl(m_db);
\r
531 SendBufferedLine("215 list of newsgroups follows");
\r
533 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
538 // check wilmat match
\r
541 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
544 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
546 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
547 SendBufferedLine(tempstr.str());
\r
551 SendBufferedLine(".");
\r
558 std::ostringstream tempstr;
\r
559 BoardList bl(m_db);
\r
562 SendBufferedLine("215 list of newsgroups follows");
\r
564 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
569 // check wilmat match
\r
572 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
575 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
577 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
578 SendBufferedLine(tempstr.str());
\r
582 SendBufferedLine(".");
\r
585 // LIST OVERVIEW.FMT
\r
588 SendBufferedLine("215 Order of fields in overview database.");
\r
589 SendBufferedLine("Subject:");
\r
590 SendBufferedLine("From:");
\r
591 SendBufferedLine("Date:");
\r
592 SendBufferedLine("Message-ID:");
\r
593 SendBufferedLine("References:");
\r
594 SendBufferedLine(":bytes");
\r
595 SendBufferedLine(":lines");
\r
596 SendBufferedLine(".");
\r
601 SendBufferedLine("501 Syntax error");
\r
602 m_log->debug("NNTPConnection::HandleListCommand unhandled LIST variant");
\r
608 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
611 std::ostringstream tempstr;
\r
613 bool validgroup=false;
\r
617 // no args and invalid boardid
\r
618 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
620 SendBufferedLine("412 No newsgroup selected");
\r
622 else if(command.m_arguments.size()==0)
\r
624 validgroup=board.Load(m_status.m_boardid);
\r
626 else if(command.m_arguments.size()==1)
\r
628 validgroup=board.Load(command.m_arguments[0]);
\r
631 lownum=board.GetLowMessageID();
\r
632 highnum=board.GetHighMessageID();
\r
636 SendBufferedLine("411 No such newsgroup");
\r
639 else if(command.m_arguments.size()==2)
\r
641 validgroup=board.Load(command.m_arguments[0]);
\r
642 std::vector<std::string> rangeparts;
\r
643 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
645 if(rangeparts.size()>0)
\r
647 StringFunctions::Convert(rangeparts[0],lownum);
\r
649 if(rangeparts.size()>1)
\r
651 StringFunctions::Convert(rangeparts[1],highnum);
\r
658 SendBufferedLine("501 Syntax error");
\r
659 m_log->debug("NNTPConnection::HandleListGroupCommand unknown arguments");
\r
665 // set boardid and messageid
\r
666 m_status.m_boardid=board.GetBoardID();
\r
667 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
671 lownum=board.GetLowMessageID();
\r
675 highnum=board.GetHighMessageID();
\r
678 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
679 SendBufferedLine(tempstr.str());
\r
681 MessageList ml(m_db);
\r
682 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
684 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
687 tempstr << (*i).GetMessageID();
\r
689 SendBufferedLine(tempstr.str());
\r
692 // end of multi-line response
\r
693 SendBufferedLine(".");
\r
700 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
702 if(command.m_arguments.size()>0)
\r
704 std::string arg=command.m_arguments[0];
\r
705 StringFunctions::UpperCase(arg,arg);
\r
708 m_status.m_mode=MODE_READER;
\r
709 if(m_status.m_allowpost==true)
\r
711 SendBufferedLine("200 Posting allowed");
\r
715 SendBufferedLine("201 Posting prohibited");
\r
718 m_log->debug("NNTPConnection::HandleModeCommand set mode to reader");
\r
722 SendBufferedLine("501 Syntax error");
\r
723 m_log->debug("NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
728 SendBufferedLine("501 Syntax error");
\r
729 m_log->debug("NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
735 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
737 if(command.m_arguments.size()>=2)
\r
739 Poco::DateTime date;
\r
743 if(command.m_arguments[0].size()==8)
\r
745 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempyear);
\r
746 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempmonth);
\r
747 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempday);
\r
750 date.assign(tempyear,tempmonth,tempday,date.hour(),date.minute(),date.second());
\r
754 m_log->fatal("NNTPConnection::HandleNewGroupsCommand error assigning date");
\r
761 If the first two digits of the year are not specified
\r
762 (this is supported only for backward compatibility), the year is to
\r
763 be taken from the current century if yy is smaller than or equal to
\r
764 the current year, and the previous century otherwise.
\r
767 Poco::DateTime now;
\r
768 century=now.year()-(now.year()%100);
\r
770 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempyear);
\r
771 tempyear<=now.year()-century ? tempyear+=century : tempyear+=(century-100);
\r
773 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
775 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempmonth);
\r
776 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempday);
\r
779 date.assign(tempyear,tempmonth,tempday);
\r
783 m_log->fatal("NNTPConnection::HandleNewGroupsCommand error assigning date");
\r
787 BoardList bl(m_db);
\r
789 bl.LoadNew(Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));
\r
791 SendBufferedLine("231 List of new newsgroups follows");
\r
793 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
795 if((*i).GetSaveReceivedMessages()==true)
\r
797 std::ostringstream tempstr;
\r
798 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << m_status.m_allowpost ? "y" : "n";
\r
799 SendBufferedLine(tempstr.str());
\r
803 SendBufferedLine(".");
\r
808 SendBufferedLine("501 Syntax error");
\r
809 m_log->debug("NNTPConnection::HandleNewGroupsCommand syntax error");
\r
816 const bool NNTPConnection::HandleNextCommand(const NNTPCommand &command)
\r
818 if(m_status.m_boardid!=-1)
\r
820 if(m_status.m_messageid!=-1)
\r
822 Message mess(m_db);
\r
824 if(mess.LoadNext(m_status.m_messageid,m_status.m_boardid))
\r
826 std::ostringstream tempstr;
\r
828 m_status.m_messageid=mess.GetMessageID();
\r
830 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
832 SendBufferedLine(tempstr.str());
\r
837 SendBufferedLine("421 No next article in this group");
\r
842 SendBufferedLine("420 Current article number is invalid");
\r
847 SendBufferedLine("412 No newsgroup selected");
\r
854 const bool NNTPConnection::HandleOverCommand(const NNTPCommand &command)
\r
856 long lowmessageid,highmessageid;
\r
857 std::string messageuuid="";
\r
859 lowmessageid=highmessageid=-2;
\r
861 if(command.m_arguments.size()==0)
\r
863 lowmessageid=m_status.m_messageid;
\r
864 highmessageid=m_status.m_messageid;
\r
869 if(command.m_arguments.size()>0 && command.m_arguments[0].find("<")==0 && command.m_arguments[0].find(">")>0)
\r
871 messageuuid=command.m_arguments[0];
\r
872 messageuuid=StringFunctions::Replace(messageuuid,"<","");
\r
873 messageuuid=StringFunctions::Replace(messageuuid,">","");
\r
875 // get rid of @ and everything after
\r
876 if(messageuuid.find("@")!=std::string::npos)
\r
878 messageuuid.erase(messageuuid.find("@"));
\r
882 // single article or range
\r
886 if(command.m_arguments[0].find("-")!=std::string::npos)
\r
888 std::vector<std::string> rangeparts;
\r
889 StringFunctions::Split(command.m_arguments[0],"-",rangeparts);
\r
891 if(rangeparts.size()>0)
\r
893 StringFunctions::Convert(rangeparts[0],lowmessageid);
\r
897 else if(rangeparts.size()>1)
\r
899 StringFunctions::Convert(rangeparts[1],highmessageid);
\r
905 StringFunctions::Convert(command.m_arguments[0],lowmessageid);
\r
910 if(messageuuid!="")
\r
912 Message mess(m_db);
\r
913 if(mess.Load(messageuuid))
\r
915 SendBufferedLine("224 Overview information follows");
\r
916 SendArticleOverInfo(mess);
\r
917 SendBufferedLine(".");
\r
921 SendBufferedLine("423 No such article");
\r
927 if(m_status.m_boardid!=-1 && bd.Load(m_status.m_boardid))
\r
930 if(highmessageid==-2)
\r
932 Message mess(m_db);
\r
933 if(mess.Load(lowmessageid,m_status.m_boardid))
\r
935 SendBufferedLine("224 Overview information follows");
\r
936 SendArticleOverInfo(mess);
\r
937 SendBufferedLine(".");
\r
941 SendBufferedLine("423 No such article in this group");
\r
944 // range with no upper bound
\r
945 else if(highmessageid==-1)
\r
947 MessageList ml(m_db);
\r
948 ml.LoadRange(lowmessageid,bd.GetHighMessageID(),m_status.m_boardid);
\r
951 SendBufferedLine("224 Overview information follows");
\r
952 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
954 SendArticleOverInfo((*i));
\r
956 SendBufferedLine(".");
\r
960 SendBufferedLine("423 Empty range");
\r
963 // range with upper and lower bound
\r
964 else if(highmessageid>=lowmessageid)
\r
966 MessageList ml(m_db);
\r
967 ml.LoadRange(lowmessageid,highmessageid,m_status.m_boardid);
\r
970 SendBufferedLine("224 Overview information follows");
\r
971 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
973 SendArticleOverInfo((*i));
\r
975 SendBufferedLine(".");
\r
979 SendBufferedLine("423 Empty range");
\r
985 SendBufferedLine("423 Empty range");
\r
990 SendBufferedLine("423 No newsgroup selected");
\r
998 const bool NNTPConnection::HandlePostCommand(const NNTPCommand &command)
\r
1000 if(m_status.m_allowpost==true)
\r
1002 SendBufferedLine("340 Send article to be posted");
\r
1003 m_status.m_isposting=true;
\r
1007 SendBufferedLine("440 Posting not permitted");
\r
1013 void NNTPConnection::HandlePostedMessage(const std::string &message)
\r
1015 Message mess(m_db);
\r
1017 if(mess.ParseNNTPMessage(message))
\r
1019 // if we authenticated, set the username to the authenticated user
\r
1020 if(m_status.m_authenticated)
\r
1022 mess.SetFromName(m_status.m_authuser.GetName());
\r
1024 // handle a messages posted to an adminboard
\r
1025 if(mess.PostedToAdministrationBoard()==true)
\r
1027 mess.HandleAdministrationMessage();
\r
1029 if(mess.StartFreenetInsert())
\r
1031 SendBufferedLine("240 Article received OK");
\r
1035 SendBufferedLine("441 Posting failed. Make sure the identity you are sending with exists!");
\r
1040 SendBufferedLine("441 Posting failed");
\r
1044 void NNTPConnection::HandleReceivedData()
\r
1046 if(m_status.m_isposting==false)
\r
1048 // get end of command line
\r
1049 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n");
\r
1051 // we got a command
\r
1052 if(endpos!=m_receivebuffer.end())
\r
1054 NNTPCommand command;
\r
1055 std::string commandline(m_receivebuffer.begin(),endpos);
\r
1057 // remove command from receive buffer
\r
1058 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+2);
\r
1060 // remove any leading/trailing whitespace
\r
1061 commandline=StringFunctions::TrimWhitespace(commandline);
\r
1063 // split out command and arguments separated by space or tab
\r
1064 StringFunctions::SplitMultiple(commandline," \t",command.m_arguments);
\r
1066 // command is first element in argument vector
\r
1067 command.m_command=command.m_arguments[0];
\r
1068 // erase command from argument vector and make it upper case
\r
1069 command.m_arguments.erase(command.m_arguments.begin());
\r
1070 StringFunctions::UpperCase(command.m_command,command.m_command);
\r
1072 if(HandleCommand(command)==true)
\r
1078 SendBufferedLine("500 Unknown command");
\r
1080 m_log->debug("NNTPConnection::HandleReceivedData received unhandled NNTP command : "+commandline);
\r
1088 // check for end of post
\r
1089 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n.\r\n");
\r
1091 if(endpos!=m_receivebuffer.end())
\r
1093 // get the message
\r
1094 std::string message(m_receivebuffer.begin(),endpos);
\r
1095 // remove from receive buffer
\r
1096 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+5);
\r
1098 // get rid of dot stuffing ( 2 dots on start of a line - used to prevent premature message end in NNTP)
\r
1099 message=StringFunctions::Replace(message,"\r\n..","\r\n.");
\r
1101 HandlePostedMessage(message);
\r
1103 // message was received, so posting is completed
\r
1104 m_status.m_isposting=false;
\r
1110 const bool NNTPConnection::HandleSetTrustCommand(const NNTPCommand &command)
\r
1112 if(command.m_arguments.size()>=3)
\r
1114 std::string type=command.m_arguments[0];
\r
1115 StringFunctions::UpperCase(type,type);
\r
1116 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="MESSAGECOMMENT" || type=="TRUSTLISTCOMMENT")
\r
1118 if(m_status.m_authenticated)
\r
1123 std::string comment="";
\r
1124 std::string nntpname="";
\r
1126 if(type=="MESSAGE" || type=="TRUSTLIST")
\r
1128 for(int i=1; i<command.m_arguments.size()-1; i++)
\r
1134 nntpname+=command.m_arguments[i];
\r
1137 if(command.m_arguments[command.m_arguments.size()-1]!="null")
\r
1139 StringFunctions::Convert(command.m_arguments[command.m_arguments.size()-1],trust);
\r
1142 if(trust>=-1 && trust<=100)
\r
1151 for(int i=1; i<command.m_arguments.size() && startpos==-1; i++)
\r
1153 if(command.m_arguments[i].size()>0 && command.m_arguments[i][0]!='\"')
\r
1159 nntpname+=command.m_arguments[i];
\r
1168 for(int i=startpos; i<command.m_arguments.size(); i++)
\r
1174 comment+=command.m_arguments[i];
\r
1176 // strip " from comment beginning and end
\r
1177 if(comment.size()>0 && comment[0]=='\"')
\r
1179 comment.erase(0,1);
\r
1181 if(comment.size()>0 && comment[comment.size()-1]=='\"')
\r
1183 comment.erase(comment.size()-1);
\r
1189 TrustExtension tr(m_db,m_status.m_authuser.GetID());
\r
1191 if(type=="MESSAGE")
\r
1193 if(tr.SetMessageTrust(nntpname,trust))
\r
1198 if(type=="TRUSTLIST")
\r
1200 if(tr.SetTrustListTrust(nntpname,trust))
\r
1205 if(type=="MESSAGECOMMENT")
\r
1207 if(tr.SetMessageTrustComment(nntpname,comment))
\r
1212 if(type=="TRUSTLISTCOMMENT")
\r
1214 if(tr.SetTrustListTrustComment(nntpname,comment))
\r
1220 if(found && valid)
\r
1222 SendBufferedLine("280 Trust Set");
\r
1224 else if(found==false)
\r
1226 SendBufferedLine("480 Identity not found");
\r
1230 SendBufferedLine("501 Syntax error");
\r
1236 SendBufferedLine("480 User not authenticated");
\r
1241 SendBufferedLine("501 Syntax error");
\r
1246 SendBufferedLine("501 Syntax error");
\r
1251 const bool NNTPConnection::HandleStatCommand(const NNTPCommand &command)
\r
1253 SendArticleParts(command);
\r
1258 const bool NNTPConnection::HandleQuitCommand(const NNTPCommand &command)
\r
1260 SendBufferedLine("205 Connection Closing");
\r
1263 m_log->information("NNTPConnection::HandleQuitCommand client closed connection");
\r
1267 void NNTPConnection::run()
\r
1269 struct timeval tv;
\r
1270 fd_set writefs,readfs;
\r
1272 std::string tempval("");
\r
1276 m_status.m_authuser.SetDB(m_db);
\r
1277 Option option(m_db);
\r
1278 option.Get("NNTPAllowPost",tempval);
\r
1279 if(tempval=="true")
\r
1281 m_status.m_allowpost=true;
\r
1284 // seed random number generater for this thread
\r
1285 srand(time(NULL));
\r
1287 if(m_status.m_allowpost==true)
\r
1289 SendBufferedLine("200 Service available, posting allowed");
\r
1293 SendBufferedLine("201 Service available, posting prohibited");
\r
1299 FD_ZERO(&writefs);
\r
1301 FD_SET(m_socket,&readfs);
\r
1302 if(m_sendbuffer.size()>0)
\r
1304 FD_SET(m_socket,&writefs);
\r
1310 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
1314 if(FD_ISSET(m_socket,&readfs))
\r
1317 HandleReceivedData();
\r
1319 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1324 else if(rval==SOCKET_ERROR)
\r
1326 m_log->error("NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1329 //process all remaining commands in buffer
\r
1330 std::vector<char>::size_type rbs=0;
\r
1331 while(rbs!=m_receivebuffer.size())
\r
1333 rbs=m_receivebuffer.size();
\r
1334 HandleReceivedData();
\r
1337 }while(!Disconnected() && !IsCancelled());
\r
1343 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1345 std::string tempval;
\r
1347 std::map<long,std::string> references;
\r
1349 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1350 line=tempval+"\t";
\r
1351 line+=message.GetSubject()+"\t";
\r
1352 line+=message.GetFromName()+"\t";
\r
1353 line+=Poco::DateTimeFormatter::format(message.GetDateTime(),"%w, %d %b %y %H:%M:%S -0000")+"\t";
\r
1354 line+=message.GetNNTPArticleID()+"\t";
\r
1355 references=message.GetInReplyTo();
\r
1356 if(references.size()>0)
\r
1358 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1360 if(i!=references.rbegin())
\r
1364 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1374 SendBufferedLine(line);
\r
1377 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1379 bool sendheaders,sendbody;
\r
1380 std::string successcode;
\r
1382 if(command.m_command=="ARTICLE")
\r
1386 successcode="220";
\r
1388 else if(command.m_command=="HEAD")
\r
1392 successcode="221";
\r
1394 else if(command.m_command=="BODY")
\r
1396 sendheaders=false;
\r
1398 successcode="222";
\r
1400 else if(command.m_command=="STAT")
\r
1402 sendheaders=false;
\r
1404 successcode="223";
\r
1407 Message message(m_db);
\r
1408 int messageid=m_status.m_messageid;
\r
1409 std::string articleid="";
\r
1410 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1412 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1414 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1416 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1417 message.Load(messageid,m_status.m_boardid);
\r
1418 m_status.m_messageid=message.GetMessageID();
\r
1423 articleid=command.m_arguments[0];
\r
1424 //strip off < and > and everthing after @
\r
1425 if(articleid.size()>0 && articleid[0]=='<')
\r
1427 articleid.erase(0,1);
\r
1429 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1431 articleid.erase(articleid.size()-1);
\r
1434 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1436 articleid.erase(articleid.find('@'));
\r
1439 message.Load(articleid);
\r
1445 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1451 if(m_status.m_boardid!=-1)
\r
1453 if(m_status.m_messageid!=-1)
\r
1455 std::ostringstream tempstr;
\r
1456 std::string article;
\r
1457 if(sendheaders&&sendbody)
\r
1459 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1461 else if(sendheaders && !sendbody)
\r
1463 article=message.GetNNTPHeaders();
\r
1464 // strip off final \r\n from headers
\r
1465 if(article.rfind("\r\n")==article.size()-2)
\r
1467 article.erase(article.size()-2);
\r
1472 article=message.GetNNTPBody();
\r
1474 // dot stuff article
\r
1475 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1477 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1479 SendBufferedLine(tempstr.str());
\r
1480 if(sendheaders || sendbody)
\r
1482 SendBufferedLine(article);
\r
1483 SendBufferedLine(".");
\r
1489 SendBufferedLine("420 Current article number is invalid");
\r
1494 SendBufferedLine("412 No newsgroup selected");
\r
1498 if(m_status.m_boardid!=-1)
\r
1500 if(message.GetMessageID()!=-1)
\r
1502 std::ostringstream tempstr;
\r
1503 std::string article;
\r
1504 if(sendheaders&&sendbody)
\r
1506 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1508 else if(sendheaders && !sendbody)
\r
1510 article=message.GetNNTPHeaders();
\r
1511 // strip off final \r\n from headers
\r
1512 if(article.rfind("\r\n")==article.size()-2)
\r
1514 article.erase(article.size()-2);
\r
1519 article=message.GetNNTPBody();
\r
1521 // dot stuff article
\r
1522 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1524 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1526 SendBufferedLine(tempstr.str());
\r
1527 if(sendheaders || sendbody)
\r
1529 SendBufferedLine(article);
\r
1530 SendBufferedLine(".");
\r
1535 SendBufferedLine("423 No article with that number");
\r
1540 SendBufferedLine("412 No newsgroup selected");
\r
1544 if(message.GetMessageID()!=-1)
\r
1546 std::string article;
\r
1547 if(sendheaders&&sendbody)
\r
1549 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1551 else if(sendheaders && !sendbody)
\r
1553 article=message.GetNNTPHeaders();
\r
1554 // strip off final \r\n from headers
\r
1555 if(article.rfind("\r\n")==article.size()-2)
\r
1557 article.erase(article.size()-2);
\r
1562 article=message.GetNNTPBody();
\r
1564 // dot stuff article
\r
1565 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1567 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1568 if(sendheaders || sendbody)
\r
1570 SendBufferedLine(article);
\r
1571 SendBufferedLine(".");
\r
1576 SendBufferedLine("430 No article with that message-id");
\r
1583 void NNTPConnection::SendBuffered(const std::string &data)
\r
1585 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1588 void NNTPConnection::SocketReceive()
\r
1590 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1593 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1598 m_log->information("NNTPConnection::SocketReceive remote host closed connection");
\r
1602 std::string errnostr;
\r
1603 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1604 // error on receive - close the connection
\r
1606 m_log->error("NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1610 void NNTPConnection::SocketSend()
\r
1612 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1614 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1617 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1621 std::string errnostr;
\r
1622 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1623 m_log->error("NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r