version 0.3.10
[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                                         std::string uuidstr=uuid.toString();\r
254                                         StringFunctions::UpperCase(uuidstr,uuidstr);\r
255                                         insert.Bind(3,uuidstr);\r
256                                         insert.Bind(4,boardid);\r
257                                         insert.Bind(5,messagebody);\r
258                                         insert.Step(true);\r
259                                         lastid=insert.GetLastInsertRowID();\r
260 \r
261                                         insert=m_db->Prepare("INSERT INTO tblMessageBoard(MessageID,BoardID) VALUES(?,?);");\r
262                                         insert.Bind(0,lastid);\r
263                                         insert.Bind(1,boardid);\r
264                                         insert.Step();\r
265 \r
266                                         m_log->debug("Message::HandleAdministrationMessage updated "+identityname+" to "+messagetruststr+" , "+trustlisttruststr);\r
267 \r
268                                 }\r
269                         }\r
270 \r
271                         st.Step();\r
272                 }\r
273         }\r
274 \r
275 }\r
276 \r
277 void Message::HandleChangeTrust()\r
278 {\r
279         if(m_changemessagetrustonreply!=0 && m_inreplyto.size()>0)\r
280         {\r
281                 int localidentityid=FindLocalIdentityID(m_fromname);\r
282                 if(localidentityid!=-1)\r
283                 {\r
284                         // make sure we have a record in tblIdentityTrust\r
285                         SQLite3DB::Statement ins=m_db->Prepare("INSERT INTO tblIdentityTrust(LocalIdentityID,IdentityID) VALUES(?,?);");\r
286 \r
287                         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
288                         st.Bind(0,localidentityid);\r
289                         st.Bind(1,m_inreplyto[0]);\r
290                         st.Step();\r
291                         if(st.RowReturned())\r
292                         {\r
293                                 int identityid=0;\r
294                                 int localmessagetrust=0;\r
295 \r
296                                 st.ResultInt(0,identityid);\r
297                                 if(st.ResultNull(1)==false)\r
298                                 {\r
299                                         st.ResultInt(1,localmessagetrust);\r
300                                 }\r
301                                 else\r
302                                 {\r
303                                         //localmessagetrust=m_minlocalmessagetrust;\r
304                                         localmessagetrust=50;\r
305                                 }\r
306 \r
307                                 localmessagetrust+=m_changemessagetrustonreply;\r
308                                 if(localmessagetrust<0)\r
309                                 {\r
310                                         localmessagetrust=0;\r
311                                 }\r
312                                 if(localmessagetrust>100)\r
313                                 {\r
314                                         localmessagetrust=100;\r
315                                 }\r
316 \r
317                                 ins.Bind(0,localidentityid);\r
318                                 ins.Bind(1,identityid);\r
319                                 ins.Step();\r
320 \r
321                                 SQLite3DB::Statement st2=m_db->Prepare("UPDATE tblIdentityTrust SET LocalMessageTrust=? WHERE IdentityID=? AND LocalIdentityID=?;");\r
322                                 st2.Bind(0,localmessagetrust);\r
323                                 st2.Bind(1,identityid);\r
324                                 st2.Bind(2,localidentityid);\r
325                                 st2.Step();\r
326 \r
327                         }\r
328                 }\r
329         }\r
330 }\r
331 \r
332 void Message::Initialize()\r
333 {\r
334         std::string tempval="";\r
335         m_messageid=-1;\r
336         m_messageuuid="";\r
337         m_subject="";\r
338         m_body="";\r
339         m_replyboardname="";\r
340         m_datetime=Poco::Timestamp();\r
341         m_fromname="";\r
342         m_boards.clear();\r
343         m_inreplyto.clear();\r
344         m_fileattachments.clear();\r
345         m_changemessagetrustonreply=0;\r
346         Option::Instance()->Get("ChangeMessageTrustOnReply",tempval);\r
347         StringFunctions::Convert(tempval,m_changemessagetrustonreply);\r
348         Option::Instance()->Get("AddNewPostFromIdentities",tempval);\r
349         if(tempval=="true")\r
350         {\r
351                 m_addnewpostfromidentities=true;\r
352         }\r
353         else\r
354         {\r
355                 m_addnewpostfromidentities=false;\r
356         }\r
357         tempval="50";\r
358         Option::Instance()->Get("MinLocalMessageTrust",tempval);\r
359         StringFunctions::Convert(tempval,m_minlocalmessagetrust);\r
360         tempval="51";\r
361         Option::Instance()->Get("MinLocalTrustListTrust",tempval);\r
362         StringFunctions::Convert(tempval,m_minlocaltrustlisttrust);\r
363 }\r
364 \r
365 const bool Message::Load(const long messageid, const long boardid)\r
366 {\r
367         \r
368         Initialize();\r
369 \r
370         std::string sql;\r
371         \r
372         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
373         if(boardid!=-1)\r
374         {\r
375                 sql+=" AND tblMessageBoard.BoardID=?";\r
376         }\r
377         sql+=";";\r
378 \r
379         SQLite3DB::Statement st=m_db->Prepare(sql);\r
380         st.Bind(0,messageid);\r
381         if(boardid!=-1)\r
382         {\r
383                 st.Bind(1,boardid);\r
384         }\r
385         st.Step();\r
386 \r
387         if(st.RowReturned())\r
388         {\r
389                 std::string tempdate;\r
390                 std::string temptime;\r
391                 int tempint=-1;\r
392                 st.ResultInt(0,tempint);\r
393                 m_messageid=tempint;\r
394                 st.ResultText(1,m_messageuuid);\r
395                 st.ResultText(2,m_subject);\r
396                 st.ResultText(3,m_body);\r
397                 st.ResultText(4,m_replyboardname);\r
398                 st.ResultText(5,tempdate);\r
399                 st.ResultText(6,temptime);\r
400                 st.ResultText(7,m_fromname);\r
401                 st.Finalize();\r
402 \r
403                 int tzdiff=0;\r
404                 if(Poco::DateTimeParser::tryParse(tempdate + " " + temptime,m_datetime,tzdiff)==false)\r
405                 {\r
406                         m_log->error("Message::Load couldn't parse date/time "+tempdate+" "+temptime);\r
407                 }\r
408 \r
409                 // strip off any \r\n in subject\r
410                 m_subject=StringFunctions::Replace(m_subject,"\r\n","");\r
411 \r
412                 // get board list\r
413                 st=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard INNER JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID WHERE tblMessageBoard.MessageID=?;");\r
414                 st.Bind(0,messageid);\r
415                 st.Step();\r
416                 while(st.RowReturned())\r
417                 {\r
418                         std::string tempval;\r
419                         st.ResultText(0,tempval);\r
420                         m_boards.push_back(tempval);\r
421                         st.Step();\r
422                 }\r
423                 st.Finalize();\r
424 \r
425                 // get in reply to list\r
426                 st=m_db->Prepare("SELECT ReplyToMessageUUID, ReplyOrder FROM tblMessageReplyTo INNER JOIN tblMessage ON tblMessageReplyTo.MessageID=tblMessage.MessageID WHERE tblMessage.MessageID=?;");\r
427                 st.Bind(0,messageid);\r
428                 st.Step();\r
429                 while(st.RowReturned())\r
430                 {\r
431                         std::string tempval;\r
432                         int tempint;\r
433                         st.ResultText(0,tempval);\r
434                         st.ResultInt(1,tempint);\r
435                         m_inreplyto[tempint]=tempval;\r
436                         st.Step();\r
437                 }\r
438                 st.Finalize();\r
439 \r
440                 return true;\r
441         }\r
442         else\r
443         {\r
444                 return false;\r
445         }\r
446 \r
447 }\r
448 \r
449 const bool Message::Load(const std::string &messageuuid)\r
450 {\r
451 \r
452         std::string uuid=messageuuid;\r
453 \r
454         if(uuid.size()>0 && uuid[0]=='<')\r
455         {\r
456                 uuid.erase(0,1);\r
457         }\r
458         if(uuid.size()>0 && uuid[uuid.size()-1]=='>')\r
459         {\r
460                 uuid.erase(uuid.size()-1);\r
461         }\r
462         if(uuid.find("@freenetproject.org")!=std::string::npos)\r
463         {\r
464                 uuid.erase(uuid.find("@freenetproject.org"));\r
465         }\r
466 \r
467         SQLite3DB::Statement st=m_db->Prepare("SELECT MessageID FROM tblMessage WHERE MessageUUID=?;");\r
468         st.Bind(0,uuid);\r
469         st.Step();\r
470 \r
471         if(st.RowReturned())\r
472         {\r
473                 int messageid;\r
474                 st.ResultInt(0,messageid);\r
475 \r
476                 return Load(messageid);\r
477         }\r
478         else\r
479         {\r
480                 return false;\r
481         }\r
482 }\r
483 \r
484 const bool Message::LoadNext(const long messageid, const long boardid)\r
485 {\r
486         std::string sql="SELECT tblMessage.MessageID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE tblMessage.MessageID>?";\r
487         if(boardid!=-1)\r
488         {\r
489                 sql+=" AND tblMessageBoard.BoardID=?";\r
490         }\r
491         sql+=";";\r
492 \r
493         SQLite3DB::Statement st=m_db->Prepare(sql);\r
494 \r
495         st.Bind(0,messageid);\r
496         if(boardid!=-1)\r
497         {\r
498                 st.Bind(1,boardid);\r
499         }\r
500         st.Step();\r
501 \r
502         if(st.RowReturned())\r
503         {\r
504                 int result;\r
505                 st.ResultInt(0,result);\r
506                 return Load(result,boardid);\r
507         }\r
508         else\r
509         {\r
510                 return false;\r
511         }\r
512 }\r
513 \r
514 const bool Message::LoadPrevious(const long messageid, const long boardid)\r
515 {\r
516         std::string sql="SELECT tblMessage.MessageID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE tblMessage.MessageID<?";\r
517         if(boardid!=-1)\r
518         {\r
519                 sql+=" AND tblMessageBoard.BoardID=?";\r
520         }\r
521         sql+=" ORDER BY tblMessage.MessageID DESC;";\r
522 \r
523         SQLite3DB::Statement st=m_db->Prepare(sql);\r
524 \r
525         st.Bind(0,messageid);\r
526         if(boardid!=-1)\r
527         {\r
528                 st.Bind(1,boardid);\r
529         }\r
530         st.Step();\r
531 \r
532         if(st.RowReturned())\r
533         {\r
534                 int result;\r
535                 st.ResultInt(0,result);\r
536                 return Load(result,boardid);\r
537         }\r
538         else\r
539         {\r
540                 return false;\r
541         }\r
542 }\r
543 \r
544 const bool Message::ParseNNTPMessage(const std::string &nntpmessage)\r
545 {\r
546 \r
547         Initialize();\r
548 \r
549         Poco::UUIDGenerator uuidgen;\r
550         Poco::UUID uuid;\r
551         CMimeMessage mime;\r
552         mime.Load(nntpmessage.c_str(),nntpmessage.size());\r
553 \r
554         // get header info\r
555         // date is always set to now regardless of what message has\r
556         m_datetime=Poco::Timestamp();\r
557 \r
558         // messageuuid is always a unique id we generate regardless of message message-id\r
559         try\r
560         {\r
561                 uuid=uuidgen.createRandom();\r
562                 m_messageuuid=uuid.toString();\r
563                 StringFunctions::UpperCase(m_messageuuid,m_messageuuid);\r
564         }\r
565         catch(...)\r
566         {\r
567                 m_log->fatal("Message::ParseNNTPMessage could not create UUID");\r
568         }\r
569         \r
570         // get from\r
571         if(mime.GetFieldValue("From"))\r
572         {\r
573                 m_fromname=mime.GetFieldValue("From");\r
574                 // remove any path folding\r
575                 m_fromname=StringFunctions::Replace(m_fromname,"\r\n","");\r
576                 m_fromname=StringFunctions::Replace(m_fromname,"\t","");\r
577                 // strip off everything between () and <> and any whitespace\r
578                 std::string::size_type startpos=m_fromname.find("(");\r
579                 std::string::size_type endpos;\r
580                 if(startpos!=std::string::npos)\r
581                 {\r
582                         endpos=m_fromname.find(")",startpos);\r
583                         if(endpos!=std::string::npos)\r
584                         {\r
585                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
586                         }\r
587                 }\r
588                 startpos=m_fromname.find("<");\r
589                 if(startpos!=std::string::npos)\r
590                 {\r
591                         endpos=m_fromname.find(">",startpos);\r
592                         if(endpos!=std::string::npos)\r
593                         {\r
594                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
595                         }\r
596                 }\r
597                 m_fromname=StringFunctions::TrimWhitespace(m_fromname);\r
598 \r
599                 // trim off " from beginning and end\r
600                 if(m_fromname.size()>0 && m_fromname[0]=='\"')\r
601                 {\r
602                         m_fromname.erase(0,1);\r
603                 }\r
604                 if(m_fromname.size()>0 && m_fromname[m_fromname.size()-1]=='\"')\r
605                 {\r
606                         m_fromname.erase(m_fromname.size()-1,1);\r
607                 }\r
608 \r
609                 m_fromname=StringFunctions::TrimWhitespace(m_fromname);\r
610         }\r
611         else\r
612         {\r
613                 m_fromname="Anonymous";\r
614         }\r
615         // get boards posted to\r
616         if(mime.GetFieldValue("Newsgroups"))\r
617         {\r
618                 std::string temp=mime.GetFieldValue("Newsgroups");\r
619                 // remove any path folding\r
620                 temp=StringFunctions::Replace(temp,"\r\n","");\r
621                 temp=StringFunctions::Replace(temp,"\t","");\r
622                 std::vector<std::string> parts;\r
623                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
624                 for(std::vector<std::string>::iterator i=parts.begin(); i!=parts.end(); i++)\r
625                 {\r
626                         (*i)=StringFunctions::Replace((*i),"<","");\r
627                         (*i)=StringFunctions::Replace((*i),">","");\r
628                         (*i)=StringFunctions::TrimWhitespace((*i));\r
629                         if((*i)!="")\r
630                         {\r
631                                 m_boards.push_back((*i));\r
632                         }\r
633                 }\r
634         }\r
635         // followup-to board - must be done after board vector populated\r
636         if(mime.GetFieldValue("Followup-To"))\r
637         {\r
638                 m_replyboardname=mime.GetFieldValue("Followup-To");\r
639                 // remove any path folding\r
640                 m_replyboardname=StringFunctions::Replace(m_replyboardname,"\r\n","");\r
641                 m_replyboardname=StringFunctions::Replace(m_replyboardname,"\t","");\r
642         }\r
643         else\r
644         {\r
645                 if(m_boards.size()>0)\r
646                 {\r
647                         m_replyboardname=m_boards[0];\r
648                 }\r
649         }\r
650         // subject\r
651         if(mime.GetFieldValue("Subject"))\r
652         {\r
653                 m_subject=mime.GetFieldValue("Subject");\r
654                 // remove any path folding\r
655                 m_subject=StringFunctions::Replace(m_subject,"\r\n","");\r
656                 m_subject=StringFunctions::Replace(m_subject,"\t","");\r
657 #if DO_CHARSET_CONVERSION\r
658                 if(mime.GetFieldCharset("Subject"))\r
659                 {\r
660                         std::string charset=mime.GetFieldCharset("Subject");\r
661                         CharsetConverter ccv;\r
662                         if(charset!="" && charset!="UTF-8" && ccv.SetConversion(charset,"UTF-8"))\r
663                         {\r
664                                 std::string output="";\r
665                                 ccv.Convert(m_subject,output);\r
666                                 m_subject=output;\r
667                         }\r
668                 }\r
669 #endif\r
670         }\r
671         else\r
672         {\r
673                 m_subject="No Subject";\r
674         }\r
675         // references\r
676         if(mime.GetFieldValue("References"))\r
677         {\r
678                 std::string temp=mime.GetFieldValue("References");\r
679                 // remove any path folding\r
680                 temp=StringFunctions::Replace(temp,"\r\n","");\r
681                 temp=StringFunctions::Replace(temp,"\t"," ");\r
682                 std::vector<std::string> parts;\r
683                 int count=0;\r
684                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
685                 for(std::vector<std::string>::reverse_iterator i=parts.rbegin(); i!=parts.rend(); i++)\r
686                 {\r
687                         if((*i).size()>2)\r
688                         {\r
689                                 // get rid of < and > and any whitespace\r
690                                 (*i)=StringFunctions::Replace((*i),"<","");\r
691                                 (*i)=StringFunctions::Replace((*i),">","");\r
692                                 (*i)=StringFunctions::TrimWhitespace((*i));\r
693                                 /*\r
694                                 // erase @ and everything after\r
695                                 if((*i).find("@")!=std::string::npos)\r
696                                 {\r
697                                         (*i).erase((*i).find("@"));\r
698                                 }\r
699                                 */\r
700                                 // only erase after @ if message is old type with @freenetproject.org\r
701                                 if((*i).find("@freenetproject.org")!=std::string::npos)\r
702                                 {\r
703                                         (*i).erase((*i).find("@"));\r
704                                 }\r
705                                 if((*i)!="")\r
706                                 {\r
707                                         m_inreplyto[count++]=(*i);\r
708                                 }\r
709                         }\r
710                 }\r
711         }\r
712 \r
713         CMimeBody::CBodyList mbl;\r
714         mime.GetBodyPartList(mbl);\r
715 \r
716         // append all text parts of nntp message to body\r
717         for(CMimeBody::CBodyList::iterator i=mbl.begin(); i!=mbl.end(); i++)\r
718         {\r
719                 if((*i)->IsText() && (*i)->GetContent())\r
720                 {\r
721                         std::string bodypart=(char *)(*i)->GetContent();\r
722 #ifdef DO_CHARSET_CONVERSION\r
723                         std::string charset=(*i)->GetCharset();\r
724                         if(charset!="" && charset!="UTF-8")\r
725                         {\r
726                                 CharsetConverter ccv;\r
727                                 if(ccv.SetConversion(charset,"UTF-8"))\r
728                                 {\r
729                                         std::string output="";\r
730                                         ccv.Convert(bodypart,output);\r
731                                         bodypart=output;\r
732                                 }\r
733                         }\r
734 #endif\r
735                         m_body+=bodypart;\r
736                 }\r
737                 // add a binary file attachment\r
738                 else if(((*i)->GetName()!="" || (*i)->GetFilename()!="") && (*i)->GetLength()>0 && (*i)->GetContent())\r
739                 {\r
740                         std::string filename="";\r
741                         std::string contenttype="";\r
742                         std::vector<unsigned char> data((*i)->GetContent(),(*i)->GetContent()+(*i)->GetContentLength());\r
743                         if((*i)->GetContentType())\r
744                         {\r
745                                 contenttype=(*i)->GetContentType();\r
746                                 // find first ; tab cr or lf and erase it and everything after it\r
747                                 std::string::size_type endpos=contenttype.find_first_of(";\t\r\n ");\r
748                                 if(endpos!=std::string::npos)\r
749                                 {\r
750                                         contenttype.erase(endpos);\r
751                                 }\r
752                         }\r
753                         filename=(*i)->GetFilename();\r
754                         if(filename=="")\r
755                         {\r
756                                 filename=(*i)->GetName();\r
757                         }\r
758                         m_fileattachments.push_back(fileattachment(filename,contenttype,data));\r
759                 }\r
760         }\r
761 \r
762         return true;\r
763 }\r
764 \r
765 const bool Message::StartFreenetInsert()\r
766 {\r
767 \r
768         MessageXML xml;\r
769         int localidentityid=-1;\r
770 \r
771         StripAdministrationBoards();\r
772 \r
773         if(m_boards.size()>0)\r
774         {\r
775 \r
776                 xml.SetMessageID(m_messageuuid);\r
777                 xml.SetSubject(m_subject);\r
778                 xml.SetBody(m_body);\r
779                 xml.SetReplyBoard(m_replyboardname);\r
780                 \r
781                 for(std::vector<std::string>::iterator i=m_boards.begin(); i!=m_boards.end(); i++)\r
782                 {\r
783                         xml.AddBoard((*i));\r
784                 }\r
785                 \r
786                 for(std::map<long,std::string>::iterator j=m_inreplyto.begin(); j!=m_inreplyto.end(); j++)\r
787                 {\r
788                         xml.AddInReplyTo((*j).first,(*j).second);\r
789                 }\r
790 \r
791                 localidentityid=FindLocalIdentityID(m_fromname);\r
792                 if(localidentityid==-1)\r
793                 {\r
794                         return false;\r
795                 }\r
796 \r
797                 // add the message delay if there is one\r
798                 SQLite3DB::Statement st=m_db->Prepare("SELECT MinMessageDelay,MaxMessageDelay FROM tblLocalIdentity WHERE LocalIdentityID=?;");\r
799                 st.Bind(0,localidentityid);\r
800                 st.Step();\r
801                 if(st.RowReturned())\r
802                 {\r
803                         int min=0;\r
804                         int max=0;\r
805                         st.ResultInt(0,min);\r
806                         st.ResultInt(1,max);\r
807 \r
808                         min<0 ? min=0 : false;\r
809                         max<0 ? max=0 : false;\r
810                         min>max ? min=max : false;\r
811 \r
812                         if(min==max)\r
813                         {\r
814                                 m_datetime+=Poco::Timespan(0,0,min,0,0);\r
815                         }\r
816                         else if(max>min)\r
817                         {\r
818                                 int delay=(rand()%(max-min))+min;\r
819                                 m_datetime+=Poco::Timespan(0,0,delay,0,0);\r
820                         }\r
821 \r
822                 }\r
823                 st.Finalize();\r
824 \r
825                 // set date in xml file AFTER we set the delay\r
826                 xml.SetDate(Poco::DateTimeFormatter::format(m_datetime,"%Y-%m-%d"));\r
827                 xml.SetTime(Poco::DateTimeFormatter::format(m_datetime,"%H:%M:%S"));\r
828 \r
829                 st=m_db->Prepare("INSERT INTO tblMessageInserts(LocalIdentityID,MessageUUID,MessageXML,SendDate) VALUES(?,?,?,?);");\r
830                 st.Bind(0,localidentityid);\r
831                 st.Bind(1,m_messageuuid);\r
832                 st.Bind(2,xml.GetXML());\r
833                 st.Bind(3,Poco::DateTimeFormatter::format(m_datetime,"%Y-%m-%d %H:%M:%S"));\r
834                 st.Step();\r
835 \r
836                 // insert file attachments into database\r
837                 st=m_db->Prepare("INSERT INTO tblFileInserts(MessageUUID,FileName,Size,MimeType,Data) VALUES(?,?,?,?,?);");\r
838                 for(std::vector<fileattachment>::iterator i=m_fileattachments.begin(); i!=m_fileattachments.end(); i++)\r
839                 {\r
840                         st.Bind(0,m_messageuuid);\r
841                         st.Bind(1,(*i).m_filename);\r
842                         st.Bind(2,(long)(*i).m_data.size());\r
843                         st.Bind(3,(*i).m_mimetype);\r
844                         st.Bind(4,&((*i).m_data[0]),(*i).m_data.size());\r
845                         st.Step();\r
846                         st.Reset();\r
847                 }\r
848 \r
849                 HandleChangeTrust();\r
850 \r
851         }\r
852 \r
853         return true;\r
854 \r
855 }\r
856 \r
857 void Message::StripAdministrationBoards()\r
858 {\r
859         SQLite3DB::Statement st=m_db->Prepare("SELECT tblBoard.BoardID FROM tblBoard INNER JOIN tblAdministrationBoard ON tblBoard.BoardID=tblAdministrationBoard.BoardID WHERE BoardName=?;");\r
860         for(std::vector<std::string>::iterator i=m_boards.begin(); i!=m_boards.end(); )\r
861         {\r
862                 st.Bind(0,(*i));\r
863                 st.Step();\r
864                 if(st.RowReturned())\r
865                 {\r
866                         if(m_replyboardname==(*i))\r
867                         {\r
868                                 m_replyboardname="";\r
869                         }\r
870                         i=m_boards.erase(i);\r
871                 }\r
872                 else\r
873                 {\r
874                         i++;\r
875                 }\r
876                 st.Reset();\r
877         }\r
878         if(m_replyboardname=="" && m_boards.begin()!=m_boards.end())\r
879         {\r
880                 m_replyboardname=(*m_boards.begin());\r
881         }\r
882 }\r