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
10 #include <algorithm>
\r
12 //#include <zthread/Thread.h>
\r
13 #include "../../include/pthreadwrapper/thread.h"
\r
19 NNTPConnection::NNTPConnection(SOCKET sock)
\r
21 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(".");
\r
156 const bool NNTPConnection::HandleCommand(const NNTPCommand &command)
\r
158 if(command.m_command=="QUIT")
\r
160 return HandleQuitCommand(command);
\r
162 if(command.m_command=="MODE")
\r
164 return HandleModeCommand(command);
\r
166 if(command.m_command=="CAPABILITIES")
\r
168 return HandleCapabilitiesCommand(command);
\r
170 if(command.m_command=="HELP")
\r
172 return HandleHelpCommand(command);
\r
174 if(command.m_command=="DATE")
\r
176 return HandleDateCommand(command);
\r
178 if(command.m_command=="LIST")
\r
180 return HandleListCommand(command);
\r
182 if(command.m_command=="GROUP")
\r
184 return HandleGroupCommand(command);
\r
186 if(command.m_command=="LISTGROUP")
\r
188 return HandleListGroupCommand(command);
\r
190 if(command.m_command=="LAST")
\r
192 return HandleLastCommand(command);
\r
194 if(command.m_command=="NEXT")
\r
196 return HandleNextCommand(command);
\r
198 if(command.m_command=="ARTICLE")
\r
200 return HandleArticleCommand(command);
\r
202 if(command.m_command=="HEAD")
\r
204 return HandleHeadCommand(command);
\r
206 if(command.m_command=="BODY")
\r
208 return HandleBodyCommand(command);
\r
210 if(command.m_command=="STAT")
\r
212 return HandleStatCommand(command);
\r
214 if(command.m_command=="NEWGROUPS")
\r
216 return HandleNewGroupsCommand(command);
\r
218 if(command.m_command=="POST")
\r
220 return HandlePostCommand(command);
\r
222 if(command.m_command=="OVER" || command.m_command=="XOVER")
\r
224 return HandleOverCommand(command);
\r
226 if(command.m_command=="AUTHINFO")
\r
228 return HandleAuthInfoCommand(command);
\r
234 const bool NNTPConnection::HandleDateCommand(const NNTPCommand &command)
\r
238 SendBufferedLine("111 "+now.Format("%Y%m%d%H%M%S"));
\r
242 const bool NNTPConnection::HandleGroupCommand(const NNTPCommand &command)
\r
244 if(command.m_arguments.size()==1)
\r
247 if(board.Load(command.m_arguments[0])==true)
\r
249 std::ostringstream tempstr;
\r
251 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
253 SendBufferedLine(tempstr.str());
\r
255 // set the current boardid to this one
\r
256 m_status.m_boardid=board.GetBoardID();
\r
257 //set the first message id, -1 if there are no messages
\r
258 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
263 SendBufferedLine("411 No such newsgroup");
\r
268 SendBufferedLine("501 Syntax error");
\r
269 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleGroupCommand syntax error");
\r
275 const bool NNTPConnection::HandleHeadCommand(const NNTPCommand &command)
\r
278 SendArticleParts(command);
\r
283 const bool NNTPConnection::HandleHelpCommand(const NNTPCommand &command)
\r
285 SendBufferedLine("100 Help text follows");
\r
286 SendBufferedLine("There is no help text");
\r
287 SendBufferedLine(".");
\r
292 const bool NNTPConnection::HandleLastCommand(const NNTPCommand &command)
\r
294 if(m_status.m_boardid!=-1)
\r
296 if(m_status.m_messageid!=-1)
\r
300 if(mess.LoadPrevious(m_status.m_messageid,m_status.m_boardid))
\r
302 std::ostringstream tempstr;
\r
304 m_status.m_messageid=mess.GetMessageID();
\r
306 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
308 SendBufferedLine(tempstr.str());
\r
313 SendBufferedLine("422 No previous article in this group");
\r
318 SendBufferedLine("420 Current article number is invalid");
\r
323 SendBufferedLine("412 No newsgroup selected");
\r
329 const bool NNTPConnection::HandleListCommand(const NNTPCommand &command)
\r
332 int type=1; // default LIST type is active
\r
333 std::string arg1="";
\r
334 std::string arg2="";
\r
337 if(command.m_arguments.size()>0)
\r
339 StringFunctions::UpperCase(command.m_arguments[0],arg1);
\r
344 else if(arg1=="NEWSGROUPS")
\r
348 else if(arg1=="OVERVIEW.FMT")
\r
358 if(command.m_arguments.size()>1)
\r
360 arg2=command.m_arguments[1];
\r
363 // LIST ACTIVE [wildmat]
\r
367 std::ostringstream tempstr;
\r
371 SendBufferedLine("215 list of newsgroups follows");
\r
373 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
378 // check wilmat match
\r
381 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
384 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
386 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << (m_status.m_allowpost ? "y" : "n");
\r
387 SendBufferedLine(tempstr.str());
\r
391 SendBufferedLine(".");
\r
398 std::ostringstream tempstr;
\r
402 SendBufferedLine("215 list of newsgroups follows");
\r
404 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
409 // check wilmat match
\r
412 show=uwildmat((*i).GetBoardName().c_str(),arg2.c_str());
\r
415 if(show==true && (*i).GetSaveReceivedMessages()==true)
\r
417 tempstr << (*i).GetBoardName() << "\t" << (*i).GetBoardDescription();
\r
418 SendBufferedLine(tempstr.str());
\r
422 SendBufferedLine(".");
\r
425 // LIST OVERVIEW.FMT
\r
428 SendBufferedLine("215 Order of fields in overview database.");
\r
429 SendBufferedLine("Subject:");
\r
430 SendBufferedLine("From:");
\r
431 SendBufferedLine("Date:");
\r
432 SendBufferedLine("Message-ID:");
\r
433 SendBufferedLine("References:");
\r
434 SendBufferedLine(":bytes");
\r
435 SendBufferedLine(":lines");
\r
436 SendBufferedLine(".");
\r
441 SendBufferedLine("501 Syntax error");
\r
442 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListCommand unhandled LIST variant");
\r
448 const bool NNTPConnection::HandleListGroupCommand(const NNTPCommand &command)
\r
451 std::ostringstream tempstr;
\r
453 bool validgroup=false;
\r
457 // no args and invalid boardid
\r
458 if(command.m_arguments.size()==0 && m_status.m_boardid==-1)
\r
460 SendBufferedLine("412 No newsgroup selected");
\r
462 else if(command.m_arguments.size()==0)
\r
464 validgroup=board.Load(m_status.m_boardid);
\r
466 else if(command.m_arguments.size()==1)
\r
468 validgroup=board.Load(command.m_arguments[0]);
\r
471 lownum=board.GetLowMessageID();
\r
472 highnum=board.GetHighMessageID();
\r
476 SendBufferedLine("411 No such newsgroup");
\r
479 else if(command.m_arguments.size()==2)
\r
481 validgroup=board.Load(command.m_arguments[0]);
\r
482 std::vector<std::string> rangeparts;
\r
483 StringFunctions::Split(command.m_arguments[1],"-",rangeparts);
\r
485 if(rangeparts.size()>0)
\r
487 StringFunctions::Convert(rangeparts[0],lownum);
\r
489 if(rangeparts.size()>1)
\r
491 StringFunctions::Convert(rangeparts[1],highnum);
\r
498 SendBufferedLine("501 Syntax error");
\r
499 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleListGroupCommand unknown arguments");
\r
505 // set boardid and messageid
\r
506 m_status.m_boardid=board.GetBoardID();
\r
507 board.GetLowMessageID()!=0 ? m_status.m_messageid=board.GetLowMessageID() : m_status.m_messageid=-1;
\r
511 lownum=board.GetLowMessageID();
\r
515 highnum=board.GetHighMessageID();
\r
518 tempstr << "211 " << board.GetMessageCount() << " " << board.GetLowMessageID() << " " << board.GetHighMessageID() << " " << board.GetBoardName();
\r
519 SendBufferedLine(tempstr.str());
\r
522 ml.LoadRange(lownum,highnum,board.GetBoardID());
\r
524 for(std::vector<Message>::iterator i=ml.begin(); i!=ml.end(); i++)
\r
527 tempstr << (*i).GetMessageID();
\r
529 SendBufferedLine(tempstr.str());
\r
532 // end of multi-line response
\r
533 SendBufferedLine(".");
\r
540 const bool NNTPConnection::HandleModeCommand(const NNTPCommand &command)
\r
542 if(command.m_arguments.size()>0)
\r
544 std::string arg=command.m_arguments[0];
\r
545 StringFunctions::UpperCase(arg,arg);
\r
548 m_status.m_mode=MODE_READER;
\r
549 if(m_status.m_allowpost==true)
\r
551 SendBufferedLine("200 Posting allowed");
\r
555 SendBufferedLine("201 Posting prohibited");
\r
558 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand set mode to reader");
\r
562 SendBufferedLine("501 Syntax error");
\r
563 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand unknown MODE argument : "+arg);
\r
568 SendBufferedLine("501 Syntax error");
\r
569 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleModeCommand no argument supplied for MODE");
\r
575 const bool NNTPConnection::HandleNewGroupsCommand(const NNTPCommand &command)
\r
577 if(command.m_arguments.size()>=2)
\r
581 if(command.m_arguments[0].size()==8)
\r
583 StringFunctions::Convert(command.m_arguments[0].substr(0,4),tempint);
\r
584 date.SetYear(tempint);
\r
585 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
586 date.SetMonth(tempint);
\r
587 StringFunctions::Convert(command.m_arguments[0].substr(6,2),tempint);
\r
588 date.SetDay(tempint);
\r
594 If the first two digits of the year are not specified
\r
595 (this is supported only for backward compatibility), the year is to
\r
596 be taken from the current century if yy is smaller than or equal to
\r
597 the current year, and the previous century otherwise.
\r
602 century=now.GetYear()-(now.GetYear()%100);
\r
604 StringFunctions::Convert(command.m_arguments[0].substr(0,2),tempint);
\r
605 tempint<=now.GetYear()-century ? tempint+=century : tempint+=(century-100);
\r
607 //tempint > 50 ? tempint+=1900 : tempint+=2000;
\r
609 date.SetYear(tempint);
\r
610 StringFunctions::Convert(command.m_arguments[0].substr(2,2),tempint);
\r
611 date.SetMonth(tempint);
\r
612 StringFunctions::Convert(command.m_arguments[0].substr(4,2),tempint);
\r
613 date.SetDay(tempint);
\r
620 bl.LoadNew(date.Format("%Y-%m-%d %H:%M:%S"));
\r
622 SendBufferedLine("231 List of new newsgroups follows");
\r
624 for(BoardList::iterator i=bl.begin(); i!=bl.end(); i++)
\r
626 if((*i).GetSaveReceivedMessages()==true)
\r
628 std::ostringstream tempstr;
\r
629 tempstr << (*i).GetBoardName() << " " << (*i).GetHighMessageID() << " " << (*i).GetLowMessageID() << " " << m_status.m_allowpost ? "y" : "n";
\r
630 SendBufferedLine(tempstr.str());
\r
634 SendBufferedLine(".");
\r
639 SendBufferedLine("501 Syntax error");
\r
640 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleNewGroupsCommand syntax error");
\r
647 const bool NNTPConnection::HandleNextCommand(const NNTPCommand &command)
\r
649 if(m_status.m_boardid!=-1)
\r
651 if(m_status.m_messageid!=-1)
\r
655 if(mess.LoadNext(m_status.m_messageid,m_status.m_boardid))
\r
657 std::ostringstream tempstr;
\r
659 m_status.m_messageid=mess.GetMessageID();
\r
661 tempstr << "223 " << mess.GetMessageID() << " " << mess.GetNNTPArticleID();
\r
663 SendBufferedLine(tempstr.str());
\r
668 SendBufferedLine("421 No next article in this group");
\r
673 SendBufferedLine("420 Current article number is invalid");
\r
678 SendBufferedLine("412 No newsgroup selected");
\r
685 const bool NNTPConnection::HandleOverCommand(const NNTPCommand &command)
\r
687 long lowmessageid,highmessageid;
\r
688 std::string messageuuid="";
\r
690 lowmessageid=highmessageid=-2;
\r
692 if(command.m_arguments.size()==0)
\r
694 lowmessageid=m_status.m_messageid;
\r
695 highmessageid=m_status.m_messageid;
\r
700 if(command.m_arguments.size()>0 && command.m_arguments[0].find("<")==0 && command.m_arguments[0].find(">")>0)
\r
702 messageuuid=command.m_arguments[0];
\r
703 messageuuid=StringFunctions::Replace(messageuuid,"<","");
\r
704 messageuuid=StringFunctions::Replace(messageuuid,">","");
\r
706 // get rid of @ and everything after
\r
707 if(messageuuid.find("@")!=std::string::npos)
\r
709 messageuuid.erase(messageuuid.find("@"));
\r
713 // single article or range
\r
717 if(command.m_arguments[0].find("-")!=std::string::npos)
\r
719 std::vector<std::string> rangeparts;
\r
720 StringFunctions::Split(command.m_arguments[0],"-",rangeparts);
\r
722 if(rangeparts.size()>0)
\r
724 StringFunctions::Convert(rangeparts[0],lowmessageid);
\r
728 else if(rangeparts.size()>1)
\r
730 StringFunctions::Convert(rangeparts[1],highmessageid);
\r
736 StringFunctions::Convert(command.m_arguments[0],lowmessageid);
\r
741 if(messageuuid!="")
\r
744 if(mess.Load(messageuuid))
\r
746 SendBufferedLine("224 Overview information follows");
\r
747 SendArticleOverInfo(mess);
\r
748 SendBufferedLine(".");
\r
752 SendBufferedLine("423 No such article");
\r
758 if(m_status.m_boardid!=-1 && bd.Load(m_status.m_boardid))
\r
761 if(highmessageid==-2)
\r
764 if(mess.Load(lowmessageid,m_status.m_boardid))
\r
766 SendBufferedLine("224 Overview information follows");
\r
767 SendArticleOverInfo(mess);
\r
768 SendBufferedLine(".");
\r
772 SendBufferedLine("423 No such article in this group");
\r
775 // range with no upper bound
\r
776 else if(highmessageid==-1)
\r
779 ml.LoadRange(lowmessageid,bd.GetHighMessageID(),m_status.m_boardid);
\r
782 SendBufferedLine("224 Overview information follows");
\r
783 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
785 SendArticleOverInfo((*i));
\r
787 SendBufferedLine(".");
\r
791 SendBufferedLine("423 Empty range");
\r
794 // range with upper and lower bound
\r
795 else if(highmessageid>=lowmessageid)
\r
798 ml.LoadRange(lowmessageid,highmessageid,m_status.m_boardid);
\r
801 SendBufferedLine("224 Overview information follows");
\r
802 for(MessageList::iterator i=ml.begin(); i!=ml.end(); i++)
\r
804 SendArticleOverInfo((*i));
\r
806 SendBufferedLine(".");
\r
810 SendBufferedLine("423 Empty range");
\r
816 SendBufferedLine("423 Empty range");
\r
821 SendBufferedLine("423 No newsgroup selected");
\r
829 const bool NNTPConnection::HandlePostCommand(const NNTPCommand &command)
\r
831 if(m_status.m_allowpost==true)
\r
833 SendBufferedLine("340 Send article to be posted");
\r
834 m_status.m_isposting=true;
\r
838 SendBufferedLine("440 Posting not permitted");
\r
844 void NNTPConnection::HandlePostedMessage(const std::string &message)
\r
848 if(mess.ParseNNTPMessage(message))
\r
850 // if we authenticated, set the username to the authenticated user
\r
851 if(m_status.m_authenticated)
\r
853 mess.SetFromName(m_status.m_authuser.GetName());
\r
855 // handle a messages posted to an adminboard
\r
856 if(mess.PostedToAdministrationBoard()==true)
\r
858 mess.HandleAdministrationMessage();
\r
860 if(mess.StartFreenetInsert())
\r
862 SendBufferedLine("240 Article received OK");
\r
866 SendBufferedLine("441 Posting failed. Make sure the identity you are sending with exists!");
\r
871 SendBufferedLine("441 Posting failed");
\r
875 void NNTPConnection::HandleReceivedData()
\r
877 if(m_status.m_isposting==false)
\r
879 // get end of command line
\r
880 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n");
\r
882 // we got a command
\r
883 if(endpos!=m_receivebuffer.end())
\r
885 NNTPCommand command;
\r
886 std::string commandline(m_receivebuffer.begin(),endpos);
\r
888 // remove command from receive buffer
\r
889 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+2);
\r
891 // remove any leading/trailing whitespace
\r
892 commandline=StringFunctions::TrimWhitespace(commandline);
\r
894 // split out command and arguments separated by space or tab
\r
895 StringFunctions::SplitMultiple(commandline," \t",command.m_arguments);
\r
897 // command is first element in argument vector
\r
898 command.m_command=command.m_arguments[0];
\r
899 // erase command from argument vector and make it upper case
\r
900 command.m_arguments.erase(command.m_arguments.begin());
\r
901 StringFunctions::UpperCase(command.m_command,command.m_command);
\r
903 if(HandleCommand(command)==true)
\r
909 SendBufferedLine("500 Unknown command");
\r
911 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPConnection::HandleReceivedData received unhandled NNTP command : "+commandline);
\r
919 // check for end of post
\r
920 std::vector<char>::iterator endpos=Find(m_receivebuffer,"\r\n.\r\n");
\r
922 if(endpos!=m_receivebuffer.end())
\r
925 std::string message(m_receivebuffer.begin(),endpos);
\r
926 // remove from receive buffer
\r
927 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+5);
\r
929 // get rid of dot stuffing ( 2 dots on start of a line - used to prevent premature message end in NNTP)
\r
930 message=StringFunctions::Replace(message,"\r\n..","\r\n.");
\r
932 HandlePostedMessage(message);
\r
934 // message was received, so posting is completed
\r
935 m_status.m_isposting=false;
\r
941 const bool NNTPConnection::HandleStatCommand(const NNTPCommand &command)
\r
943 SendArticleParts(command);
\r
948 const bool NNTPConnection::HandleQuitCommand(const NNTPCommand &command)
\r
950 SendBufferedLine("205 Connection Closing");
\r
953 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::HandleQuitCommand client closed connection");
\r
957 void NNTPConnection::Run()
\r
960 fd_set writefs,readfs;
\r
963 // seed random number generater for this thread
\r
966 if(m_status.m_allowpost==true)
\r
968 SendBufferedLine("200 Service available, posting allowed");
\r
972 SendBufferedLine("201 Service available, posting prohibited");
\r
980 FD_SET(m_socket,&readfs);
\r
981 if(m_sendbuffer.size()>0)
\r
983 FD_SET(m_socket,&writefs);
\r
989 rval=select(m_socket+1,&readfs,&writefs,0,&tv);
\r
993 if(FD_ISSET(m_socket,&readfs))
\r
996 HandleReceivedData();
\r
998 if(m_socket!=INVALID_SOCKET && FD_ISSET(m_socket,&writefs))
\r
1003 else if(rval==SOCKET_ERROR)
\r
1005 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::run select returned -1 : "+GetSocketErrorMessage());
\r
1008 // }while(!Disconnected() && !ZThread::Thread::interrupted());
\r
1009 }while(!Disconnected() && !IsCancelled());
\r
1015 void NNTPConnection::SendArticleOverInfo(Message &message)
\r
1017 std::string tempval;
\r
1019 std::map<long,std::string> references;
\r
1021 StringFunctions::Convert(message.GetMessageID(),tempval);
\r
1022 line=tempval+"\t";
\r
1023 line+=message.GetSubject()+"\t";
\r
1024 line+=message.GetFromName()+"\t";
\r
1025 line+=message.GetDateTime().Format("%a, %d %b %y %H:%M:%S -0000")+"\t";
\r
1026 line+=message.GetNNTPArticleID()+"\t";
\r
1027 references=message.GetInReplyTo();
\r
1028 if(references.size()>0)
\r
1030 for(std::map<long,std::string>::reverse_iterator i=references.rbegin(); i!=references.rend(); i++)
\r
1032 if(i!=references.rbegin())
\r
1036 line+="<"+(*i).second+">"; //+"@freenetproject.org>";
\r
1046 SendBufferedLine(line);
\r
1049 void NNTPConnection::SendArticleParts(const NNTPConnection::NNTPCommand &command)
\r
1051 bool sendheaders,sendbody;
\r
1052 std::string successcode;
\r
1054 if(command.m_command=="ARTICLE")
\r
1058 successcode="220";
\r
1060 else if(command.m_command=="HEAD")
\r
1064 successcode="221";
\r
1066 else if(command.m_command=="BODY")
\r
1068 sendheaders=false;
\r
1070 successcode="222";
\r
1072 else if(command.m_command=="STAT")
\r
1074 sendheaders=false;
\r
1076 successcode="223";
\r
1080 int messageid=m_status.m_messageid;
\r
1081 std::string articleid="";
\r
1082 int type=0; // default to current messageid, 1=messageid, 2=articleid
\r
1084 if(command.m_arguments.size()==1 && command.m_arguments[0].size()>0)
\r
1086 if(command.m_arguments[0].find("<")==std::string::npos)
\r
1088 StringFunctions::Convert(command.m_arguments[0],messageid);
\r
1089 message.Load(messageid,m_status.m_boardid);
\r
1090 m_status.m_messageid=message.GetMessageID();
\r
1095 articleid=command.m_arguments[0];
\r
1096 //strip off < and > and everthing after @
\r
1097 if(articleid.size()>0 && articleid[0]=='<')
\r
1099 articleid.erase(0,1);
\r
1101 if(articleid.size()>0 && articleid[articleid.size()-1]=='>')
\r
1103 articleid.erase(articleid.size()-1);
\r
1106 if(articleid.size()>0 && articleid.find('@')!=std::string::npos)
\r
1108 articleid.erase(articleid.find('@'));
\r
1111 message.Load(articleid);
\r
1117 message.Load(m_status.m_messageid,m_status.m_boardid);
\r
1123 if(m_status.m_boardid!=-1)
\r
1125 if(m_status.m_messageid!=-1)
\r
1127 std::ostringstream tempstr;
\r
1128 std::string article;
\r
1129 if(sendheaders&&sendbody)
\r
1131 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1133 else if(sendheaders && !sendbody)
\r
1135 article=message.GetNNTPHeaders();
\r
1136 // strip off final \r\n from headers
\r
1137 if(article.rfind("\r\n")==article.size()-2)
\r
1139 article.erase(article.size()-2);
\r
1144 article=message.GetNNTPBody();
\r
1146 // dot stuff article
\r
1147 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1149 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1151 SendBufferedLine(tempstr.str());
\r
1152 if(sendheaders || sendbody)
\r
1154 SendBufferedLine(article);
\r
1155 SendBufferedLine(".");
\r
1161 SendBufferedLine("420 Current article number is invalid");
\r
1166 SendBufferedLine("412 No newsgroup selected");
\r
1170 if(m_status.m_boardid!=-1)
\r
1172 if(message.GetMessageID()!=-1)
\r
1174 std::ostringstream tempstr;
\r
1175 std::string article;
\r
1176 if(sendheaders&&sendbody)
\r
1178 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1180 else if(sendheaders && !sendbody)
\r
1182 article=message.GetNNTPHeaders();
\r
1183 // strip off final \r\n from headers
\r
1184 if(article.rfind("\r\n")==article.size()-2)
\r
1186 article.erase(article.size()-2);
\r
1191 article=message.GetNNTPBody();
\r
1193 // dot stuff article
\r
1194 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1196 tempstr << successcode << " " << message.GetMessageID() << " " << message.GetNNTPArticleID();
\r
1198 SendBufferedLine(tempstr.str());
\r
1199 if(sendheaders || sendbody)
\r
1201 SendBufferedLine(article);
\r
1202 SendBufferedLine(".");
\r
1207 SendBufferedLine("423 No article with that number");
\r
1212 SendBufferedLine("412 No newsgroup selected");
\r
1216 if(message.GetMessageID()!=-1)
\r
1218 std::string article;
\r
1219 if(sendheaders&&sendbody)
\r
1221 article=message.GetNNTPHeaders()+"\r\n"+message.GetNNTPBody();
\r
1223 else if(sendheaders && !sendbody)
\r
1225 article=message.GetNNTPHeaders();
\r
1226 // strip off final \r\n from headers
\r
1227 if(article.rfind("\r\n")==article.size()-2)
\r
1229 article.erase(article.size()-2);
\r
1234 article=message.GetNNTPBody();
\r
1236 // dot stuff article
\r
1237 article=StringFunctions::Replace(article,"\r\n.","\r\n..");
\r
1239 SendBufferedLine(successcode+" 0 "+message.GetNNTPArticleID());
\r
1240 if(sendheaders || sendbody)
\r
1242 SendBufferedLine(article);
\r
1243 SendBufferedLine(".");
\r
1248 SendBufferedLine("430 No article with that message-id");
\r
1255 void NNTPConnection::SendBuffered(const std::string &data)
\r
1257 m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());
\r
1260 void NNTPConnection::SocketReceive()
\r
1262 int rval=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);
\r
1265 m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+rval);
\r
1270 m_log->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPConnection::SocketReceive remote host closed connection");
\r
1274 std::string errnostr;
\r
1275 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1276 // error on receive - close the connection
\r
1278 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketReceive recv returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r
1282 void NNTPConnection::SocketSend()
\r
1284 if(m_sendbuffer.size()>0 && m_socket!=INVALID_SOCKET)
\r
1286 int rval=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);
\r
1289 m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+rval);
\r
1293 std::string errnostr;
\r
1294 StringFunctions::Convert(GetSocketErrorNumber(),errnostr);
\r
1295 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPConnection::SocketSend returned -1 : "+errnostr+" - "+GetSocketErrorMessage());
\r