1 #include "../../include/freenet/messagerequester.h"
\r
2 #include "../../include/freenet/messagexml.h"
\r
10 MessageRequester::MessageRequester()
\r
15 MessageRequester::MessageRequester(FCPv2 *fcp):IIndexRequester<std::string>(fcp)
\r
20 const long MessageRequester::GetBoardID(const std::string &boardname)
\r
22 std::string lowerboard=boardname;
\r
23 StringFunctions::LowerCase(lowerboard,lowerboard);
\r
24 SQLite3DB::Statement st=m_db->Prepare("SELECT BoardID FROM tblBoard WHERE BoardName=?;");
\r
25 st.Bind(0,lowerboard);
\r
28 if(st.RowReturned())
\r
31 st.ResultInt(0,boardid);
\r
38 st=m_db->Prepare("INSERT INTO tblBoard(BoardName,DateAdded,SaveReceivedMessages) VALUES(?,?,?);");
\r
39 st.Bind(0,boardname);
\r
40 st.Bind(1,now.Format("%Y-%m-%d %H:%M:%S"));
\r
41 if(m_savemessagesfromnewboards)
\r
50 return st.GetLastInsertRowID();
\r
54 const std::string MessageRequester::GetIdentityName(const long identityid)
\r
56 SQLite3DB::Statement st=m_db->Prepare("SELECT Name,PublicKey FROM tblIdentity WHERE IdentityID=?;");
\r
57 st.Bind(0,identityid);
\r
59 if(st.RowReturned())
\r
61 std::vector<std::string> keyparts;
\r
64 st.ResultText(0,name);
\r
65 st.ResultText(1,key);
\r
67 StringFunctions::SplitMultiple(key,"@,",keyparts);
\r
69 if(keyparts.size()>1)
\r
71 return name+"@"+keyparts[1];
\r
75 return name+"@invalidpublickey";
\r
84 const bool MessageRequester::HandleAllData(FCPMessage &message)
\r
86 SQLite3DB::Statement st;
\r
87 std::vector<std::string> idparts;
\r
89 std::vector<char> data;
\r
93 bool inserted=false;
\r
94 bool validmessage=true;
\r
95 long savetoboardcount=0;
\r
97 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
98 StringFunctions::Convert(message["DataLength"],datalength);
\r
99 StringFunctions::Convert(idparts[2],identityid);
\r
100 StringFunctions::Convert(idparts[4],index);
\r
102 // wait for all data to be received from connection
\r
103 while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)
\r
108 // if we got disconnected- return immediately
\r
109 if(m_fcp->Connected()==false)
\r
114 // receive the file
\r
115 data.resize(datalength);
\r
116 m_fcp->ReceiveRaw(&data[0],datalength);
\r
118 // mark this index as received
\r
119 st=m_db->Prepare("UPDATE tblMessageRequests SET Found='true' WHERE IdentityID=? AND Day=? AND RequestIndex=?;");
\r
120 st.Bind(0,identityid);
\r
121 st.Bind(1,idparts[3]);
\r
126 // parse file into xml and update the database
\r
127 if(xml.ParseXML(std::string(data.begin(),data.end()))==true)
\r
129 std::vector<std::string> boards=xml.GetBoards();
\r
130 std::map<long,std::string> replyto=xml.GetInReplyTo();
\r
132 if(boards.size()>m_maxboardspermessage)
\r
134 boards.resize(m_maxboardspermessage);
\r
137 if(boards.size()<=0)
\r
139 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData Message XML did not contain any boards! "+message["Identifier"]);
\r
140 // remove this identityid from request list
\r
141 RemoveFromRequestList(idparts[1]);
\r
144 if(xml.GetReplyBoard()=="")
\r
146 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData Message XML did not contain a reply board! "+message["Identifier"]);
\r
147 // remove this identityid from request list
\r
148 RemoveFromRequestList(idparts[1]);
\r
152 // make sure the reply board is on the board list we are saving - if not, replace the last element of boards with the reply board
\r
153 if(xml.GetReplyBoard()!="" && std::find(boards.begin(),boards.end(),xml.GetReplyBoard())==boards.end() && boards.size()>0)
\r
155 boards[boards.size()-1]=xml.GetReplyBoard();
\r
158 // make sure domain of message id match 43 characters of public key of identity (remove - and ~) - if not, discard message
\r
159 // implement after 0.1.12 is released
\r
160 st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");
\r
161 st.Bind(0,identityid);
\r
163 if(st.RowReturned())
\r
165 std::vector<std::string> uuidparts;
\r
166 std::vector<std::string> keyparts;
\r
167 std::string keypart="";
\r
168 std::string publickey="";
\r
170 st.ResultText(0,publickey);
\r
172 StringFunctions::SplitMultiple(publickey,"@,",keyparts);
\r
173 StringFunctions::SplitMultiple(xml.GetMessageID(),"@",uuidparts);
\r
175 if(uuidparts.size()>1 && keyparts.size()>1)
\r
177 keypart=StringFunctions::Replace(StringFunctions::Replace(keyparts[1],"-",""),"~","");
\r
178 if(keypart!=uuidparts[1])
\r
180 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData MessageID in Message doesn't match public key of identity : "+message["Identifier"]);
\r
181 validmessage=false;
\r
186 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData Error with identity's public key or Message ID : "+message["Identifier"]);
\r
187 validmessage=false;
\r
192 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData Error couldn't find identity : "+message["Identifier"]);
\r
193 validmessage=false;
\r
196 // make sure we will at least save to 1 board before inserting message
\r
197 savetoboardcount=0;
\r
198 for(std::vector<std::string>::iterator bi=boards.begin(); bi!=boards.end(); bi++)
\r
200 if(SaveToBoard((*bi)))
\r
202 savetoboardcount++;
\r
206 if(validmessage && savetoboardcount>0)
\r
208 st=m_db->Prepare("INSERT INTO tblMessage(IdentityID,FromName,MessageDate,MessageTime,Subject,MessageUUID,ReplyBoardID,Body,MessageIndex) VALUES(?,?,?,?,?,?,?,?,?);");
\r
209 st.Bind(0,identityid);
\r
210 st.Bind(1,GetIdentityName(identityid));
\r
211 st.Bind(2,xml.GetDate());
\r
212 st.Bind(3,xml.GetTime());
\r
213 st.Bind(4,xml.GetSubject());
\r
214 st.Bind(5,xml.GetMessageID());
\r
215 st.Bind(6,GetBoardID(xml.GetReplyBoard()));
\r
216 st.Bind(7,xml.GetBody());
\r
218 inserted=st.Step(true);
\r
219 int messageid=st.GetLastInsertRowID();
\r
224 st=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");
\r
225 for(std::vector<std::string>::iterator i=boards.begin(); i!=boards.end(); i++)
\r
227 if(SaveToBoard((*i)))
\r
229 st.Bind(0,messageid);
\r
230 st.Bind(1,GetBoardID((*i)));
\r
237 st=m_db->Prepare("INSERT INTO tblMessageReplyTo(MessageID,ReplyToMessageUUID,ReplyOrder) VALUES(?,?,?);");
\r
238 for(std::map<long,std::string>::iterator j=replyto.begin(); j!=replyto.end(); j++)
\r
240 st.Bind(0,messageid);
\r
241 st.Bind(1,(*j).second);
\r
242 st.Bind(2,(*j).first);
\r
248 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageRequester::HandleAllData parsed Message XML file : "+message["Identifier"]);
\r
251 else // couldn't insert - was already in database
\r
253 //m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAddData could not insert message into database. "+message["Identifier"]);
\r
256 } // if validmessage
\r
260 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleAllData error parsing Message XML file : "+message["Identifier"]);
\r
263 RemoveFromRequestList(idparts[1]);
\r
268 const bool MessageRequester::HandleGetFailed(FCPMessage &message)
\r
271 SQLite3DB::Statement st;
\r
272 std::vector<std::string> idparts;
\r
273 std::string requestid;
\r
278 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
279 requestid=idparts[1];
\r
280 StringFunctions::Convert(idparts[2],identityid);
\r
281 StringFunctions::Convert(idparts[4],index);
\r
283 // if this is a fatal error - insert index into database so we won't try to download this index again
\r
284 if(message["Fatal"]=="true")
\r
286 st=m_db->Prepare("UPDATE tblMessageRequests SET Found='true' WHERE IdentityID=? AND Day=? AND RequestIndex=?;");
\r
287 st.Bind(0,identityid);
\r
288 st.Bind(1,idparts[3]);
\r
293 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"MessageRequester::HandleGetFailed fatal error requesting "+message["Identifier"]);
\r
296 // remove this identityid from request list
\r
297 RemoveFromRequestList(requestid);
\r
302 void MessageRequester::Initialize()
\r
304 m_fcpuniquename="MessageRequester";
\r
305 std::string tempval;
\r
306 Option::Instance()->Get("MaxMessageRequests",tempval);
\r
307 StringFunctions::Convert(tempval,m_maxrequests);
\r
308 if(m_maxrequests<1)
\r
311 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxMessageRequests is currently set at "+tempval+". It must be 1 or greater.");
\r
313 if(m_maxrequests>100)
\r
315 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxMessageRequests is currently set at "+tempval+". This value might be incorrectly configured.");
\r
317 Option::Instance()->Get("MessageDownloadMaxDaysBackward",tempval);
\r
318 StringFunctions::Convert(tempval,m_maxdaysbackward);
\r
319 if(m_maxdaysbackward<0)
\r
321 m_maxdaysbackward=0;
\r
322 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MessageDownloadMaxDaysBackward is currently set at "+tempval+". It must be 0 or greater.");
\r
324 if(m_maxdaysbackward>30)
\r
326 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MessageDownloadMaxDaysBackward is currently set at "+tempval+". This value might be incorrectly configured.");
\r
328 Option::Instance()->Get("MaxPeerMessagesPerDay",tempval);
\r
329 StringFunctions::Convert(tempval,m_maxpeermessages);
\r
330 if(m_maxpeermessages<1)
\r
332 m_maxpeermessages=1;
\r
333 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxPeerMessagesPerDay is currently set at "+tempval+". It must be 1 or greater.");
\r
335 if(m_maxpeermessages<20 || m_maxpeermessages>1000)
\r
337 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxPeerMessagesPerDay is currently set at "+tempval+". This value might be incorrectly configured. The suggested value is 200.");
\r
339 Option::Instance()->Get("MaxBoardsPerMessage",tempval);
\r
340 StringFunctions::Convert(tempval,m_maxboardspermessage);
\r
341 if(m_maxboardspermessage<1)
\r
343 m_maxboardspermessage=1;
\r
344 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxBoardsPerMessage is currently set at "+tempval+". It must be 1 or greater.");
\r
346 if(m_maxboardspermessage>20)
\r
348 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxBoardsPerMessage is currently set at "+tempval+". This value might be incorrectly configured.");
\r
350 Option::Instance()->Get("SaveMessagesFromNewBoards",tempval);
\r
351 if(tempval=="true")
\r
353 m_savemessagesfromnewboards=true;
\r
357 m_savemessagesfromnewboards=false;
\r
361 void MessageRequester::PopulateIDList()
\r
370 date.SetToGMTime();
\r
371 date.Add(0,0,0,-m_maxdaysbackward);
\r
373 sql="SELECT tblIdentity.IdentityID,Day,RequestIndex ";
\r
374 sql+="FROM tblMessageRequests INNER JOIN tblIdentity ON tblMessageRequests.IdentityID=tblIdentity.IdentityID ";
\r
375 sql+="WHERE (tblIdentity.LocalMessageTrust IS NULL OR tblIdentity.LocalMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalMessageTrust')) ";
\r
376 sql+="AND FromMessageList='true' AND Found='false' AND Day>='"+date.Format("%Y-%m-%d")+"' ";
\r
377 sql+="AND (tblIdentity.PeerMessageTrust IS NULL OR tblIdentity.PeerMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerMessageTrust')) ";
\r
380 SQLite3DB::Statement st=m_db->Prepare(sql);
\r
385 while(st.RowReturned())
\r
387 st.ResultText(0,val1);
\r
388 st.ResultText(1,val2);
\r
389 st.ResultText(2,val3);
\r
392 StringFunctions::Convert(val3,requestindex);
\r
394 // only continue if index is < max messages we will accept from a peer
\r
395 if(requestindex<m_maxpeermessages)
\r
397 if(m_ids.find(val1+"*"+val2+"*"+val3)==m_ids.end())
\r
399 m_ids[val1+"*"+val2+"*"+val3]=false;
\r
407 const bool MessageRequester::SaveToBoard(const std::string &boardname)
\r
410 SQLite3DB::Statement st=m_db->Prepare("SELECT SaveReceivedMessages FROM tblBoard WHERE BoardName=?;");
\r
411 st.Bind(0,boardname);
\r
413 if(st.RowReturned())
\r
415 std::string val="";
\r
416 st.ResultText(0,val);
\r
429 void MessageRequester::StartRequest(const std::string &requestid)
\r
431 FCPMessage message;
\r
432 std::vector<std::string> parts;
\r
433 std::string tempval;
\r
436 std::string indexstr;
\r
437 std::string publickey;
\r
439 StringFunctions::Split(requestid,"*",parts);
\r
440 StringFunctions::Convert(parts[0],identityid);
\r
441 StringFunctions::Convert(parts[1],date);
\r
444 SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");
\r
445 st.Bind(0,identityid);
\r
448 if(st.RowReturned())
\r
450 st.ResultText(0,publickey);
\r
452 message.SetName("ClientGet");
\r
453 message["URI"]=publickey+m_messagebase+"|"+date+"|Message|"+indexstr+".xml";
\r
454 message["Identifier"]=m_fcpuniquename+"|"+requestid+"|"+parts[0]+"|"+parts[1]+"|"+parts[2]+"|"+message["URI"];
\r
455 message["ReturnType"]="direct";
\r
456 message["MaxSize"]="1000000"; // 1 MB
\r
457 message["MaxRetries"]="-1"; // use new ULPR since we are fairly sure message exists since the author says it does
\r
459 m_fcp->SendMessage(message);
\r
461 m_requesting.push_back(requestid);
\r
463 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"MessageRequester::StartRequest requesting "+message["Identifier"]);
\r
466 m_ids[requestid]=true;
\r