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