10c7f804cSAxel Dörfler/*
281805393SAxel Dörfler * Copyright 2011-2016, Haiku, Inc. All rights reserved.
30c7f804cSAxel Dörfler * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
40c7f804cSAxel Dörfler */
5f7215ac8SNathan Whitehorn
6f7215ac8SNathan Whitehorn
7dfc6cf01SPhilippe Houdoin#include <stdio.h>
8dfc6cf01SPhilippe Houdoin#include <stdlib.h>
9715bf3d1SAxel Dörfler
10715bf3d1SAxel Dörfler#include <fs_attr.h>
11dfc6cf01SPhilippe Houdoin
12f7215ac8SNathan Whitehorn#include <Alert.h>
13109459c8SMurai Takashi#include <Autolock.h>
14dfc6cf01SPhilippe Houdoin#include <Directory.h>
15f7215ac8SNathan Whitehorn#include <E-mail.h>
16109459c8SMurai Takashi#include <FindDirectory.h>
17dfc6cf01SPhilippe Houdoin#include <Node.h>
18f7215ac8SNathan Whitehorn#include <NodeInfo.h>
19f7215ac8SNathan Whitehorn#include <NodeMonitor.h>
20dfc6cf01SPhilippe Houdoin#include <Path.h>
21715bf3d1SAxel Dörfler#include <Query.h>
221af4fa4bSClemens Zeidler#include <Roster.h>
23dfc6cf01SPhilippe Houdoin#include <String.h>
24dfc6cf01SPhilippe Houdoin#include <StringList.h>
25dfc6cf01SPhilippe Houdoin#include <VolumeRoster.h>
26f7215ac8SNathan Whitehorn
27715bf3d1SAxel Dörfler#include <MailFilter.h>
28b8d2bbd6SClemens Zeidler#include <MailDaemon.h>
29f7215ac8SNathan Whitehorn#include <MailProtocol.h>
301af4fa4bSClemens Zeidler#include <MailSettings.h>
31dfc6cf01SPhilippe Houdoin
32715bf3d1SAxel Dörfler#include <mail_util.h>
33146357b5SAxel Dörfler#include <MailPrivate.h>
34d33e4744SAxel Dörfler#include <NodeMessage.h>
35715bf3d1SAxel Dörfler
361af4fa4bSClemens Zeidler#include "HaikuMailFormatFilter.h"
37f7215ac8SNathan Whitehorn
38dfc6cf01SPhilippe Houdoin
39146357b5SAxel Dörflerusing namespace BPrivate;
40f7215ac8SNathan Whitehorn
41f7215ac8SNathan Whitehorn
4262eec600SAxel DörflerBMailProtocol::BMailProtocol(const char* name,
4362eec600SAxel Dörfler	const BMailAccountSettings& settings)
441af4fa4bSClemens Zeidler	:
4562eec600SAxel Dörfler	BLooper(_LooperName(name, settings)),
46715bf3d1SAxel Dörfler	fAccountSettings(settings),
47715bf3d1SAxel Dörfler	fMailNotifier(NULL)
48f7215ac8SNathan Whitehorn{
49715bf3d1SAxel Dörfler	AddFilter(new HaikuMailFormatFilter(*this, settings));
50f7215ac8SNathan Whitehorn}
51f7215ac8SNathan Whitehorn
52f7215ac8SNathan Whitehorn
53715bf3d1SAxel DörflerBMailProtocol::~BMailProtocol()
541af4fa4bSClemens Zeidler{
55715bf3d1SAxel Dörfler	delete fMailNotifier;
56eb9b1980SIngo Weinhold
57715bf3d1SAxel Dörfler	for (int i = 0; i < fFilterList.CountItems(); i++)
58715bf3d1SAxel Dörfler		delete fFilterList.ItemAt(i);
59dfc6cf01SPhilippe Houdoin
60146357b5SAxel Dörfler	std::map<entry_ref, image_id>::iterator it = fFilterImages.begin();
61715bf3d1SAxel Dörfler	for (; it != fFilterImages.end(); it++)
62715bf3d1SAxel Dörfler		unload_add_on(it->second);
631af4fa4bSClemens Zeidler}
64f7215ac8SNathan Whitehorn
65f7215ac8SNathan Whitehorn
66715bf3d1SAxel Dörflerconst BMailAccountSettings&
67715bf3d1SAxel DörflerBMailProtocol::AccountSettings() const
681af4fa4bSClemens Zeidler{
69715bf3d1SAxel Dörfler	return fAccountSettings;
701af4fa4bSClemens Zeidler}
71dfc6cf01SPhilippe Houdoin
72f7215ac8SNathan Whitehorn
731af4fa4bSClemens Zeidlervoid
74715bf3d1SAxel DörflerBMailProtocol::SetMailNotifier(BMailNotifier* mailNotifier)
751af4fa4bSClemens Zeidler{
76715bf3d1SAxel Dörfler	delete fMailNotifier;
77715bf3d1SAxel Dörfler	fMailNotifier = mailNotifier;
781af4fa4bSClemens Zeidler}
79f7215ac8SNathan Whitehorn
80dfc6cf01SPhilippe Houdoin
81715bf3d1SAxel DörflerBMailNotifier*
82715bf3d1SAxel DörflerBMailProtocol::MailNotifier() const
831af4fa4bSClemens Zeidler{
84715bf3d1SAxel Dörfler	return fMailNotifier;
851af4fa4bSClemens Zeidler}
86dfc6cf01SPhilippe Houdoin
87eb9b1980SIngo Weinhold
88715bf3d1SAxel Dörflerbool
89715bf3d1SAxel DörflerBMailProtocol::AddFilter(BMailFilter* filter)
90f7215ac8SNathan Whitehorn{
91109459c8SMurai Takashi	BAutolock locker(const_cast< BMailProtocol * >(this));
92715bf3d1SAxel Dörfler	return fFilterList.AddItem(filter);
931af4fa4bSClemens Zeidler}
941af4fa4bSClemens Zeidler
95dfc6cf01SPhilippe Houdoin
96715bf3d1SAxel Dörflerint32
97715bf3d1SAxel DörflerBMailProtocol::CountFilter() const
981af4fa4bSClemens Zeidler{
99109459c8SMurai Takashi	BAutolock locker(const_cast< BMailProtocol * >(this));
100715bf3d1SAxel Dörfler	return fFilterList.CountItems();
1011af4fa4bSClemens Zeidler}
1021af4fa4bSClemens Zeidler
1031af4fa4bSClemens Zeidler
104715bf3d1SAxel DörflerBMailFilter*
105715bf3d1SAxel DörflerBMailProtocol::FilterAt(int32 index) const
1061af4fa4bSClemens Zeidler{
107109459c8SMurai Takashi	BAutolock locker(const_cast< BMailProtocol * >(this));
108715bf3d1SAxel Dörfler	return fFilterList.ItemAt(index);
1091af4fa4bSClemens Zeidler}
1101af4fa4bSClemens Zeidler
1111af4fa4bSClemens Zeidler
112715bf3d1SAxel DörflerBMailFilter*
113715bf3d1SAxel DörflerBMailProtocol::RemoveFilter(int32 index)
1141af4fa4bSClemens Zeidler{
115109459c8SMurai Takashi	BAutolock locker(const_cast< BMailProtocol * >(this));
116715bf3d1SAxel Dörfler	return fFilterList.RemoveItemAt(index);
1171af4fa4bSClemens Zeidler}
1181af4fa4bSClemens Zeidler
1191af4fa4bSClemens Zeidler
120715bf3d1SAxel Dörflerbool
121715bf3d1SAxel DörflerBMailProtocol::RemoveFilter(BMailFilter* filter)
1221af4fa4bSClemens Zeidler{
123109459c8SMurai Takashi	BAutolock locker(const_cast< BMailProtocol * >(this));
124715bf3d1SAxel Dörfler	return fFilterList.RemoveItem(filter);
1251af4fa4bSClemens Zeidler}
1261af4fa4bSClemens Zeidler
1271af4fa4bSClemens Zeidler
128715bf3d1SAxel Dörflervoid
129715bf3d1SAxel DörflerBMailProtocol::MessageReceived(BMessage* message)
1301af4fa4bSClemens Zeidler{
131549949b2SAxel Dörfler	BLooper::MessageReceived(message);
1321af4fa4bSClemens Zeidler}
1331af4fa4bSClemens Zeidler
1341af4fa4bSClemens Zeidler
1351af4fa4bSClemens Zeidlervoid
136715bf3d1SAxel DörflerBMailProtocol::ShowError(const char* error)
1371af4fa4bSClemens Zeidler{
138715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
139715bf3d1SAxel Dörfler		MailNotifier()->ShowError(error);
1401af4fa4bSClemens Zeidler}
1411af4fa4bSClemens Zeidler
1421af4fa4bSClemens Zeidler
1431af4fa4bSClemens Zeidlervoid
144715bf3d1SAxel DörflerBMailProtocol::ShowMessage(const char* message)
1451af4fa4bSClemens Zeidler{
146715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
147715bf3d1SAxel Dörfler		MailNotifier()->ShowMessage(message);
1481af4fa4bSClemens Zeidler}
1491af4fa4bSClemens Zeidler
1501af4fa4bSClemens Zeidler
1511af4fa4bSClemens Zeidlervoid
152715bf3d1SAxel DörflerBMailProtocol::SetTotalItems(uint32 items)
1531af4fa4bSClemens Zeidler{
154715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
155715bf3d1SAxel Dörfler		MailNotifier()->SetTotalItems(items);
1561af4fa4bSClemens Zeidler}
1571af4fa4bSClemens Zeidler
1581af4fa4bSClemens Zeidler
159715bf3d1SAxel Dörflervoid
160715bf3d1SAxel DörflerBMailProtocol::SetTotalItemsSize(uint64 size)
1611af4fa4bSClemens Zeidler{
162715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
163715bf3d1SAxel Dörfler		MailNotifier()->SetTotalItemsSize(size);
1641af4fa4bSClemens Zeidler}
1651af4fa4bSClemens Zeidler
1661af4fa4bSClemens Zeidler
167715bf3d1SAxel Dörflervoid
168715bf3d1SAxel DörflerBMailProtocol::ReportProgress(uint32 messages, uint64 bytes,
169715bf3d1SAxel Dörfler	const char* message)
1701af4fa4bSClemens Zeidler{
171715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
172715bf3d1SAxel Dörfler		MailNotifier()->ReportProgress(messages, bytes, message);
1731af4fa4bSClemens Zeidler}
1741af4fa4bSClemens Zeidler
1751af4fa4bSClemens Zeidler
176715bf3d1SAxel Dörflervoid
177715bf3d1SAxel DörflerBMailProtocol::ResetProgress(const char* message)
1781af4fa4bSClemens Zeidler{
179715bf3d1SAxel Dörfler	if (MailNotifier() != NULL)
180715bf3d1SAxel Dörfler		MailNotifier()->ResetProgress(message);
1811af4fa4bSClemens Zeidler}
1821af4fa4bSClemens Zeidler
1831af4fa4bSClemens Zeidler
1841af4fa4bSClemens Zeidlervoid
185715bf3d1SAxel DörflerBMailProtocol::NotifyNewMessagesToFetch(int32 count)
1861af4fa4bSClemens Zeidler{
1871af4fa4bSClemens Zeidler	ResetProgress();
188715bf3d1SAxel Dörfler	SetTotalItems(count);
1891af4fa4bSClemens Zeidler}
1901af4fa4bSClemens Zeidler
1911af4fa4bSClemens Zeidler
192549949b2SAxel DörflerBMailFilterAction
193d33e4744SAxel DörflerBMailProtocol::ProcessHeaderFetched(entry_ref& ref, BFile& file,
194d33e4744SAxel Dörfler	BMessage& attributes)
1951af4fa4bSClemens Zeidler{
196d33e4744SAxel Dörfler	BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes);
197d33e4744SAxel Dörfler	if (action >= B_OK && action != B_DELETE_MAIL_ACTION)
198d33e4744SAxel Dörfler		file << attributes;
199549949b2SAxel Dörfler
200d33e4744SAxel Dörfler	return action;
201d33e4744SAxel Dörfler}
202549949b2SAxel Dörfler
203549949b2SAxel Dörfler
204d33e4744SAxel Dörflervoid
205d33e4744SAxel DörflerBMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile& file,
206d33e4744SAxel Dörfler	BMessage& attributes)
207d33e4744SAxel Dörfler{
208d33e4744SAxel Dörfler	_NotifyBodyFetched(ref, file, attributes);
209d33e4744SAxel Dörfler	file << attributes;
2101af4fa4bSClemens Zeidler}
2111af4fa4bSClemens Zeidler
2121af4fa4bSClemens Zeidler
213d33e4744SAxel DörflerBMailFilterAction
214d33e4744SAxel DörflerBMailProtocol::ProcessMessageFetched(entry_ref& ref, BFile& file,
215d33e4744SAxel Dörfler	BMessage& attributes)
2161af4fa4bSClemens Zeidler{
217d33e4744SAxel Dörfler	BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes);
218d33e4744SAxel Dörfler	if (action >= B_OK && action != B_DELETE_MAIL_ACTION) {
219d33e4744SAxel Dörfler		_NotifyBodyFetched(ref, file, attributes);
220d33e4744SAxel Dörfler		file << attributes;
221d33e4744SAxel Dörfler	}
222d33e4744SAxel Dörfler
223d33e4744SAxel Dörfler	return action;
2241af4fa4bSClemens Zeidler}
2251af4fa4bSClemens Zeidler
2261af4fa4bSClemens Zeidler
2271af4fa4bSClemens Zeidlervoid
228d33e4744SAxel DörflerBMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile& file)
2291af4fa4bSClemens Zeidler{
2301af4fa4bSClemens Zeidler	for (int i = 0; i < fFilterList.CountItems(); i++)
231d33e4744SAxel Dörfler		fFilterList.ItemAt(i)->MessageReadyToSend(ref, file);
2321af4fa4bSClemens Zeidler}
2331af4fa4bSClemens Zeidler
2341af4fa4bSClemens Zeidler
2351af4fa4bSClemens Zeidlervoid
236d33e4744SAxel DörflerBMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile& file)
2371af4fa4bSClemens Zeidler{
2381af4fa4bSClemens Zeidler	for (int i = 0; i < fFilterList.CountItems(); i++)
239d33e4744SAxel Dörfler		fFilterList.ItemAt(i)->MessageSent(ref, file);
2401af4fa4bSClemens Zeidler}
2411af4fa4bSClemens Zeidler
2421af4fa4bSClemens Zeidler
2431af4fa4bSClemens Zeidlervoid
244715bf3d1SAxel DörflerBMailProtocol::LoadFilters(const BMailProtocolSettings& settings)
2451af4fa4bSClemens Zeidler{
2461af4fa4bSClemens Zeidler	for (int i = 0; i < settings.CountFilterSettings(); i++) {
247715bf3d1SAxel Dörfler		BMailAddOnSettings* filterSettings = settings.FilterSettingsAt(i);
248ca3341c7SAxel Dörfler		BMailFilter* filter = _LoadFilter(*filterSettings);
249715bf3d1SAxel Dörfler		if (filter != NULL)
250715bf3d1SAxel Dörfler			AddFilter(filter);
251f7215ac8SNathan Whitehorn	}
252f7215ac8SNathan Whitehorn}
253f7215ac8SNathan Whitehorn
254f7215ac8SNathan Whitehorn
25562eec600SAxel Dörfler/*static*/ BString
25662eec600SAxel DörflerBMailProtocol::_LooperName(const char* addOnName,
25762eec600SAxel Dörfler	const BMailAccountSettings& settings)
25862eec600SAxel Dörfler{
25962eec600SAxel Dörfler	BString name = addOnName;
26062eec600SAxel Dörfler
26162eec600SAxel Dörfler	const char* accountName = settings.Name();
26262eec600SAxel Dörfler	if (accountName != NULL && accountName[0] != '\0')
26362eec600SAxel Dörfler		name << " " << accountName;
26462eec600SAxel Dörfler
26562eec600SAxel Dörfler	return name;
26662eec600SAxel Dörfler}
26762eec600SAxel Dörfler
26862eec600SAxel Dörfler
269715bf3d1SAxel DörflerBMailFilter*
270ca3341c7SAxel DörflerBMailProtocol::_LoadFilter(const BMailAddOnSettings& settings)
2711af4fa4bSClemens Zeidler{
272ca3341c7SAxel Dörfler	const entry_ref& ref = settings.AddOnRef();
273146357b5SAxel Dörfler	std::map<entry_ref, image_id>::iterator it = fFilterImages.find(ref);
2741af4fa4bSClemens Zeidler	image_id image;
2751af4fa4bSClemens Zeidler	if (it != fFilterImages.end())
2761af4fa4bSClemens Zeidler		image = it->second;
2771af4fa4bSClemens Zeidler	else {
2781af4fa4bSClemens Zeidler		BEntry entry(&ref);
2791af4fa4bSClemens Zeidler		BPath path(&entry);
2801af4fa4bSClemens Zeidler		image = load_add_on(path.Path());
2811af4fa4bSClemens Zeidler	}
2821af4fa4bSClemens Zeidler	if (image < 0)
2831af4fa4bSClemens Zeidler		return NULL;
2841af4fa4bSClemens Zeidler
285ca3341c7SAxel Dörfler	BMailFilter* (*instantiateFilter)(BMailProtocol& protocol,
286ca3341c7SAxel Dörfler		const BMailAddOnSettings& settings);
287715bf3d1SAxel Dörfler	if (get_image_symbol(image, "instantiate_filter", B_SYMBOL_TYPE_TEXT,
288ca3341c7SAxel Dörfler			(void**)&instantiateFilter) != B_OK) {
2891af4fa4bSClemens Zeidler		unload_add_on(image);
2901af4fa4bSClemens Zeidler		return NULL;
291f7215ac8SNathan Whitehorn	}
2921af4fa4bSClemens Zeidler
2931af4fa4bSClemens Zeidler	fFilterImages[ref] = image;
294ca3341c7SAxel Dörfler	return instantiateFilter(*this, settings);
295f7215ac8SNathan Whitehorn}
296f7215ac8SNathan Whitehorn
297f7215ac8SNathan Whitehorn
298d33e4744SAxel DörflerBMailFilterAction
299d33e4744SAxel DörflerBMailProtocol::_ProcessHeaderFetched(entry_ref& ref, BFile& file,
300d33e4744SAxel Dörfler	BMessage& attributes)
301d33e4744SAxel Dörfler{
302d33e4744SAxel Dörfler	entry_ref outRef = ref;
303d33e4744SAxel Dörfler
304d33e4744SAxel Dörfler	for (int i = 0; i < fFilterList.CountItems(); i++) {
305d33e4744SAxel Dörfler		BMailFilterAction action = fFilterList.ItemAt(i)->HeaderFetched(outRef,
306d33e4744SAxel Dörfler			file, attributes);
307d33e4744SAxel Dörfler		if (action == B_DELETE_MAIL_ACTION) {
308d33e4744SAxel Dörfler			// We have to delete the message
309d33e4744SAxel Dörfler			BEntry entry(&ref);
310d33e4744SAxel Dörfler			status_t status = entry.Remove();
311d33e4744SAxel Dörfler			if (status != B_OK) {
312d33e4744SAxel Dörfler				fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could "
313d33e4744SAxel Dörfler					"not delete mail: %s\n", strerror(status));
314d33e4744SAxel Dörfler			}
315d33e4744SAxel Dörfler			return B_DELETE_MAIL_ACTION;
316d33e4744SAxel Dörfler		}
317d33e4744SAxel Dörfler	}
318d33e4744SAxel Dörfler
319d33e4744SAxel Dörfler	if (ref == outRef)
320d33e4744SAxel Dörfler		return B_NO_MAIL_ACTION;
321d33e4744SAxel Dörfler
322d33e4744SAxel Dörfler	// We have to rename the file
323d33e4744SAxel Dörfler	node_ref newParentRef;
324d33e4744SAxel Dörfler	newParentRef.device = outRef.device;
325d33e4744SAxel Dörfler	newParentRef.node = outRef.directory;
326d33e4744SAxel Dörfler
327d33e4744SAxel Dörfler	BDirectory newParent(&newParentRef);
328d33e4744SAxel Dörfler	status_t status = newParent.InitCheck();
329d33e4744SAxel Dörfler	BString workerName;
330d33e4744SAxel Dörfler	if (status == B_OK) {
331d33e4744SAxel Dörfler		int32 uniqueNumber = 1;
332d33e4744SAxel Dörfler		do {
333d33e4744SAxel Dörfler			workerName = outRef.name;
334d33e4744SAxel Dörfler			if (uniqueNumber > 1)
335d33e4744SAxel Dörfler				workerName << "_" << uniqueNumber;
336d33e4744SAxel Dörfler
337d33e4744SAxel Dörfler			// TODO: support copying to another device!
338d33e4744SAxel Dörfler			BEntry entry(&ref);
339d33e4744SAxel Dörfler			status = entry.Rename(workerName);
340d33e4744SAxel Dörfler
341d33e4744SAxel Dörfler			uniqueNumber++;
342d33e4744SAxel Dörfler		} while (status == B_FILE_EXISTS);
343d33e4744SAxel Dörfler	}
344d33e4744SAxel Dörfler
345d33e4744SAxel Dörfler	if (status != B_OK) {
346d33e4744SAxel Dörfler		fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could not "
347d33e4744SAxel Dörfler			"rename mail (%s)! (should be: %s)\n", strerror(status),
348d33e4744SAxel Dörfler			workerName.String());
349d33e4744SAxel Dörfler	}
350d33e4744SAxel Dörfler
351d33e4744SAxel Dörfler	ref = outRef;
352d33e4744SAxel Dörfler	ref.set_name(workerName.String());
353d33e4744SAxel Dörfler
354d33e4744SAxel Dörfler	return B_MOVE_MAIL_ACTION;
355d33e4744SAxel Dörfler}
356d33e4744SAxel Dörfler
357d33e4744SAxel Dörfler
358d33e4744SAxel Dörflervoid
359d33e4744SAxel DörflerBMailProtocol::_NotifyBodyFetched(const entry_ref& ref, BFile& file,
360d33e4744SAxel Dörfler	BMessage& attributes)
361d33e4744SAxel Dörfler{
362d33e4744SAxel Dörfler	for (int i = 0; i < fFilterList.CountItems(); i++)
363d33e4744SAxel Dörfler		fFilterList.ItemAt(i)->BodyFetched(ref, file, attributes);
364d33e4744SAxel Dörfler}
365d33e4744SAxel Dörfler
366d33e4744SAxel Dörfler
3670c7f804cSAxel Dörfler// #pragma mark -
3680c7f804cSAxel Dörfler
3690c7f804cSAxel Dörfler
37062eec600SAxel DörflerBInboundMailProtocol::BInboundMailProtocol(const char* name,
37162eec600SAxel Dörfler	const BMailAccountSettings& settings)
3721af4fa4bSClemens Zeidler	:
37362eec600SAxel Dörfler	BMailProtocol(name, settings)
3741af4fa4bSClemens Zeidler{
3751af4fa4bSClemens Zeidler	LoadFilters(fAccountSettings.InboundSettings());
3761af4fa4bSClemens Zeidler}
3771af4fa4bSClemens Zeidler
378