1 #include "../../include/nntp/nntpconnection.h"
\r
2 #include "../../include/nntp/uwildmat.h"
\r
3 #include "../../include/stringfunctions.h"
\r
4 #include "../../include/datetime.h"
\r
5 #include "../../include/boardlist.h"
\r
6 #include "../../include/message.h"
\r
7 #include "../../include/messagelist.h"
\r
8 #include "../../include/option.h"
\r
9 #include "../../include/nntp/extensiontrust.h"
\r
11 #include <algorithm>
\r
13 //#include <zthread/Thread.h>
\r
14 #include "../../include/pthreadwrapper/thread.h"
\r
20 NNTPConnection::NNTPConnection(SOCKET sock)
\r
22 std::string tempval;
\r
25 m_tempbuffer.resize(32768);
\r
27 m_status.m_isposting=false;
\r
28 m_status.m_allowpost=false;
\r
29 m_status.m_boardid=-1;
\r
30 m_status.m_messageid=-1;
\r
31 m_status.m_mode=MODE_NONE;
\r
32 m_status.m_authenticated=false;
\r
34 Option::Instance()->Get("NNTPAllowPost",tempval);
\r
37 m_status.m_allowpost=true;
\r
42 NNTPConnection::~NNTPConnection()
\r
47 void NNTPConnection::Disconnect()
\r
49 if(m_socket!=INVALID_SOCKET)
\r
52 closesocket(m_socket);
\r
56 m_socket=INVALID_SOCKET;
\r
60 std::vector<char>::iterator NNTPConnection::Find(std::vector<char> &buffer, const std::string &val)
\r
62 return std::search(buffer.begin(),buffer.end(),val.begin(),val.end());
\r
65 const bool NNTPConnection::HandleArticleCommand(const NNTPCommand &command)
\r
68 SendArticleParts(command);
\r
73 const bool NNTPConnection::HandleAuthInfoCommand(const NNTPCommand &command)
\r
75 if(command.m_arguments.size()<2)
\r
77 SendBufferedLine("501 Syntax error");
\r
79 else if(m_status.m_authenticated==true)
\r
81 SendBufferedLine("502 Command unavailable"); // not available when already authenticated
\r
85 std::string arg=command.m_arguments[0];
\r
86 StringFunctions::UpperCase(arg,arg);
\r
87 std::string name="";
\r
88 // get remaining args as part of the name since a name might have a space and the args are split on spaces
\r
89 for(std::vector<std::string>::const_iterator i=command.m_arguments.begin()+1; i!=command.m_arguments.end(); i++)
\r
91 // we split on the space, so add it back
\r
92 if(i!=command.m_arguments.begin()+1)
\r
100 LocalIdentity localid;
\r
101 if(localid.Load(name))
\r
103 m_status.m_authuser=localid;
\r
104 m_status.m_authenticated=true;
\r
105 SendBufferedLine("281 Authentication accepted");
\r
109 SendBufferedLine("481 Authentication failed");
\r
112 else if(arg=="PASS")
\r
114 SendBufferedLine("482 Authentication commands issued out of sequence"); // only require username
\r
118 SendBufferedLine("501 Syntax error");
\r
125 const bool NNTPConnection::HandleBodyCommand(const NNTPCommand &command)
\r
127 SendArticleParts(command);
\r
132 const bool NNTPConnection::HandleCapabilitiesCommand(const NNTPCommand &command)
\r
135 SendBufferedLine("101 Capability list :");
\r
136 SendBufferedLine("VERSION 2");
\r
137 if(m_status.m_authenticated==false) // RFC 4643 2.2 0 - don't advertise MODE-READER after authentication
\r
139 SendBufferedLine("MODE-READER");
\r
141 SendBufferedLine("READER");
\r
142 SendBufferedLine("LIST OVERVIEW.FMT");
\r
143 SendBufferedLine("OVER MSGID");
\r
144 if(m_status.m_allowpost==true)
\r
146 SendBufferedLine("POST");
\r
148 if(m_status.m_authenticated==false)
\r
150 SendBufferedLine("AUTHINFO USER");
\r
152 SendBufferedLine("XFMSTRUST");
\r
153 SendBufferedLine(".");
\r
158 const bool NNTPConnection::HandleCommand(const NNTPCommand &command)
\r
160 if(command.m_command=="QUIT")
\r
162 return HandleQuitCommand(command);
\r
164 if(command.m_command=="MODE")
\r
166 return HandleModeCommand(command);
\r
168 if(command.m_command=="CAPABILITIES")
\r
170 return HandleCapabilitiesCommand(command);
\r
172 if(command.m_command=="HELP")
\r
174 return HandleHelpCommand(command);
\r
176 if(command.m_command=="DATE")
\r
178 return HandleDateCommand(command);
\r
180 if(command.m_command=="LIST")
\r
182 return HandleListCommand(command);
\r
184 if(command.m_command=="GROUP")
\r
186 return HandleGroupCommand(command);
\r
188 if(command.m_command=="LISTGROUP")
\r
190 return HandleListGroupCommand(command);
\r
192 if(command.m_command=="LAST")
\r
194 return HandleLastCommand(command);
\r
196 if(command.m_command=="NEXT")
\r
198 return HandleNextCommand(command);
\r
200 if(command.m_command=="ARTICLE")
\r
202 return HandleArticleCommand(command);
\r
204 if(command.m_command=="HEAD")
\r
206 return HandleHeadCommand(command);
\r
208 if(command.m_command=="BODY")
\r
210 return HandleBodyCommand(command);
\r
212 if(command.m_command=="STAT")
\r
214 return HandleStatCommand(command);
\r
216 if(command.m_command=="NEWGROUPS")
\r
218 return HandleNewGroupsCommand(command);
\r
220 if(command.m_command=="POST")
\r
222 return HandlePostCommand(command);
\r
224 if(command.m_command=="OVER" || command.m_command=="XOVER")
\r
226 return HandleOverCommand(command);
\r
228 if(command.m_command=="AUTHINFO")
\r
230 return HandleAuthInfoCommand(command);
\r
232 if(command.m_command=="XGETTRUST")
\r
234 return HandleGetTrustCommand(command);
\r
236 if(command.m_command=="XSETTRUST")
\r
238 return HandleSetTrustCommand(command);
\r
240 if(command.m_command=="XGETTRUSTLIST")
\r
242 return HandleGetTrustListCommand(command);
\r
248 const bool NNTPConnection::HandleDateCommand(const NNTPCommand &command)
\r
252 SendBufferedLine("111 "+now.Format("%Y%m%d%H%M%S"));
\r
256 const bool NNTPConnection::HandleGetTrustCommand(const NNTPCommand &command)
\r
258 if(command.m_arguments.size()>=2)
\r
260 std::string type=command.m_arguments[0];
\r
261 StringFunctions::UpperCase(type,type);
\r
262 if(type=="MESSAGE" || type=="TRUSTLIST" || type=="PEERMESSAGE" || type=="PEERTRUSTLIST")
\r
264 if(m_status.m_authenticated)
\r
268 std::string nntpname="";
\r
269 for(int i=1; i<command.m_arguments.size(); i++)
\r
275 nntpname+=command.m_arguments[i];
\r
278 TrustExtension tr(m_status.m_authuser.GetID());
\r
280 if(type=="MESSAGE")
\r
282 if(tr.GetMessageTrust(nntpname,trust))
\r
287 else if(type=="TRUSTLIST")
\r
289 if(tr.GetTrustListTrust(nntpname,trust))
\r
294 else if(type=="PEERMESSAGE")
\r
296 if(tr.GetPeerMessageTrust(nntpname,trust))
\r
301 else if(type=="PEERTRUSTLIST")
\r
303 if(tr.GetPeerTrustListTrust(nntpname,trust))
\r
309 if(trust>=0 && found)
\r
311 std::string truststr="";
\r
312 StringFunctions::Convert(trust,truststr);
\r
313 SendBufferedLine("280 "+truststr);
\r
317 SendBufferedLine("281 null");
\r
321 SendBufferedLine("480 Identity not found");
\r
327 SendBufferedLine("480 User not authenticated");
\r
332 SendBufferedLine("501 Syntax error");
\r
337 SendBufferedLine("501 Syntax error");
\r
342 const bool NNTPConnection::HandleGetTrustListCommand(const NNTPCommand &command)
\r
344 if(m_status.m_authenticated)
\r
346 TrustExtension tr(m_status.m_authuser.GetID());
\r
347 std::map<std::string,TrustExtension::trust> trustlist;
\r
348 if(tr.GetTrustList(trustlist))
\r
350 SendBufferedLine("280 Trust list follows");
\r
351 for(std::map<std::string,TrustExtension::trust>::iterator i=trustlist.begin(); i!=trustlist.end(); i++)
\r
353 std::ostringstream tempstr;
\r
354 tempstr << (*i).first << "\t";
\r
355 if((*i).second.m_localmessagetrust>-1)
\r
357 tempstr << (*i).second.m_localmessagetrust;
\r
364 if((*i).second.m_localtrustlisttrust>-1)
\r
366 tempstr << (*i).second.m_localtrustlisttrust;
\r
373 if((*i).second.m_peermessagetrust>-1)
\r
375 tempstr << (*i).second.m_peermessagetrust;
\r
382 if((*i).second.m_peertrustlisttrust>-1)
\r
384 tempstr << (*i).second.m_peertrustlisttrust;
\r
391 tempstr << (*i).second.m_messagetrustcomment;
\r
393 tempstr << (*i).second.m_trustlisttrustcomment;
\r
395 SendBufferedLine(tempstr.str());
\r
397 SendBufferedLine(".");
\r
401 SendBufferedLine("501 Syntax error");
\r
406 SendBufferedLine("480 User not authenticated");
\r
411 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
413 if(command.m_arguments.size()==1)
\r
416 if(board.Load(command.m_arguments[0])==true)
\r
418 std::ostringstream tempstr;
\r
420 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
422 SendBufferedLine(tempstr.str());
\r
424 // set the current boardid to this one
\r
425 m_status.m_boardid=board.GetBoardID();
\r
426 //set the first message id, -1 if there are no messages
\r
427 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
432 SendBufferedLine("411 No such newsgroup");
\r
437 SendBufferedLine("501 Syntax error");
\r
438 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleGroupCommand syntax error");
\r
444 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
447 SendArticleParts(command);
\r
452 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
454 SendBufferedLine("100 Help text follows");
\r
455 SendBufferedLine("There is no help text");
\r
456 SendBufferedLine(".");
\r
461 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
463 if(m_status.m_boardid!=-1)
\r
465 if(m_status.m_messageid!=-1)
\r
469 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
471 std::ostringstream tempstr;
\r
473 m_status.m_messageid=mess.GetMessageID();
\r
475 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
477 SendBufferedLine(tempstr.str());
\r
482 SendBufferedLine("422 No previous article in this group");
\r
487 SendBufferedLine("420 Current article number is invalid");
\r
492 SendBufferedLine("412 No newsgroup selected");
\r
498 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
501 int type=1; // default LIST type is active
\r
502 std::string arg1="";
\r
503 std::string arg2="";
\r
506 if(command.m_arguments.size()>0)
\r
508 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
513 else if(arg1=="NEWSGROUPS")
\r
517 else if(arg1=="OVERVIEW.FMT")
\r
527 if(command.m_arguments.size()>1)
\r
529 arg2=command.m_arguments[1];
\r
532 // LIST ACTIVE [wildmat]
\r
536 std::ostringstream tempstr;
\r
540 SendBufferedLine("215 list of newsgroups follows");
\r
542 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
547 // check wilmat match
\r
550 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
553 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
555 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
556 SendBufferedLine(tempstr.str());
\r
560 SendBufferedLine(".");
\r
567 std::ostringstream tempstr;
\r
571 SendBufferedLine("215 list of newsgroups follows");
\r
573 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
578 // check wilmat match
\r
581 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
584 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
586 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
587 SendBufferedLine(tempstr.str());
\r
591 SendBufferedLine(".");
\r
594 // LIST OVERVIEW.FMT
\r
597 SendBufferedLine("215 Order of fields in overview database.");
\r
598 SendBufferedLine("Subject:");
\r
599 SendBufferedLine("From:");
\r
600 SendBufferedLine("Date:");
\r
601 SendBufferedLine("Message-ID:");
\r
602 SendBufferedLine("References:");
\r
603 SendBufferedLine(":bytes");
\r
604 SendBufferedLine(":lines");
\r
605 SendBufferedLine(".");
\r
610 SendBufferedLine("501 Syntax error");
\r
611 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListCommand unhandled LIST variant");
\r
617 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
620 std::ostringstream tempstr;
\r
622 bool validgroup=false;
\r
626 // no args and invalid boardid
\r
627 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
629 SendBufferedLine("412 No newsgroup selected");
\r
631 else if(command.m_arguments.size()==0)
\r
633 validgroup=board.Load(m_status.m_boardid);
\r
635 else if(command.m_arguments.size()==1)
\r
637 validgroup=board.Load(command.m_arguments[0]);
\r
640 lownum=board.GetLowMessageID();
\r
641 highnum=board.GetHighMessageID();
\r
645 SendBufferedLine("411 No such newsgroup");
\r
648 else if(command.m_arguments.size()==2)
\r
650 validgroup=board.Load(command.m_arguments[0]);
\r
651 std::vector<std::string> rangeparts;
\r
652 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
654 if(rangeparts.size()>0)
\r
656 StringFunctions::Convert(rangeparts[0],lownum);
\r
658 if(rangeparts.size()>1)
\r
660 StringFunctions::Convert(rangeparts[1],highnum);
\r
667 SendBufferedLine("501 Syntax error");
\r
668 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListGroupCommand unknown arguments");
\r
674 // set boardid and messageid
\r
675 m_status.m_boardid=board.GetBoardID();
\r
676 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
680 lownum=board.GetLowMessageID();
\r
684 highnum=board.GetHighMessageID();
\r
687 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
688 SendBufferedLine(tempstr.str());
\r
691 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
693 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
696 tempstr << (*i).GetMessageID();
\r
698 SendBufferedLine(tempstr.str());
\r
701 // end of multi-line response
\r
702 SendBufferedLine(".");
\r
709 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
711 if(command.m_arguments.size()>0)
\r
713 std::string arg=command.m_arguments[0];
\r
714 StringFunctions::UpperCase(arg,arg);
\r
717 m_status.m_mode=MODE_READER;
\r
718 if(m_status.m_allowpost==true)
\r
720 SendBufferedLine("200 Posting allowed");
\r
724 SendBufferedLine("201 Posting prohibited");
\r
727 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand set mode to reader");
\r
731 SendBufferedLine("501 Syntax error");
\r
732 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
737 SendBufferedLine("501 Syntax error");
\r
738 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
744 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
746 if(command.m_arguments.size()>=2)
\r
750 if(command.m_arguments[0].size()==8)
\r
752 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempint);
\r
753 date.SetYear(tempint);
\r
754 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
755 date.SetMonth(tempint);
\r
756 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempint);
\r
757 date.SetDay(tempint);
\r
763 If the first two digits of the year are not specified
\r
764 (this is supported only for backward compatibility), the year is to
\r
765 be taken from the current century if yy is smaller than or equal to
\r
766 the current year, and the previous century otherwise.
\r
771 century=now.GetYear()-(now.GetYear()%100);
\r
773 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempint);
\r
774 tempint<=now.GetYear()-century ? tempint+=century : tempint+=(century-100);
\r
776 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
778 date.SetYear(tempint);
\r
779 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempint);
\r
780 date.SetMonth(tempint);
\r
781 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
782 date.SetDay(tempint);
\r
789 bl.LoadNew(date.Format("%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->WriteLog(LogFile::LOGLEVEL_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
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
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
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
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
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
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->WriteLog(LogFile::LOGLEVEL_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_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->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::HandleQuitCommand client closed connection");
\r
1267 void NNTPConnection::Run()
\r
1269 struct timeval tv;
\r
1270 fd_set writefs,readfs;
\r
1273 // seed random number generater for this thread
\r
1274 srand(time(NULL));
\r
1276 if(m_status.m_allowpost==true)
\r
1278 SendBufferedLine("200 Service available, posting allowed");
\r
1282 SendBufferedLine("201 Service available, posting prohibited");
\r
1288 FD_ZERO(&writefs);
\r
1290 FD_SET(m_socket,&readfs);
\r
1291 if(m_sendbuffer.size()>0)
\r
1293 FD_SET(m_socket,&writefs);
\r
1299 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
1303 if(FD_ISSET(m_socket,&readfs))
\r
1306 HandleReceivedData();
\r
1308 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1313 else if(rval==SOCKET_ERROR)
\r
1315 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1318 // }while(!Disconnected() && !ZThread::Thread::interrupted());
\r
1319 }while(!Disconnected() && !IsCancelled());
\r
1325 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1327 std::string tempval;
\r
1329 std::map<long,std::string> references;
\r
1331 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1332 line=tempval+"\t";
\r
1333 line+=message.GetSubject()+"\t";
\r
1334 line+=message.GetFromName()+"\t";
\r
1335 line+=message.GetDateTime().Format("%a, %d %b %y %H:%M:%S -0000")+"\t";
\r
1336 line+=message.GetNNTPArticleID()+"\t";
\r
1337 references=message.GetInReplyTo();
\r
1338 if(references.size()>0)
\r
1340 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1342 if(i!=references.rbegin())
\r
1346 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1356 SendBufferedLine(line);
\r
1359 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1361 bool sendheaders,sendbody;
\r
1362 std::string successcode;
\r
1364 if(command.m_command=="ARTICLE")
\r
1368 successcode="220";
\r
1370 else if(command.m_command=="HEAD")
\r
1374 successcode="221";
\r
1376 else if(command.m_command=="BODY")
\r
1378 sendheaders=false;
\r
1380 successcode="222";
\r
1382 else if(command.m_command=="STAT")
\r
1384 sendheaders=false;
\r
1386 successcode="223";
\r
1390 int messageid=m_status.m_messageid;
\r
1391 std::string articleid="";
\r
1392 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1394 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1396 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1398 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1399 message.Load(messageid,m_status.m_boardid);
\r
1400 m_status.m_messageid=message.GetMessageID();
\r
1405 articleid=command.m_arguments[0];
\r
1406 //strip off < and > and everthing after @
\r
1407 if(articleid.size()>0 && articleid[0]=='<')
\r
1409 articleid.erase(0,1);
\r
1411 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1413 articleid.erase(articleid.size()-1);
\r
1416 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1418 articleid.erase(articleid.find('@'));
\r
1421 message.Load(articleid);
\r
1427 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1433 if(m_status.m_boardid!=-1)
\r
1435 if(m_status.m_messageid!=-1)
\r
1437 std::ostringstream tempstr;
\r
1438 std::string article;
\r
1439 if(sendheaders&&sendbody)
\r
1441 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1443 else if(sendheaders && !sendbody)
\r
1445 article=message.GetNNTPHeaders();
\r
1446 // strip off final \r\n from headers
\r
1447 if(article.rfind("\r\n")==article.size()-2)
\r
1449 article.erase(article.size()-2);
\r
1454 article=message.GetNNTPBody();
\r
1456 // dot stuff article
\r
1457 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1459 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1461 SendBufferedLine(tempstr.str());
\r
1462 if(sendheaders || sendbody)
\r
1464 SendBufferedLine(article);
\r
1465 SendBufferedLine(".");
\r
1471 SendBufferedLine("420 Current article number is invalid");
\r
1476 SendBufferedLine("412 No newsgroup selected");
\r
1480 if(m_status.m_boardid!=-1)
\r
1482 if(message.GetMessageID()!=-1)
\r
1484 std::ostringstream tempstr;
\r
1485 std::string article;
\r
1486 if(sendheaders&&sendbody)
\r
1488 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1490 else if(sendheaders && !sendbody)
\r
1492 article=message.GetNNTPHeaders();
\r
1493 // strip off final \r\n from headers
\r
1494 if(article.rfind("\r\n")==article.size()-2)
\r
1496 article.erase(article.size()-2);
\r
1501 article=message.GetNNTPBody();
\r
1503 // dot stuff article
\r
1504 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1506 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1508 SendBufferedLine(tempstr.str());
\r
1509 if(sendheaders || sendbody)
\r
1511 SendBufferedLine(article);
\r
1512 SendBufferedLine(".");
\r
1517 SendBufferedLine("423 No article with that number");
\r
1522 SendBufferedLine("412 No newsgroup selected");
\r
1526 if(message.GetMessageID()!=-1)
\r
1528 std::string article;
\r
1529 if(sendheaders&&sendbody)
\r
1531 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1533 else if(sendheaders && !sendbody)
\r
1535 article=message.GetNNTPHeaders();
\r
1536 // strip off final \r\n from headers
\r
1537 if(article.rfind("\r\n")==article.size()-2)
\r
1539 article.erase(article.size()-2);
\r
1544 article=message.GetNNTPBody();
\r
1546 // dot stuff article
\r
1547 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1549 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1550 if(sendheaders || sendbody)
\r
1552 SendBufferedLine(article);
\r
1553 SendBufferedLine(".");
\r
1558 SendBufferedLine("430 No article with that message-id");
\r
1565 void NNTPConnection::SendBuffered(const std::string &data)
\r
1567 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1570 void NNTPConnection::SocketReceive()
\r
1572 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1575 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1580 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::SocketReceive remote host closed connection");
\r
1584 std::string errnostr;
\r
1585 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1586 // error on receive - close the connection
\r
1588 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1592 void NNTPConnection::SocketSend()
\r
1594 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1596 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1599 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1603 std::string errnostr;
\r
1604 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1605 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r