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