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