xref: /haiku/src/kits/mail/MailProtocol.cpp (revision 81ec973846ea4816c53ed8901822e43c8b06878d)
1 /*
2  * Copyright 2011-2012, Haiku, Inc. All rights reserved.
3  * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
4  */
5 
6 
7 //#include <assert.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 
11 #include <fs_attr.h>
12 
13 #include <Alert.h>
14 #include <Directory.h>
15 #include <FindDirectory.h>
16 #include <E-mail.h>
17 #include <Locker.h>
18 #include <Node.h>
19 #include <NodeInfo.h>
20 #include <NodeMonitor.h>
21 #include <Path.h>
22 #include <Query.h>
23 #include <Roster.h>
24 #include <String.h>
25 #include <StringList.h>
26 #include <VolumeRoster.h>
27 
28 #include <MailFilter.h>
29 #include <MailDaemon.h>
30 #include <MailProtocol.h>
31 #include <MailSettings.h>
32 
33 #include <mail_util.h>
34 #include <MailPrivate.h>
35 
36 #include "HaikuMailFormatFilter.h"
37 
38 
39 using namespace BPrivate;
40 
41 
42 const uint32 kMsgDeleteMessage = '&DeM';
43 const uint32 kMsgAppendMessage = '&ApM';
44 
45 const uint32 kMsgMoveFile = '&MoF';
46 const uint32 kMsgDeleteFile = '&DeF';
47 const uint32 kMsgFileRenamed = '&FiR';
48 const uint32 kMsgFileDeleted = '&FDe';
49 const uint32 kMsgInit = '&Ini';
50 
51 const uint32 kMsgSendMessage = '&SeM';
52 
53 
54 BMailProtocol::BMailProtocol(const BMailAccountSettings& settings)
55 	:
56 	fAccountSettings(settings),
57 	fMailNotifier(NULL)
58 {
59 	AddFilter(new HaikuMailFormatFilter(*this, settings));
60 }
61 
62 
63 BMailProtocol::~BMailProtocol()
64 {
65 	delete fMailNotifier;
66 
67 	for (int i = 0; i < fFilterList.CountItems(); i++)
68 		delete fFilterList.ItemAt(i);
69 
70 	std::map<entry_ref, image_id>::iterator it = fFilterImages.begin();
71 	for (; it != fFilterImages.end(); it++)
72 		unload_add_on(it->second);
73 }
74 
75 
76 const BMailAccountSettings&
77 BMailProtocol::AccountSettings() const
78 {
79 	return fAccountSettings;
80 }
81 
82 
83 void
84 BMailProtocol::SetMailNotifier(BMailNotifier* mailNotifier)
85 {
86 	delete fMailNotifier;
87 	fMailNotifier = mailNotifier;
88 }
89 
90 
91 BMailNotifier*
92 BMailProtocol::MailNotifier() const
93 {
94 	return fMailNotifier;
95 }
96 
97 
98 bool
99 BMailProtocol::AddFilter(BMailFilter* filter)
100 {
101 	BLocker locker(this);
102 	return fFilterList.AddItem(filter);
103 }
104 
105 
106 int32
107 BMailProtocol::CountFilter() const
108 {
109 	BLocker locker(this);
110 	return fFilterList.CountItems();
111 }
112 
113 
114 BMailFilter*
115 BMailProtocol::FilterAt(int32 index) const
116 {
117 	BLocker locker(this);
118 	return fFilterList.ItemAt(index);
119 }
120 
121 
122 BMailFilter*
123 BMailProtocol::RemoveFilter(int32 index)
124 {
125 	BLocker locker(this);
126 	return fFilterList.RemoveItemAt(index);
127 }
128 
129 
130 bool
131 BMailProtocol::RemoveFilter(BMailFilter* filter)
132 {
133 	BLocker locker(this);
134 	return fFilterList.RemoveItem(filter);
135 }
136 
137 
138 void
139 BMailProtocol::MessageReceived(BMessage* message)
140 {
141 	switch (message->what) {
142 		case kMsgMoveFile:
143 		{
144 			entry_ref file;
145 			message->FindRef("file", &file);
146 			entry_ref dir;
147 			message->FindRef("directory", &dir);
148 			BDirectory directory(&dir);
149 			MoveMessage(file, directory);
150 			break;
151 		}
152 
153 		case kMsgDeleteFile:
154 		{
155 			entry_ref file;
156 			message->FindRef("file", &file);
157 			DeleteMessage(file);
158 			break;
159 		}
160 
161 		case kMsgFileRenamed:
162 		{
163 			entry_ref from;
164 			message->FindRef("from", &from);
165 			entry_ref to;
166 			message->FindRef("to", &to);
167 			FileRenamed(from, to);
168 			break;
169 		}
170 
171 		case kMsgFileDeleted:
172 		{
173 			node_ref node;
174 			message->FindInt32("device",&node.device);
175 			message->FindInt64("node", &node.node);
176 			FileDeleted(node);
177 			break;
178 		}
179 
180 		default:
181 			BLooper::MessageReceived(message);
182 	}
183 }
184 
185 
186 status_t
187 BMailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir)
188 {
189 	BEntry entry(&ref);
190 	return entry.MoveTo(&dir);
191 }
192 
193 
194 status_t
195 BMailProtocol::DeleteMessage(const entry_ref& ref)
196 {
197 	BEntry entry(&ref);
198 	return entry.Remove();
199 }
200 
201 
202 void
203 BMailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to)
204 {
205 }
206 
207 
208 void
209 BMailProtocol::FileDeleted(const node_ref& node)
210 {
211 }
212 
213 
214 void
215 BMailProtocol::ShowError(const char* error)
216 {
217 	if (MailNotifier() != NULL)
218 		MailNotifier()->ShowError(error);
219 }
220 
221 
222 void
223 BMailProtocol::ShowMessage(const char* message)
224 {
225 	if (MailNotifier() != NULL)
226 		MailNotifier()->ShowMessage(message);
227 }
228 
229 
230 void
231 BMailProtocol::SetTotalItems(uint32 items)
232 {
233 	if (MailNotifier() != NULL)
234 		MailNotifier()->SetTotalItems(items);
235 }
236 
237 
238 void
239 BMailProtocol::SetTotalItemsSize(uint64 size)
240 {
241 	if (MailNotifier() != NULL)
242 		MailNotifier()->SetTotalItemsSize(size);
243 }
244 
245 
246 void
247 BMailProtocol::ReportProgress(uint32 messages, uint64 bytes,
248 	const char* message)
249 {
250 	if (MailNotifier() != NULL)
251 		MailNotifier()->ReportProgress(messages, bytes, message);
252 }
253 
254 
255 void
256 BMailProtocol::ResetProgress(const char* message)
257 {
258 	if (MailNotifier() != NULL)
259 		MailNotifier()->ResetProgress(message);
260 }
261 
262 
263 void
264 BMailProtocol::NotifyNewMessagesToFetch(int32 count)
265 {
266 	ResetProgress();
267 	SetTotalItems(count);
268 }
269 
270 
271 void
272 BMailProtocol::NotifyHeaderFetched(const entry_ref& ref, BFile* data)
273 {
274 	for (int i = 0; i < fFilterList.CountItems(); i++)
275 		fFilterList.ItemAt(i)->HeaderFetched(ref, data);
276 }
277 
278 
279 void
280 BMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile* data)
281 {
282 	for (int i = 0; i < fFilterList.CountItems(); i++)
283 		fFilterList.ItemAt(i)->BodyFetched(ref, data);
284 }
285 
286 
287 void
288 BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data)
289 {
290 	for (int i = 0; i < fFilterList.CountItems(); i++)
291 		fFilterList.ItemAt(i)->MessageReadyToSend(ref, data);
292 }
293 
294 
295 void
296 BMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile* data)
297 {
298 	for (int i = 0; i < fFilterList.CountItems(); i++)
299 		fFilterList.ItemAt(i)->MessageSent(ref, data);
300 }
301 
302 
303 void
304 BMailProtocol::LoadFilters(const BMailProtocolSettings& settings)
305 {
306 	for (int i = 0; i < settings.CountFilterSettings(); i++) {
307 		BMailAddOnSettings* filterSettings = settings.FilterSettingsAt(i);
308 		BMailFilter* filter = _LoadFilter(*filterSettings);
309 		if (filter != NULL)
310 			AddFilter(filter);
311 	}
312 }
313 
314 
315 BMailFilter*
316 BMailProtocol::_LoadFilter(const BMailAddOnSettings& settings)
317 {
318 	const entry_ref& ref = settings.AddOnRef();
319 	std::map<entry_ref, image_id>::iterator it = fFilterImages.find(ref);
320 	image_id image;
321 	if (it != fFilterImages.end())
322 		image = it->second;
323 	else {
324 		BEntry entry(&ref);
325 		BPath path(&entry);
326 		image = load_add_on(path.Path());
327 	}
328 	if (image < 0)
329 		return NULL;
330 
331 	BMailFilter* (*instantiateFilter)(BMailProtocol& protocol,
332 		const BMailAddOnSettings& settings);
333 	if (get_image_symbol(image, "instantiate_filter", B_SYMBOL_TYPE_TEXT,
334 			(void**)&instantiateFilter) != B_OK) {
335 		unload_add_on(image);
336 		return NULL;
337 	}
338 
339 	fFilterImages[ref] = image;
340 	return instantiateFilter(*this, settings);
341 }
342 
343 
344 // #pragma mark -
345 
346 
347 BInboundMailProtocol::BInboundMailProtocol(const BMailAccountSettings& settings)
348 	:
349 	BMailProtocol(settings)
350 {
351 	LoadFilters(fAccountSettings.InboundSettings());
352 }
353 
354 
355 BInboundMailProtocol::~BInboundMailProtocol()
356 {
357 }
358 
359 
360 void
361 BInboundMailProtocol::MessageReceived(BMessage* message)
362 {
363 	switch (message->what) {
364 		case kMsgSyncMessages:
365 		{
366 			NotiyMailboxSynchronized(SyncMessages());
367 			break;
368 		}
369 
370 		case kMsgFetchBody:
371 		{
372 			entry_ref ref;
373 			message->FindRef("ref", &ref);
374 			status_t status = FetchBody(ref);
375 
376 			BMessenger target;
377 			if (message->FindMessenger("target", &target) != B_OK)
378 				break;
379 
380 			BMessage message(B_MAIL_BODY_FETCHED);
381 			message.AddInt32("status", status);
382 			message.AddRef("ref", &ref);
383 			target.SendMessage(&message);
384 			break;
385 		}
386 
387 		case kMsgMarkMessageAsRead:
388 		{
389 			entry_ref ref;
390 			message->FindRef("ref", &ref);
391 			read_flags read = (read_flags)message->FindInt32("read");
392 			MarkMessageAsRead(ref, read);
393 			break;
394 		}
395 
396 		case kMsgDeleteMessage:
397 		{
398 			entry_ref ref;
399 			message->FindRef("ref", &ref);
400 			DeleteMessage(ref);
401 			break;
402 		}
403 
404 		case kMsgAppendMessage:
405 		{
406 			entry_ref ref;
407 			message->FindRef("ref", &ref);
408 			AppendMessage(ref);
409 			break;
410 		}
411 
412 		default:
413 			BMailProtocol::MessageReceived(message);
414 			break;
415 	}
416 }
417 
418 
419 status_t
420 BInboundMailProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag)
421 {
422 	BNode node(&ref);
423 	return write_read_attr(node, flag);
424 }
425 
426 
427 status_t
428 BInboundMailProtocol::AppendMessage(const entry_ref& ref)
429 {
430 	return B_OK;
431 }
432 
433 
434 void
435 BInboundMailProtocol::NotiyMailboxSynchronized(status_t status)
436 {
437 	for (int32 i = 0; i < CountFilter(); i++)
438 		FilterAt(i)->MailboxSynchronized(status);
439 }
440 
441 
442 // #pragma mark -
443 
444 
445 BOutboundMailProtocol::BOutboundMailProtocol(
446 	const BMailAccountSettings& settings)
447 	:
448 	BMailProtocol(settings)
449 {
450 	LoadFilters(fAccountSettings.OutboundSettings());
451 }
452 
453 
454 BOutboundMailProtocol::~BOutboundMailProtocol()
455 {
456 }
457 
458 
459 void
460 BOutboundMailProtocol::MessageReceived(BMessage* message)
461 {
462 	switch (message->what) {
463 		case kMsgSendMessage:
464 			SendMessages(*message, message->FindInt64("bytes"));
465 			break;
466 
467 		default:
468 			BMailProtocol::MessageReceived(message);
469 	}
470 }
471