diff --git a/headers/os/add-ons/mail_daemon/MailProtocol.h b/headers/os/add-ons/mail_daemon/MailProtocol.h index 19f2250b7b..6ae1dffb7b 100644 --- a/headers/os/add-ons/mail_daemon/MailProtocol.h +++ b/headers/os/add-ons/mail_daemon/MailProtocol.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2015, Haiku, Inc. All Rights Reserved. + * Copyright 2004-2016, Haiku, Inc. All Rights Reserved. * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2011 Clemens Zeidler. All rights reserved. * @@ -136,13 +136,22 @@ public: virtual void MessageReceived(BMessage* message); virtual status_t SyncMessages() = 0; - virtual status_t FetchBody(const entry_ref& ref) = 0; + virtual status_t FetchBody(const entry_ref& ref, + BMessenger* replyTo); virtual status_t MarkMessageAsRead(const entry_ref& ref, read_flags flags = B_READ); - virtual status_t DeleteMessage(const entry_ref& ref) = 0; + virtual status_t DeleteMessage(const entry_ref& ref); virtual status_t AppendMessage(const entry_ref& ref); + static void ReplyBodyFetched(const BMessenger& replyTo, + const entry_ref& ref, status_t status); + protected: + virtual status_t HandleFetchBody(const entry_ref& ref, + const BMessenger& replyTo) = 0; + + virtual status_t HandleDeleteMessage(const entry_ref& ref) = 0; + void NotiyMailboxSynchronized(status_t status); }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp index 7a758f8f25..76869ac1d2 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2011-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -7,6 +7,7 @@ #include "IMAPConnectionWorker.h" #include +#include #include @@ -141,12 +142,13 @@ public: class FetchBodiesCommand : public SyncCommand, public IMAP::FetchListener { public: FetchBodiesCommand(IMAPFolder& folder, IMAPMailbox& mailbox, - std::vector& entries) + MessageUIDList& entries, const BMessenger* replyTo = NULL) : fFolder(folder), fMailbox(mailbox), fEntries(entries) { + folder.RegisterPendingBodies(entries, replyTo); } virtual status_t Process(IMAPConnectionWorker& worker) @@ -160,18 +162,23 @@ public: fEntries.erase(fEntries.begin()); status_t status = WorkerPrivate(worker).SelectMailbox(fFolder); + if (status == B_OK) { + printf("IMAP: fetch body for %" B_PRIu32 "\n", fUID); + // Since RFC3501 does not specify whether the FETCH response may + // alter the order of the message data items we request, we cannot + // request more than a single UID at a time, or else we may not be + // able to assign the data to the correct message beforehand. + IMAP::FetchCommand fetch(fUID, fUID, IMAP::kFetchBody); + fetch.SetListener(this); + + status = protocol.ProcessCommand(fetch); + } + if (status == B_OK) + status = fFetchStatus; if (status != B_OK) - return status; + fFolder.StoringBodyFailed(fRef, fUID, status); - printf("IMAP: fetch body for %" B_PRIu32 "\n", fUID); - // Since RFC3501 does not specify whether the FETCH response may - // alter the order of the message data items we request, we cannot - // request more than a single UID at a time, or else we may not be - // able to assign the data to the correct message beforehand. - IMAP::FetchCommand fetch(fUID, fUID, IMAP::kFetchBody); - fetch.SetListener(this); - - return protocol.ProcessCommand(fetch); + return status; } virtual bool IsDone() const @@ -194,7 +201,7 @@ public: private: IMAPFolder& fFolder; IMAPMailbox& fMailbox; - std::vector fEntries; + MessageUIDList fEntries; uint32 fUID; entry_ref fRef; BFile fFile; @@ -362,6 +369,9 @@ public: if (entries[i].uid > fFolder->LastUID()) { fTotalBytes += entries[i].size; fUIDsToFetch.push_back(entries[i].uid); + } else { + fFolder->UpdateMessageFlags(entries[i].uid, + entries[i].flags); } } @@ -413,6 +423,50 @@ private: }; +class UpdateFlagsCommand : public WorkerCommand { +public: + UpdateFlagsCommand(IMAPFolder& folder, IMAPMailbox& mailbox, + MessageUIDList& entries, uint32 flags) + : + fFolder(folder), + fMailbox(mailbox), + fEntries(entries), + fFlags(flags) + { + } + + virtual status_t Process(IMAPConnectionWorker& worker) + { + if (fEntries.empty()) + return B_OK; + + fUID = *fEntries.begin(); + fEntries.erase(fEntries.begin()); + + status_t status = WorkerPrivate(worker).SelectMailbox(fFolder); + if (status == B_OK) { + IMAP::Protocol& protocol = WorkerPrivate(worker).Protocol(); + IMAP::SetFlagsCommand set(fUID, fFlags); + status = protocol.ProcessCommand(set); + } + + return status; + } + + virtual bool IsDone() const + { + return fEntries.empty(); + } + +private: + IMAPFolder& fFolder; + IMAPMailbox& fMailbox; + MessageUIDList fEntries; + uint32 fUID; + uint32 fFlags; +}; + + struct CommandDelete { inline void operator()(WorkerCommand* command) @@ -567,9 +621,34 @@ IMAPConnectionWorker::EnqueueCheckMailboxes() status_t -IMAPConnectionWorker::EnqueueRetrieveMail(entry_ref& ref) +IMAPConnectionWorker::EnqueueFetchBody(IMAPFolder& folder, uint32 uid, + const BMessenger& replyTo) { - return B_OK; + IMAPMailbox* mailbox = _MailboxFor(folder); + if (mailbox == NULL) + return B_ENTRY_NOT_FOUND; + + std::vector uids; + uids.push_back(uid); + + return _EnqueueCommand(new FetchBodiesCommand(folder, *mailbox, uids, + &replyTo)); +} + + +status_t +IMAPConnectionWorker::EnqueueUpdateFlags(IMAPFolder& folder, uint32 uid, + uint32 flags) +{ + IMAPMailbox* mailbox = _MailboxFor(folder); + if (mailbox == NULL) + return B_ENTRY_NOT_FOUND; + + std::vector uids; + uids.push_back(uid); + + return _EnqueueCommand(new UpdateFlagsCommand(folder, *mailbox, uids, + flags)); } @@ -595,6 +674,8 @@ IMAPConnectionWorker::MessageExpungeReceived(uint32 index) if (fSelectedBox == NULL) return; + BLocker locker(this); + IMAPMailbox* mailbox = _MailboxFor(*fSelectedBox); if (mailbox != NULL) { mailbox->RemoveMessageEntry(index); diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h index 7c6314639e..a259a43520 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2011-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef IMAP_CONNECTION_WORKER_H @@ -9,7 +9,6 @@ #include #include -//#include "Commands.h" #include "Protocol.h" @@ -20,7 +19,6 @@ class Settings; class WorkerCommand; class WorkerPrivate; - typedef BObjectList WorkerCommandList; @@ -46,7 +44,10 @@ public: status_t EnqueueCheckSubscribedFolders(); status_t EnqueueCheckMailboxes(); - status_t EnqueueRetrieveMail(entry_ref& ref); + status_t EnqueueFetchBody(IMAPFolder& folder, + uint32 uid, const BMessenger& replyTo); + status_t EnqueueUpdateFlags(IMAPFolder& folder, + uint32 uid, uint32 flags); // Handler listener virtual void MessageExistsReceived(uint32 index); 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 a7c4c92a65..0ae442d9a7 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2012-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -13,10 +13,11 @@ #include #include #include +#include #include #include -#include "Commands.h" +#include #include "IMAPProtocol.h" @@ -91,16 +92,37 @@ IMAPFolder::IMAPFolder(IMAPProtocol& protocol, const BString& mailboxName, fRef(ref), fMailboxName(mailboxName), fUIDValidity(UINT32_MAX), - fLastUID(0) + fLastUID(0), + fListener(NULL) +{ + mutex_init(&fLock, "imap folder lock"); +} + + +IMAPFolder::~IMAPFolder() +{ +} + + +status_t +IMAPFolder::Init() { // Initialize from folder attributes - BNode node(&ref); - if (node.InitCheck() != B_OK) - return; + BNode node(&fRef); + status_t status = node.InitCheck(); + if (status != B_OK) + return status; + + node_ref nodeRef; + status = node.GetNodeRef(&nodeRef); + if (status != B_OK) + return status; + + fNodeID = nodeRef.node; BString originalMailboxName; if (node.ReadAttrString(kMailboxNameAttribute, &originalMailboxName) == B_OK - && originalMailboxName != mailboxName) { + && originalMailboxName != fMailboxName) { // TODO: mailbox name has changed } @@ -110,24 +132,20 @@ IMAPFolder::IMAPFolder(IMAPProtocol& protocol, const BString& mailboxName, fLastUID); attr_info info; - status_t status = node.GetAttrInfo(kStateAttribute, &info); + status = node.GetAttrInfo(kStateAttribute, &info); if (status == B_OK) { struct entry { uint32 uid; uint32 flags; } _PACKED; struct entry* entries = (struct entry*)malloc(info.size); - if (entries == NULL) { - // TODO: indicate B_NO_MEMORY - return; - } + if (entries == NULL) + return B_NO_MEMORY; ssize_t bytesRead = node.ReadAttr(kStateAttribute, B_RAW_TYPE, 0, entries, info.size); - if (bytesRead != info.size) { - // TODO: indicate read error resp. corrupted data - return; - } + if (bytesRead != info.size) + return B_BAD_DATA; for (size_t i = 0; i < info.size / sizeof(entry); i++) { uint32 uid = B_BENDIAN_TO_HOST_INT32(entries[i].uid); @@ -137,21 +155,20 @@ IMAPFolder::IMAPFolder(IMAPProtocol& protocol, const BString& mailboxName, } } - // Initialize current state from actual folder - // TODO: this should be done in another thread - //_InitializeFolderState(); -} - - -IMAPFolder::~IMAPFolder() -{ + return B_OK; } void IMAPFolder::SetListener(FolderListener* listener) { + ASSERT(fListener == NULL); + fListener = listener; + + // Initialize current state from actual folder + // TODO: this should be done in another thread + _InitializeFolderState(); } @@ -169,20 +186,33 @@ IMAPFolder::SetUIDValidity(uint32 uidValidity) status_t -IMAPFolder::GetMessageEntryRef(uint32 uid, entry_ref& ref) const +IMAPFolder::GetMessageEntryRef(uint32 uid, entry_ref& ref) { - UIDToRefMap::const_iterator found = fRefMap.find(uid); - if (found == fRefMap.end()) + MutexLocker locker(fLock); + return _GetMessageEntryRef(uid, ref); +} + + +status_t +IMAPFolder::GetMessageUID(const entry_ref& ref, uint32& uid) const +{ + BNode node(&ref); + status_t status = node.InitCheck(); + if (status != B_OK) + return status; + + uid = _ReadUniqueID(node); + if (uid == 0) return B_ENTRY_NOT_FOUND; - ref = found->second; return B_OK; } uint32 -IMAPFolder::MessageFlags(uint32 uid) const +IMAPFolder::MessageFlags(uint32 uid) { + MutexLocker locker(fLock); UIDToFlagsMap::const_iterator found = fFlagsMap.find(uid); if (found == fFlagsMap.end()) return 0; @@ -191,13 +221,71 @@ IMAPFolder::MessageFlags(uint32 uid) const } +void +IMAPFolder::UpdateMessageFlags(uint32 uid, uint32 mailboxFlags) +{ + if (uid > LastUID()) + return; + + entry_ref ref; + BNode node; + + while (true) { + status_t status = GetMessageEntryRef(uid, ref); + if (status == B_ENTRY_NOT_FOUND) { + // The message does not exist anymore locally, delete it on the server + // TODO: copy it to the trash directory first! + fProtocol.UpdateMessageFlags(*this, uid, IMAP::kDeleted); + return; + } + if (status == B_OK) + status = node.SetTo(&ref); + if (status == B_TIMED_OUT) + continue; + if (status != B_OK) + return; + + break; + } + + uint32 previousFlags = MessageFlags(uid); + uint32 currentFlags = previousFlags; + if (_MailToIMAPFlags(node, currentFlags) != B_OK) + return; + + // Compare flags to previous/current flags, and update either the + // message on the server, or the message locally (or even both) + + uint32 nextFlags = mailboxFlags; + _TestMessageFlags(previousFlags, mailboxFlags, currentFlags, + IMAP::kSeen, nextFlags); + _TestMessageFlags(previousFlags, mailboxFlags, currentFlags, + IMAP::kAnswered, nextFlags); + + if (nextFlags != previousFlags) + _WriteFlags(node, nextFlags); + if (currentFlags != nextFlags) { + // Update mail message attributes + BMessage attributes; + _IMAPToMailFlags(nextFlags, attributes); + node << attributes; + + fFlagsMap[uid] = nextFlags; + } + if (mailboxFlags != nextFlags) { + // Update server flags + fProtocol.UpdateMessageFlags(*this, uid, nextFlags); + } +} + + /*! Stores the given \a stream into a temporary file using the provided BFile object. A new file will be created, and the \a ref object will point to it. The file will remain open when this method exits without an error. \a length will reflect how many bytes are left to read in case there - were an error. + was an error. */ status_t IMAPFolder::StoreMessage(uint32 fetchFlags, BDataIO& stream, @@ -228,16 +316,13 @@ void IMAPFolder::MessageStored(entry_ref& ref, BFile& file, uint32 fetchFlags, uint32 uid, uint32 flags) { + _WriteUniqueIDValidity(file); _WriteUniqueID(file, uid); if ((fetchFlags & IMAP::kFetchFlags) != 0) _WriteFlags(file, flags); - // TODO: add some utility function for this in libmail.so BMessage attributes; - if ((flags & IMAP::kAnswered) != 0) - attributes.AddString(B_MAIL_ATTR_STATUS, "Answered"); - else if ((flags & IMAP::kSeen) != 0) - attributes.AddString(B_MAIL_ATTR_STATUS, "Read"); + _IMAPToMailFlags(flags, attributes); fProtocol.MessageStored(*this, ref, file, fetchFlags, attributes); file.Unset(); @@ -258,6 +343,29 @@ IMAPFolder::MessageStored(entry_ref& ref, BFile& file, uint32 fetchFlags, } +/*! Pushes the refs for the pending bodies to the pending bodies list. + This allows to prevent retrieving bodies more than once. +*/ +void +IMAPFolder::RegisterPendingBodies(IMAP::MessageUIDList& uids, + const BMessenger* replyTo) +{ + MutexLocker locker(fLock); + + MessengerList messengers; + if (replyTo != NULL) + messengers.push_back(*replyTo); + + IMAP::MessageUIDList::const_iterator iterator = uids.begin(); + for (; iterator != uids.end(); iterator++) { + if (replyTo != NULL) + fPendingBodies[*iterator].push_back(*replyTo); + else + fPendingBodies[*iterator].begin(); + } +} + + /*! Appends the given \a stream as body to the message file for the specified unique ID. The file will remain open when this method exits without an error. @@ -293,6 +401,15 @@ IMAPFolder::BodyStored(entry_ref& ref, BFile& file, uint32 uid) BMessage attributes; fProtocol.MessageStored(*this, ref, file, IMAP::kFetchBody, attributes); file.Unset(); + + _NotifyStoredBody(ref, uid, B_OK); +} + + +void +IMAPFolder::StoringBodyFailed(const entry_ref& ref, uint32 uid, status_t error) +{ + _NotifyStoredBody(ref, uid, error); } @@ -302,15 +419,6 @@ IMAPFolder::DeleteMessage(uint32 uid) } -/*! Called when the flags of a message changed on the server. This will update - the flags for the local file. -*/ -void -IMAPFolder::SetMessageFlags(uint32 uid, uint32 flags) -{ -} - - void IMAPFolder::MessageReceived(BMessage* message) { @@ -320,12 +428,7 @@ IMAPFolder::MessageReceived(BMessage* message) void IMAPFolder::_InitializeFolderState() { - // Create set of the last known UID state - if an entry is found, it - // is being removed from the list. The remaining entries were deleted. - std::set lastUIDs; - UIDToFlagsMap::iterator iterator = fFlagsMap.begin(); - for (; iterator != fFlagsMap.end(); iterator++) - lastUIDs.insert(iterator->first); + fInitializing = true; BDirectory directory(&fRef); BEntry entry; @@ -336,30 +439,42 @@ IMAPFolder::_InitializeFolderState() || node.SetTo(&entry) != B_OK) continue; + uint32 uidValidity = _ReadUniqueIDValidity(node); + if (uidValidity != fUIDValidity) { + // TODO: add file to mailbox + continue; + } uint32 uid = _ReadUniqueID(node); uint32 flags = _ReadFlags(node); - // TODO: make sure a listener exists at this point! - std::set::iterator found = lastUIDs.find(uid); - if (found != lastUIDs.end()) { - // The message is still around - lastUIDs.erase(found); - - uint32 flagsFound = MessageFlags(uid); - if (flagsFound != flags) { - // Its flags have changed locally, and need to be updated - fListener->MessageFlagsChanged(_Token(uid), ref, - flagsFound, flags); - } - } else { - // This is a new message - // TODO: the token must be the originating token! - uid = fListener->MessageAdded(_Token(uid), ref); - _WriteUniqueID(node, uid); - } + MutexLocker locker(fLock); fRefMap.insert(std::make_pair(uid, ref)); + fFlagsMap.insert(std::make_pair(uid, flags)); + +// // TODO: make sure a listener exists at this point! +// std::set::iterator found = lastUIDs.find(uid); +// if (found != lastUIDs.end()) { +// // The message is still around +// lastUIDs.erase(found); +// +// uint32 flagsFound = MessageFlags(uid); +// if (flagsFound != flags) { +// // Its flags have changed locally, and need to be updated +// fListener->MessageFlagsChanged(_Token(uid), ref, +// flagsFound, flags); +// } +// } else { +// // This is a new message +// // TODO: the token must be the originating token! +// uid = fListener->MessageAdded(_Token(uid), ref); +// _WriteUniqueID(node, uid); +// } +// + fRefMap.insert(std::make_pair(uid, ref)); } + + fInitializing = false; } @@ -375,8 +490,99 @@ IMAPFolder::_Token(uint32 uid) const } +void +IMAPFolder::_NotifyStoredBody(const entry_ref& ref, uint32 uid, status_t status) +{ + MutexLocker locker(fLock); + MessengerMap::iterator found = fPendingBodies.find(uid); + if (found != fPendingBodies.end()) { + MessengerList messengers = found->second; + fPendingBodies.erase(found); + locker.Unlock(); + + MessengerList::iterator iterator = messengers.begin(); + for (; iterator != messengers.end(); iterator++) + BInboundMailProtocol::ReplyBodyFetched(*iterator, ref, status); + } +} + + +status_t +IMAPFolder::_GetMessageEntryRef(uint32 uid, entry_ref& ref) const +{ + UIDToRefMap::const_iterator found = fRefMap.find(uid); + if (found == fRefMap.end()) + return fInitializing ? B_TIMED_OUT : B_ENTRY_NOT_FOUND; + + ref = found->second; + return B_OK; +} + + +void +IMAPFolder::_IMAPToMailFlags(uint32 flags, BMessage& attributes) +{ + // TODO: add some utility function for this in libmail.so + if ((flags & IMAP::kAnswered) != 0) + attributes.AddString(B_MAIL_ATTR_STATUS, "Answered"); + else if ((flags & IMAP::kFlagged) != 0) + attributes.AddString(B_MAIL_ATTR_STATUS, "Starred"); + else if ((flags & IMAP::kSeen) != 0) + attributes.AddString(B_MAIL_ATTR_STATUS, "Read"); +} + + +status_t +IMAPFolder::_MailToIMAPFlags(BNode& node, uint32& flags) +{ + BString mailStatus; + status_t status = node.ReadAttrString(B_MAIL_ATTR_STATUS, &mailStatus); + if (status != B_OK) + return status; + + flags &= ~(IMAP::kAnswered | IMAP::kSeen); + + // TODO: add some utility function for this in libmail.so + if (mailStatus == "Answered") + flags |= IMAP::kAnswered | IMAP::kSeen; + else if (mailStatus == "Read") + flags |= IMAP::kSeen; + else if (mailStatus == "Starred") + flags |= IMAP::kFlagged | IMAP::kSeen; + + return B_OK; +} + + +void +IMAPFolder::_TestMessageFlags(uint32 previousFlags, uint32 mailboxFlags, + uint32 currentFlags, uint32 testFlag, uint32& nextFlags) +{ + if ((previousFlags & testFlag) != (mailboxFlags & testFlag)) { + if ((previousFlags & testFlag) == (currentFlags & testFlag)) { + // The flags on the mailbox changed, update local flags + nextFlags &= ~testFlag; + nextFlags |= mailboxFlags & testFlag; + } else { + // Both flags changed. Since we don't have the means to do + // conflict resolution, we use a best effort mechanism + nextFlags |= testFlag; + } + return; + } + + // Previous message flags, and mailbox flags are identical, see + // if the user changed the flag locally + if ((currentFlags & testFlag) != (previousFlags & testFlag)) { + // Flag changed, update mailbox + nextFlags &= ~testFlag; + nextFlags |= currentFlags & testFlag; + } +} + + uint32 -IMAPFolder::_ReadUniqueID(BNode& node) +IMAPFolder::_ReadUniqueID(BNode& node) const { // For compatibility we must assume that the UID is stored as a string BString string; @@ -388,8 +594,9 @@ IMAPFolder::_ReadUniqueID(BNode& node) status_t -IMAPFolder::_WriteUniqueID(BNode& node, uint32 uid) +IMAPFolder::_WriteUniqueID(BNode& node, uint32 uid) const { + // For compatibility we must assume that the UID is stored as a string BString string; string << uid; @@ -398,21 +605,36 @@ IMAPFolder::_WriteUniqueID(BNode& node, uint32 uid) uint32 -IMAPFolder::_ReadFlags(BNode& node) +IMAPFolder::_ReadUniqueIDValidity(BNode& node) const +{ + + return _ReadUInt32(node, kUIDValidityAttribute); +} + + +status_t +IMAPFolder::_WriteUniqueIDValidity(BNode& node) const +{ + return _WriteUInt32(node, kUIDValidityAttribute, fUIDValidity); +} + + +uint32 +IMAPFolder::_ReadFlags(BNode& node) const { return _ReadUInt32(node, kFlagsAttribute); } status_t -IMAPFolder::_WriteFlags(BNode& node, uint32 flags) +IMAPFolder::_WriteFlags(BNode& node, uint32 flags) const { return _WriteUInt32(node, kFlagsAttribute, flags); } uint32 -IMAPFolder::_ReadUInt32(BNode& node, const char* attribute) +IMAPFolder::_ReadUInt32(BNode& node, const char* attribute) const { uint32 value; ssize_t bytesRead = node.ReadAttr(attribute, B_UINT32_TYPE, 0, @@ -425,7 +647,7 @@ IMAPFolder::_ReadUInt32(BNode& node, const char* attribute) status_t -IMAPFolder::_WriteUInt32(BNode& node, const char* attribute, uint32 value) +IMAPFolder::_WriteUInt32(BNode& node, const char* attribute, uint32 value) const { ssize_t bytesWritten = node.WriteAttr(attribute, B_UINT32_TYPE, 0, &value, sizeof(uint32)); @@ -437,7 +659,7 @@ IMAPFolder::_WriteUInt32(BNode& node, const char* attribute, uint32 value) status_t -IMAPFolder::_WriteStream(BFile& file, BDataIO& stream, size_t& length) +IMAPFolder::_WriteStream(BFile& file, BDataIO& stream, size_t& length) const { char buffer[65535]; while (length > 0) { diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h index f818cd814c..3ffa96e079 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2012-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef IMAP_FOLDER_H @@ -14,6 +14,10 @@ #include #include +#include + +#include "Commands.h" + class BFile; class IMAPProtocol; @@ -50,16 +54,23 @@ public: const entry_ref& ref); virtual ~IMAPFolder(); + status_t Init(); + const BString& MailboxName() const { return fMailboxName; } + ino_t NodeID() const { return fNodeID; } void SetListener(FolderListener* listener); void SetUIDValidity(uint32 uidValidity); uint32 LastUID() const { return fLastUID; } - status_t GetMessageEntryRef(uint32 uid, - entry_ref& ref) const; - uint32 MessageFlags(uint32 uid) const; + status_t GetMessageEntryRef(uint32 uid, entry_ref& ref); + status_t GetMessageUID(const entry_ref& ref, + uint32& uid) const; + uint32 MessageFlags(uint32 uid); + + void UpdateMessageFlags(uint32 uid, + uint32 mailboxFlags); status_t StoreMessage(uint32 fetchFlags, BDataIO& stream, size_t& length, entry_ref& ref, @@ -68,49 +79,75 @@ public: uint32 fetchFlags, uint32 uid, uint32 flags); + void RegisterPendingBodies( + IMAP::MessageUIDList& uids, + const BMessenger* replyTo); status_t StoreBody(uint32 uid, BDataIO& stream, size_t& length, entry_ref& ref, BFile& file); void BodyStored(entry_ref& ref, BFile& file, uint32 uid); + void StoringBodyFailed(const entry_ref& ref, + uint32 uid, status_t error); void DeleteMessage(uint32 uid); - void SetMessageFlags(uint32 uid, uint32 flags); virtual void MessageReceived(BMessage* message); private: void _InitializeFolderState(); const MessageToken _Token(uint32 uid) const; - uint32 _ReadUniqueID(BNode& node); - status_t _WriteUniqueID(BNode& node, uint32 uid); - uint32 _ReadFlags(BNode& node); - status_t _WriteFlags(BNode& node, uint32 flags); + void _NotifyStoredBody(const entry_ref& ref, + uint32 uid, status_t status); + status_t _GetMessageEntryRef(uint32 uid, + entry_ref& ref) const; - uint32 _ReadUInt32(BNode& node, const char* attribute); + void _IMAPToMailFlags(uint32 flags, + BMessage& attributes); + status_t _MailToIMAPFlags(BNode& node, uint32& flags); + void _TestMessageFlags(uint32 previousFlags, + uint32 mailboxFlags, uint32 currentFlags, + uint32 testFlag, uint32& nextFlags); + + uint32 _ReadUniqueID(BNode& node) const; + status_t _WriteUniqueID(BNode& node, uint32 uid) const; + uint32 _ReadUniqueIDValidity(BNode& node) const; + status_t _WriteUniqueIDValidity(BNode& node) const; + uint32 _ReadFlags(BNode& node) const; + status_t _WriteFlags(BNode& node, uint32 flags) const; + + uint32 _ReadUInt32(BNode& node, + const char* attribute) const; status_t _WriteUInt32(BNode& node, - const char* attribute, uint32 value); + const char* attribute, uint32 value) const; status_t _WriteStream(BFile& file, BDataIO& stream, - size_t& length); + size_t& length) const; private: + typedef std::vector MessengerList; #if __GNUC__ >= 4 typedef __gnu_cxx::hash_map UIDToFlagsMap; typedef __gnu_cxx::hash_map UIDToRefMap; + typedef __gnu_cxx::hash_map MessengerMap; #else typedef std::hash_map UIDToFlagsMap; typedef std::hash_map UIDToRefMap; + typedef std::hash_map MessengerMap; #endif IMAPProtocol& fProtocol; const entry_ref fRef; BString fMailboxName; + ino_t fNodeID; uint32 fUIDValidity; uint32 fLastUID; FolderListener* fListener; + mutex fLock; + bool fInitializing; UIDToRefMap fRefMap; UIDToFlagsMap fFlagsMap; + MessengerMap fPendingBodies; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp index deaf958c43..4a8603ff73 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -86,7 +86,7 @@ IMAPMailbox::MessageAdded(const MessageToken& fromToken, const entry_ref& ref) { printf("IMAP: message added %s, uid %" B_PRIu32 "\n", ref.name, fromToken.uid); - return 0; + return fromToken.uid; } 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 fc81fdf275..b25ba73301 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -7,6 +7,7 @@ #include "IMAPProtocol.h" #include +#include #include "IMAPConnectionWorker.h" #include "IMAPFolder.h" @@ -27,6 +28,8 @@ IMAPProtocol::IMAPProtocol(const BMailAccountSettings& settings) destination.Path(), strerror(status)); } + mutex_init(&fWorkerLock, "imap worker lock"); + PostMessage(B_READY_TO_RUN); } @@ -61,6 +64,8 @@ IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol, bool idle) if (idle) workersWanted = std::min(fSettings.MaxConnections(), totalMailboxes); + MutexLocker locker(fWorkerLock); + if (newFolders.IsEmpty() && fWorkers.CountItems() == workersWanted) { // Nothing to do - we've already distributed everything return B_OK; @@ -70,6 +75,7 @@ IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol, bool idle) for (int32 i = 0; i < fWorkers.CountItems(); i++) { fWorkers.ItemAt(i)->RemoveAllMailboxes(); } + fWorkerMap.clear(); // Create/remove connection workers as allowed and needed while (fWorkers.CountItems() < workersWanted) { @@ -104,7 +110,11 @@ IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol, bool idle) FolderMap::iterator iterator = fFolders.begin(); int32 index = 0; for (; iterator != fFolders.end(); iterator++) { - fWorkers.ItemAt(index)->AddMailbox(iterator->second); + IMAPConnectionWorker* worker = fWorkers.ItemAt(index); + IMAPFolder* folder = iterator->second; + worker->AddMailbox(folder); + fWorkerMap.insert(std::make_pair(folder, worker)); + index = (index + 1) % fWorkers.CountItems(); } @@ -116,13 +126,21 @@ IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol, bool idle) void IMAPProtocol::WorkerQuit(IMAPConnectionWorker* worker) { + MutexLocker locker(fWorkerLock); fWorkers.RemoveItem(worker); + + WorkerMap::iterator iterator = fWorkerMap.begin(); + while (iterator != fWorkerMap.end()) { + WorkerMap::iterator removed = iterator++; + if (removed->second == worker) + fWorkerMap.erase(removed); + } } void -IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, BFile& stream, - uint32 fetchFlags, BMessage& attributes) +IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, + BFile& stream, uint32 fetchFlags, BMessage& attributes) { if ((fetchFlags & (IMAP::kFetchHeader | IMAP::kFetchBody)) == (IMAP::kFetchHeader | IMAP::kFetchBody)) { @@ -135,11 +153,26 @@ IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, BFile& stream, } +status_t +IMAPProtocol::UpdateMessageFlags(IMAPFolder& folder, uint32 uid, uint32 flags) +{ + MutexLocker locker(fWorkerLock); + + WorkerMap::const_iterator found = fWorkerMap.find(&folder); + if (found == fWorkerMap.end()) + return B_ERROR; + + IMAPConnectionWorker* worker = found->second; + return worker->EnqueueUpdateFlags(folder, uid, flags); +} + + status_t IMAPProtocol::SyncMessages() { puts("IMAP: sync"); + MutexLocker locker(fWorkerLock); if (fWorkers.IsEmpty()) { // Create main (and possibly initial) connection worker IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, @@ -157,14 +190,6 @@ IMAPProtocol::SyncMessages() } -status_t -IMAPProtocol::FetchBody(const entry_ref& ref) -{ - printf("IMAP: fetch body %s\n", ref.name); - return B_ERROR; -} - - status_t IMAPProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flags) { @@ -173,14 +198,6 @@ IMAPProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flags) } -status_t -IMAPProtocol::DeleteMessage(const entry_ref& ref) -{ - printf("IMAP: delete message %s\n", ref.name); - return B_ERROR; -} - - status_t IMAPProtocol::AppendMessage(const entry_ref& ref) { @@ -204,6 +221,38 @@ IMAPProtocol::MessageReceived(BMessage* message) } +status_t +IMAPProtocol::HandleFetchBody(const entry_ref& ref, const BMessenger& replyTo) +{ + printf("IMAP: fetch body %s\n", ref.name); + MutexLocker locker(fWorkerLock); + + IMAPFolder* folder = _FolderFor(ref.directory); + if (folder == NULL) + return B_ENTRY_NOT_FOUND; + + uint32 uid; + status_t status = folder->GetMessageUID(ref, uid); + if (status != B_OK) + return status; + + WorkerMap::const_iterator found = fWorkerMap.find(folder); + if (found == fWorkerMap.end()) + return B_ERROR; + + IMAPConnectionWorker* worker = found->second; + return worker->EnqueueFetchBody(*folder, uid, replyTo); +} + + +status_t +IMAPProtocol::HandleDeleteMessage(const entry_ref& ref) +{ + printf("IMAP: delete message %s\n", ref.name); + return B_ERROR; +} + + void IMAPProtocol::ReadyToRun() { @@ -239,7 +288,27 @@ IMAPProtocol::_CreateFolder(const BString& mailbox, const BString& separator) return NULL; } - return new IMAPFolder(*this, mailbox, ref); + IMAPFolder* folder = new IMAPFolder(*this, mailbox, ref); + status = folder->Init(); + if (status != B_OK) { + fprintf(stderr, "Initializing folder %s failed: %s\n", path.Path(), + strerror(status)); + return NULL; + } + + fFolderNodeMap.insert(std::make_pair(folder->NodeID(), folder)); + return folder; +} + + +IMAPFolder* +IMAPProtocol::_FolderFor(ino_t directory) +{ + FolderNodeMap::const_iterator found = fFolderNodeMap.find(directory); + if (found != fFolderNodeMap.end()) + return found->second; + + return NULL; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h index fb3d1441aa..57ab5816d6 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2013-2016, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef IMAP_PROTOCOL_H @@ -11,6 +11,9 @@ #include #include +#include + +#include "Commands.h" #include "Settings.h" @@ -38,27 +41,39 @@ public: entry_ref& ref, BFile& stream, uint32 fetchFlags, BMessage& attributes); + status_t UpdateMessageFlags(IMAPFolder& folder, + uint32 uid, uint32 flags); + virtual status_t SyncMessages(); - virtual status_t FetchBody(const entry_ref& ref); virtual status_t MarkMessageAsRead(const entry_ref& ref, read_flags flags = B_READ); - virtual status_t DeleteMessage(const entry_ref& ref); virtual status_t AppendMessage(const entry_ref& ref); virtual void MessageReceived(BMessage* message); protected: + virtual status_t HandleFetchBody(const entry_ref& ref, + const BMessenger& replyTo); + virtual status_t HandleDeleteMessage(const entry_ref& ref); + void ReadyToRun(); private: IMAPFolder* _CreateFolder(const BString& mailbox, const BString& separator); + IMAPFolder* _FolderFor(ino_t directory); status_t _EnqueueCheckMailboxes(); protected: + typedef std::map WorkerMap; + typedef std::map FolderNodeMap; + Settings fSettings; + mutex fWorkerLock; BObjectList fWorkers; + WorkerMap fWorkerMap; FolderMap fFolders; + FolderNodeMap fFolderNodeMap; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp index bb4abbf1d8..31cf6e459d 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015, Haiku, Inc. All rights reserved. + * Copyright 2011-2016, Haiku, Inc. All rights reserved. * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. */ @@ -473,7 +473,7 @@ SetFlagsCommand::SetFlagsCommand(uint32 uid, uint32 flags) BString SetFlagsCommand::CommandString() { - BString command = "STORE "; + BString command = "UID STORE "; command << fUID << " FLAGS (" << GenerateFlagString(fFlags) << ")"; return command; 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 f06dd9f11c..4ecdfc525a 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2015, Haiku, Inc. All rights reserved. + * Copyright 2007-2016, Haiku, Inc. All rights reserved. * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2011, Clemens Zeidler * @@ -253,7 +253,7 @@ POP3Protocol::SyncMessages() status_t -POP3Protocol::FetchBody(const entry_ref& ref) +POP3Protocol::HandleFetchBody(const entry_ref& ref, const BMessenger& replyTo) { ResetProgress("Fetch body"); SetTotalItems(1); @@ -303,6 +303,7 @@ POP3Protocol::FetchBody(const entry_ref& ref) BMessage attributes; NotifyBodyFetched(ref, file, attributes); + ReplyBodyFetched(replyTo, ref, B_OK); if (!leaveOnServer) Delete(toRetrieve); @@ -316,7 +317,7 @@ POP3Protocol::FetchBody(const entry_ref& ref) status_t -POP3Protocol::DeleteMessage(const entry_ref& ref) +POP3Protocol::HandleDeleteMessage(const entry_ref& ref) { status_t error = Connect(); if (error < B_OK) diff --git a/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.h b/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.h index f83e9918e5..c4cf020300 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.h +++ b/src/add-ons/mail_daemon/inbound_protocols/pop3/POP3.h @@ -1,5 +1,5 @@ /* - * Copyright 2007-2013, Haiku Inc. All Rights Reserved. + * Copyright 2007-2016, Haiku Inc. All Rights Reserved. * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2011, Clemens Zeidler * @@ -35,14 +35,16 @@ public: status_t Disconnect(); status_t SyncMessages(); - status_t FetchBody(const entry_ref& ref); - status_t DeleteMessage(const entry_ref& ref); status_t Retrieve(int32 message, BPositionIO* to); status_t GetHeader(int32 message, BPositionIO* to); void Delete(int32 index); protected: + virtual status_t HandleFetchBody(const entry_ref& ref, + const BMessenger& replyTo); + virtual status_t HandleDeleteMessage(const entry_ref& ref); + // pop3 methods status_t Open(const char* server, int port, int protocol); diff --git a/src/apps/mail/MailWindow.cpp b/src/apps/mail/MailWindow.cpp index 27ed9118e7..b29e1a15c5 100644 --- a/src/apps/mail/MailWindow.cpp +++ b/src/apps/mail/MailWindow.cpp @@ -1036,6 +1036,7 @@ TMailWindow::MessageReceived(BMessage* msg) { status_t status = msg->FindInt32("status"); if (status != B_OK) { + fprintf(stderr, "Body could not be fetched: %s\n", strerror(status)); PostMessage(B_QUIT_REQUESTED); break; } @@ -2862,7 +2863,9 @@ TMailWindow::OpenMessage(const entry_ref* ref, uint32 characterSetForDecoding) if (strcmp(mimeType, B_PARTIAL_MAIL_TYPE) == 0) { BMessenger listener(this); - BMailDaemon().FetchBody(*ref, &listener); + status_t status = BMailDaemon().FetchBody(*ref, &listener); + if (status != B_OK) + fprintf(stderr, "Could not fetch body: %s\n", strerror(status)); fileInfo.GetType(mimeType); _SetDownloading(true); } else diff --git a/src/kits/mail/MailProtocol.cpp b/src/kits/mail/MailProtocol.cpp index f73d959cad..eb3bcc1698 100644 --- a/src/kits/mail/MailProtocol.cpp +++ b/src/kits/mail/MailProtocol.cpp @@ -1,10 +1,9 @@ /* - * Copyright 2011-2015, Haiku, Inc. All rights reserved. + * Copyright 2011-2016, Haiku, Inc. All rights reserved. * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. */ -//#include #include #include @@ -415,17 +414,15 @@ BInboundMailProtocol::MessageReceived(BMessage* message) case kMsgFetchBody: { entry_ref ref; - message->FindRef("ref", &ref); - status_t status = FetchBody(ref); - - BMessenger target; - if (message->FindMessenger("target", &target) != B_OK) + if (message->FindRef("ref", &ref) != B_OK) break; - BMessage message(B_MAIL_BODY_FETCHED); - message.AddInt32("status", status); - message.AddRef("ref", &ref); - target.SendMessage(&message); + BMessenger target; + message->FindMessenger("target", &target); + + status_t status = HandleFetchBody(ref, target); + if (status != B_OK) + ReplyBodyFetched(target, ref, status); break; } @@ -461,6 +458,18 @@ BInboundMailProtocol::MessageReceived(BMessage* message) } +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) { @@ -469,6 +478,13 @@ BInboundMailProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag) } +status_t +BInboundMailProtocol::DeleteMessage(const entry_ref& ref) +{ + return B_ERROR; +} + + status_t BInboundMailProtocol::AppendMessage(const entry_ref& ref) { @@ -476,6 +492,17 @@ BInboundMailProtocol::AppendMessage(const entry_ref& ref) } +/*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) { diff --git a/src/kits/mail/mail_util.cpp b/src/kits/mail/mail_util.cpp index 05bb4e7efe..8fec8828d4 100644 --- a/src/kits/mail/mail_util.cpp +++ b/src/kits/mail/mail_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011-2016, Haiku, Inc. All rights reserved. * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. */ @@ -159,13 +159,13 @@ write_read_attr(BNode& node, read_flags flag) < 0) return B_ERROR; - // manage the status string only if it currently has a "read" status + // Manage the status string only if it currently has a known state BString currentStatus; - if (node.ReadAttrString(B_MAIL_ATTR_STATUS, ¤tStatus) == B_OK) { - if (currentStatus.ICompare("New") != 0 - && currentStatus.ICompare("Read") != 0 - && currentStatus.ICompare("Seen") != 0) - return B_OK; + if (node.ReadAttrString(B_MAIL_ATTR_STATUS, ¤tStatus) == B_OK + && currentStatus.ICompare("New") != 0 + && currentStatus.ICompare("Read") != 0 + && currentStatus.ICompare("Seen") != 0) { + return B_OK; } const char* statusString = flag == B_READ ? "Read" diff --git a/src/servers/mail/MailDaemonApplication.cpp b/src/servers/mail/MailDaemonApplication.cpp index dc1d2fe39b..0a9c486e6c 100644 --- a/src/servers/mail/MailDaemonApplication.cpp +++ b/src/servers/mail/MailDaemonApplication.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007-2015, Haiku, Inc. All rights reserved. + * Copyright 2007-2016, Haiku, Inc. All rights reserved. * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. @@ -67,16 +67,6 @@ public: { } - status_t FetchBody(const entry_ref& ref, BMessenger* replyTo) - { - BMessage message(kMsgFetchBody); - message.AddRef("ref", &ref); - if (replyTo != NULL) - message.AddMessenger("target", *replyTo); - - return SendMessage(&message); - } - status_t MarkAsRead(const entry_ref& ref, read_flags flag) { BMessage message(kMsgMarkMessageAsRead); @@ -248,7 +238,7 @@ MailDaemonApplication::RefsReceived(BMessage* message) if (message->FindMessenger("target", &target) != B_OK) replyTo = NULL; - InboundMessenger(protocol).FetchBody(ref, replyTo); + protocol->FetchBody(ref, replyTo); } }