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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user