Mail Kit: Changed how filter changes work.

* BMailFilter::HeaderFetched() now only alters the entry_ref, and returns
  B_MOVE_MAIL_ACTION to move a mail.
* Instead of potentially moving the file around several times, the
  BMailProtocol now takes care of carrying out the filter action just once,
  including trying to make the file name unique.
* This also allows the IMAP add-on to know the final location of the mail,
  and thus downloading a message actually works.
* However, with my test inbox, it currently hangs, and a current Debugger does
  not work on my older system -- I guess I need to update.
* Replaced the duplicated space mechanism within the "HaikuMailFormatFilter"
  that is substantially faster, and handles all whitespace, not just spaces.
  It will also replace tabs with spaces.
This commit is contained in:
Axel Dörfler
2015-01-06 15:26:37 +01:00
parent c1f779e350
commit 549949b26f
14 changed files with 215 additions and 198 deletions
+5 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012, Haiku, Inc. All Rights Reserved.
* Copyright 2011-2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MAIL_FILTER_H
@@ -21,16 +21,14 @@ public:
virtual ~BMailFilter();
// Message hooks if filter is installed to an inbound protocol
virtual void HeaderFetched(const entry_ref& ref,
BFile* file);
virtual void BodyFetched(const entry_ref& ref, BFile* file);
virtual BMailFilterAction HeaderFetched(entry_ref& ref, BFile& file);
virtual void BodyFetched(const entry_ref& ref, BFile& file);
virtual void MailboxSynchronized(status_t status);
// Message hooks if filter is installed to an outbound protocol
virtual void MessageReadyToSend(const entry_ref& ref,
BFile* file);
virtual void MessageSent(const entry_ref& ref,
BFile* file);
BFile& file);
virtual void MessageSent(const entry_ref& ref, BFile& file);
protected:
BMailProtocol& fMailProtocol;
+13 -10
View File
@@ -43,6 +43,13 @@ public:
};
typedef status_t BMailFilterAction;
#define B_NO_MAIL_ACTION 0
#define B_MOVE_MAIL_ACTION 1
#define B_DELETE_MAIL_ACTION 2
class BMailProtocol : public BLooper {
public:
BMailProtocol(
@@ -68,10 +75,6 @@ public:
BDirectory& dir);
virtual status_t DeleteMessage(const entry_ref& ref);
virtual void FileRenamed(const entry_ref& from,
const entry_ref& to);
virtual void FileDeleted(const node_ref& node);
// Convenience methods that call the BMailNotifier
void ShowError(const char* error);
void ShowMessage(const char* message);
@@ -88,17 +91,17 @@ protected:
void ReportProgress(uint32 items, uint64 bytes,
const char* message = NULL);
void ResetProgress(const char* message = NULL);
void NotifyNewMessagesToFetch(int32 nMessages);
// Filter notifications
void NotifyNewMessagesToFetch(int32 nMessages);
void NotifyHeaderFetched(const entry_ref& ref,
BFile* mail);
BMailFilterAction ProcessHeaderFetched(entry_ref& ref,
BFile& mail);
void NotifyBodyFetched(const entry_ref& ref,
BFile* mail);
BFile& mail);
void NotifyMessageReadyToSend(const entry_ref& ref,
BFile* mail);
BFile& mail);
void NotifyMessageSent(const entry_ref& ref,
BFile* mail);
BFile& mail);
void LoadFilters(
const BMailProtocolSettings& settings);
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2012, Haiku, Inc. All rights reserved.
* Copyright 2004-2013, Haiku, Inc. All rights reserved.
* Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -56,50 +56,55 @@ RuleFilter::RuleFilter(BMailProtocol& protocol,
}
void
RuleFilter::HeaderFetched(const entry_ref& ref, BFile* file)
BMailFilterAction
RuleFilter::HeaderFetched(entry_ref& ref, BFile& file)
{
// That field doesn't exist? NO match
if (fAttribute == "")
return;
return B_NO_MAIL_ACTION;
attr_info info;
if (file->GetAttrInfo("Subject", &info) != B_OK
if (file.GetAttrInfo("Subject", &info) != B_OK
|| info.type != B_STRING_TYPE)
return;
return B_NO_MAIL_ACTION;
char* buffer = new char[info.size];
if (file->ReadAttr(fAttribute, B_STRING_TYPE, 0, buffer, info.size) < 0) {
if (file.ReadAttr(fAttribute, B_STRING_TYPE, 0, buffer, info.size) < 0) {
delete[] buffer;
return;
return B_NO_MAIL_ACTION;
}
BString data = buffer;
delete[] buffer;
if (!fMatcher.Match(data)) {
// We're not supposed to do anything
return;
return B_NO_MAIL_ACTION;
}
switch (fAction) {
case ACTION_MOVE_TO:
{
BDirectory dir(fMoveTarget);
// TODO: move is currently broken!
// fMailProtocol.Looper()->TriggerFileMove(ref, dir);
break;
node_ref nodeRef;
status_t status = dir.GetNodeRef(&nodeRef);
if (status != B_OK)
return status;
ref.device = nodeRef.device;
ref.directory = nodeRef.node;
return B_MOVE_MAIL_ACTION;
}
case ACTION_DELETE_MESSAGE:
// TODO trash!?
// fMailProtocol.Looper()->TriggerFileDeletion(ref);
break;
return B_DELETE_MAIL_ACTION;
case ACTION_SET_FLAGS_TO:
file->WriteAttrString("MAIL:filter_flags", &fSetFlags);
file.WriteAttrString("MAIL:filter_flags", &fSetFlags);
break;
case ACTION_REPLY_WITH:
file->WriteAttr("MAIL:reply_with", B_INT32_TYPE, 0, &fReplyAccount,
file.WriteAttr("MAIL:reply_with", B_INT32_TYPE, 0, &fReplyAccount,
sizeof(int32));
break;
case ACTION_SET_AS_READ:
@@ -113,7 +118,7 @@ RuleFilter::HeaderFetched(const entry_ref& ref, BFile* file)
fprintf(stderr,"Unknown do_what: 0x%04x!\n", fAction);
}
return;
return B_NO_MAIL_ACTION;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2012, Haiku, Inc. All rights reserved.
* Copyright 2004-2013, Haiku, Inc. All rights reserved.
* Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -21,8 +21,7 @@ public:
RuleFilter(BMailProtocol& protocol,
const BMailAddOnSettings& settings);
virtual void HeaderFetched(const entry_ref& ref,
BFile* file);
virtual BMailFilterAction HeaderFetched(entry_ref& ref, BFile& file);
private:
BString fAttribute;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012, Haiku, Inc. All rights reserved.
* Copyright 2002-2013, Haiku, Inc. All rights reserved.
* Copyright 2002 Alexander G. M. Smith.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
@@ -66,15 +66,16 @@ SpamFilter::~SpamFilter()
}
void
SpamFilter::HeaderFetched(const entry_ref& ref, BFile* file)
BMailFilterAction
SpamFilter::HeaderFetched(entry_ref& ref, BFile& file)
{
_CheckForSpam(file);
return B_NO_MAIL_ACTION;
}
void
SpamFilter::BodyFetched(const entry_ref& ref, BFile* file)
SpamFilter::BodyFetched(const entry_ref& ref, BFile& file)
{
if (fHeaderOnly)
return;
@@ -84,7 +85,7 @@ SpamFilter::BodyFetched(const entry_ref& ref, BFile* file)
// untrain the partial part before training on the complete message, but we
// don't know how big it was, so instead just ignore the message.
attr_info attributeInfo;
if (file->GetAttrInfo ("MAIL:classification", &attributeInfo) == B_OK)
if (file.GetAttrInfo ("MAIL:classification", &attributeInfo) == B_OK)
return;
_CheckForSpam(file);
@@ -92,22 +93,22 @@ SpamFilter::BodyFetched(const entry_ref& ref, BFile* file)
status_t
SpamFilter::_CheckForSpam(BFile* file)
SpamFilter::_CheckForSpam(BFile& file)
{
// Get a connection to the spam database server. Launch if needed, should
// only need it once, unless another e-mail thread shuts down the server
// inbetween messages. This code used to be in InitCheck, but apparently
// that isn't called.
printf("Checking for Spam Server.\n");
if (fLaunchAttemptCount == 0 || !fMessengerToServer.IsValid ()) {
if (fLaunchAttemptCount == 0 || !fMessengerToServer.IsValid()) {
if (_GetTokenizeMode() != B_OK)
return B_ERROR;
}
off_t dataSize;
file->GetSize(&dataSize);
file.GetSize(&dataSize);
char* stringBuffer = new char[dataSize + 1];
file->Read(stringBuffer, dataSize);
file.Read(stringBuffer, dataSize);
stringBuffer[dataSize] = 0; // Add an end of string NUL, just in case.
float spamRatio;
@@ -118,7 +119,7 @@ SpamFilter::_CheckForSpam(BFile* file)
// training example (don't train if it is uncertain).
if (fAutoTraining && (spamRatio >= fSpamCutoffRatio
|| spamRatio < fGenuineCutoffRatio)) {
_TrainServer(stringBuffer, dataSize, spamRatio);
_TrainServer(stringBuffer, dataSize, spamRatio);
}
delete[] stringBuffer;
@@ -127,12 +128,12 @@ SpamFilter::_CheckForSpam(BFile* file)
const char *classificationString;
classificationString = spamRatio >= fSpamCutoffRatio ? "Spam"
: spamRatio < fGenuineCutoffRatio ? "Genuine" : "Uncertain";
file->WriteAttr("MAIL:classification", B_STRING_TYPE, 0 /* offset */,
file.WriteAttr("MAIL:classification", B_STRING_TYPE, 0 /* offset */,
classificationString, strlen(classificationString) + 1);
// Store the spam ratio in an attribute called MAIL:ratio_spam,
// attached to the eventual output file.
file->WriteAttr("MAIL:ratio_spam", B_FLOAT_TYPE, 0 /* offset */, &spamRatio,
file.WriteAttr("MAIL:ratio_spam", B_FLOAT_TYPE, 0 /* offset */, &spamRatio,
sizeof(spamRatio));
// Also add it to the subject, if requested.
@@ -280,16 +281,16 @@ SpamFilter::_TrainServer(const char* stringBuffer, off_t dataSize,
status_t
SpamFilter::_AddSpamToSubject(BNode* file, float spamRatio)
SpamFilter::_AddSpamToSubject(BNode& file, float spamRatio)
{
attr_info info;
if (file->GetAttrInfo("Subject", &info) != B_OK)
if (file.GetAttrInfo("Subject", &info) != B_OK)
return B_ERROR;
if (info.type != B_STRING_TYPE)
return B_ERROR;
char* buffer = new char[info.size];
if (file->ReadAttr("Subject", B_STRING_TYPE, 0, buffer, info.size) < 0) {
if (file.ReadAttr("Subject", B_STRING_TYPE, 0, buffer, info.size) < 0) {
delete[] buffer;
return B_ERROR;
}
@@ -302,7 +303,7 @@ SpamFilter::_AddSpamToSubject(BNode* file, float spamRatio)
newSubjectString << buffer;
delete[] buffer;
if (file->WriteAttr("Subject", B_STRING_TYPE, 0, newSubjectString.String(),
if (file.WriteAttr("Subject", B_STRING_TYPE, 0, newSubjectString.String(),
newSubjectString.Length()) < 0)
return B_ERROR;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011, Haiku, Inc. All rights reserved.
* Copyright 2002-2013, Haiku, Inc. All rights reserved.
* Copyright 2002 Alexander G. M. Smith.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
@@ -18,12 +18,11 @@ public:
const BMailAddOnSettings& settings);
virtual ~SpamFilter();
virtual void HeaderFetched(const entry_ref& ref,
BFile* file);
virtual void BodyFetched(const entry_ref& ref, BFile* file);
virtual BMailFilterAction HeaderFetched(entry_ref& ref, BFile& file);
virtual void BodyFetched(const entry_ref& ref, BFile& file);
private:
status_t _CheckForSpam(BFile* file);
status_t _CheckForSpam(BFile& file);
//! If the server is not running start it
status_t _CheckForSpamServer();
status_t _GetTokenizeMode();
@@ -31,7 +30,7 @@ private:
float& ratio);
status_t _TrainServer(const char* data, off_t dataSize,
float spamRatio);
status_t _AddSpamToSubject(BNode* file, float spamRatio);
status_t _AddSpamToSubject(BNode& file, float spamRatio);
private:
bool fAddSpamToSubject;
@@ -231,8 +231,6 @@ IMAPFolder::MessageStored(entry_ref& ref, BFile& file, uint32 fetchFlags,
if ((fetchFlags & IMAP::kFetchFlags) != 0)
_WriteFlags(file, flags);
// TODO: the call below may move/rename the file - this prevents downloading
// the body to the correct file!
fProtocol.MessageStored(*this, ref, file, fetchFlags);
file.Unset();
@@ -126,10 +126,13 @@ void
IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, BFile& stream,
uint32 fetchFlags)
{
if ((fetchFlags & IMAP::kFetchHeader) != 0)
NotifyHeaderFetched(ref, &stream);
if ((fetchFlags & IMAP::kFetchHeader) != 0) {
BMailFilterAction action = ProcessHeaderFetched(ref, stream);
if (action < B_OK || action == B_DELETE_MAIL_ACTION)
return;
}
if ((fetchFlags & IMAP::kFetchBody) != 0)
NotifyBodyFetched(ref, &stream);
NotifyBodyFetched(ref, stream);
}
@@ -218,8 +218,8 @@ POP3Protocol::SyncMessages()
printf("POP3: Failed to download body %s\n ", uid);
break;
}
NotifyHeaderFetched(ref, &file);
NotifyBodyFetched(ref, &file);
ProcessHeaderFetched(ref, file);
NotifyBodyFetched(ref, file);
if (!leaveOnServer)
Delete(toRetrieve);
@@ -230,7 +230,7 @@ POP3Protocol::SyncMessages()
printf("POP3: Failed to download header %s\n ", uid);
break;
}
NotifyHeaderFetched(ref, &file);
ProcessHeaderFetched(ref, file);
}
ReportProgress(1, 0);
@@ -302,7 +302,7 @@ POP3Protocol::FetchBody(const entry_ref& ref)
return status;
}
NotifyBodyFetched(ref, &file);
NotifyBodyFetched(ref, file);
if (!leaveOnServer)
Delete(toRetrieve);
@@ -1,5 +1,5 @@
/*
* Copyright 2007-2012, Haiku, Inc. All rights reserved.
* Copyright 2007-2013, Haiku, Inc. All rights reserved.
* Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
*
@@ -546,11 +546,11 @@ SMTPProtocol::_SendMessage(const entry_ref& ref)
return B_ERROR;
}
NotifyMessageReadyToSend(ref, &file);
NotifyMessageReadyToSend(ref, file);
status = Send(to, from, &file);
if (status != B_OK)
return status;
NotifyMessageSent(ref, &file);
NotifyMessageSent(ref, file);
off_t size = 0;
file.GetSize(&size);
+65 -45
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012, Haiku, Inc. All rights reserved.
* Copyright 2011-2013, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
*
@@ -97,10 +97,10 @@ HaikuMailFormatFilter::DescriptiveName() const
}
void
HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file)
BMailFilterAction
HaikuMailFormatFilter::HeaderFetched(entry_ref& ref, BFile& file)
{
file->Seek(0, SEEK_SET);
file.Seek(0, SEEK_SET);
BMessage attributes;
// TODO: attributes.AddInt32(B_MAIL_ATTR_CONTENT, length);
@@ -109,9 +109,17 @@ HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file)
BString header;
off_t size;
if (file->GetSize(&size) == B_OK) {
if (file.GetSize(&size) == B_OK) {
char* buffer = header.LockBuffer(size);
file->Read(buffer, size);
if (buffer == NULL)
return B_NO_MEMORY;
ssize_t bytesRead = file.Read(buffer, size);
if (bytesRead < 0)
return bytesRead;
if (bytesRead != size)
return B_IO_ERROR;
header.UnlockBuffer(size);
}
@@ -151,9 +159,6 @@ HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file)
if (name.Length() <= 0)
name = "No Subject";
attributes.AddString(B_MAIL_ATTR_THREAD, name);
// Avoid hidden files, starting with a dot.
if (name[0] == '.')
name.Prepend ("_");
// Convert the date into a year-month-day fixed digit width format, so that
// sorting by file name will give all the messages with the same subject in
@@ -174,11 +179,11 @@ HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file)
timeFields.tm_hour, timeFields.tm_min, timeFields.tm_sec);
name << " " << numericDateString;
BString worker = attributes.FindString(B_MAIL_ATTR_FROM);
extract_address_name(worker);
name << " " << worker;
BString workerName = attributes.FindString(B_MAIL_ATTR_FROM);
extract_address_name(workerName);
name << " " << workerName;
name.Truncate(222); // reserve space for the uniquer
name.Truncate(222); // reserve space for the unique number
// Get rid of annoying characters which are hard to use in the shell.
name.ReplaceAll('/', '_');
@@ -187,49 +192,36 @@ HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file)
name.ReplaceAll('!', '_');
name.ReplaceAll('<', '_');
name.ReplaceAll('>', '_');
// Remove multiple spaces.
while (name.FindFirst(" ") >= 0)
name.Replace(" ", " ", 1024);
_RemoveExtraWhitespace(name);
_RemoveLeadingDots(name);
// Avoid files starting with a dot.
worker = name;
int32 identicalNumber = 1;
status_t status = _SetFileName(ref, worker);
while (status == B_FILE_EXISTS) {
identicalNumber++;
file << attributes;
worker = name;
worker << "_" << identicalNumber;
status = _SetFileName(ref, worker);
}
if (status < B_OK) {
printf("FolderFilter::ProcessMailMessage: could not rename mail (%s)! "
"(should be: %s)\n",strerror(status), worker.String());
} else {
entry_ref to(ref.device, ref.directory, worker);
fMailProtocol.FileRenamed(ref, to);
}
(*file) << attributes;
BNodeInfo info(file);
// TODO: find a way to not set that twice for each complete mail
BNodeInfo info(&file);
info.SetType(B_PARTIAL_MAIL_TYPE);
ref.set_name(name.String());
return B_MOVE_MAIL_ACTION;
}
void
HaikuMailFormatFilter::BodyFetched(const entry_ref& ref, BFile* file)
HaikuMailFormatFilter::BodyFetched(const entry_ref& ref, BFile& file)
{
BNodeInfo info(file);
BNodeInfo info(&file);
info.SetType(B_MAIL_TYPE);
}
void
HaikuMailFormatFilter::MessageSent(const entry_ref& ref, BFile* file)
HaikuMailFormatFilter::MessageSent(const entry_ref& ref, BFile& file)
{
mail_flags flags = B_MAIL_SENT;
file->WriteAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32));
file->WriteAttr(B_MAIL_ATTR_STATUS, B_STRING_TYPE, 0, "Sent", 5);
file.WriteAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32));
file.WriteAttr(B_MAIL_ATTR_STATUS, B_STRING_TYPE, 0, "Sent", 5);
if (!fOutboundDirectory.IsEmpty()) {
create_directory(fOutboundDirectory, 755);
@@ -243,11 +235,39 @@ HaikuMailFormatFilter::MessageSent(const entry_ref& ref, BFile* file)
}
status_t
HaikuMailFormatFilter::_SetFileName(const entry_ref& ref, const BString& name)
void
HaikuMailFormatFilter::_RemoveExtraWhitespace(BString& name)
{
BEntry entry(&ref);
return entry.Rename(name);
int spaces = 0;
for (int i = 0; i <= name.Length();) {
if (i < name.Length() && isspace(name.ByteAt(i))) {
spaces++;
i++;
} else if (spaces > 0) {
int remove = spaces - 1;
// Also remove leading and trailing spaces
if (i == remove + 1 || i == name.Length())
remove++;
else
name[i - spaces] = ' ';
name.Remove(i - remove, remove);
i -= remove;
spaces = 0;
} else
i++;
}
}
void
HaikuMailFormatFilter::_RemoveLeadingDots(BString& name)
{
int dots = 0;
while (dots < name.Length() && name.ByteAt(dots) == '.')
dots++;
if (dots > 0)
name.Remove(0, dots);
}
+6 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012, Haiku, Inc. All rights reserved.
* Copyright 2011-2013, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
@@ -18,15 +18,14 @@ public:
virtual BString DescriptiveName() const;
void HeaderFetched(const entry_ref& ref,
BFile* file);
void BodyFetched(const entry_ref& ref, BFile* file);
BMailFilterAction HeaderFetched(entry_ref& ref, BFile& file);
void BodyFetched(const entry_ref& ref, BFile& file);
void MessageSent(const entry_ref& ref, BFile* file);
void MessageSent(const entry_ref& ref, BFile& file);
private:
status_t _SetFileName(const entry_ref& ref,
const BString& name);
void _RemoveExtraWhitespace(BString& name);
void _RemoveLeadingDots(BString& name);
BString _ExtractName(const BString& from);
private:
+8 -6
View File
@@ -1,5 +1,6 @@
/*
* Copyright 2011-2012, Haiku, Inc. All rights reserved.
* Copyright 2011-2013, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
@@ -20,14 +21,15 @@ BMailFilter::~BMailFilter()
}
void
BMailFilter::HeaderFetched(const entry_ref& ref, BFile* file)
BMailFilterAction
BMailFilter::HeaderFetched(entry_ref& ref, BFile& file)
{
return B_NO_MAIL_ACTION;
}
void
BMailFilter::BodyFetched(const entry_ref& ref, BFile* file)
BMailFilter::BodyFetched(const entry_ref& ref, BFile& file)
{
}
@@ -39,12 +41,12 @@ BMailFilter::MailboxSynchronized(status_t status)
void
BMailFilter::MessageReadyToSend(const entry_ref& ref, BFile* file)
BMailFilter::MessageReadyToSend(const entry_ref& ref, BFile& file)
{
}
void
BMailFilter::MessageSent(const entry_ref& ref, BFile* file)
BMailFilter::MessageSent(const entry_ref& ref, BFile& file)
{
}
+58 -68
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2012, Haiku, Inc. All rights reserved.
* Copyright 2011-2013, Haiku, Inc. All rights reserved.
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
*/
@@ -42,12 +42,6 @@ using namespace BPrivate;
const uint32 kMsgDeleteMessage = '&DeM';
const uint32 kMsgAppendMessage = '&ApM';
const uint32 kMsgMoveFile = '&MoF';
const uint32 kMsgDeleteFile = '&DeF';
const uint32 kMsgFileRenamed = '&FiR';
const uint32 kMsgFileDeleted = '&FDe';
const uint32 kMsgInit = '&Ini';
const uint32 kMsgSendMessage = '&SeM';
@@ -138,48 +132,7 @@ BMailProtocol::RemoveFilter(BMailFilter* filter)
void
BMailProtocol::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgMoveFile:
{
entry_ref file;
message->FindRef("file", &file);
entry_ref dir;
message->FindRef("directory", &dir);
BDirectory directory(&dir);
MoveMessage(file, directory);
break;
}
case kMsgDeleteFile:
{
entry_ref file;
message->FindRef("file", &file);
DeleteMessage(file);
break;
}
case kMsgFileRenamed:
{
entry_ref from;
message->FindRef("from", &from);
entry_ref to;
message->FindRef("to", &to);
FileRenamed(from, to);
break;
}
case kMsgFileDeleted:
{
node_ref node;
message->FindInt32("device",&node.device);
message->FindInt64("node", &node.node);
FileDeleted(node);
break;
}
default:
BLooper::MessageReceived(message);
}
BLooper::MessageReceived(message);
}
@@ -199,18 +152,6 @@ BMailProtocol::DeleteMessage(const entry_ref& ref)
}
void
BMailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to)
{
}
void
BMailProtocol::FileDeleted(const node_ref& node)
{
}
void
BMailProtocol::ShowError(const char* error)
{
@@ -268,16 +209,65 @@ BMailProtocol::NotifyNewMessagesToFetch(int32 count)
}
void
BMailProtocol::NotifyHeaderFetched(const entry_ref& ref, BFile* data)
BMailFilterAction
BMailProtocol::ProcessHeaderFetched(entry_ref& ref, BFile& data)
{
for (int i = 0; i < fFilterList.CountItems(); i++)
fFilterList.ItemAt(i)->HeaderFetched(ref, data);
entry_ref outRef = ref;
for (int i = 0; i < fFilterList.CountItems(); i++) {
BMailFilterAction action = fFilterList.ItemAt(i)->HeaderFetched(outRef,
data);
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);
} 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* data)
BMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile& data)
{
for (int i = 0; i < fFilterList.CountItems(); i++)
fFilterList.ItemAt(i)->BodyFetched(ref, data);
@@ -285,7 +275,7 @@ BMailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile* data)
void
BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data)
BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile& data)
{
for (int i = 0; i < fFilterList.CountItems(); i++)
fFilterList.ItemAt(i)->MessageReadyToSend(ref, data);
@@ -293,7 +283,7 @@ BMailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data)
void
BMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile* data)
BMailProtocol::NotifyMessageSent(const entry_ref& ref, BFile& data)
{
for (int i = 0; i < fFilterList.CountItems(); i++)
fFilterList.ItemAt(i)->MessageSent(ref, data);