version 0.3.0
[fms.git] / src / message.cpp
1 #include "../include/message.h"\r
2 #include "../include/nntp/mime/Mime.h"\r
3 #include "../include/stringfunctions.h"\r
4 #include "../include/freenet/messagexml.h"\r
5 #include "../include/option.h"\r
6 \r
7 #include <Poco/DateTimeParser.h>\r
8 #include <Poco/DateTimeFormatter.h>\r
9 #include <Poco/UUIDGenerator.h>\r
10 #include <Poco/UUID.h>\r
11 #include <algorithm>\r
12 \r
13 #ifdef DO_CHARSET_CONVERSION\r
14         #include "../include/charsetconverter.h"\r
15 #endif\r
16 \r
17 #ifdef XMEM\r
18         #include <xmem.h>\r
19 #endif\r
20 \r
21 Message::Message()\r
22 {\r
23         Initialize();\r
24 }\r
25 \r
26 Message::Message(const long messageid)\r
27 {\r
28         Load(messageid);\r
29 }\r
30 \r
31 const bool Message::CheckForAdministrationBoard(const std::vector<std::string> &boards)\r
32 {\r
33         std::string name;\r
34         SQLite3DB::Statement st=m_db->Prepare("SELECT BoardName FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID;");\r
35         st.Step();\r
36         \r
37         while(st.RowReturned())\r
38         {\r
39                 st.ResultText(0,name);\r
40 \r
41                 if(std::find(boards.begin(),boards.end(),name)!=boards.end())\r
42                 {\r
43                         return true;\r
44                 }\r
45                 \r
46                 st.Step();\r
47         }\r
48 \r
49         return false;\r
50 }\r
51 \r
52 const int Message::FindLocalIdentityID(const std::string &name)\r
53 {\r
54         SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblLocalIdentity WHERE Name=?;");\r
55         st.Bind(0,name);\r
56         st.Step();\r
57         if(st.RowReturned())\r
58         {\r
59                 int result=-1;\r
60                 st.ResultInt(0,result);\r
61                 return result;\r
62         }\r
63         else\r
64         {\r
65                 if(m_addnewpostfromidentities==true)\r
66                 {\r
67                         Poco::DateTime now;\r
68                         st=m_db->Prepare("INSERT INTO tblLocalIdentity(Name,DateCreated) VALUES(?,?);");\r
69                         st.Bind(0,name);\r
70                         st.Bind(1,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
71                         st.Step(true);\r
72                         return st.GetLastInsertRowID();\r
73                 }\r
74                 else\r
75                 {\r
76                         return -1;\r
77                 }\r
78         }\r
79 }\r
80 \r
81 const std::string Message::GetNNTPArticleID() const\r
82 {\r
83         // old message - before 0.1.12 - doesn't have @domain so add @freenetproject.org\r
84         if(m_messageuuid.find("@")==std::string::npos)\r
85         {\r
86                 return "<"+m_messageuuid+"@freenetproject.org>";\r
87         }\r
88         else\r
89         {\r
90                 return "<"+m_messageuuid+">";\r
91         }\r
92 }\r
93 \r
94 const std::string Message::GetNNTPBody() const\r
95 {\r
96         return m_body;\r
97 }\r
98 \r
99 const std::string Message::GetNNTPHeaders() const\r
100 {\r
101         std::string rval("");\r
102 \r
103         rval+="From: "+m_fromname+"\r\n";\r
104         rval+="Newsgroups: ";\r
105         for(std::vector<std::string>::const_iterator i=m_boards.begin(); i!=m_boards.end(); i++)\r
106         {\r
107                 if(i!=m_boards.begin())\r
108                 {\r
109                         rval+=",";\r
110                 }\r
111                 rval+=(*i);\r
112         }\r
113         rval+="\r\n";\r
114         rval+="Subject: "+m_subject+"\r\n";\r
115         // format time as  : Wdy, DD Mon YY HH:MM:SS TIMEZONE\r
116         rval+="Date: "+Poco::DateTimeFormatter::format(m_datetime,"%w, %d %b %y %H:%M:%S -0000")+"\r\n";\r
117         if(m_inreplyto.size()>0)\r
118         {\r
119                 rval+="References: ";\r
120                 for(std::map<long,std::string>::const_reverse_iterator j=m_inreplyto.rbegin(); j!=m_inreplyto.rend(); j++)\r
121                 {\r
122                         if(j!=m_inreplyto.rend())\r
123                         {\r
124                                 rval+=" ";\r
125                         }\r
126                         // old message - before 0.1.12 - doesn't have @domain so add @freenetproject.org\r
127                         if((*j).second.find("@")==std::string::npos)\r
128                         {\r
129                                 rval+="<"+(*j).second+"@freenetproject.org>";\r
130                         }\r
131                         else\r
132                         {\r
133                                 rval+="<"+(*j).second+">";\r
134                         }\r
135                 }\r
136                 rval+="\r\n";\r
137         }\r
138         rval+="Followup-To: "+m_replyboardname+"\r\n";\r
139         rval+="Path: freenet\r\n";\r
140         rval+="Message-ID: "+GetNNTPArticleID()+"\r\n";\r
141         rval+="Content-Type: text/plain; charset=UTF-8\r\n";\r
142 \r
143         return rval;\r
144 }\r
145 \r
146 void Message::HandleAdministrationMessage()\r
147 {\r
148         // only continue if this message was actually a reply to another message\r
149         if(m_inreplyto.size()>0)\r
150         {\r
151                 int localidentityid=-1;\r
152                 int boardid=0;\r
153                 std::string boardname="";\r
154                 std::string identityname="";\r
155                 int identityid;\r
156                 int changemessagetrust=0;\r
157                 int changetrustlisttrust=0;\r
158                 int origmessagetrust=0;\r
159                 int origtrustlisttrust=0;\r
160                 SQLite3DB::Statement st=m_db->Prepare("SELECT tblBoard.BoardID,BoardName,ModifyLocalMessageTrust,ModifyLocalTrustListTrust FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID;");\r
161                 st.Step();\r
162 \r
163                 localidentityid=FindLocalIdentityID(m_fromname);\r
164 \r
165                 while(st.RowReturned() && localidentityid!=-1)\r
166                 {\r
167                         st.ResultInt(0,boardid);\r
168                         st.ResultText(1,boardname);\r
169                         st.ResultInt(2,changemessagetrust);\r
170                         st.ResultInt(3,changetrustlisttrust);\r
171 \r
172                         if(std::find(m_boards.begin(),m_boards.end(),boardname)!=m_boards.end())\r
173                         {\r
174                                 SQLite3DB::Statement origmess=m_db->Prepare("SELECT tblIdentity.IdentityID,tblIdentity.Name,tblIdentityTrust.LocalMessageTrust,tblIdentityTrust.LocalTrustListTrust FROM tblIdentity INNER JOIN tblMessage ON tblIdentity.IdentityID=tblMessage.IdentityID LEFT JOIN (SELECT IdentityID,LocalMessageTrust,LocalTrustListTrust FROM tblIdentityTrust WHERE LocalIdentityID=?) AS 'tblIdentityTrust' ON tblIdentity.IdentityID=tblIdentityTrust.IdentityID WHERE tblMessage.MessageUUID=?;");\r
175                                 origmess.Bind(0,localidentityid);\r
176                                 origmess.Bind(1,m_inreplyto[0]);\r
177                                 origmess.Step();\r
178 \r
179                                 if(origmess.RowReturned())\r
180                                 {\r
181                                         origmess.ResultInt(0,identityid);\r
182                                         origmess.ResultText(1,identityname);\r
183                                         if(origmess.ResultNull(2)==false)\r
184                                         {\r
185                                                 origmess.ResultInt(2,origmessagetrust);\r
186                                         }\r
187                                         else\r
188                                         {\r
189                                                 //origmessagetrust=m_minlocalmessagetrust;\r
190                                                 origmessagetrust=50;\r
191                                         }\r
192                                         if(origmess.ResultNull(3)==false)\r
193                                         {\r
194                                                 origmess.ResultInt(3,origtrustlisttrust);\r
195                                         }\r
196                                         else\r
197                                         {\r
198                                                 //origtrustlisttrust=m_minlocaltrustlisttrust;\r
199                                                 origtrustlisttrust=50;\r
200                                         }\r
201 \r
202                                         origmessagetrust+=changemessagetrust;\r
203                                         origtrustlisttrust+=changetrustlisttrust;\r
204 \r
205                                         origmessagetrust<0 ? origmessagetrust=0 : false;\r
206                                         origmessagetrust>100 ? origmessagetrust=100 : false;\r
207                                         origtrustlisttrust<0 ? origtrustlisttrust=0 : false;\r
208                                         origtrustlisttrust>100 ? origtrustlisttrust=100 : false;\r
209 \r
210                                         // make sure we have a record in tblIdentityTrust\r
211                                         SQLite3DB::Statement ins=m_db->Prepare("INSERT INTO tblIdentityTrust(LocalIdentityID,IdentityID) VALUES(?,?);");\r
212                                         ins.Bind(0,localidentityid);\r
213                                         ins.Bind(1,identityid);\r
214                                         ins.Step();\r
215 \r
216                                         // update new trust levels\r
217                                         SQLite3DB::Statement update=m_db->Prepare("UPDATE tblIdentityTrust SET LocalMessageTrust=?, LocalTrustListTrust=? WHERE IdentityID=? AND LocalIdentityID=?;");\r
218                                         update.Bind(0,origmessagetrust);\r
219                                         update.Bind(1,origtrustlisttrust);\r
220                                         update.Bind(2,identityid);\r
221                                         update.Bind(3,localidentityid);\r
222                                         update.Step();\r
223 \r
224                                         // insert message to show what id was changed and what current levels are\r
225                                         int lastid=0;\r
226                                         std::string messagebody;\r
227                                         std::string messagetruststr="";\r
228                                         std::string trustlisttruststr="";\r
229 \r
230                                         Poco::UUIDGenerator uuidgen;\r
231                                         Poco::UUID uuid;\r
232 \r
233                                         try\r
234                                         {\r
235                                                 uuid=uuidgen.createRandom();\r
236                                         }\r
237                                         catch(...)\r
238                                         {\r
239                                                 m_log->fatal("Message::HandleAdministrationMessage could not generate a UUID");\r
240                                         }\r
241 \r
242                                         Poco::DateTime now;\r
243                                         StringFunctions::Convert(origmessagetrust,messagetruststr);\r
244                                         StringFunctions::Convert(origtrustlisttrust,trustlisttruststr);\r
245                                         messagebody="Trust List of "+m_fromname+"\r\n";\r
246                                         messagebody="Trust Changed for "+identityname+"\r\n";\r
247                                         messagebody+="Local Message Trust : "+messagetruststr+"\r\n";\r
248                                         messagebody+="Local Trust List Trust : "+trustlisttruststr+"\r\n";\r
249                                         SQLite3DB::Statement insert=m_db->Prepare("INSERT INTO tblMessage(FromName,MessageDate,MessageTime,Subject,MessageUUID,ReplyBoardID,Body) VALUES('FMS',?,?,?,?,?,?);");\r
250                                         insert.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d"));\r
251                                         insert.Bind(1,Poco::DateTimeFormatter::format(now,"%H:%M:%S"));\r
252                                         insert.Bind(2,identityname+" Trust Changed");\r
253                                         insert.Bind(3,uuid.toString());\r
254                                         insert.Bind(4,boardid);\r
255                                         insert.Bind(5,messagebody);\r
256                                         insert.Step(true);\r
257                                         lastid=insert.GetLastInsertRowID();\r
258 \r
259                                         insert=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");\r
260                                         insert.Bind(0,lastid);\r
261                                         insert.Bind(1,boardid);\r
262                                         insert.Step();\r
263 \r
264                                         m_log->debug("Message::HandleAdministrationMessage updated "+identityname+" to "+messagetruststr+" , "+trustlisttruststr);\r
265 \r
266                                 }\r
267                         }\r
268 \r
269                         st.Step();\r
270                 }\r
271         }\r
272 \r
273 }\r
274 \r
275 void Message::HandleChangeTrust()\r
276 {\r
277         if(m_changemessagetrustonreply!=0 && m_inreplyto.size()>0)\r
278         {\r
279                 int localidentityid=FindLocalIdentityID(m_fromname);\r
280                 if(localidentityid!=-1)\r
281                 {\r
282                         // make sure we have a record in tblIdentityTrust\r
283                         SQLite3DB::Statement ins=m_db->Prepare("INSERT INTO tblIdentityTrust(LocalIdentityID,IdentityID) VALUES(?,?);");\r
284 \r
285                         SQLite3DB::Statement st=m_db->Prepare("SELECT tblIdentity.IdentityID,tblIdentityTrust.LocalMessageTrust FROM tblIdentity INNER JOIN tblMessage ON tblIdentity.IdentityID=tblMessage.IdentityID LEFT JOIN (SELECT IdentityID,LocalMessageTrust FROM tblIdentityTrust WHERE LocalIdentityID=?) AS 'tblIdentityTrust' ON tblIdentity.IdentityID=tblIdentityTrust.IdentityID WHERE tblMessage.MessageUUID=?;");\r
286                         st.Bind(0,localidentityid);\r
287                         st.Bind(1,m_inreplyto[0]);\r
288                         st.Step();\r
289                         if(st.RowReturned())\r
290                         {\r
291                                 int identityid=0;\r
292                                 int localmessagetrust=0;\r
293 \r
294                                 st.ResultInt(0,identityid);\r
295                                 if(st.ResultNull(1)==false)\r
296                                 {\r
297                                         st.ResultInt(1,localmessagetrust);\r
298                                 }\r
299                                 else\r
300                                 {\r
301                                         //localmessagetrust=m_minlocalmessagetrust;\r
302                                         localmessagetrust=50;\r
303                                 }\r
304 \r
305                                 localmessagetrust+=m_changemessagetrustonreply;\r
306                                 if(localmessagetrust<0)\r
307                                 {\r
308                                         localmessagetrust=0;\r
309                                 }\r
310                                 if(localmessagetrust>100)\r
311                                 {\r
312                                         localmessagetrust=100;\r
313                                 }\r
314 \r
315                                 ins.Bind(0,localidentityid);\r
316                                 ins.Bind(1,identityid);\r
317                                 ins.Step();\r
318 \r
319                                 SQLite3DB::Statement st2=m_db->Prepare("UPDATE tblIdentityTrust SET LocalMessageTrust=? WHERE IdentityID=? AND LocalIdentityID=?;");\r
320                                 st2.Bind(0,localmessagetrust);\r
321                                 st2.Bind(1,identityid);\r
322                                 st2.Bind(2,localidentityid);\r
323                                 st2.Step();\r
324 \r
325                         }\r
326                 }\r
327         }\r
328 }\r
329 \r
330 void Message::Initialize()\r
331 {\r
332         std::string tempval="";\r
333         m_messageid=-1;\r
334         m_messageuuid="";\r
335         m_subject="";\r
336         m_body="";\r
337         m_replyboardname="";\r
338         m_datetime=Poco::Timestamp();\r
339         m_fromname="";\r
340         m_boards.clear();\r
341         m_inreplyto.clear();\r
342         m_fileattachments.clear();\r
343         m_changemessagetrustonreply=0;\r
344         Option::Instance()->Get("ChangeMessageTrustOnReply",tempval);\r
345         StringFunctions::Convert(tempval,m_changemessagetrustonreply);\r
346         Option::Instance()->Get("AddNewPostFromIdentities",tempval);\r
347         if(tempval=="true")\r
348         {\r
349                 m_addnewpostfromidentities=true;\r
350         }\r
351         else\r
352         {\r
353                 m_addnewpostfromidentities=false;\r
354         }\r
355         tempval="50";\r
356         Option::Instance()->Get("MinLocalMessageTrust",tempval);\r
357         StringFunctions::Convert(tempval,m_minlocalmessagetrust);\r
358         tempval="51";\r
359         Option::Instance()->Get("MinLocalTrustListTrust",tempval);\r
360         StringFunctions::Convert(tempval,m_minlocaltrustlisttrust);\r
361 }\r
362 \r
363 const bool Message::Load(const long messageid, const long boardid)\r
364 {\r
365         \r
366         Initialize();\r
367 \r
368         std::string sql;\r
369         \r
370         sql="SELECT tblMessage.MessageID, MessageUUID, Subject, Body, tblBoard.BoardName, MessageDate, MessageTime, FromName FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID INNER JOIN tblBoard ON tblMessage.ReplyBoardID=tblBoard.BoardID WHERE tblMessage.MessageID=?";\r
371         if(boardid!=-1)\r
372         {\r
373                 sql+=" AND tblMessageBoard.BoardID=?";\r
374         }\r
375         sql+=";";\r
376 \r
377         SQLite3DB::Statement st=m_db->Prepare(sql);\r
378         st.Bind(0,messageid);\r
379         if(boardid!=-1)\r
380         {\r
381                 st.Bind(1,boardid);\r
382         }\r
383         st.Step();\r
384 \r
385         if(st.RowReturned())\r
386         {\r
387                 std::string tempdate;\r
388                 std::string temptime;\r
389                 int tempint=-1;\r
390                 st.ResultInt(0,tempint);\r
391                 m_messageid=tempint;\r
392                 st.ResultText(1,m_messageuuid);\r
393                 st.ResultText(2,m_subject);\r
394                 st.ResultText(3,m_body);\r
395                 st.ResultText(4,m_replyboardname);\r
396                 st.ResultText(5,tempdate);\r
397                 st.ResultText(6,temptime);\r
398                 st.ResultText(7,m_fromname);\r
399                 st.Finalize();\r
400 \r
401                 int tzdiff=0;\r
402                 if(Poco::DateTimeParser::tryParse(tempdate + " " + temptime,m_datetime,tzdiff)==false)\r
403                 {\r
404                         m_log->error("Message::Load couldn't parse date/time "+tempdate+" "+temptime);\r
405                 }\r
406 \r
407                 // strip off any \r\n in subject\r
408                 m_subject=StringFunctions::Replace(m_subject,"\r\n","");\r
409 \r
410                 // get board list\r
411                 st=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard INNER JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID WHERE tblMessageBoard.MessageID=?;");\r
412                 st.Bind(0,messageid);\r
413                 st.Step();\r
414                 while(st.RowReturned())\r
415                 {\r
416                         std::string tempval;\r
417                         st.ResultText(0,tempval);\r
418                         m_boards.push_back(tempval);\r
419                         st.Step();\r
420                 }\r
421                 st.Finalize();\r
422 \r
423                 // get in reply to list\r
424                 st=m_db->Prepare("SELECT ReplyToMessageUUID, ReplyOrder FROM tblMessageReplyTo INNER JOIN tblMessage ON tblMessageReplyTo.MessageID=tblMessage.MessageID WHERE tblMessage.MessageID=?;");\r
425                 st.Bind(0,messageid);\r
426                 st.Step();\r
427                 while(st.RowReturned())\r
428                 {\r
429                         std::string tempval;\r
430                         int tempint;\r
431                         st.ResultText(0,tempval);\r
432                         st.ResultInt(1,tempint);\r
433                         m_inreplyto[tempint]=tempval;\r
434                         st.Step();\r
435                 }\r
436                 st.Finalize();\r
437 \r
438                 return true;\r
439         }\r
440         else\r
441         {\r
442                 return false;\r
443         }\r
444 \r
445 }\r
446 \r
447 const bool Message::Load(const std::string &messageuuid)\r
448 {\r
449 \r
450         std::string uuid=messageuuid;\r
451 \r
452         if(uuid.size()>0 && uuid[0]=='<')\r
453         {\r
454                 uuid.erase(0,1);\r
455         }\r
456         if(uuid.size()>0 && uuid[uuid.size()-1]=='>')\r
457         {\r
458                 uuid.erase(uuid.size()-1);\r
459         }\r
460         if(uuid.find("@freenetproject.org")!=std::string::npos)\r
461         {\r
462                 uuid.erase(uuid.find("@freenetproject.org"));\r
463         }\r
464 \r
465         SQLite3DB::Statement st=m_db->Prepare("SELECT MessageID FROM tblMessage WHERE MessageUUID=?;");\r
466         st.Bind(0,uuid);\r
467         st.Step();\r
468 \r
469         if(st.RowReturned())\r
470         {\r
471                 int messageid;\r
472                 st.ResultInt(0,messageid);\r
473 \r
474                 return Load(messageid);\r
475         }\r
476         else\r
477         {\r
478                 return false;\r
479         }\r
480 }\r
481 \r
482 const bool Message::LoadNext(const long messageid, const long boardid)\r
483 {\r
484         std::string sql="SELECT tblMessage.MessageID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE tblMessage.MessageID>?";\r
485         if(boardid!=-1)\r
486         {\r
487                 sql+=" AND tblMessageBoard.BoardID=?";\r
488         }\r
489         sql+=";";\r
490 \r
491         SQLite3DB::Statement st=m_db->Prepare(sql);\r
492 \r
493         st.Bind(0,messageid);\r
494         if(boardid!=-1)\r
495         {\r
496                 st.Bind(1,boardid);\r
497         }\r
498         st.Step();\r
499 \r
500         if(st.RowReturned())\r
501         {\r
502                 int result;\r
503                 st.ResultInt(0,result);\r
504                 return Load(result,boardid);\r
505         }\r
506         else\r
507         {\r
508                 return false;\r
509         }\r
510 }\r
511 \r
512 const bool Message::LoadPrevious(const long messageid, const long boardid)\r
513 {\r
514         std::string sql="SELECT tblMessage.MessageID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE tblMessage.MessageID<?";\r
515         if(boardid!=-1)\r
516         {\r
517                 sql+=" AND tblMessageBoard.BoardID=?";\r
518         }\r
519         sql+=" ORDER BY tblMessage.MessageID DESC;";\r
520 \r
521         SQLite3DB::Statement st=m_db->Prepare(sql);\r
522 \r
523         st.Bind(0,messageid);\r
524         if(boardid!=-1)\r
525         {\r
526                 st.Bind(1,boardid);\r
527         }\r
528         st.Step();\r
529 \r
530         if(st.RowReturned())\r
531         {\r
532                 int result;\r
533                 st.ResultInt(0,result);\r
534                 return Load(result,boardid);\r
535         }\r
536         else\r
537         {\r
538                 return false;\r
539         }\r
540 }\r
541 \r
542 const bool Message::ParseNNTPMessage(const std::string &nntpmessage)\r
543 {\r
544 \r
545         Initialize();\r
546 \r
547         Poco::UUIDGenerator uuidgen;\r
548         Poco::UUID uuid;\r
549         CMimeMessage mime;\r
550         mime.Load(nntpmessage.c_str(),nntpmessage.size());\r
551 \r
552         // get header info\r
553         // date is always set to now regardless of what message has\r
554         m_datetime=Poco::Timestamp();\r
555 \r
556         // messageuuid is always a unique id we generate regardless of message message-id\r
557         try\r
558         {\r
559                 uuid=uuidgen.createRandom();\r
560         }\r
561         catch(...)\r
562         {\r
563                 m_log->fatal("Message::ParseNNTPMessage could not create UUID");\r
564         }\r
565         \r
566         // get from\r
567         if(mime.GetFieldValue("From"))\r
568         {\r
569                 m_fromname=mime.GetFieldValue("From");\r
570                 // remove any path folding\r
571                 m_fromname=StringFunctions::Replace(m_fromname,"\r\n","");\r
572                 m_fromname=StringFunctions::Replace(m_fromname,"\t","");\r
573                 // strip off everything between () and <> and any whitespace\r
574                 std::string::size_type startpos=m_fromname.find("(");\r
575                 std::string::size_type endpos;\r
576                 if(startpos!=std::string::npos)\r
577                 {\r
578                         endpos=m_fromname.find(")",startpos);\r
579                         if(endpos!=std::string::npos)\r
580                         {\r
581                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
582                         }\r
583                 }\r
584                 startpos=m_fromname.find("<");\r
585                 if(startpos!=std::string::npos)\r
586                 {\r
587                         endpos=m_fromname.find(">",startpos);\r
588                         if(endpos!=std::string::npos)\r
589                         {\r
590                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
591                         }\r
592                 }\r
593                 m_fromname=StringFunctions::TrimWhitespace(m_fromname);\r
594 \r
595                 // trim off " from beginning and end\r
596                 if(m_fromname.size()>0 && m_fromname[0]=='\"')\r
597                 {\r
598                         m_fromname.erase(0,1);\r
599                 }\r
600                 if(m_fromname.size()>0 && m_fromname[m_fromname.size()-1]=='\"')\r
601                 {\r
602                         m_fromname.erase(m_fromname.size()-1,1);\r
603                 }\r
604 \r
605                 m_fromname=StringFunctions::TrimWhitespace(m_fromname);\r
606         }\r
607         else\r
608         {\r
609                 m_fromname="Anonymous";\r
610         }\r
611         // get boards posted to\r
612         if(mime.GetFieldValue("Newsgroups"))\r
613         {\r
614                 std::string temp=mime.GetFieldValue("Newsgroups");\r
615                 // remove any path folding\r
616                 temp=StringFunctions::Replace(temp,"\r\n","");\r
617                 temp=StringFunctions::Replace(temp,"\t","");\r
618                 std::vector<std::string> parts;\r
619                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
620                 for(std::vector<std::string>::iterator i=parts.begin(); i!=parts.end(); i++)\r
621                 {\r
622                         (*i)=StringFunctions::Replace((*i),"<","");\r
623                         (*i)=StringFunctions::Replace((*i),">","");\r
624                         (*i)=StringFunctions::TrimWhitespace((*i));\r
625                         if((*i)!="")\r
626                         {\r
627                                 m_boards.push_back((*i));\r
628                         }\r
629                 }\r
630         }\r
631         // followup-to board - must be done after board vector populated\r
632         if(mime.GetFieldValue("Followup-To"))\r
633         {\r
634                 m_replyboardname=mime.GetFieldValue("Followup-To");\r
635                 // remove any path folding\r
636                 m_replyboardname=StringFunctions::Replace(m_replyboardname,"\r\n","");\r
637                 m_replyboardname=StringFunctions::Replace(m_replyboardname,"\t","");\r
638         }\r
639         else\r
640         {\r
641                 if(m_boards.size()>0)\r
642                 {\r
643                         m_replyboardname=m_boards[0];\r
644                 }\r
645         }\r
646         // subject\r
647         if(mime.GetFieldValue("Subject"))\r
648         {\r
649                 m_subject=mime.GetFieldValue("Subject");\r
650                 // remove any path folding\r
651                 m_subject=StringFunctions::Replace(m_subject,"\r\n","");\r
652                 m_subject=StringFunctions::Replace(m_subject,"\t","");\r
653 #if DO_CHARSET_CONVERSION\r
654                 if(mime.GetFieldCharset("Subject"))\r
655                 {\r
656                         std::string charset=mime.GetFieldCharset("Subject");\r
657                         CharsetConverter ccv;\r
658                         if(charset!="" && charset!="UTF-8" && ccv.SetConversion(charset,"UTF-8"))\r
659                         {\r
660                                 std::string output="";\r
661                                 ccv.Convert(m_subject,output);\r
662                                 m_subject=output;\r
663                         }\r
664                 }\r
665 #endif\r
666         }\r
667         else\r
668         {\r
669                 m_subject="No Subject";\r
670         }\r
671         // references\r
672         if(mime.GetFieldValue("References"))\r
673         {\r
674                 std::string temp=mime.GetFieldValue("References");\r
675                 // remove any path folding\r
676                 temp=StringFunctions::Replace(temp,"\r\n","");\r
677                 temp=StringFunctions::Replace(temp,"\t","");\r
678                 std::vector<std::string> parts;\r
679                 int count=0;\r
680                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
681                 for(std::vector<std::string>::reverse_iterator i=parts.rbegin(); i!=parts.rend(); i++)\r
682                 {\r
683                         // get rid of < and > and any whitespace\r
684                         (*i)=StringFunctions::Replace((*i),"<","");\r
685                         (*i)=StringFunctions::Replace((*i),">","");\r
686                         (*i)=StringFunctions::TrimWhitespace((*i));\r
687                         /*\r
688                         // erase @ and everything after\r
689                         if((*i).find("@")!=std::string::npos)\r
690                         {\r
691                                 (*i).erase((*i).find("@"));\r
692                         }\r
693                         */\r
694                         // only erase after @ if message is old type with @freenetproject.org\r
695                         if((*i).find("@freenetproject.org")!=std::string::npos)\r
696                         {\r
697                                 (*i).erase((*i).find("@"));\r
698                         }\r
699                         if((*i)!="")\r
700                         {\r
701                                 m_inreplyto[count++]=(*i);\r
702                         }\r
703                 }\r
704         }\r
705 \r
706         CMimeBody::CBodyList mbl;\r
707         mime.GetBodyPartList(mbl);\r
708 \r
709         // append all text parts of nntp message to body\r
710         for(CMimeBody::CBodyList::iterator i=mbl.begin(); i!=mbl.end(); i++)\r
711         {\r
712                 if((*i)->IsText() && (*i)->GetContent())\r
713                 {\r
714                         std::string bodypart=(char *)(*i)->GetContent();\r
715 #ifdef DO_CHARSET_CONVERSION\r
716                         std::string charset=(*i)->GetCharset();\r
717                         if(charset!="" && charset!="UTF-8")\r
718                         {\r
719                                 CharsetConverter ccv;\r
720                                 if(ccv.SetConversion(charset,"UTF-8"))\r
721                                 {\r
722                                         std::string output="";\r
723                                         ccv.Convert(bodypart,output);\r
724                                         bodypart=output;\r
725                                 }\r
726                         }\r
727 #endif\r
728                         m_body+=bodypart;\r
729                 }\r
730                 // add a binary file attachment\r
731                 else if(((*i)->GetName()!="" || (*i)->GetFilename()!="") && (*i)->GetLength()>0 && (*i)->GetContent())\r
732                 {\r
733                         std::string filename="";\r
734                         std::string contenttype="";\r
735                         std::vector<unsigned char> data((*i)->GetContent(),(*i)->GetContent()+(*i)->GetContentLength());\r
736                         if((*i)->GetContentType())\r
737                         {\r
738                                 contenttype=(*i)->GetContentType();\r
739                                 // find first ; tab cr or lf and erase it and everything after it\r
740                                 std::string::size_type endpos=contenttype.find_first_of(";\t\r\n ");\r
741                                 if(endpos!=std::string::npos)\r
742                                 {\r
743                                         contenttype.erase(endpos);\r
744                                 }\r
745                         }\r
746                         filename=(*i)->GetFilename();\r
747                         if(filename=="")\r
748                         {\r
749                                 filename=(*i)->GetName();\r
750                         }\r
751                         m_fileattachments.push_back(fileattachment(filename,contenttype,data));\r
752                 }\r
753         }\r
754 \r
755         return true;\r
756 }\r
757 \r
758 const bool Message::StartFreenetInsert()\r
759 {\r
760 \r
761         MessageXML xml;\r
762         int localidentityid=-1;\r
763 \r
764         StripAdministrationBoards();\r
765 \r
766         if(m_boards.size()>0)\r
767         {\r
768 \r
769                 xml.SetMessageID(m_messageuuid);\r
770                 xml.SetSubject(m_subject);\r
771                 xml.SetBody(m_body);\r
772                 xml.SetReplyBoard(m_replyboardname);\r
773                 \r
774                 for(std::vector<std::string>::iterator i=m_boards.begin(); i!=m_boards.end(); i++)\r
775                 {\r
776                         xml.AddBoard((*i));\r
777                 }\r
778                 \r
779                 for(std::map<long,std::string>::iterator j=m_inreplyto.begin(); j!=m_inreplyto.end(); j++)\r
780                 {\r
781                         xml.AddInReplyTo((*j).first,(*j).second);\r
782                 }\r
783 \r
784                 localidentityid=FindLocalIdentityID(m_fromname);\r
785                 if(localidentityid==-1)\r
786                 {\r
787                         return false;\r
788                 }\r
789 \r
790                 // add the message delay if there is one\r
791                 SQLite3DB::Statement st=m_db->Prepare("SELECT MinMessageDelay,MaxMessageDelay FROM tblLocalIdentity WHERE LocalIdentityID=?;");\r
792                 st.Bind(0,localidentityid);\r
793                 st.Step();\r
794                 if(st.RowReturned())\r
795                 {\r
796                         int min=0;\r
797                         int max=0;\r
798                         st.ResultInt(0,min);\r
799                         st.ResultInt(1,max);\r
800 \r
801                         min<0 ? min=0 : false;\r
802                         max<0 ? max=0 : false;\r
803                         min>max ? min=max : false;\r
804 \r
805                         if(min==max)\r
806                         {\r
807                                 m_datetime+=Poco::Timespan(0,0,min,0,0);\r
808                         }\r
809                         else if(max>min)\r
810                         {\r
811                                 int delay=(rand()%(max-min))+min;\r
812                                 m_datetime+=Poco::Timespan(0,0,delay,0,0);\r
813                         }\r
814 \r
815                 }\r
816                 st.Finalize();\r
817 \r
818                 // set date in xml file AFTER we set the delay\r
819                 xml.SetDate(Poco::DateTimeFormatter::format(m_datetime,"%Y-%m-%d"));\r
820                 xml.SetTime(Poco::DateTimeFormatter::format(m_datetime,"%H:%M:%S"));\r
821 \r
822                 st=m_db->Prepare("INSERT INTO tblMessageInserts(LocalIdentityID,MessageUUID,MessageXML,SendDate) VALUES(?,?,?,?);");\r
823                 st.Bind(0,localidentityid);\r
824                 st.Bind(1,m_messageuuid);\r
825                 st.Bind(2,xml.GetXML());\r
826                 st.Bind(3,Poco::DateTimeFormatter::format(m_datetime,"%Y-%m-%d %H:%M:%S"));\r
827                 st.Step();\r
828 \r
829                 // insert file attachments into database\r
830                 st=m_db->Prepare("INSERT INTO tblFileInserts(MessageUUID,FileName,Size,MimeType,Data) VALUES(?,?,?,?,?);");\r
831                 for(std::vector<fileattachment>::iterator i=m_fileattachments.begin(); i!=m_fileattachments.end(); i++)\r
832                 {\r
833                         st.Bind(0,m_messageuuid);\r
834                         st.Bind(1,(*i).m_filename);\r
835                         st.Bind(2,(long)(*i).m_data.size());\r
836                         st.Bind(3,(*i).m_mimetype);\r
837                         st.Bind(4,&((*i).m_data[0]),(*i).m_data.size());\r
838                         st.Step();\r
839                         st.Reset();\r
840                 }\r
841 \r
842                 HandleChangeTrust();\r
843 \r
844         }\r
845 \r
846         return true;\r
847 \r
848 }\r
849 \r
850 void Message::StripAdministrationBoards()\r
851 {\r
852         SQLite3DB::Statement st=m_db->Prepare("SELECT tblBoard.BoardID FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID WHERE BoardName=?;");\r
853         for(std::vector<std::string>::iterator i=m_boards.begin(); i!=m_boards.end(); )\r
854         {\r
855                 st.Bind(0,(*i));\r
856                 st.Step();\r
857                 if(st.RowReturned())\r
858                 {\r
859                         if(m_replyboardname==(*i))\r
860                         {\r
861                                 m_replyboardname="";\r
862                         }\r
863                         i=m_boards.erase(i);\r
864                 }\r
865                 else\r
866                 {\r
867                         i++;\r
868                 }\r
869                 st.Reset();\r
870         }\r
871         if(m_replyboardname=="" && m_boards.begin()!=m_boards.end())\r
872         {\r
873                 m_replyboardname=(*m_boards.begin());\r
874         }\r
875 }\r