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