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