1 /*
2 ** Copyright 2002-2008, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #include "libmail_config.h"
7 #include "addressbookadd.H"
8 #include "rfc2047encode.H"
9 #include "attachments.H"
10 #include "headers.H"
11 #include "envelope.H"
12 #include "rfcaddr.H"
13 #include "misc.H"
14 #include <courier-unicode.h>
15 #include <ctype.h>
16 #include <vector>
17 #include <errno.h>
18 #include <cstring>
19
20 using namespace std;
21
Add(mail::addressbook * addressBookArg,mail::addressbook::Entry entryArg,string oldUidArg,mail::callback & callbackArg)22 mail::addressbook::Add::Add(mail::addressbook *addressBookArg,
23 mail::addressbook::Entry entryArg,
24 string oldUidArg,
25 mail::callback &callbackArg)
26 : addressBook(addressBookArg),
27 oldUid(oldUidArg),
28 callback(callbackArg),
29 addMessage(NULL)
30 {
31 totCnt=1;
32 currentNum=0;
33 newEntries.push_back(entryArg);
34 }
35
Add(mail::addressbook * addressBookArg,std::list<mail::addressbook::Entry> & entries,mail::callback & callbackArg)36 mail::addressbook::Add::Add(mail::addressbook *addressBookArg,
37 std::list<mail::addressbook::Entry> &entries,
38 mail::callback &callbackArg)
39 : addressBook(addressBookArg),
40 callback(callbackArg),
41 addMessage(NULL)
42 {
43 newEntries.insert(newEntries.end(),
44 entries.begin(),
45 entries.end());
46 totCnt=newEntries.size();
47 currentNum=0;
48 }
49
go()50 void mail::addressbook::Add::go()
51 {
52 callback.reportProgress(0, 0, currentNum, totCnt);
53 if (newEntries.empty())
54 {
55 successFunc= &mail::addressbook::Add::checked;
56 addressBook->server->checkNewMail( *this );
57 return;
58 }
59
60 multipart_params.clear();
61
62 mail::addressbook::Entry &newEntry=newEntries.front();
63
64 nickname=toutf8(newEntry.nickname);
65
66 string::iterator b=nickname.begin(), e=nickname.end();
67
68 while (b != e)
69 {
70 char c= *b++;
71
72 if ( (int)(unsigned char)c < ' ' || c == '[' || c == ']')
73 {
74 fail("Invalid address book nickname.");
75 return;
76 }
77 }
78
79 if (newEntry.addresses.size() == 0)
80 {
81 fail("Invalid address.");
82 return;
83 }
84
85 mail::addMessage *addp=
86 addressBook->folder->addMessage(*this);
87
88 if (!addp)
89 return;
90
91 time(&addp->messageDate);
92
93 addMessage=addp;
94
95 successFunc= &mail::addressbook::Add::addedIntro;
96
97 multipart_params.push_back(0);
98
99 mail::Header::list headers;
100
101 headers << mail::Header::mime("Content-Type", "text/plain")
102 ("charset", "utf-8");
103
104
105 mail::Attachment intro(headers,
106 "This message is used to store Libmail's"
107 " address book. Please do not modify\n"
108 "this folder, and message!\n",
109 "utf-8");
110
111 addMessage->assembleContent(multipart_params.end()[-1], intro,
112 *this);
113 }
114
addedIntro(string successMsg)115 void mail::addressbook::Add::addedIntro(string successMsg)
116 {
117 mail::Header::list headers;
118 mail::addressbook::Entry &newEntry=newEntries.front();
119
120 headers << mail::Header::plain("Content-Type",
121 "text/x-libmail-addressbook");
122
123
124 mail::Attachment addresses(headers, "VERSION: 2\n" +
125 mail::address::toString("Address: ",
126 newEntry.addresses)
127 + "\n", "utf-8", "8bit");
128
129 successFunc= &mail::addressbook::Add::addedBeef;
130
131 multipart_params.push_back(0);
132
133 addMessage->assembleContent(multipart_params.end()[-1], addresses,
134 *this);
135 }
136
addedBeef(string successMsg)137 void mail::addressbook::Add::addedBeef(string successMsg)
138 {
139 // Assemble the multipart message.
140
141 mail::Header::list headers;
142
143 vector<mail::emailAddress> from_addresses;
144
145 from_addresses.push_back(mail::address("Libmail Address Book",
146 "libmail@localhost"));
147
148 headers << mail::Header::addresslist("From", from_addresses);
149 headers << mail::Header::encoded("Subject",
150 "[" + nickname + "]",
151 "utf-8");
152
153 successFunc= &mail::addressbook::Add::addedAll;
154 addMessage->assembleMultipart(dummyRet, headers, multipart_params,
155 "multipart/mixed", *this);
156 }
157
addedAll(string successMsg)158 void mail::addressbook::Add::addedAll(string successMsg)
159 {
160 newEntries.pop_front();
161 successFunc= &mail::addressbook::Add::added;
162 if (!addMessage->assemble())
163 {
164 addMessage->fail(strerror(errno));
165 return;
166 }
167 addMessage->go();
168 }
169
170
~Add()171 mail::addressbook::Add::~Add()
172 {
173 }
174
success(string successMsg)175 void mail::addressbook::Add::success(string successMsg)
176 {
177 (this->*successFunc)(successMsg);
178 }
179
180 //
181 // After adding a new entry, make sure it gets added to the index.
182 //
183
added(string successMsg)184 void mail::addressbook::Add::added(string successMsg)
185 {
186 ++currentNum;
187 go();
188 }
189
190 //
191 // Now, update our address book index.
192
checked(string successMsg)193 void mail::addressbook::Add::checked(string successMsg)
194 {
195 size_t n=addressBook->index.size();
196
197 size_t n2=addressBook->server->getFolderIndexSize();
198
199 vector<size_t> msgNums;
200
201 while (n < n2)
202 msgNums.push_back(n++);
203
204 if (msgNums.size() == 0)
205 {
206 reindexed(successMsg); // Unlikely
207 return;
208 }
209
210 addressBook->index.insert(addressBook->index.end(),
211 msgNums.size(), Index());
212
213 successFunc= &mail::addressbook::Add::reindexed;
214
215 addressBook->server->readMessageAttributes(msgNums,
216 addressBook->server
217 -> ENVELOPE,
218 *this);
219 }
220
messageEnvelopeCallback(size_t messageNumber,const mail::envelope & envelope)221 void mail::addressbook::Add::messageEnvelopeCallback(size_t messageNumber,
222 const mail::envelope
223 &envelope)
224 {
225 addressBook->setIndex(messageNumber, envelope.subject);
226 }
227
reportProgress(size_t bytesCompleted,size_t bytesEstimatedTotal,size_t messagesCompleted,size_t messagesEstimatedTotal)228 void mail::addressbook::Add::reportProgress(size_t bytesCompleted,
229 size_t bytesEstimatedTotal,
230
231 size_t messagesCompleted,
232 size_t messagesEstimatedTotal)
233 {
234 callback.reportProgress(bytesCompleted, bytesEstimatedTotal,
235 messagesCompleted, messagesEstimatedTotal);
236 }
237
reindexed(string successMsg)238 void mail::addressbook::Add::reindexed(string successMsg)
239 {
240 try {
241 // If this is meant to replace another entry, delete it then.
242
243 if (oldUid.size() > 0)
244 {
245 addressBook->del(oldUid, callback);
246 }
247 else
248 callback.success(successMsg);
249 delete this;
250 } catch (...) {
251 delete this;
252 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
253 }
254 }
255
fail(string failMsg)256 void mail::addressbook::Add::fail(string failMsg)
257 {
258 try {
259 callback.fail(failMsg);
260 delete this;
261 } catch (...) {
262 delete this;
263 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
264 }
265 }
266
267