c15b5302b717ae11a89ed6824684e6188893a236
[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 \r
7 #include <algorithm>\r
8 \r
9 #ifdef XMEM\r
10         #include <xmem.h>\r
11 #endif\r
12 \r
13 Message::Message()\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 Message::Message(const long messageid)\r
19 {\r
20         Load(messageid);\r
21 }\r
22 \r
23 const std::string Message::GetNNTPArticleID() const\r
24 {\r
25         return "<"+m_messageuuid+">";\r
26 }\r
27 \r
28 const std::string Message::GetNNTPBody() const\r
29 {\r
30         return m_body;\r
31 }\r
32 \r
33 const std::string Message::GetNNTPHeaders() const\r
34 {\r
35         std::string rval("");\r
36 \r
37         rval+="From: "+m_fromname+"\r\n";\r
38         rval+="Newsgroups: ";\r
39         for(std::vector<std::string>::const_iterator i=m_boards.begin(); i!=m_boards.end(); i++)\r
40         {\r
41                 if(i!=m_boards.begin())\r
42                 {\r
43                         rval+=",";\r
44                 }\r
45                 rval+=(*i);\r
46         }\r
47         rval+="\r\n";\r
48         rval+="Subject: "+m_subject+"\r\n";\r
49         // format time as  : Wdy, DD Mon YY HH:MM:SS TIMEZONE\r
50         rval+="Date: "+m_datetime.Format("%a, %d %b %y %H:%M:%S -0000")+"\r\n";\r
51         if(m_inreplyto.size()>0)\r
52         {\r
53                 rval+="References: ";\r
54                 for(std::map<long,std::string>::const_reverse_iterator j=m_inreplyto.rbegin(); j!=m_inreplyto.rend(); j++)\r
55                 {\r
56                         if(j!=m_inreplyto.rend())\r
57                         {\r
58                                 rval+=" ";\r
59                         }\r
60                         rval+="<"+(*j).second+">";\r
61                 }\r
62                 rval+="\r\n";\r
63         }\r
64         rval+="Followup-To: "+m_replyboardname+"\r\n";\r
65         rval+="Path: freenet\r\n";\r
66         rval+="Message-ID: "+GetNNTPArticleID()+"\r\n";\r
67         rval+="Content-Type: text/plain; charset=UTF-8\r\n";\r
68 \r
69         return rval;\r
70 }\r
71 \r
72 void Message::Initialize()\r
73 {\r
74         m_messageid=-1;\r
75         m_messageuuid="";\r
76         m_subject="";\r
77         m_body="";\r
78         m_replyboardname="";\r
79         m_datetime.Set();\r
80         m_fromname="";\r
81         m_boards.clear();\r
82         m_inreplyto.clear();\r
83 }\r
84 \r
85 const bool Message::Load(const long messageid, const long boardid)\r
86 {\r
87         \r
88         Initialize();\r
89 \r
90         std::string sql;\r
91         \r
92         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
93         if(boardid!=-1)\r
94         {\r
95                 sql+=" AND tblMessageBoard.BoardID=?";\r
96         }\r
97         sql+=";";\r
98 \r
99         SQLite3DB::Statement st=m_db->Prepare(sql);\r
100         st.Bind(0,messageid);\r
101         if(boardid!=-1)\r
102         {\r
103                 st.Bind(1,boardid);\r
104         }\r
105         st.Step();\r
106 \r
107         if(st.RowReturned())\r
108         {\r
109                 std::string tempdate;\r
110                 std::string temptime;\r
111                 int tempint=-1;\r
112                 st.ResultInt(0,tempint);\r
113                 m_messageid=tempint;\r
114                 st.ResultText(1,m_messageuuid);\r
115                 st.ResultText(2,m_subject);\r
116                 st.ResultText(3,m_body);\r
117                 st.ResultText(4,m_replyboardname);\r
118                 st.ResultText(5,tempdate);\r
119                 st.ResultText(6,temptime);\r
120                 m_datetime.Set(tempdate + " " + temptime);\r
121                 st.ResultText(7,m_fromname);\r
122                 st.Finalize();\r
123 \r
124                 // get board list\r
125                 st=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard INNER JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID WHERE tblMessageBoard.MessageID=?;");\r
126                 st.Bind(0,messageid);\r
127                 st.Step();\r
128                 while(st.RowReturned())\r
129                 {\r
130                         std::string tempval;\r
131                         st.ResultText(0,tempval);\r
132                         m_boards.push_back(tempval);\r
133                         st.Step();\r
134                 }\r
135                 st.Finalize();\r
136 \r
137                 // get in reply to list\r
138                 st=m_db->Prepare("SELECT ReplyToMessageUUID, ReplyOrder FROM tblMessageReplyTo INNER JOIN tblMessage ON tblMessageReplyTo.MessageID=tblMessage.MessageID WHERE tblMessage.MessageID=?;");\r
139                 st.Bind(0,messageid);\r
140                 st.Step();\r
141                 while(st.RowReturned())\r
142                 {\r
143                         std::string tempval;\r
144                         int tempint;\r
145                         st.ResultText(0,tempval);\r
146                         st.ResultInt(1,tempint);\r
147                         m_inreplyto[tempint]=tempval;\r
148                         st.Step();\r
149                 }\r
150                 st.Finalize();\r
151 \r
152                 return true;\r
153         }\r
154         else\r
155         {\r
156                 return false;\r
157         }\r
158 \r
159 }\r
160 \r
161 const bool Message::Load(const std::string &messageuuid)\r
162 {\r
163         SQLite3DB::Statement st=m_db->Prepare("SELECT MessageID FROM tblMessage WHERE MessageUUID=?;");\r
164         st.Bind(0,messageuuid);\r
165         st.Step();\r
166 \r
167         if(st.RowReturned())\r
168         {\r
169                 int messageid;\r
170                 st.ResultInt(0,messageid);\r
171 \r
172                 return Load(messageid);\r
173         }\r
174         else\r
175         {\r
176                 return false;\r
177         }\r
178 }\r
179 \r
180 const bool Message::LoadNext(const long messageid, const long boardid)\r
181 {\r
182         std::string sql="SELECT MessageID FROM tblMessage WHERE MessageID>?";\r
183         if(boardid!=-1)\r
184         {\r
185                 sql+=" AND BoardID=?";\r
186         }\r
187         sql+=";";\r
188 \r
189         SQLite3DB::Statement st=m_db->Prepare(sql);\r
190 \r
191         st.Bind(0,messageid);\r
192         if(boardid!=-1)\r
193         {\r
194                 st.Bind(1,boardid);\r
195         }\r
196         st.Step();\r
197 \r
198         if(st.RowReturned())\r
199         {\r
200                 int result;\r
201                 st.ResultInt(0,result);\r
202                 return Load(result,boardid);\r
203         }\r
204         else\r
205         {\r
206                 return false;\r
207         }\r
208 }\r
209 \r
210 const bool Message::LoadPrevious(const long messageid, const long boardid)\r
211 {\r
212         std::string sql="SELECT MessageID FROM tblMessage WHERE MessageID<?";\r
213         if(boardid!=-1)\r
214         {\r
215                 sql+=" AND BoardID=?";\r
216         }\r
217         sql+=";";\r
218 \r
219         SQLite3DB::Statement st=m_db->Prepare(sql);\r
220 \r
221         st.Bind(0,messageid);\r
222         if(boardid!=-1)\r
223         {\r
224                 st.Bind(1,boardid);\r
225         }\r
226         st.Step();\r
227 \r
228         if(st.RowReturned())\r
229         {\r
230                 int result;\r
231                 st.ResultInt(0,result);\r
232                 return Load(result,boardid);\r
233         }\r
234         else\r
235         {\r
236                 return false;\r
237         }\r
238 }\r
239 \r
240 const bool Message::ParseNNTPMessage(const std::string &nntpmessage)\r
241 {\r
242 \r
243         Initialize();\r
244 \r
245         UUIDGenerator uuid;\r
246         CMimeMessage mime;\r
247         mime.Load(nntpmessage.c_str(),nntpmessage.size());\r
248 \r
249         // get header info\r
250         // date is always set to now regardless of what message has\r
251         m_datetime.SetToGMTime();\r
252         // messageuuid is always a unique id we generate regardless of message message-id\r
253         m_messageuuid=uuid.Generate();\r
254         // get from\r
255         if(mime.GetFieldValue("From"))\r
256         {\r
257                 m_fromname=mime.GetFieldValue("From");\r
258                 // strip off everything between () and <> and any whitespace\r
259                 std::string::size_type startpos=m_fromname.find("(");\r
260                 std::string::size_type endpos;\r
261                 if(startpos!=std::string::npos)\r
262                 {\r
263                         endpos=m_fromname.find(")",startpos);\r
264                         if(endpos!=std::string::npos)\r
265                         {\r
266                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
267                         }\r
268                 }\r
269                 startpos=m_fromname.find("<");\r
270                 if(startpos!=std::string::npos)\r
271                 {\r
272                         endpos=m_fromname.find(">",startpos);\r
273                         if(endpos!=std::string::npos)\r
274                         {\r
275                                 m_fromname.erase(startpos,(endpos-startpos)+1);\r
276                         }\r
277                 }\r
278                 m_fromname=StringFunctions::TrimWhitespace(m_fromname);\r
279         }\r
280         else\r
281         {\r
282                 m_fromname="Anonymous";\r
283         }\r
284         // get boards posted to\r
285         if(mime.GetFieldValue("Newsgroups"))\r
286         {\r
287                 std::string temp=mime.GetFieldValue("Newsgroups");\r
288                 std::vector<std::string> parts;\r
289                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
290                 for(std::vector<std::string>::iterator i=parts.begin(); i!=parts.end(); i++)\r
291                 {\r
292                         (*i)=StringFunctions::Replace((*i),"<","");\r
293                         (*i)=StringFunctions::Replace((*i),">","");\r
294                         (*i)=StringFunctions::TrimWhitespace((*i));\r
295                         if((*i)!="")\r
296                         {\r
297                                 m_boards.push_back((*i));\r
298                         }\r
299                 }\r
300         }\r
301         // followup-to board - must be done after board vector populated\r
302         if(mime.GetFieldValue("Followup-To"))\r
303         {\r
304                 m_replyboardname=mime.GetFieldValue("Followup-To");\r
305         }\r
306         else\r
307         {\r
308                 if(m_boards.size()>0)\r
309                 {\r
310                         m_replyboardname=m_boards[0];\r
311                 }\r
312         }\r
313         // subject\r
314         if(mime.GetFieldValue("Subject"))\r
315         {\r
316                 m_subject=mime.GetFieldValue("Subject");\r
317         }\r
318         else\r
319         {\r
320                 m_subject="No Subject";\r
321         }\r
322         // references\r
323         if(mime.GetFieldValue("References"))\r
324         {\r
325                 std::string temp=mime.GetFieldValue("References");\r
326                 std::vector<std::string> parts;\r
327                 int count=0;\r
328                 StringFunctions::SplitMultiple(temp,", \t",parts);\r
329                 for(std::vector<std::string>::reverse_iterator i=parts.rbegin(); i!=parts.rend(); i++)\r
330                 {\r
331                         (*i)=StringFunctions::Replace((*i),"<","");\r
332                         (*i)=StringFunctions::Replace((*i),">","");\r
333                         (*i)=StringFunctions::TrimWhitespace((*i));\r
334                         if((*i)!="")\r
335                         {\r
336                                 m_inreplyto[count++]=(*i);\r
337                         }\r
338                 }\r
339         }\r
340 \r
341         CMimeBody::CBodyList mbl;\r
342         mime.GetBodyPartList(mbl);\r
343 \r
344         // append all text parts of nntp message to body\r
345         for(CMimeBody::CBodyList::iterator i=mbl.begin(); i!=mbl.end(); i++)\r
346         {\r
347                 if((*i)->IsText() && (*i)->GetContent())\r
348                 {\r
349                         m_body+=(char *)(*i)->GetContent();\r
350                 }\r
351         }\r
352 \r
353         return true;\r
354 }\r
355 \r
356 void Message::StartFreenetInsert()\r
357 {\r
358         MessageXML xml;\r
359         int localidentityid=-1;\r
360 \r
361         xml.SetMessageID(m_messageuuid);\r
362         xml.SetSubject(m_subject);\r
363         xml.SetBody(m_body);\r
364         xml.SetReplyBoard(m_replyboardname);\r
365         xml.SetDate(m_datetime.Format("%Y-%m-%d"));\r
366         xml.SetTime(m_datetime.Format("%H:%M:%S"));\r
367         \r
368         for(std::vector<std::string>::iterator i=m_boards.begin(); i!=m_boards.end(); i++)\r
369         {\r
370                 xml.AddBoard((*i));\r
371         }\r
372         \r
373         for(std::map<long,std::string>::iterator j=m_inreplyto.begin(); j!=m_inreplyto.end(); j++)\r
374         {\r
375                 xml.AddInReplyTo((*j).first,(*j).second);\r
376         }\r
377 \r
378         // find identity to insert with\r
379         SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblLocalIdentity WHERE Name=?;");\r
380         st.Bind(0,m_fromname);\r
381         st.Step();\r
382 \r
383         // couldn't find identity with this name - insert a new identity\r
384         if(!st.RowReturned())\r
385         {\r
386                 DateTime now;\r
387                 now.SetToGMTime();\r
388                 st=m_db->Prepare("INSERT INTO tblLocalIdentity(Name) VALUES(?);");\r
389                 st.Bind(0,m_fromname);\r
390                 st.Step(true);\r
391                 localidentityid=st.GetLastInsertRowID();\r
392         }\r
393         else\r
394         {\r
395                 st.ResultInt(0,localidentityid);\r
396         }\r
397 \r
398         st=m_db->Prepare("INSERT INTO tblMessageInserts(LocalIdentityID,MessageUUID,MessageXML) VALUES(?,?,?);");\r
399         st.Bind(0,localidentityid);\r
400         st.Bind(1,m_messageuuid);\r
401         st.Bind(2,xml.GetXML());\r
402         st.Step();\r
403 \r
404 }\r