added 1 changeset to branch 'refs/remotes/axeld-github/imap' old head: 22074d6029b2eab8027e00c2fb013e096306fe03 new head: fcab7c5e00eb195fb42177209b2f7985560db84b overview: https://github.com/axeld/haiku/compare/22074d6...fcab7c5 ---------------------------------------------------------------------------- fcab7c5: 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. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: fcab7c5e00eb195fb42177209b2f7985560db84b Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Wed Jun 26 22:30:14 2013 UTC ---------------------------------------------------------------------------- 14 files changed, 215 insertions(+), 198 deletions(-) headers/os/add-ons/mail_daemon/MailFilter.h | 12 +- headers/os/add-ons/mail_daemon/MailProtocol.h | 23 ++-- .../inbound_filters/match_header/RuleFilter.cpp | 41 +++--- .../inbound_filters/match_header/RuleFilter.h | 5 +- .../inbound_filters/spam_filter/SpamFilter.cpp | 33 ++--- .../inbound_filters/spam_filter/SpamFilter.h | 11 +- .../inbound_protocols/imap/IMAPFolder.cpp | 2 - .../inbound_protocols/imap/IMAPProtocol.cpp | 9 +- .../mail_daemon/inbound_protocols/pop3/POP3.cpp | 8 +- .../mail_daemon/outbound_protocols/smtp/SMTP.cpp | 6 +- src/kits/mail/HaikuMailFormatFilter.cpp | 110 +++++++++------- src/kits/mail/HaikuMailFormatFilter.h | 13 +- src/kits/mail/MailFilter.cpp | 14 ++- src/kits/mail/MailProtocol.cpp | 126 +++++++++---------- ---------------------------------------------------------------------------- diff --git a/headers/os/add-ons/mail_daemon/MailFilter.h b/headers/os/add-ons/mail_daemon/MailFilter.h index c16f269..b071c70 100644 --- a/headers/os/add-ons/mail_daemon/MailFilter.h +++ b/headers/os/add-ons/mail_daemon/MailFilter.h @@ -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; diff --git a/headers/os/add-ons/mail_daemon/MailProtocol.h b/headers/os/add-ons/mail_daemon/MailProtocol.h index bb90719..f263fc0 100644 --- a/headers/os/add-ons/mail_daemon/MailProtocol.h +++ b/headers/os/add-ons/mail_daemon/MailProtocol.h @@ -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); diff --git a/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.cpp b/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.cpp index 023840e..75bc5dd 100644 --- a/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.cpp +++ b/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.cpp @@ -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; } diff --git a/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.h b/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.h index b262407..ef24e80 100644 --- a/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.h +++ b/src/add-ons/mail_daemon/inbound_filters/match_header/RuleFilter.h @@ -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; diff --git a/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.cpp b/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.cpp index cfb3587..5544c83 100644 --- a/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.cpp +++ b/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.cpp @@ -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 <haiku@xxxxxxxxxxxxxxxxxx> * 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. @@ -279,16 +280,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; } @@ -301,7 +302,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; diff --git a/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.h b/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.h index 9650007..15368c5 100644 --- a/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.h +++ b/src/add-ons/mail_daemon/inbound_filters/spam_filter/SpamFilter.h @@ -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 <haiku@xxxxxxxxxxxxxxxxxx> * 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; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp index a7abf30..7a026af 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp @@ -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(); diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp index 5499c06..b9605b1 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp @@ -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); } diff --git a/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp b/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp index 8573b27..9a1f3cd 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp @@ -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); diff --git a/src/add-ons/mail_daemon/outbound_protocols/smtp/SMTP.cpp b/src/add-ons/mail_daemon/outbound_protocols/smtp/SMTP.cpp index 0d98809..e9adae1 100644 --- a/src/add-ons/mail_daemon/outbound_protocols/smtp/SMTP.cpp +++ b/src/add-ons/mail_daemon/outbound_protocols/smtp/SMTP.cpp @@ -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@xxxxxxxxxxxxxxxxxx> * @@ -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); diff --git a/src/kits/mail/HaikuMailFormatFilter.cpp b/src/kits/mail/HaikuMailFormatFilter.cpp index f0db565..96a28fa 100644 --- a/src/kits/mail/HaikuMailFormatFilter.cpp +++ b/src/kits/mail/HaikuMailFormatFilter.cpp @@ -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@xxxxxxxxxxxxxxxxxx> * 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); - - worker = name; - int32 identicalNumber = 1; - status_t status = _SetFileName(ref, worker); - while (status == B_FILE_EXISTS) { - identicalNumber++; - - 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); - } + _RemoveExtraWhitespace(name); + _RemoveLeadingDots(name); + // Avoid files starting with a dot. - (*file) << attributes; + 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); } diff --git a/src/kits/mail/HaikuMailFormatFilter.h b/src/kits/mail/HaikuMailFormatFilter.h index bf16c64..2eebb60 100644 --- a/src/kits/mail/HaikuMailFormatFilter.h +++ b/src/kits/mail/HaikuMailFormatFilter.h @@ -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@xxxxxxxxxxxxxxxxxx> * 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: diff --git a/src/kits/mail/MailFilter.cpp b/src/kits/mail/MailFilter.cpp index 5ef9115..7c7d626 100644 --- a/src/kits/mail/MailFilter.cpp +++ b/src/kits/mail/MailFilter.cpp @@ -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) { } diff --git a/src/kits/mail/MailProtocol.cpp b/src/kits/mail/MailProtocol.cpp index 4111315..b39185c 100644 --- a/src/kits/mail/MailProtocol.cpp +++ b/src/kits/mail/MailProtocol.cpp @@ -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); } @@ -200,18 +153,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) { if (MailNotifier() != NULL) @@ -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);