109459c8a5
Signed-off-by: Jérôme Duval <jerome.duval@gmail.com>
504 lines
9.9 KiB
C++
504 lines
9.9 KiB
C++
/*
|
|
* Copyright 2011-2016, Haiku, Inc. All rights reserved.
|
|
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <fs_attr.h>
|
|
|
|
#include <Alert.h>
|
|
#include <Autolock.h>
|
|
#include <Directory.h>
|
|
#include <E-mail.h>
|
|
#include <FindDirectory.h>
|
|
#include <Node.h>
|
|
#include <NodeInfo.h>
|
|
#include <NodeMonitor.h>
|
|
#include <Path.h>
|
|
#include <Query.h>
|
|
#include <Roster.h>
|
|
#include <String.h>
|
|
#include <StringList.h>
|
|
#include <VolumeRoster.h>
|
|
|
|
#include <MailFilter.h>
|
|
#include <MailDaemon.h>
|
|
#include <MailProtocol.h>
|
|
#include <MailSettings.h>
|
|
|
|
#include <mail_util.h>
|
|
#include <MailPrivate.h>
|
|
#include <NodeMessage.h>
|
|
|
|
#include "HaikuMailFormatFilter.h"
|
|
|
|
|
|
using namespace BPrivate;
|
|
|
|
|
|
BMailProtocol::BMailProtocol(const char* name,
|
|
const BMailAccountSettings& settings)
|
|
:
|
|
BLooper(_LooperName(name, settings)),
|
|
fAccountSettings(settings),
|
|
fMailNotifier(NULL)
|
|
{
|
|
AddFilter(new HaikuMailFormatFilter(*this, settings));
|
|
}
|
|
|
|
|
|
BMailProtocol::~BMailProtocol()
|
|
{
|
|
delete fMailNotifier;
|
|
|
|
for (int i = 0; i < fFilterList.CountItems(); i++)
|
|
delete fFilterList.ItemAt(i);
|
|
|
|
std::map<entry_ref, image_id>::iterator it = fFilterImages.begin();
|
|
for (; it != fFilterImages.end(); it++)
|
|
unload_add_on(it->second);
|
|
}
|
|
|
|
|
|
const BMailAccountSettings&
|
|
BMailProtocol::AccountSettings() const
|
|
{
|
|
return fAccountSettings;
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::SetMailNotifier(BMailNotifier* mailNotifier)
|
|
{
|
|
delete fMailNotifier;
|
|
fMailNotifier = mailNotifier;
|
|
}
|
|
|
|
|
|
BMailNotifier*
|
|
BMailProtocol::MailNotifier() const
|
|
{
|
|
return fMailNotifier;
|
|
}
|
|
|
|
|
|
bool
|
|
BMailProtocol::AddFilter(BMailFilter* filter)
|
|
{
|
|
BAutolock locker(const_cast< BMailProtocol * >(this));
|
|
return fFilterList.AddItem(filter);
|
|
}
|
|
|
|
|
|
int32
|
|
BMailProtocol::CountFilter() const
|
|
{
|
|
BAutolock locker(const_cast< BMailProtocol * >(this));
|
|
return fFilterList.CountItems();
|
|
}
|
|
|
|
|
|
BMailFilter*
|
|
BMailProtocol::FilterAt(int32 index) const
|
|
{
|
|
BAutolock locker(const_cast< BMailProtocol * >(this));
|
|
return fFilterList.ItemAt(index);
|
|
}
|
|
|
|
|
|
BMailFilter*
|
|
BMailProtocol::RemoveFilter(int32 index)
|
|
{
|
|
BAutolock locker(const_cast< BMailProtocol * >(this));
|
|
return fFilterList.RemoveItemAt(index);
|
|
}
|
|
|
|
|
|
bool
|
|
BMailProtocol::RemoveFilter(BMailFilter* filter)
|
|
{
|
|
BAutolock locker(const_cast< BMailProtocol * >(this));
|
|
return fFilterList.RemoveItem(filter);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::MessageReceived(BMessage* message)
|
|
{
|
|
BLooper::MessageReceived(message);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::ShowError(const char* error)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->ShowError(error);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::ShowMessage(const char* message)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->ShowMessage(message);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::SetTotalItems(uint32 items)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->SetTotalItems(items);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::SetTotalItemsSize(uint64 size)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->SetTotalItemsSize(size);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::ReportProgress(uint32 messages, uint64 bytes,
|
|
const char* message)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->ReportProgress(messages, bytes, message);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::ResetProgress(const char* message)
|
|
{
|
|
if (MailNotifier() != NULL)
|
|
MailNotifier()->ResetProgress(message);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::NotifyNewMessagesToFetch(int32 count)
|
|
{
|
|
ResetProgress();
|
|
SetTotalItems(count);
|
|
}
|
|
|
|
|
|
BMailFilterAction
|
|
BMailProtocol::ProcessHeaderFetched(entry_ref& ref, BFile& file,
|
|
BMessage& attributes)
|
|
{
|
|
BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes);
|
|
if (action >= B_OK && action != B_DELETE_MAIL_ACTION)
|
|
file << attributes;
|
|
|
|
return action;
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile& file,
|
|
BMessage& attributes)
|
|
{
|
|
_NotifyBodyFetched(ref, file, attributes);
|
|
file << attributes;
|
|
}
|
|
|
|
|
|
BMailFilterAction
|
|
BMailProtocol::ProcessMessageFetched(entry_ref& ref, BFile& file,
|
|
BMessage& attributes)
|
|
{
|
|
BMailFilterAction action = _ProcessHeaderFetched(ref, file, attributes);
|
|
if (action >= B_OK && action != B_DELETE_MAIL_ACTION) {
|
|
_NotifyBodyFetched(ref, file, attributes);
|
|
file << attributes;
|
|
}
|
|
|
|
return action;
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile& file)
|
|
{
|
|
for (int i = 0; i < fFilterList.CountItems(); i++)
|
|
fFilterList.ItemAt(i)->MessageReadyToSend(ref, file);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile& file)
|
|
{
|
|
for (int i = 0; i < fFilterList.CountItems(); i++)
|
|
fFilterList.ItemAt(i)->MessageSent(ref, file);
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::LoadFilters(const BMailProtocolSettings& settings)
|
|
{
|
|
for (int i = 0; i < settings.CountFilterSettings(); i++) {
|
|
BMailAddOnSettings* filterSettings = settings.FilterSettingsAt(i);
|
|
BMailFilter* filter = _LoadFilter(*filterSettings);
|
|
if (filter != NULL)
|
|
AddFilter(filter);
|
|
}
|
|
}
|
|
|
|
|
|
/*static*/ BString
|
|
BMailProtocol::_LooperName(const char* addOnName,
|
|
const BMailAccountSettings& settings)
|
|
{
|
|
BString name = addOnName;
|
|
|
|
const char* accountName = settings.Name();
|
|
if (accountName != NULL && accountName[0] != '\0')
|
|
name << " " << accountName;
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
BMailFilter*
|
|
BMailProtocol::_LoadFilter(const BMailAddOnSettings& settings)
|
|
{
|
|
const entry_ref& ref = settings.AddOnRef();
|
|
std::map<entry_ref, image_id>::iterator it = fFilterImages.find(ref);
|
|
image_id image;
|
|
if (it != fFilterImages.end())
|
|
image = it->second;
|
|
else {
|
|
BEntry entry(&ref);
|
|
BPath path(&entry);
|
|
image = load_add_on(path.Path());
|
|
}
|
|
if (image < 0)
|
|
return NULL;
|
|
|
|
BMailFilter* (*instantiateFilter)(BMailProtocol& protocol,
|
|
const BMailAddOnSettings& settings);
|
|
if (get_image_symbol(image, "instantiate_filter", B_SYMBOL_TYPE_TEXT,
|
|
(void**)&instantiateFilter) != B_OK) {
|
|
unload_add_on(image);
|
|
return NULL;
|
|
}
|
|
|
|
fFilterImages[ref] = image;
|
|
return instantiateFilter(*this, settings);
|
|
}
|
|
|
|
|
|
BMailFilterAction
|
|
BMailProtocol::_ProcessHeaderFetched(entry_ref& ref, BFile& file,
|
|
BMessage& attributes)
|
|
{
|
|
entry_ref outRef = ref;
|
|
|
|
for (int i = 0; i < fFilterList.CountItems(); i++) {
|
|
BMailFilterAction action = fFilterList.ItemAt(i)->HeaderFetched(outRef,
|
|
file, attributes);
|
|
if (action == B_DELETE_MAIL_ACTION) {
|
|
// We have to delete the message
|
|
BEntry entry(&ref);
|
|
status_t status = entry.Remove();
|
|
if (status != B_OK) {
|
|
fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could "
|
|
"not delete mail: %s\n", strerror(status));
|
|
}
|
|
return B_DELETE_MAIL_ACTION;
|
|
}
|
|
}
|
|
|
|
if (ref == outRef)
|
|
return B_NO_MAIL_ACTION;
|
|
|
|
// We have to rename the file
|
|
node_ref newParentRef;
|
|
newParentRef.device = outRef.device;
|
|
newParentRef.node = outRef.directory;
|
|
|
|
BDirectory newParent(&newParentRef);
|
|
status_t status = newParent.InitCheck();
|
|
BString workerName;
|
|
if (status == B_OK) {
|
|
int32 uniqueNumber = 1;
|
|
do {
|
|
workerName = outRef.name;
|
|
if (uniqueNumber > 1)
|
|
workerName << "_" << uniqueNumber;
|
|
|
|
// TODO: support copying to another device!
|
|
BEntry entry(&ref);
|
|
status = entry.Rename(workerName);
|
|
|
|
uniqueNumber++;
|
|
} while (status == B_FILE_EXISTS);
|
|
}
|
|
|
|
if (status != B_OK) {
|
|
fprintf(stderr, "BMailProtocol::NotifyHeaderFetched(): could not "
|
|
"rename mail (%s)! (should be: %s)\n", strerror(status),
|
|
workerName.String());
|
|
}
|
|
|
|
ref = outRef;
|
|
ref.set_name(workerName.String());
|
|
|
|
return B_MOVE_MAIL_ACTION;
|
|
}
|
|
|
|
|
|
void
|
|
BMailProtocol::_NotifyBodyFetched(const entry_ref& ref, BFile& file,
|
|
BMessage& attributes)
|
|
{
|
|
for (int i = 0; i < fFilterList.CountItems(); i++)
|
|
fFilterList.ItemAt(i)->BodyFetched(ref, file, attributes);
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
BInboundMailProtocol::BInboundMailProtocol(const char* name,
|
|
const BMailAccountSettings& settings)
|
|
:
|
|
BMailProtocol(name, settings)
|
|
{
|
|
LoadFilters(fAccountSettings.InboundSettings());
|
|
}
|
|
|
|
|
|
BInboundMailProtocol::~BInboundMailProtocol()
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
BInboundMailProtocol::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
case kMsgSyncMessages:
|
|
{
|
|
NotiyMailboxSynchronized(SyncMessages());
|
|
break;
|
|
}
|
|
|
|
case kMsgFetchBody:
|
|
{
|
|
entry_ref ref;
|
|
if (message->FindRef("ref", &ref) != B_OK)
|
|
break;
|
|
|
|
BMessenger target;
|
|
message->FindMessenger("target", &target);
|
|
|
|
status_t status = HandleFetchBody(ref, target);
|
|
if (status != B_OK)
|
|
ReplyBodyFetched(target, ref, status);
|
|
break;
|
|
}
|
|
|
|
case kMsgMarkMessageAsRead:
|
|
{
|
|
entry_ref ref;
|
|
message->FindRef("ref", &ref);
|
|
read_flags read = (read_flags)message->FindInt32("read");
|
|
MarkMessageAsRead(ref, read);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
BMailProtocol::MessageReceived(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
BInboundMailProtocol::FetchBody(const entry_ref& ref, BMessenger* replyTo)
|
|
{
|
|
BMessage message(kMsgFetchBody);
|
|
message.AddRef("ref", &ref);
|
|
if (replyTo != NULL)
|
|
message.AddMessenger("target", *replyTo);
|
|
|
|
return BMessenger(this).SendMessage(&message);
|
|
}
|
|
|
|
|
|
status_t
|
|
BInboundMailProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag)
|
|
{
|
|
BNode node(&ref);
|
|
return write_read_attr(node, flag);
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
BInboundMailProtocol::ReplyBodyFetched(const BMessenger& replyTo,
|
|
const entry_ref& ref, status_t status)
|
|
{
|
|
BMessage message(B_MAIL_BODY_FETCHED);
|
|
message.AddInt32("status", status);
|
|
message.AddRef("ref", &ref);
|
|
replyTo.SendMessage(&message);
|
|
}
|
|
|
|
|
|
void
|
|
BInboundMailProtocol::NotiyMailboxSynchronized(status_t status)
|
|
{
|
|
for (int32 i = 0; i < CountFilter(); i++)
|
|
FilterAt(i)->MailboxSynchronized(status);
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
BOutboundMailProtocol::BOutboundMailProtocol(const char* name,
|
|
const BMailAccountSettings& settings)
|
|
:
|
|
BMailProtocol(name, settings)
|
|
{
|
|
LoadFilters(fAccountSettings.OutboundSettings());
|
|
}
|
|
|
|
|
|
BOutboundMailProtocol::~BOutboundMailProtocol()
|
|
{
|
|
}
|
|
|
|
|
|
status_t
|
|
BOutboundMailProtocol::SendMessages(const BMessage& files, off_t totalBytes)
|
|
{
|
|
BMessage message(kMsgSendMessages);
|
|
message.Append(files);
|
|
message.AddInt64("bytes", totalBytes);
|
|
|
|
return BMessenger(this).SendMessage(&message);
|
|
}
|
|
|
|
|
|
void
|
|
BOutboundMailProtocol::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
case kMsgSendMessages:
|
|
HandleSendMessages(*message, message->FindInt64("bytes"));
|
|
break;
|
|
|
|
default:
|
|
BMailProtocol::MessageReceived(message);
|
|
}
|
|
}
|