ee2dfaf38f279987c12a4a937b3a22831f6c1020
[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::HandleAllData(FCPMessage &message)\r
23 {       \r
24         SQLite3DB::Statement st;\r
25         SQLite3DB::Statement trustst;\r
26         std::vector<std::string> idparts;\r
27         long datalength;\r
28         std::vector<char> data;\r
29         MessageListXML xml;\r
30         long identityid;\r
31         long index;\r
32 \r
33         StringFunctions::Split(message["Identifier"],"|",idparts);\r
34         StringFunctions::Convert(message["DataLength"],datalength);\r
35         StringFunctions::Convert(idparts[1],identityid);\r
36         StringFunctions::Convert(idparts[2],index);\r
37 \r
38         // wait for all data to be received from connection\r
39         while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
40         {\r
41                 m_fcp->Update(1);\r
42         }\r
43 \r
44         // if we got disconnected- return immediately\r
45         if(m_fcp->Connected()==false)\r
46         {\r
47                 return false;\r
48         }\r
49 \r
50         // receive the file\r
51         data.resize(datalength);\r
52         m_fcp->ReceiveRaw(&data[0],datalength);\r
53 \r
54         // parse file into xml and update the database\r
55         if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
56         {\r
57 \r
58                 SQLite3DB::Statement st=m_db->Prepare("SELECT IdentityID FROM tblMessageRequests WHERE IdentityID=? AND Day=? AND RequestIndex=?;");\r
59                 SQLite3DB::Statement spk=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
60                 SQLite3DB::Statement mst=m_db->Prepare("INSERT INTO tblMessageRequests(IdentityID,Day,RequestIndex,FromMessageList) VALUES(?,?,?,'true');");\r
61                 for(long i=0; i<xml.MessageCount(); i++)\r
62                 {\r
63                         st.Bind(0,identityid);\r
64                         st.Bind(1,xml.GetDate(i));\r
65                         st.Bind(2,xml.GetIndex(i));\r
66                         st.Step();\r
67                         if(st.RowReturned()==false)\r
68                         {\r
69                                 mst.Bind(0,identityid);\r
70                                 mst.Bind(1,xml.GetDate(i));\r
71                                 mst.Bind(2,xml.GetIndex(i));\r
72                                 mst.Step();\r
73                                 mst.Reset();\r
74                         }\r
75                         st.Reset();\r
76                 }\r
77 \r
78                 // insert external message indexes\r
79                 for(long i=0; i<xml.ExternalMessageCount(); i++)\r
80                 {\r
81                         if(xml.GetExternalType(i)=="Keyed")\r
82                         {\r
83                                 spk.Bind(0,xml.GetExternalIdentity(i));\r
84                                 spk.Step();\r
85                                 if(spk.RowReturned())\r
86                                 {\r
87                                         int thisidentityid=0;\r
88                                         spk.ResultInt(0,thisidentityid);\r
89                                         mst.Bind(0,thisidentityid);\r
90                                         mst.Bind(1,xml.GetExternalDate(i));\r
91                                         mst.Bind(2,xml.GetExternalIndex(i));\r
92                                         mst.Step();\r
93                                         mst.Reset();\r
94                                 }\r
95                                 spk.Reset();\r
96                         }\r
97                 }\r
98 \r
99                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
100                 st.Bind(0,identityid);\r
101                 st.Bind(1,idparts[4]);\r
102                 st.Bind(2,index);\r
103                 st.Step();\r
104                 st.Finalize();\r
105 \r
106                 m_log->debug("MessageListRequester::HandleAllData parsed MessageList XML file : "+message["Identifier"]);\r
107         }\r
108         else\r
109         {\r
110                 // bad data - mark index\r
111                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
112                 st.Bind(0,identityid);\r
113                 st.Bind(1,idparts[4]);\r
114                 st.Bind(2,index);\r
115                 st.Step();\r
116                 st.Finalize();\r
117 \r
118                 m_log->error("MessageListRequester::HandleAllData error parsing MessageList XML file : "+message["Identifier"]);\r
119         }\r
120 \r
121         // remove this identityid from request list\r
122         RemoveFromRequestList(identityid);\r
123 \r
124         return true;\r
125 \r
126 }\r
127 \r
128 const bool MessageListRequester::HandleGetFailed(FCPMessage &message)\r
129 {\r
130         SQLite3DB::Statement st;\r
131         std::vector<std::string> idparts;\r
132         long identityid;\r
133         long index;\r
134 \r
135         StringFunctions::Split(message["Identifier"],"|",idparts);\r
136         StringFunctions::Convert(idparts[1],identityid);\r
137         StringFunctions::Convert(idparts[2],index);     \r
138 \r
139         // code 27 - permanent redirect\r
140         if(message["Code"]=="27")\r
141         {\r
142                 StartRedirectRequest(message);\r
143                 return true;\r
144         }\r
145 \r
146         // if this is a fatal error - insert index into database so we won't try to download this index again\r
147         if(message["Fatal"]=="true")\r
148         {\r
149                 st=m_db->Prepare("INSERT INTO tblMessageListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
150                 st.Bind(0,identityid);\r
151                 st.Bind(1,idparts[4]);\r
152                 st.Bind(2,index);\r
153                 st.Step();\r
154                 st.Finalize();\r
155 \r
156                 m_log->error("MessageListRequester::HandleGetFailed fatal error code="+message["Code"]+" requesting "+message["Identifier"]);\r
157         }\r
158 \r
159         // remove this identityid from request list\r
160         RemoveFromRequestList(identityid);\r
161 \r
162         return true;\r
163 }\r
164 \r
165 void MessageListRequester::Initialize()\r
166 {\r
167         m_fcpuniquename="MessageListRequester";\r
168         std::string tempval;\r
169         Option::Instance()->Get("MaxMessageListRequests",tempval);\r
170         StringFunctions::Convert(tempval,m_maxrequests);\r
171         if(m_maxrequests<1)\r
172         {\r
173                 m_maxrequests=1;\r
174                 m_log->error("Option MaxMessageListRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
175         }\r
176         if(m_maxrequests>100)\r
177         {\r
178                 m_log->warning("Option MaxMessageListRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
179         }\r
180 \r
181         Option::Instance()->Get("LocalTrustOverridesPeerTrust",tempval);\r
182         if(tempval=="true")\r
183         {\r
184                 m_localtrustoverrides=true;\r
185         }\r
186         else\r
187         {\r
188                 m_localtrustoverrides=false;\r
189         }\r
190 \r
191 }\r
192 \r
193 void MessageListRequester::PopulateIDList()\r
194 {\r
195         Poco::DateTime date;\r
196         int id;\r
197 \r
198         SQLite3DB::Statement st;\r
199 \r
200         // 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
201         if(m_localtrustoverrides==false)\r
202         {\r
203                 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
204         }\r
205         else\r
206         {\r
207                 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
208         }\r
209         st.Step();\r
210 \r
211         m_ids.clear();\r
212 \r
213         while(st.RowReturned())\r
214         {\r
215                 st.ResultInt(0,id);\r
216                 m_ids[id]=false;\r
217                 st.Step();\r
218         }\r
219 }\r
220 \r
221 void MessageListRequester::StartRedirectRequest(FCPMessage &message)\r
222 {\r
223         std::vector<std::string> parts;\r
224         std::string indexstr="";\r
225         std::string identityidstr="";\r
226         std::string datestr="";\r
227         FCPMessage newmessage;\r
228 \r
229         // get the new edition #\r
230         StringFunctions::Split(message["RedirectURI"],"/",parts);\r
231         //edition # is 2nd to last part\r
232         if(parts.size()>2)\r
233         {\r
234                 indexstr=parts[parts.size()-2];\r
235         }\r
236 \r
237         // get identityid\r
238         parts.clear();\r
239         StringFunctions::Split(message["Identifier"],"|",parts);\r
240         if(parts.size()>1)\r
241         {\r
242                 identityidstr=parts[1];\r
243         }\r
244         if(parts.size()>4)\r
245         {\r
246                 datestr=parts[4];\r
247         }\r
248 \r
249         newmessage.SetName("ClientGet");\r
250         newmessage["URI"]=StringFunctions::UriDecode(message["RedirectURI"]);\r
251         newmessage["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|_|"+datestr+"|"+newmessage["URI"];\r
252         newmessage["ReturnType"]="direct";\r
253         newmessage["MaxSize"]="1000000";\r
254 \r
255         m_fcp->SendMessage(newmessage);\r
256 \r
257 }\r
258 \r
259 void MessageListRequester::StartRequest(const long &id)\r
260 {\r
261         Poco::DateTime now;\r
262         FCPMessage message;\r
263         std::string publickey;\r
264         int index=0;\r
265         std::string indexstr;\r
266         std::string identityidstr;\r
267 \r
268         SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
269         st.Bind(0,id);\r
270         st.Step();\r
271 \r
272         if(st.RowReturned())\r
273         {\r
274                 st.ResultText(0,publickey);\r
275 \r
276                 now=Poco::Timestamp();\r
277 \r
278                 SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblMessageListRequests WHERE Day=? AND IdentityID=?;");\r
279                 st2.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d"));\r
280                 st2.Bind(1,id);\r
281                 st2.Step();\r
282 \r
283                 index=0;\r
284                 if(st2.RowReturned())\r
285                 {\r
286                         if(st2.ResultNull(0)==false)\r
287                         {\r
288                                 st2.ResultInt(0,index);\r
289                                 // don't increment index here - the node will let us know if there is a new edition\r
290                                 // 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
291                                 index++;\r
292                         }\r
293                 }\r
294                 st2.Finalize();\r
295 \r
296                 StringFunctions::Convert(index,indexstr);\r
297                 StringFunctions::Convert(id,identityidstr);\r
298 \r
299                 message.SetName("ClientGet");\r
300                 message["URI"]="USK"+publickey.substr(3)+m_messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y.%m.%d")+"|MessageList/"+indexstr+"/MessageList.xml";\r
301                 message["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|_|"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"|"+message["URI"];\r
302                 message["ReturnType"]="direct";\r
303                 message["MaxSize"]="1000000";\r
304 \r
305                 m_fcp->SendMessage(message);\r
306 \r
307                 m_requesting.push_back(id);\r
308         }\r
309         st.Finalize();\r
310 \r
311         m_ids[id]=true;\r
312 }\r