version 0.3.29
[fms.git] / src / freenet / siteinserter.cpp
1 #include "../../include/freenet/siteinserter.h"\r
2 #include "../../include/global.h"\r
3 \r
4 #include <Poco/DateTime.h>\r
5 #include <Poco/Timespan.h>\r
6 #include <Poco/DateTimeFormatter.h>\r
7 #include <cstdio>\r
8 \r
9 #ifdef XMEM\r
10         #include <xmem.h>\r
11 #endif\r
12 \r
13 SiteInserter::SiteInserter(SQLite3DB::DB *db):IIndexInserter<long>(db)\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 SiteInserter::SiteInserter(SQLite3DB::DB *db, FCPv2::Connection *fcp):IIndexInserter<long>(db,fcp)\r
19 {\r
20         Initialize();\r
21 }\r
22 \r
23 void SiteInserter::CheckForNeededInsert()\r
24 {\r
25         // only do 1 insert at a time\r
26         if(m_inserting.size()==0)\r
27         {\r
28                 Poco::DateTime date;\r
29                 date.assign(date.year(),date.month(),date.day(),0,0,0);\r
30 \r
31                 SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblLocalIdentity WHERE PublishFreesite='true' AND (LastInsertedFreesite IS NULL OR LastInsertedFreesite<?);");\r
32                 st.Bind(0,Poco::DateTimeFormatter::format(date,"%Y-%m-%d"));\r
33 \r
34                 st.Step();\r
35                 if(st.RowReturned())\r
36                 {\r
37                         int localidentityid=0;\r
38                         st.ResultInt(0,localidentityid);\r
39                         StartInsert(localidentityid);\r
40                 }\r
41         }\r
42 }\r
43 \r
44 std::string SiteInserter::GenerateIndex(const std::string &htmltemplate, const long localidentityid, const std::string &name)\r
45 {\r
46         std::string content="";\r
47 \r
48         SQLite3DB::Statement boardst=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard INNER JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID WHERE tblMessageBoard.MessageID=? ORDER BY tblBoard.BoardName COLLATE NOCASE;");\r
49         SQLite3DB::Statement st=m_db->Prepare("SELECT tblMessage.Body, tblMessage.Subject, tblMessage.MessageID FROM tblMessage INNER JOIN tblIdentity ON tblMessage.IdentityID=tblIdentity.IdentityID INNER JOIN tblLocalIdentity ON tblIdentity.PublicKey=tblLocalIdentity.PublicKey WHERE tblLocalIdentity.LocalIdentityID=? ORDER BY tblMessage.MessageDate DESC, tblMessage.MessageTime DESC LIMIT 0,10;");\r
50         st.Bind(0,localidentityid);\r
51         st.Step();\r
52 \r
53         while(st.RowReturned())\r
54         {\r
55                 std::string post="";\r
56                 std::string subject="";\r
57                 std::string boards="";\r
58                 int messageid=0;\r
59 \r
60                 st.ResultText(0,post);\r
61                 st.ResultText(1,subject);\r
62                 st.ResultInt(2,messageid);\r
63 \r
64                 boardst.Bind(0,messageid);\r
65                 boardst.Step();\r
66                 while(boardst.RowReturned())\r
67                 {\r
68                         std::string board="";\r
69                         boardst.ResultText(0,board);\r
70                         if(boards!="")\r
71                         {\r
72                                 boards+=",";\r
73                         }\r
74                         boards+=board;\r
75                         boardst.Step();\r
76                 }\r
77                 boardst.Reset();\r
78 \r
79                 content+="<div class=\"post\">";\r
80                 content+="<div class=\"postboards\">";\r
81                 content+=SanitizeOutput(boards);\r
82                 content+="</div>";\r
83                 content+="<div class=\"postsubject\">";\r
84                 content+=SanitizeOutput(subject);\r
85                 content+="</div>";\r
86                 content+="<div class=\"postbody\">";\r
87                 content+=SanitizeOutput(post);\r
88                 //post=SanitizeOutput(post);\r
89                 //StringFunctions::Replace(post,"\r\n","<br>");\r
90                 //content+=post;\r
91                 content+="</div>";\r
92                 content+="</div>";\r
93 \r
94                 st.Step();\r
95         }\r
96 \r
97         return StringFunctions::Replace(htmltemplate,"[CONTENT]",content);\r
98 \r
99 }\r
100 \r
101 std::string SiteInserter::GenerateLinks(const bool publishtrustlist, const bool publishboardlist)\r
102 {\r
103         std::string links="";\r
104         links+="<ul>";\r
105         links+="<li><a href=\"index.htm\">Home</a></li>";\r
106         if(publishtrustlist)\r
107         {\r
108                 links+="<li><a href=\"trustlist.htm\">Trust List</a></li>";\r
109         }\r
110         if(publishboardlist)\r
111         {\r
112 //              links+="<li><a href=\"boardlist.htm\">Board List</a></li>";\r
113         }\r
114         links+="</ul>";\r
115         return links;\r
116 }\r
117 \r
118 void SiteInserter::GeneratePages(const long localidentityid, std::string &uskkey, std::map<std::string,std::string> &pages)\r
119 {\r
120         SQLite3DB::Statement st=m_db->Prepare("SELECT Name, PrivateKey, PublishTrustList, PublishBoardList, FreesiteEdition FROM tblLocalIdentity WHERE LocalIdentityID=?;");\r
121         st.Bind(0,localidentityid);\r
122         st.Step();\r
123 \r
124         if(st.RowReturned())\r
125         {\r
126                 std::string htmltemplate="";\r
127                 std::string filename="";\r
128                 std::string name="";\r
129                 std::string key="";\r
130                 std::string publishtrustliststr="";\r
131                 std::string publishboardliststr="";\r
132                 bool publishtrustlist=false;\r
133                 bool publishboardlist=false;\r
134                 std::string editionstr="";\r
135 \r
136                 st.ResultText(0,name);\r
137                 st.ResultText(1,key);\r
138                 st.ResultText(2,publishtrustliststr);\r
139                 st.ResultText(3,publishboardliststr);\r
140                 st.ResultText(4,editionstr);\r
141 \r
142                 publishtrustliststr=="true" ? publishtrustlist=true : publishtrustlist=false;\r
143                 publishboardliststr=="true" ? publishboardlist=true : publishboardlist=false;\r
144                 // no edition exists - start at 0\r
145                 if(editionstr=="")\r
146                 {\r
147                         editionstr="0";\r
148                 }\r
149                 // previous edition exists - add 1\r
150                 else\r
151                 {\r
152                         int edition=0;\r
153                         StringFunctions::Convert(editionstr,edition);\r
154                         edition++;\r
155                         StringFunctions::Convert(edition,editionstr);\r
156                 }\r
157 \r
158                 // make SSK a USK\r
159                 if(key.find("SSK@")==0)\r
160                 {\r
161                         key.erase(0,3);\r
162                         key="USK"+key;\r
163                 }\r
164                 key+=m_messagebase+"/"+editionstr+"/";\r
165                 uskkey=key;\r
166 \r
167                 filename=name+"-template.htm";\r
168                 FILE *infile=fopen(filename.c_str(),"rb");\r
169                 if(!infile)\r
170                 {\r
171                         infile=fopen("site-template.htm","rb");\r
172                 }\r
173                 if(infile)\r
174                 {\r
175                         fseek(infile,0,SEEK_END);\r
176                         long len=ftell(infile);\r
177                         fseek(infile,0,SEEK_SET);\r
178 \r
179                         std::vector<unsigned char> data;\r
180                         data.resize(len);\r
181                         fread(&data[0],1,data.size(),infile);\r
182                         fclose(infile);\r
183 \r
184                         htmltemplate.append(data.begin(),data.end());\r
185 \r
186                         htmltemplate=StringFunctions::Replace(htmltemplate,"[LINKS]",GenerateLinks(publishtrustlist,publishboardlist));\r
187                         htmltemplate=StringFunctions::Replace(htmltemplate,"[IDENTITYNAME]",SanitizeOutput(name));\r
188 \r
189                         pages["index.htm"]=GenerateIndex(htmltemplate,localidentityid,name);\r
190                         if(publishtrustlist)\r
191                         {\r
192                                 pages["trustlist.htm"]=GenerateTrustList(htmltemplate,localidentityid,name);\r
193                         }\r
194                         if(publishboardlist)\r
195                         {\r
196 //                              pages["boardlist.htm"]=GenerateBoardList(htmltemplate,localidentityid,name);\r
197                         }\r
198 \r
199                 }\r
200                 else\r
201                 {\r
202                         m_log->error("SiteInserter::GeneratePages unable to open "+filename+" or site-template.htm.");\r
203                 }\r
204 \r
205                 // get extra files that the user wants to add to the Freesite\r
206                 filename=name+"-files.txt";\r
207                 infile=fopen(filename.c_str(),"rb");\r
208                 if(infile)\r
209                 {\r
210                         std::vector<std::string> files;\r
211 \r
212                         fseek(infile,0,SEEK_END);\r
213                         long len=ftell(infile);\r
214                         fseek(infile,0,SEEK_SET);\r
215 \r
216                         std::vector<unsigned char> data;\r
217                         data.resize(len);\r
218                         fread(&data[0],1,data.size(),infile);\r
219                         fclose(infile);\r
220 \r
221                         // split on \r and \n - on systems with \r\n line endings there will be blank entries, but we'll just skip those\r
222                         std::string filecontent(data.begin(),data.end());\r
223                         StringFunctions::SplitMultiple(filecontent,"\r\n",files);\r
224 \r
225                         for(std::vector<std::string>::iterator i=files.begin(); i!=files.end(); i++)\r
226                         {\r
227                                 if((*i)!="" && (*i).find("index.htm")==std::string::npos && (*i).find("trustlist.htm")==std::string::npos && (*i).find("files.htm")==std::string::npos)\r
228                                 {\r
229                                         filename=(*i);\r
230                                         infile=fopen(filename.c_str(),"rb");\r
231                                         if(infile)\r
232                                         {\r
233                                                 fseek(infile,0,SEEK_END);\r
234                                                 len=ftell(infile);\r
235                                                 fseek(infile,0,SEEK_SET);\r
236 \r
237                                                 data.resize(len);\r
238                                                 fread(&data[0],1,data.size(),infile);\r
239                                                 fclose(infile);\r
240 \r
241                                                 filecontent="";\r
242                                                 filecontent.append(data.begin(),data.end());\r
243 \r
244                                                 // strip off path from filename\r
245                                                 while(filename.find_first_of("/")!=std::string::npos)\r
246                                                 {\r
247                                                         filename.erase(0,filename.find_first_of("/")+1);\r
248                                                 }\r
249 \r
250                                                 if(filecontent.size()>0)\r
251                                                 {\r
252                                                         pages[filename]=filecontent;\r
253                                                 }\r
254 \r
255                                         }\r
256                                         else\r
257                                         {\r
258                                                 m_log->error("SiteInserter::GeneratePages could not include user file "+(*i));\r
259                                         }\r
260                                 }\r
261                         }\r
262 \r
263                 }\r
264 \r
265         }\r
266 }\r
267 \r
268 std::string SiteInserter::GenerateTrustList(const std::string &htmltemplate, const long localidentityid, const std::string &name)\r
269 {\r
270         std::string content="";\r
271         Poco::DateTime date;\r
272 \r
273         date-=Poco::Timespan(20,0,0,0,0);\r
274         SQLite3DB::Statement st=m_db->Prepare("SELECT Name,PublicKey,tblIdentityTrust.LocalMessageTrust,tblIdentityTrust.LocalTrustListTrust,tblIdentity.IdentityID,tblIdentityTrust.MessageTrustComment,tblIdentityTrust.TrustListTrustComment,tblIdentity.FreesiteEdition FROM tblIdentity LEFT JOIN (SELECT IdentityID,LocalMessageTrust,LocalTrustListTrust,MessageTrustComment,TrustListTrustComment FROM tblIdentityTrust WHERE LocalIdentityID=?) AS 'tblIdentityTrust' ON tblIdentity.IdentityID=tblIdentityTrust.IdentityID WHERE PublicKey IS NOT NULL AND LastSeen IS NOT NULL AND LastSeen>=? ORDER BY Name COLLATE NOCASE;");\r
275         st.Bind(0,localidentityid);\r
276         st.Bind(1,Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));\r
277         st.Step();\r
278 \r
279         content+="<table class=\"trustlist\">";\r
280         content+="<tr class=\"title\"><thcolspan=\"5\">";\r
281         content+="Trust List of "+SanitizeOutput(name);\r
282         content+="</th></tr>";\r
283         content+="<tr class=\"headings\"><th></th><th>Message Trust</th><th>Message Comment</th><th>Trust List Trust</th><th>Trust Comment</th></tr>";\r
284         while(st.RowReturned())\r
285         {\r
286                 std::string idname="";\r
287                 std::string thisid="";\r
288                 std::string messagetrustcomment="";\r
289                 std::string trustlisttrustcomment="";\r
290                 std::string messagetrust="";\r
291                 std::string trustlisttrust="";\r
292                 std::string publickey="";\r
293                 std::string uskkey="";\r
294                 std::string freesiteedition="";\r
295 \r
296                 st.ResultText(0,idname);\r
297                 st.ResultText(1,publickey);\r
298                 st.ResultText(2,messagetrust);\r
299                 st.ResultText(3,trustlisttrust);\r
300                 st.ResultText(4,thisid);\r
301                 st.ResultText(5,messagetrustcomment);\r
302                 st.ResultText(6,trustlisttrustcomment);\r
303                 st.ResultText(7,freesiteedition);\r
304 \r
305                 if(freesiteedition!="")\r
306                 {\r
307                         if(publickey.find("SSK@")==0)\r
308                         {\r
309                                 uskkey=publickey;\r
310                                 uskkey.erase(0,3);\r
311                                 uskkey="USK"+uskkey;\r
312                                 uskkey+=m_messagebase+"/"+freesiteedition+"/";\r
313                         }\r
314                 }\r
315 \r
316                 content+="<tr>";\r
317                 if(freesiteedition!="")\r
318                 {\r
319                         content+="<td><div><a href=\""+uskkey+"\">"+SanitizeOutput(CreateShortIdentityName(idname,publickey))+"</a></div></td>";\r
320                 }\r
321                 else\r
322                 {\r
323                         content+="<td><div>"+SanitizeOutput(CreateShortIdentityName(idname,publickey))+"</div></td>";\r
324                 }\r
325                 content+="<td "+GetClassString(messagetrust)+">"+messagetrust+"</td>";\r
326                 content+="<td>"+SanitizeOutput(messagetrustcomment)+"</td>";\r
327                 content+="<td "+GetClassString(trustlisttrust)+">"+trustlisttrust+"</td>";\r
328                 content+="<td>"+SanitizeOutput(trustlisttrustcomment)+"</td>";\r
329                 content+="</tr>\r\n";\r
330 \r
331                 st.Step();\r
332         }\r
333         content+="</table>";\r
334 \r
335         return StringFunctions::Replace(htmltemplate,"[CONTENT]",content);\r
336 \r
337 }\r
338 \r
339 const std::string SiteInserter::GetClassString(const std::string &trustlevel)\r
340 {\r
341         int tempint=0;\r
342         std::string tempstr;\r
343 \r
344         StringFunctions::Convert(trustlevel,tempint);\r
345         tempint/=10;\r
346         StringFunctions::Convert(tempint,tempstr);\r
347 \r
348         if(trustlevel!="")\r
349         {\r
350                 return "class=\"trust"+tempstr+"\"";\r
351         }\r
352         else\r
353         {\r
354                 return "";\r
355         }\r
356 }\r
357 \r
358 const bool SiteInserter::HandlePutFailed(FCPv2::Message &message)\r
359 {\r
360         std::vector<std::string> idparts;\r
361         long localidentityid;\r
362 \r
363         StringFunctions::Split(message["Identifier"],"|",idparts);\r
364         StringFunctions::Convert(idparts[1],localidentityid);\r
365 \r
366         RemoveFromInsertList(localidentityid);\r
367 \r
368         m_log->error("SiteInserter::HandlePutFailed failed to insert Freesite, Freenet error code : "+message["Code"]);\r
369 \r
370         return true;\r
371 }\r
372 \r
373 const bool SiteInserter::HandlePutSuccessful(FCPv2::Message &message)\r
374 {\r
375         std::vector<std::string> idparts;\r
376         std::vector<std::string> uriparts;\r
377         long localidentityid;\r
378         int edition=-1;\r
379         Poco::DateTime now;\r
380 \r
381         StringFunctions::Split(message["Identifier"],"|",idparts);\r
382         StringFunctions::Convert(idparts[1],localidentityid);\r
383 \r
384         // edition is very last part of uri\r
385         StringFunctions::Split(message["URI"],"/",uriparts);\r
386         if(uriparts.size()>0)\r
387         {\r
388                 StringFunctions::Convert(uriparts[uriparts.size()-1],edition);\r
389         }\r
390 \r
391         SQLite3DB::Statement st=m_db->Prepare("UPDATE tblLocalIdentity SET LastInsertedFreesite=?, FreesiteEdition=? WHERE LocalIdentityID=?;");\r
392         st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
393         st.Bind(1,edition);\r
394         st.Bind(2,localidentityid);\r
395         st.Step();\r
396 \r
397         m_log->information("SiteInserter::HandlePutSuccessful successfully inserted Freesite.");\r
398 \r
399         RemoveFromInsertList(localidentityid);\r
400 \r
401         return true;\r
402 }\r
403 \r
404 void SiteInserter::Initialize()\r
405 {\r
406         m_fcpuniquename="SiteInserter";\r
407 }\r
408 \r
409 const std::string SiteInserter::SanitizeOutput(const std::string &input)\r
410 {\r
411         // must do & first because all other elements have & in them!\r
412         std::string output=StringFunctions::Replace(input,"&","&amp;");\r
413         output=StringFunctions::Replace(output,"<","&lt;");\r
414         output=StringFunctions::Replace(output,">","&gt;");\r
415         output=StringFunctions::Replace(output,"\"","&quot;");\r
416         output=StringFunctions::Replace(output," ","&nbsp;");\r
417         return output;\r
418 }\r
419 \r
420 const bool SiteInserter::StartInsert(const long &localidentityid)\r
421 {\r
422         FCPv2::Message message;\r
423         std::string localidentityidstr="";\r
424         std::string sizestr="";\r
425         std::string uskkey="";\r
426         std::map<std::string,std::string> pages;\r
427         int filenum=0;\r
428 \r
429         StringFunctions::Convert(localidentityid,localidentityidstr);\r
430 \r
431         GeneratePages(localidentityid,uskkey,pages);\r
432 \r
433         message.SetName("ClientPutComplexDir");\r
434         message["URI"]=uskkey;\r
435         message["Identifier"]=m_fcpuniquename+"|"+localidentityidstr+"|"+message["URI"];\r
436         message["DefaultName"]="index.htm";\r
437 \r
438         // add each page to the message\r
439         for(std::map<std::string,std::string>::iterator pagei=pages.begin(); pagei!=pages.end(); pagei++)\r
440         {\r
441                 std::string filenumstr;\r
442                 StringFunctions::Convert(filenum,filenumstr);\r
443 \r
444                 sizestr="0";\r
445                 StringFunctions::Convert((*pagei).second.size(),sizestr);\r
446 \r
447                 message["Files."+filenumstr+".Name"]=(*pagei).first;\r
448                 message["Files."+filenumstr+".UploadFrom"]="direct";\r
449                 message["Files."+filenumstr+".DataLength"]=sizestr;\r
450 \r
451                 filenum++;\r
452         }\r
453 \r
454         m_fcp->Send(message);\r
455 \r
456         // send data of each page\r
457         for(std::map<std::string,std::string>::iterator pagei=pages.begin(); pagei!=pages.end(); pagei++)\r
458         {\r
459                 m_fcp->Send(std::vector<char>((*pagei).second.begin(),(*pagei).second.end()));\r
460         }\r
461 \r
462         m_inserting.push_back(localidentityid);\r
463 \r
464         return true;\r
465 \r
466 }\r