xref: /haiku/src/kits/mail/MailProtocol.cpp (revision cb9c3e9cede30851ba29be2e955fb8cfcecef7ac)
1 /* BMailProtocol - the base class for protocol filters
2 **
3 ** Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
4 */
5 
6 
7 #include <stdio.h>
8 #include <fs_attr.h>
9 #include <stdlib.h>
10 #include <assert.h>
11 
12 #include <Alert.h>
13 #include <Directory.h>
14 #include <FindDirectory.h>
15 #include <Query.h>
16 #include <E-mail.h>
17 #include <Node.h>
18 #include <NodeInfo.h>
19 #include <NodeMonitor.h>
20 #include <Path.h>
21 #include <Roster.h>
22 #include <String.h>
23 #include <StringList.h>
24 #include <VolumeRoster.h>
25 
26 #include <MDRLanguage.h>
27 
28 #include <mail_util.h>
29 #include <MailAddon.h>
30 #include <MailDaemon.h>
31 #include <MailProtocol.h>
32 #include <MailSettings.h>
33 
34 #include "HaikuMailFormatFilter.h"
35 
36 
37 using std::map;
38 
39 
40 MailFilter::MailFilter(MailProtocol& protocol, AddonSettings* settings)
41 	:
42 	fMailProtocol(protocol),
43 	fAddonSettings(settings)
44 {
45 
46 }
47 
48 
49 MailFilter::~MailFilter()
50 {
51 
52 }
53 
54 
55 void
56 MailFilter::HeaderFetched(const entry_ref& ref, BFile* file)
57 {
58 
59 }
60 
61 
62 void
63 MailFilter::BodyFetched(const entry_ref& ref, BFile* file)
64 {
65 
66 }
67 
68 
69 void
70 MailFilter::MailboxSynced(status_t status)
71 {
72 
73 }
74 
75 
76 void
77 MailFilter::MessageReadyToSend(const entry_ref& ref, BFile* file)
78 {
79 
80 }
81 
82 
83 void
84 MailFilter::MessageSent(const entry_ref& ref, BFile* file)
85 {
86 
87 }
88 
89 
90 MailProtocol::MailProtocol(BMailAccountSettings* settings)
91 	:
92 	fMailNotifier(NULL),
93 	fProtocolThread(NULL)
94 {
95 	fAccountSettings = *settings;
96 
97 	AddFilter(new HaikuMailFormatFilter(*this, settings));
98 }
99 
100 
101 MailProtocol::~MailProtocol()
102 {
103 	delete fMailNotifier;
104 
105 	for (int i = 0; i < fFilterList.CountItems(); i++)
106 		delete fFilterList.ItemAt(i);
107 
108 	map<entry_ref, image_id>::iterator it = fFilterImages.begin();
109 	for (; it != fFilterImages.end(); it++)
110 		unload_add_on(it->second);
111 }
112 
113 
114 BMailAccountSettings&
115 MailProtocol::AccountSettings()
116 {
117 	return fAccountSettings;
118 }
119 
120 
121 void
122 MailProtocol::SetProtocolThread(MailProtocolThread* protocolThread)
123 {
124 	if (fProtocolThread) {
125 		fProtocolThread->Lock();
126 		for (int i = 0; i < fHandlerList.CountItems(); i++)
127 			fProtocolThread->RemoveHandler(fHandlerList.ItemAt(i));
128 		fProtocolThread->Unlock();
129 	}
130 
131 	fProtocolThread = protocolThread;
132 
133 	if (!fProtocolThread)
134 		return;
135 
136 	fProtocolThread->Lock();
137 	for (int i = 0; i < fHandlerList.CountItems(); i++)
138 		fProtocolThread->AddHandler(fHandlerList.ItemAt(i));
139 	fProtocolThread->Unlock();
140 
141 	AddedToLooper();
142 }
143 
144 
145 MailProtocolThread*
146 MailProtocol::Looper()
147 {
148 	return fProtocolThread;
149 }
150 
151 
152 bool
153 MailProtocol::AddHandler(BHandler* handler)
154 {
155 	if (!fHandlerList.AddItem(handler))
156 		return false;
157 	if (fProtocolThread) {
158 		fProtocolThread->Lock();
159 		fProtocolThread->AddHandler(handler);
160 		fProtocolThread->Unlock();
161 	}
162 	return true;
163 }
164 
165 
166 bool
167 MailProtocol::RemoveHandler(BHandler* handler)
168 {
169 	if (!fHandlerList.RemoveItem(handler))
170 		return false;
171 	if (fProtocolThread) {
172 		fProtocolThread->Lock();
173 		fProtocolThread->RemoveHandler(handler);
174 		fProtocolThread->Unlock();
175 	}
176 	return true;
177 }
178 
179 
180 void
181 MailProtocol::SetMailNotifier(MailNotifier* mailNotifier)
182 {
183 	delete fMailNotifier;
184 	fMailNotifier = mailNotifier;
185 }
186 
187 
188 void
189 MailProtocol::ShowError(const char* error)
190 {
191 	if (fMailNotifier)
192 		fMailNotifier->ShowError(error);
193 }
194 
195 
196 void
197 MailProtocol::ShowMessage(const char* message)
198 {
199 	if (fMailNotifier)
200 		fMailNotifier->ShowMessage(message);
201 }
202 
203 
204 void
205 MailProtocol::SetTotalItems(int32 items)
206 {
207 	if (fMailNotifier)
208 		fMailNotifier->SetTotalItems(items);
209 }
210 
211 
212 void
213 MailProtocol::SetTotalItemsSize(int32 size)
214 {
215 	if (fMailNotifier)
216 		fMailNotifier->SetTotalItemsSize(size);
217 }
218 
219 
220 void
221 MailProtocol::ReportProgress(int bytes, int messages, const char* message)
222 {
223 	if (fMailNotifier)
224 		fMailNotifier->ReportProgress(bytes, messages, message);
225 }
226 
227 
228 void
229 MailProtocol::ResetProgress(const char* message)
230 {
231 	if (fMailNotifier)
232 		fMailNotifier->ResetProgress(message);
233 }
234 
235 
236 bool
237 MailProtocol::AddFilter(MailFilter* filter)
238 {
239 	return fFilterList.AddItem(filter);
240 }
241 
242 
243 int32
244 MailProtocol::CountFilter()
245 {
246 	return fFilterList.CountItems();
247 }
248 
249 
250 MailFilter*
251 MailProtocol::FilterAt(int32 index)
252 {
253 	return fFilterList.ItemAt(index);
254 }
255 
256 
257 MailFilter*
258 MailProtocol::RemoveFilter(int32 index)
259 {
260 	return fFilterList.RemoveItemAt(index);
261 }
262 
263 
264 bool
265 MailProtocol::RemoveFilter(MailFilter* filter)
266 {
267 	return fFilterList.RemoveItem(filter);
268 }
269 
270 
271 void
272 MailProtocol::NotifyNewMessagesToFetch(int32 nMessages)
273 {
274 	ResetProgress();
275 	SetTotalItems(nMessages);
276 }
277 
278 
279 void
280 MailProtocol::NotifyHeaderFetched(const entry_ref& ref, BFile* data)
281 {
282 	for (int i = 0; i < fFilterList.CountItems(); i++)
283 		fFilterList.ItemAt(i)->HeaderFetched(ref, data);
284 }
285 
286 
287 void
288 MailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile* data)
289 {
290 	for (int i = 0; i < fFilterList.CountItems(); i++)
291 		fFilterList.ItemAt(i)->BodyFetched(ref, data);
292 }
293 
294 
295 void
296 MailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data)
297 {
298 	for (int i = 0; i < fFilterList.CountItems(); i++)
299 		fFilterList.ItemAt(i)->MessageReadyToSend(ref, data);
300 }
301 
302 
303 void
304 MailProtocol::NotifyMessageSent(const entry_ref& ref, BFile* data)
305 {
306 	for (int i = 0; i < fFilterList.CountItems(); i++)
307 		fFilterList.ItemAt(i)->MessageSent(ref, data);
308 }
309 
310 
311 status_t
312 MailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir)
313 {
314 	BEntry entry(&ref);
315 	return entry.MoveTo(&dir);
316 }
317 
318 
319 status_t
320 MailProtocol::DeleteMessage(const entry_ref& ref)
321 {
322 	BEntry entry(&ref);
323 	return entry.Remove();
324 }
325 
326 
327 void
328 MailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to)
329 {
330 
331 }
332 
333 
334 void
335 MailProtocol::FileDeleted(const node_ref& node)
336 {
337 
338 }
339 
340 
341 void
342 MailProtocol::LoadFilters(MailAddonSettings& settings)
343 {
344 	for (int i = 0; i < settings.CountFilterSettings(); i++) {
345 		AddonSettings* filterSettings = settings.FilterSettingsAt(i);
346 		MailFilter* filter = _LoadFilter(filterSettings);
347 		if (!filter)
348 			continue;
349 		AddFilter(filter);
350 	}
351 }
352 
353 
354 MailFilter*
355 MailProtocol::_LoadFilter(AddonSettings* filterSettings)
356 {
357 	const entry_ref& ref = filterSettings->AddonRef();
358 	map<entry_ref, image_id>::iterator it = fFilterImages.find(ref);
359 	image_id image;
360 	if (it != fFilterImages.end())
361 		image = it->second;
362 	else {
363 		BEntry entry(&ref);
364 		BPath path(&entry);
365 		image = load_add_on(path.Path());
366 	}
367 	if (image < 0)
368 		return NULL;
369 
370 	MailFilter* (*instantiate_mailfilter)(MailProtocol& protocol,
371 		AddonSettings* settings);
372 	if (get_image_symbol(image, "instantiate_mailfilter",
373 		B_SYMBOL_TYPE_TEXT, (void **)&instantiate_mailfilter)
374 			!= B_OK) {
375 		unload_add_on(image);
376 		return NULL;
377 	}
378 
379 	fFilterImages[ref] = image;
380 	return (*instantiate_mailfilter)(*this, filterSettings);
381 }
382 
383 
384 InboundProtocol::InboundProtocol(BMailAccountSettings* settings)
385 	:
386 	MailProtocol(settings)
387 {
388 	LoadFilters(fAccountSettings.InboundSettings());
389 }
390 
391 
392 InboundProtocol::~InboundProtocol()
393 {
394 
395 }
396 
397 
398 status_t
399 InboundProtocol::AppendMessage(const entry_ref& ref)
400 {
401 	return false;
402 }
403 
404 
405 status_t
406 InboundProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag)
407 {
408 	BNode node(&ref);
409 	return write_read_attr(node, flag);
410 }
411 
412 
413 OutboundProtocol::OutboundProtocol(BMailAccountSettings* settings)
414 	:
415 	MailProtocol(settings)
416 {
417 	LoadFilters(fAccountSettings.OutboundSettings());
418 }
419 
420 
421 OutboundProtocol::~OutboundProtocol()
422 {
423 
424 }
425 
426 
427 const uint32 kMsgMoveFile = '&MoF';
428 const uint32 kMsgDeleteFile = '&DeF';
429 const uint32 kMsgFileRenamed = '&FiR';
430 const uint32 kMsgFileDeleted = '&FDe';
431 const uint32 kMsgInit = '&Ini';
432 
433 
434 MailProtocolThread::MailProtocolThread(MailProtocol* protocol)
435 	:
436 	fMailProtocol(protocol)
437 {
438 	PostMessage(kMsgInit);
439 }
440 
441 
442 void
443 MailProtocolThread::SetStopNow()
444 {
445 	fMailProtocol->SetStopNow();
446 }
447 
448 
449 void
450 MailProtocolThread::MessageReceived(BMessage* message)
451 {
452 	switch (message->what) {
453 	case kMsgInit:
454 		fMailProtocol->SetProtocolThread(this);
455 		break;
456 
457 	case kMsgMoveFile:
458 	{
459 		entry_ref file;
460 		message->FindRef("file", &file);
461 		entry_ref dir;
462 		message->FindRef("directory", &dir);
463 		BDirectory directory(&dir);
464 		fMailProtocol->MoveMessage(file, directory);
465 		break;
466 	}
467 
468 	case kMsgDeleteFile:
469 	{
470 		entry_ref file;
471 		message->FindRef("file", &file);
472 		fMailProtocol->DeleteMessage(file);
473 		break;
474 	}
475 
476 	case kMsgFileRenamed:
477 	{
478 		entry_ref from;
479 		message->FindRef("from", &from);
480 		entry_ref to;
481 		message->FindRef("to", &to);
482 		fMailProtocol->FileRenamed(from, to);
483 	}
484 
485 	case kMsgFileDeleted:
486 	{
487 		node_ref node;
488 		message->FindInt32("device",&node.device);
489 		message->FindInt64("node", &node.node);
490 		fMailProtocol->FileDeleted(node);
491 	}
492 
493 	default:
494 		BLooper::MessageReceived(message);
495 	}
496 }
497 
498 
499 void
500 MailProtocolThread::TriggerFileMove(const entry_ref& ref, BDirectory& dir)
501 {
502 	BMessage message(kMsgMoveFile);
503 	message.AddRef("file", &ref);
504 	BEntry entry;
505 	dir.GetEntry(&entry);
506 	entry_ref dirRef;
507 	entry.GetRef(&dirRef);
508 	message.AddRef("directory", &dirRef);
509 	PostMessage(&message);
510 }
511 
512 
513 void
514 MailProtocolThread::TriggerFileDeletion(const entry_ref& ref)
515 {
516 	BMessage message(kMsgDeleteFile);
517 	message.AddRef("file", &ref);
518 	PostMessage(&message);
519 }
520 
521 
522 void
523 MailProtocolThread::TriggerFileRenamed(const entry_ref& from,
524 	const entry_ref& to)
525 {
526 	BMessage message(kMsgFileRenamed);
527 	message.AddRef("from", &from);
528 	message.AddRef("to", &to);
529 	PostMessage(&message);
530 }
531 
532 
533 void
534 MailProtocolThread::TriggerFileDeleted(const node_ref& node)
535 {
536 	BMessage message(kMsgFileDeleted);
537 	message.AddInt32("device", node.device);
538 	message.AddInt64("node", node.node);
539 	PostMessage(&message);
540 }
541 
542 
543 const uint32 kMsgSyncMessages = '&SyM';
544 const uint32 kMsgDeleteMessage = '&DeM';
545 const uint32 kMsgAppendMessage = '&ApM';
546 
547 
548 InboundProtocolThread::InboundProtocolThread(InboundProtocol* protocol)
549 	:
550 	MailProtocolThread(protocol),
551 	fProtocol(protocol)
552 {
553 
554 }
555 
556 
557 InboundProtocolThread::~InboundProtocolThread()
558 {
559 	fProtocol->SetProtocolThread(NULL);
560 }
561 
562 
563 void
564 InboundProtocolThread::MessageReceived(BMessage* message)
565 {
566 	switch (message->what) {
567 	case kMsgSyncMessages:
568 	{
569 		status_t status = fProtocol->SyncMessages();
570 		_NotiyMailboxSynced(status);
571 		break;
572 	}
573 
574 	case kMsgFetchBody:
575 	{
576 		entry_ref ref;
577 		message->FindRef("ref", &ref);
578 		status_t status = fProtocol->FetchBody(ref);
579 
580 		BMessenger target;
581 		if (message->FindMessenger("target", &target) != B_OK)
582 			break;
583 
584 		BMessage message(kMsgBodyFetched);
585 		message.AddInt32("status", status);
586 		message.AddRef("ref", &ref);
587 		target.SendMessage(&message);
588 		break;
589 	}
590 
591 	case kMsgMarkMessageAsRead:
592 	{
593 		entry_ref ref;
594 		message->FindRef("ref", &ref);
595 		read_flags read = (read_flags)message->FindInt32("read");
596 		fProtocol->MarkMessageAsRead(ref, read);
597 		break;
598 	}
599 
600 	case kMsgDeleteMessage:
601 	{
602 		entry_ref ref;
603 		message->FindRef("ref", &ref);
604 		fProtocol->DeleteMessage(ref);
605 		break;
606 	}
607 
608 	case kMsgAppendMessage:
609 	{
610 		entry_ref ref;
611 		message->FindRef("ref", &ref);
612 		fProtocol->AppendMessage(ref);
613 		break;
614 	}
615 
616 	default:
617 		MailProtocolThread::MessageReceived(message);
618 	}
619 }
620 
621 
622 void
623 InboundProtocolThread::SyncMessages()
624 {
625 	PostMessage(kMsgSyncMessages);
626 }
627 
628 
629 void
630 InboundProtocolThread::FetchBody(const entry_ref& ref, BMessenger* listener)
631 {
632 	BMessage message(kMsgFetchBody);
633 	message.AddRef("ref", &ref);
634 	if (listener)
635 		message.AddMessenger("target", *listener);
636 	PostMessage(&message);
637 }
638 
639 
640 void
641 InboundProtocolThread::MarkMessageAsRead(const entry_ref& ref, read_flags flag)
642 {
643 	BMessage message(kMsgMarkMessageAsRead);
644 	message.AddRef("ref", &ref);
645 	message.AddInt32("read", flag);
646 	PostMessage(&message);
647 }
648 
649 
650 void
651 InboundProtocolThread::DeleteMessage(const entry_ref& ref)
652 {
653 	BMessage message(kMsgDeleteMessage);
654 	message.AddRef("ref", &ref);
655 	PostMessage(&message);
656 }
657 
658 
659 void
660 InboundProtocolThread::AppendMessage(const entry_ref& ref)
661 {
662 	BMessage message(kMsgAppendMessage);
663 	message.AddRef("ref", &ref);
664 	PostMessage(&message);
665 }
666 
667 
668 void
669 InboundProtocolThread::_NotiyMailboxSynced(status_t status)
670 {
671 	for (int i = 0; i < fProtocol->CountFilter(); i++)
672 		fProtocol->FilterAt(i)->MailboxSynced(status);
673 }
674 
675 
676 const uint32 kMsgSendMessage = '&SeM';
677 
678 
679 OutboundProtocolThread::OutboundProtocolThread(OutboundProtocol* protocol)
680 	:
681 	MailProtocolThread(protocol),
682 	fProtocol(protocol)
683 {
684 
685 }
686 
687 
688 OutboundProtocolThread::~OutboundProtocolThread()
689 {
690 	fProtocol->SetProtocolThread(NULL);
691 }
692 
693 
694 void
695 OutboundProtocolThread::MessageReceived(BMessage* message)
696 {
697 	switch (message->what) {
698 	case kMsgSendMessage:
699 	{
700 		std::vector<entry_ref> mails;
701 		for (int32 i = 0; ;i++) {
702 			entry_ref ref;
703 			if (message->FindRef("ref", i, &ref) != B_OK)
704 				break;
705 			mails.push_back(ref);
706 		}
707 		size_t size = message->FindInt32("size");
708 		fProtocol->SendMessages(mails, size);
709 		break;
710 	}
711 
712 	default:
713 		MailProtocolThread::MessageReceived(message);
714 	}
715 }
716 
717 
718 void
719 OutboundProtocolThread::SendMessages(const std::vector<entry_ref>& mails,
720 	size_t totalBytes)
721 {
722 	BMessage message(kMsgSendMessage);
723 	for (unsigned int i = 0; i < mails.size(); i++)
724 		message.AddRef("ref", &mails[i]);
725 	message.AddInt32("size", totalBytes);
726 	PostMessage(&message);
727 }
728