1d42675d59379b4f464ee98aa0dbd7349f6defd6
[fms.git] / src / freenet / messagelistrequester.cpp
1 #include "../../include/freenet/messagelistrequester.h"\r
2 #include "../../include/freenet/messagelistxml.h"\r
3 \r
4 #include <Poco/DateTime.h>\r
5 #include <Poco/DateTimeFormatter.h>\r
6 #include <Poco/Timestamp.h>\r
7 \r
8 #ifdef XMEM\r
9         #include <xmem.h>\r
10 #endif\r
11 \r
12 MessageListRequester::MessageListRequester()\r
13 {\r
14         Initialize();\r
15 }\r
16 \r
17 MessageListRequester::MessageListRequester(FCPv2 *fcp):IIndexRequester<long>(fcp)\r
18 {\r
19         Initialize();\r
20 }\r
21 \r
22 const bool MessageListRequester::CheckDateNotFuture(const std::string &datestr) const\r
23 {\r
24         std::vector<std::string> dateparts;\r
25         int year=0;\r
26         int month=0;\r
27         int day=0;\r
28         Poco::DateTime today;\r
29 \r
30         StringFunctions::Split(datestr,"-",dateparts);\r
31         if(dateparts.size()==3)\r
32         {\r
33                 StringFunctions::Convert(dateparts[0],year);\r
34                 StringFunctions::Convert(dateparts[1],month);\r
35                 StringFunctions::Convert(dateparts[2],day);\r
36                 if(today.year()>year || (today.year()==year && today.month()>month) || (today.year()==year && today.month()==month && today.day()>=day))\r
37                 {\r
38                         return true;\r
39                 }\r
40                 else\r
41                 {\r
42                         return false;\r
43                 }\r
44         }\r
45         else\r
46         {\r
47                 return false;\r
48         }\r
49 \r
50 }\r
51 \r
52 void MessageListRequester::GetBoardList(std::map<std::string,bool> &boards)\r
53 {\r
54         SQLite3DB::Statement st=m_db->Prepare("SELECT BoardName, SaveReceivedMessages FROM tblBoard;");\r
55         st.Step();\r
56         while(st.RowReturned())\r
57         {\r
58                 std::string boardname="";\r
59                 std::string tempval="";\r
60                 st.ResultText(0,boardname);\r
61                 st.ResultText(1,tempval);\r
62 \r
63                 if(tempval=="true")\r
64                 {\r
65                         boards[boardname]=true;\r
66                 }\r
67                 else\r
68                 {\r
69                         boards[boardname]=false;\r
70                 }\r
71 \r
72                 st.Step();\r
73         }\r
74 }\r
75 \r
76 const bool MessageListRequester::HandleAllData(FCPMessage &message)\r
77 {       \r
78         SQLite3DB::Statement st;\r
79         SQLite3DB::Statement trustst;\r
80         std::vector<std::string> idparts;\r
81         long datalength;\r
82         std::vector<char> data;\r
83         MessageListXML xml;\r
84         long identityid;\r
85         long index;\r
86         std::map<std::string,bool> boards;      // list of boards and if we will save messages for that board or not\r
87         bool addmessage=false;\r
88         std::string boardsstr="";\r
89         std::string datestr="";\r
90         std::vector<std::string> dateparts;\r
91 \r
92         GetBoardList(boards);\r
93 \r
94         StringFunctions::Split(message["Identifier"],"|",idparts);\r
95         StringFunctions::Convert(message["DataLength"],datalength);\r
96         StringFunctions::Convert(idparts[1],identityid);\r
97         StringFunctions::Convert(idparts[2],index);\r
98 \r
99         // wait for all data to be received from connection\r
100         while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
101         {\r
102                 m_fcp->Update(1);\r
103         }\r
104 \r
105         // if we got disconnected- return immediately\r
106         if(m_fcp->Connected()==false)\r
107         {\r
108                 return false;\r
109         }\r
110 \r
111         // receive the file\r
112         data.resize(datalength);\r
113         m_fcp->ReceiveRaw(&data[0],datalength);\r
114 \r
115         // parse file into xml and update the database\r
116         if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
117         {\r
118 \r
119                 SQLite3DB::Statement st=m_db->Prepare("SELECT IdentityID FROM tblMessageRequests WHERE IdentityID=? AND Day=? AND RequestIndex=?;");\r
120                 SQLite3DB::Statement spk=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
121                 SQLite3DB::Statement mst=m_db->Prepare("INSERT INTO tblMessageRequests(IdentityID,Day,RequestIndex,FromMessageList) VALUES(?,?,?,'true');");\r
122                 for(long i=0; i<xml.MessageCount(); i++)\r
123                 {\r
124 \r
125                         // go through each board the message was posted to and see if we are saving messages to that board\r
126                         // if the board isn't found, see if we are saving messages to new boards\r
127                         boardsstr="";\r
128                         addmessage=false;\r
129                         std::vector<std::string> messageboards=xml.GetBoards(i);\r
130                         for(std::vector<std::string>::iterator j=messageboards.begin(); j!=messageboards.end(); j++)\r
131                         {\r
132                                 if(boards.find((*j))!=boards.end())\r
133                                 {\r
134                                         if(boards[(*j)]==true)\r
135                                         {\r
136                                                 addmessage=true;\r
137                                         }\r
138                                 }\r
139                                 else if(m_savetonewboards==true)\r
140                                 {\r
141                                         addmessage=true;\r
142                                 }\r
143                                 if(j!=messageboards.begin())\r
144                                 {\r
145                                         boardsstr+=", ";\r
146                                 }\r
147                                 boardsstr+=(*j);\r
148                         }\r
149 \r
150                         if(CheckDateNotFuture(xml.GetDate(i))==false)\r
151                         {\r
152                                 addmessage=false;\r
153                                 m_log->error("MessageListRequester::HandleAllData date for message is in future! "+xml.GetDate(i));\r
154                         }\r
155 \r
156                         if(addmessage==true)\r
157                         {\r
158                                 st.Bind(0,identityid);\r
159                                 st.Bind(1,xml.GetDate(i));\r
160                                 st.Bind(2,xml.GetIndex(i));\r
161                                 st.Step();\r
162                                 if(st.RowReturned()==false)\r
163                                 {\r
164                                         mst.Bind(0,identityid);\r
165                                         mst.Bind(1,xml.GetDate(i));\r
166                                         mst.Bind(2,xml.GetIndex(i));\r
167                                         mst.Step();\r
168                                         mst.Reset();\r
169                                 }\r
170                                 st.Reset();\r
171                         }\r
172                         else\r
173                         {\r
174                                 m_log->trace("MessageListRequester::HandleAllData will not download message posted to "+boardsstr);\r
175                         }\r
176                 }\r
177 \r
178                 // insert external message indexes\r
179                 for(long i=0; i<xml.ExternalMessageCount(); i++)\r
180                 {\r
181                         if(xml.GetExternalType(i)=="Keyed")\r
182                         {\r
183                                 // go through each board the message was posted to and see if we are saving messages to that board\r
184                                 // if the board isn't found, see if we are saving messages to new boards\r
185                                 boardsstr="";\r
186                                 addmessage=false;\r
187                                 std::vector<std::string> messageboards=xml.GetExternalBoards(i);\r
188                                 for(std::vector<std::string>::iterator j=messageboards.begin(); j!=messageboards.end(); j++)\r
189                                 {\r
190                                         if(boards.find((*j))!=boards.end())\r
191                                         {\r
192                                                 if(boards[(*j)]==true)\r
193                                                 {\r
194                                                         addmessage=true;\r
195                                                 }\r
196                                         }\r
197                                         else if(m_savetonewboards==true)\r
198                                         {\r
199                                                 addmessage=true;\r
200                                         }\r
201                                         if(j!=messageboards.begin())\r
202                                         {\r
203                                                 boardsstr+=", ";\r
204                                         }\r
205                                         boardsstr+=(*j);\r
206                                 }\r
207 \r
208                                 if(CheckDateNotFuture(xml.GetExternalDate(i))==false)\r
209                                 {\r
210                                         addmessage=false;\r
211                                         m_log->error("MessageListRequester::HandleAllData date for external message is in future! "+xml.GetExternalDate(i));\r
212                                 }\r
213 \r
214                                 if(addmessage==true)\r
215                                 {\r
216                                         spk.Bind(0,xml.GetExternalIdentity(i));\r
217                                         spk.Step();\r
218                                         if(spk.RowReturned())\r
219                                         {\r
220                                                 int thisidentityid=0;\r
221                                                 spk.ResultInt(0,thisidentityid);\r
222                                                 mst.Bind(0,thisidentityid);\r
223                                                 mst.Bind(1,xml.GetExternalDate(i));\r
224                                                 mst.Bind(2,xml.GetExternalIndex(i));\r
225                                                 mst.Step();\r
226                                                 mst.Reset();\r
227                                         }\r
228                                         spk.Reset();\r
229                                 }\r
230                                 else\r
231                                 {\r
232                                         m_log->trace("MessageListRequester::HandleAllData will not download external message posted to "+boardsstr+" from " + xml.GetExternalIdentity(i));\r
233                                 }\r
234                         }\r
235                 }\r
236 \r
237                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
238                 st.Bind(0,identityid);\r
239                 st.Bind(1,idparts[4]);\r
240                 st.Bind(2,index);\r
241                 st.Step();\r
242                 st.Finalize();\r
243 \r
244                 m_log->debug("MessageListRequester::HandleAllData parsed MessageList XML file : "+message["Identifier"]);\r
245         }\r
246         else\r
247         {\r
248                 // bad data - mark index\r
249                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
250                 st.Bind(0,identityid);\r
251                 st.Bind(1,idparts[4]);\r
252                 st.Bind(2,index);\r
253                 st.Step();\r
254                 st.Finalize();\r
255 \r
256                 m_log->error("MessageListRequester::HandleAllData error parsing MessageList XML file : "+message["Identifier"]);\r
257         }\r
258 \r
259         // remove this identityid from request list\r
260         RemoveFromRequestList(identityid);\r
261 \r
262         return true;\r
263 \r
264 }\r
265 \r
266 const bool MessageListRequester::HandleGetFailed(FCPMessage &message)\r
267 {\r
268         SQLite3DB::Statement st;\r
269         std::vector<std::string> idparts;\r
270         long identityid;\r
271         long index;\r
272 \r
273         StringFunctions::Split(message["Identifier"],"|",idparts);\r
274         StringFunctions::Convert(idparts[1],identityid);\r
275         StringFunctions::Convert(idparts[2],index);     \r
276 \r
277         // code 27 - permanent redirect\r
278         if(message["Code"]=="27")\r
279         {\r
280                 StartRedirectRequest(message);\r
281                 return true;\r
282         }\r
283 \r
284         // if this is a fatal error - insert index into database so we won't try to download this index again\r
285         if(message["Fatal"]=="true")\r
286         {\r
287                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
288                 st.Bind(0,identityid);\r
289                 st.Bind(1,idparts[4]);\r
290                 st.Bind(2,index);\r
291                 st.Step();\r
292                 st.Finalize();\r
293 \r
294                 m_log->error("MessageListRequester::HandleGetFailed fatal error code="+message["Code"]+" requesting "+message["Identifier"]);\r
295         }\r
296 \r
297         // remove this identityid from request list\r
298         RemoveFromRequestList(identityid);\r
299 \r
300         return true;\r
301 }\r
302 \r
303 void MessageListRequester::Initialize()\r
304 {\r
305         m_fcpuniquename="MessageListRequester";\r
306         std::string tempval="";\r
307 \r
308         m_maxrequests=0;\r
309         Option::Instance()->GetInt("MaxMessageListRequests",m_maxrequests);\r
310         if(m_maxrequests<1)\r
311         {\r
312                 m_maxrequests=1;\r
313                 m_log->error("Option MaxMessageListRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
314         }\r
315         if(m_maxrequests>100)\r
316         {\r
317                 m_log->warning("Option MaxMessageListRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
318         }\r
319 \r
320         tempval="";\r
321         Option::Instance()->Get("LocalTrustOverridesPeerTrust",tempval);\r
322         if(tempval=="true")\r
323         {\r
324                 m_localtrustoverrides=true;\r
325         }\r
326         else\r
327         {\r
328                 m_localtrustoverrides=false;\r
329         }\r
330 \r
331         tempval="";\r
332         Option::Instance()->Get("SaveMessagesFromNewBoards",tempval);\r
333         if(tempval=="true")\r
334         {\r
335                 m_savetonewboards=true;\r
336         }\r
337         else\r
338         {\r
339                 m_savetonewboards=false;\r
340         }\r
341 \r
342 }\r
343 \r
344 void MessageListRequester::PopulateIDList()\r
345 {\r
346         Poco::DateTime date;\r
347         int id;\r
348 \r
349         SQLite3DB::Statement st;\r
350 \r
351         // select identities we want to query (we've seen them today) - sort by their trust level (descending) with secondary sort on how long ago we saw them (ascending)\r
352         if(m_localtrustoverrides==false)\r
353         {\r
354                 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND LastSeen>='"+Poco::DateTimeFormatter::format(date,"%Y-%m-%d")+"' AND (LocalMessageTrust IS NULL OR LocalMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalMessageTrust')) AND (PeerMessageTrust IS NULL OR PeerMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerMessageTrust')) ORDER BY LocalMessageTrust+LocalTrustListTrust DESC, LastSeen;");\r
355         }\r
356         else\r
357         {\r
358                 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND LastSeen>='"+Poco::DateTimeFormatter::format(date,"%Y-%m-%d")+"' AND (LocalMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalMessageTrust') OR (LocalMessageTrust IS NULL AND (PeerMessageTrust IS NULL OR PeerMessageTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerMessageTrust')))) ORDER BY LocalMessageTrust+LocalTrustListTrust DESC, LastSeen;");\r
359         }\r
360         st.Step();\r
361 \r
362         m_ids.clear();\r
363 \r
364         while(st.RowReturned())\r
365         {\r
366                 st.ResultInt(0,id);\r
367                 m_ids[id]=false;\r
368                 st.Step();\r
369         }\r
370 }\r
371 \r
372 void MessageListRequester::StartRedirectRequest(FCPMessage &message)\r
373 {\r
374         std::vector<std::string> parts;\r
375         std::string indexstr="";\r
376         std::string identityidstr="";\r
377         std::string datestr="";\r
378         FCPMessage newmessage;\r
379 \r
380         // get the new edition #\r
381         StringFunctions::Split(message["RedirectURI"],"/",parts);\r
382         //edition # is 2nd to last part\r
383         if(parts.size()>2)\r
384         {\r
385                 indexstr=parts[parts.size()-2];\r
386         }\r
387 \r
388         // get identityid\r
389         parts.clear();\r
390         StringFunctions::Split(message["Identifier"],"|",parts);\r
391         if(parts.size()>1)\r
392         {\r
393                 identityidstr=parts[1];\r
394         }\r
395         if(parts.size()>4)\r
396         {\r
397                 datestr=parts[4];\r
398         }\r
399 \r
400         newmessage.SetName("ClientGet");\r
401         newmessage["URI"]=StringFunctions::UriDecode(message["RedirectURI"]);\r
402         newmessage["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|_|"+datestr+"|"+newmessage["URI"];\r
403         newmessage["ReturnType"]="direct";\r
404         newmessage["MaxSize"]="1000000";\r
405 \r
406         m_fcp->SendMessage(newmessage);\r
407 \r
408 }\r
409 \r
410 void MessageListRequester::StartRequest(const long &id)\r
411 {\r
412         Poco::DateTime now;\r
413         FCPMessage message;\r
414         std::string publickey;\r
415         int index=0;\r
416         std::string indexstr;\r
417         std::string identityidstr;\r
418 \r
419         SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
420         st.Bind(0,id);\r
421         st.Step();\r
422 \r
423         if(st.RowReturned())\r
424         {\r
425                 st.ResultText(0,publickey);\r
426 \r
427                 now=Poco::Timestamp();\r
428 \r
429                 SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblMessageListRequests WHERE Day=? AND IdentityID=?;");\r
430                 st2.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d"));\r
431                 st2.Bind(1,id);\r
432                 st2.Step();\r
433 \r
434                 index=0;\r
435                 if(st2.RowReturned())\r
436                 {\r
437                         if(st2.ResultNull(0)==false)\r
438                         {\r
439                                 st2.ResultInt(0,index);\r
440                                 // don't increment index here - the node will let us know if there is a new edition\r
441                                 // 2008-05-31 - well actually the node isn't reliably retreiving the latest edition for USKs, so we DO need to increment the index\r
442                                 index++;\r
443                         }\r
444                 }\r
445                 st2.Finalize();\r
446 \r
447                 StringFunctions::Convert(index,indexstr);\r
448                 StringFunctions::Convert(id,identityidstr);\r
449 \r
450                 message.SetName("ClientGet");\r
451                 message["URI"]="USK"+publickey.substr(3)+m_messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y.%m.%d")+"|MessageList/"+indexstr+"/MessageList.xml";\r
452                 message["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|_|"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"|"+message["URI"];\r
453                 message["ReturnType"]="direct";\r
454                 message["MaxSize"]="1000000";\r
455 \r
456                 m_fcp->SendMessage(message);\r
457 \r
458                 m_requesting.push_back(id);\r
459         }\r
460         st.Finalize();\r
461 \r
462         m_ids[id]=true;\r
463 }\r