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