[haiku-commits] BRANCH axeld-github.imap [49c03e1] in src: add-ons/mail_daemon/inbound_protocols/imap servers/mail

  • From: axeld-github.imap <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 23 May 2013 01:00:37 +0200 (CEST)

added 4 changesets to branch 'refs/remotes/axeld-github/imap'
old head: 455e6baab2e44265a8c97b12ade9d5047ff7f9b3
new head: 49c03e1c524312652a0e400a7201a10b882efb64
overview: https://github.com/axeld/haiku/compare/455e6ba...49c03e1

----------------------------------------------------------------------------

d107e0a: mail_daemon: cleanup, 30s auto check startup delay.
  
  * Refactored new message retrieval a bit, so that the notification strings
    aren't duplicated.
  * The daemon now waits 30 seconds before doing the first mail check.

8615ddf: IMAP: make the body fetch limit setting available.
  
  * This is set by the ProtocolConfigView -- there should really be
    some constant for this.

636ddb7: IMAP: if connecting fails, try again a few times.
  
  * Also documented SyncCommand.

49c03e1: IMAP: work in progress of downloading the mail body.
  
  * Most things are in place now, we just try to download the body to the
    wrong file, as the final location is currently unknown.
  * Added local only kPartialMessage flag for mails, but it's not being
    used yet.

                                   [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

12 files changed, 386 insertions(+), 114 deletions(-)
.../imap/IMAPConnectionWorker.cpp                | 120 ++++++++++++++--
.../inbound_protocols/imap/IMAPFolder.cpp        | 138 ++++++++++++++-----
.../inbound_protocols/imap/IMAPFolder.h          |  26 +++-
.../inbound_protocols/imap/IMAPMailbox.cpp       |  30 ++++
.../inbound_protocols/imap/IMAPMailbox.h         |  19 +++
.../inbound_protocols/imap/IMAPProtocol.cpp      |   3 +-
.../inbound_protocols/imap/IMAPProtocol.h        |   3 +-
.../inbound_protocols/imap/Settings.cpp          |   7 +
.../inbound_protocols/imap/Settings.h            |   1 +
.../inbound_protocols/imap/imap_lib/Commands.h   |  12 +-
src/servers/mail/MailDaemonApplication.cpp       | 135 ++++++++++--------
src/servers/mail/MailDaemonApplication.h         |   6 +-

############################################################################

Commit:      d107e0acaee11ab692574592e34b8f87e78b365e
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Wed May 22 21:15:29 2013 UTC

mail_daemon: cleanup, 30s auto check startup delay.

* Refactored new message retrieval a bit, so that the notification strings
  aren't duplicated.
* The daemon now waits 30 seconds before doing the first mail check.

----------------------------------------------------------------------------

diff --git a/src/servers/mail/MailDaemonApplication.cpp 
b/src/servers/mail/MailDaemonApplication.cpp
index 1ed531e..b34ba1f 100644
--- a/src/servers/mail/MailDaemonApplication.cpp
+++ b/src/servers/mail/MailDaemonApplication.cpp
@@ -39,8 +39,13 @@
 #define B_TRANSLATION_CONTEXT "MailDaemon"
 
 
+static const uint32 kMsgStartAutoCheck = 'stAC';
 static const uint32 kMsgAutoCheck = 'moto';
 
+static const bigtime_t kStartAutoCheckDelay = 30000000;
+       // Wait 30 seconds before the first auto check - this usually lets the
+       // boot process settle down, and give the network a chance to come up.
+
 
 struct send_mails_info {
        send_mails_info()
@@ -212,56 +217,20 @@ MailDaemonApplication::ReadyToRun()
        InstallDeskbarIcon();
 
        _InitAccounts();
-       _UpdateAutoCheck(fSettingsFile.AutoCheckInterval());
-
-       BVolume volume;
-       BVolumeRoster roster;
 
-       fNewMessages = 0;
+       // Start auto mail check with a delay
+       BMessage startAutoCheck(kMsgStartAutoCheck);
+       BMessageRunner::StartSending(this, &startAutoCheck,
+               kStartAutoCheckDelay, 1);
 
-       while (roster.GetNextVolume(&volume) == B_OK) {
-               BQuery* query = new BQuery;
-
-               query->SetTarget(this);
-               query->SetVolume(&volume);
-               query->PushAttr(B_MAIL_ATTR_STATUS);
-               query->PushString("New");
-               query->PushOp(B_EQ);
-               query->PushAttr("BEOS:TYPE");
-               query->PushString("text/x-email");
-               query->PushOp(B_EQ);
-               query->PushAttr("BEOS:TYPE");
-               query->PushString("text/x-partial-email");
-               query->PushOp(B_EQ);
-               query->PushOp(B_OR);
-               query->PushOp(B_AND);
-               query->Fetch();
-
-               BEntry entry;
-               while (query->GetNextEntry(&entry) == B_OK)
-                       fNewMessages++;
-
-               fQueries.AddItem(query);
-       }
-
-       BString string, numString;
-       if (fNewMessages > 0) {
-               if (fNewMessages != 1)
-                       string << B_TRANSLATE("%num new messages.");
-               else
-                       string << B_TRANSLATE("%num new message.");
-
-               numString << fNewMessages;
-               string.ReplaceFirst("%num", numString);
-       } else
-               string = B_TRANSLATE("No new messages");
+       _InitNewMessagesCount();
 
        fCentralBeep = false;
 
        fNotification = new BNotification(B_INFORMATION_NOTIFICATION);
        fNotification->SetGroup(B_TRANSLATE("Mail status"));
-       fNotification->SetTitle(string);
        fNotification->SetMessageID("daemon_status");
+       _UpdateNewMessagesNotification();
 
        app_info info;
        be_roster->GetAppInfo(B_MAIL_DAEMON_SIGNATURE, &info);
@@ -270,7 +239,7 @@ MailDaemonApplication::ReadyToRun()
        BIconUtils::GetVectorIcon(&node, "BEOS:ICON", &icon);
        fNotification->SetIcon(&icon);
 
-       fLEDAnimation = new LEDAnimation;
+       fLEDAnimation = new LEDAnimation();
        SetPulseRate(1000000);
 }
 
@@ -307,6 +276,10 @@ void
 MailDaemonApplication::MessageReceived(BMessage* msg)
 {
        switch (msg->what) {
+               case kMsgStartAutoCheck:
+                       _UpdateAutoCheckRunner();
+                       break;
+
                case kMsgAutoCheck:
                        // TODO: check whether internet is up and running!
 
@@ -325,7 +298,7 @@ MailDaemonApplication::MessageReceived(BMessage* msg)
 
                case kMsgSettingsUpdated:
                        fSettingsFile.Reload();
-                       _UpdateAutoCheck(fSettingsFile.AutoCheckInterval());
+                       _UpdateAutoCheckRunner();
                        break;
 
                case kMsgAccountsChanged:
@@ -442,21 +415,7 @@ MailDaemonApplication::MessageReceived(BMessage* msg)
                                        break;
                        }
 
-                       BString string, numString;
-
-                       if (fNewMessages > 0) {
-                               if (fNewMessages != 1)
-                                       string << B_TRANSLATE("%num new 
messages.");
-                               else
-                                       string << B_TRANSLATE("%num new 
message.");
-
-                       numString << fNewMessages;
-                       string.ReplaceFirst("%num", numString);
-                       }
-                       else
-                               string << B_TRANSLATE("No new messages.");
-
-                       fNotification->SetTitle(string.String());
+                       _UpdateNewMessagesNotification();
                        if (fNotifyMode != B_MAIL_SHOW_STATUS_WINDOW_NEVER)
                                fNotification->Send();
                        break;
@@ -838,8 +797,64 @@ MailDaemonApplication::_OutboundProtocol(int32 account)
 
 
 void
-MailDaemonApplication::_UpdateAutoCheck(bigtime_t interval)
+MailDaemonApplication::_InitNewMessagesCount()
+{
+       BVolume volume;
+       BVolumeRoster roster;
+
+       fNewMessages = 0;
+
+       while (roster.GetNextVolume(&volume) == B_OK) {
+               BQuery* query = new BQuery;
+
+               query->SetTarget(this);
+               query->SetVolume(&volume);
+               query->PushAttr(B_MAIL_ATTR_STATUS);
+               query->PushString("New");
+               query->PushOp(B_EQ);
+               query->PushAttr("BEOS:TYPE");
+               query->PushString("text/x-email");
+               query->PushOp(B_EQ);
+               query->PushAttr("BEOS:TYPE");
+               query->PushString("text/x-partial-email");
+               query->PushOp(B_EQ);
+               query->PushOp(B_OR);
+               query->PushOp(B_AND);
+               query->Fetch();
+
+               BEntry entry;
+               while (query->GetNextEntry(&entry) == B_OK)
+                       fNewMessages++;
+
+               fQueries.AddItem(query);
+       }
+}
+
+
+void
+MailDaemonApplication::_UpdateNewMessagesNotification()
+{
+       BString title;
+       if (fNewMessages > 0) {
+               if (fNewMessages != 1)
+                       title << B_TRANSLATE("%num new messages.");
+               else
+                       title << B_TRANSLATE("%num new message.");
+
+               BString numString;
+               numString << fNewMessages;
+               title.ReplaceFirst("%num", numString);
+       } else
+               title = B_TRANSLATE("No new messages");
+
+       fNotification->SetTitle(title.String());
+}
+
+
+void
+MailDaemonApplication::_UpdateAutoCheckRunner()
 {
+       bigtime_t interval = fSettingsFile.AutoCheckInterval();
        if (interval > 0) {
                if (fAutoCheckRunner != NULL) {
                        fAutoCheckRunner->SetInterval(interval);
diff --git a/src/servers/mail/MailDaemonApplication.h 
b/src/servers/mail/MailDaemonApplication.h
index 343c0c6..7960f15 100644
--- a/src/servers/mail/MailDaemonApplication.h
+++ b/src/servers/mail/MailDaemonApplication.h
@@ -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>
  * Distributed under the terms of the MIT License.
@@ -78,7 +78,9 @@ private:
                        BInboundMailProtocol* _InboundProtocol(int32 account);
                        BOutboundMailProtocol* _OutboundProtocol(int32 account);
 
-                       void                            
_UpdateAutoCheck(bigtime_t interval);
+                       void                            _InitNewMessagesCount();
+                       void                            
_UpdateNewMessagesNotification();
+                       void                            
_UpdateAutoCheckRunner();
 
                        void                            
_AddMessage(send_mails_info& info,
                                                                        const 
BEntry& entry, const BNode& node);

############################################################################

Commit:      8615ddf6df78de41ff16bcb15b5dc4d516a77755
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Wed May 22 22:40:27 2013 UTC

IMAP: make the body fetch limit setting available.

* This is set by the ProtocolConfigView -- there should really be
  some constant for this.

----------------------------------------------------------------------------

diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp 
b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp
index a5673ea..397d951 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp
@@ -101,3 +101,10 @@ Settings::IdleMode() const
 {
        return fMessage.GetBool("idle", true);
 }
+
+
+int32
+Settings::BodyFetchLimit() const
+{
+       return fMessage.GetInt32("partial_download_limit", -1);
+}
diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h 
b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h
index 3555e00..40c268c 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h
@@ -30,6 +30,7 @@ public:
 
                        int32                           MaxConnections() const;
                        bool                            IdleMode() const;
+                       int32                           BodyFetchLimit() const;
 
 private:
                        const BMessage          fMessage;

############################################################################

Commit:      636ddb712ba5c3713453e773b5e24ecfd393aa5e
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Wed May 22 22:43:16 2013 UTC

IMAP: if connecting fails, try again a few times.

* Also documented SyncCommand.

----------------------------------------------------------------------------

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 7cdf655..79ef13b 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp
@@ -89,6 +89,10 @@ public:
 };
 
 
+/*!    All commands that inherit from this class will automatically maintain 
the
+       worker's fSyncPending member, and will thus prevent syncing more than 
once
+       concurrently.
+*/
 class SyncCommand : public WorkerCommand {
 };
 
@@ -613,8 +617,19 @@ IMAPConnectionWorker::_Connect()
        if (fProtocol.IsConnected())
                return B_OK;
 
-       status_t status = fProtocol.Connect(fSettings.ServerAddress(),
-               fSettings.Username(), fSettings.Password(), fSettings.UseSSL());
+       status_t status;
+       int tries = 6;
+       while (tries-- > 0) {
+               status = fProtocol.Connect(fSettings.ServerAddress(),
+                       fSettings.Username(), fSettings.Password(), 
fSettings.UseSSL());
+               if (status == B_OK)
+                       break;
+
+               // Wait for 10 seconds, and try again
+               snooze(10000000);
+       }
+       // TODO: if other workers are connected, but it fails for us, we need to
+       // remove this worker, and reduce the number of concurrent connections
        if (status != B_OK)
                return status;
 

############################################################################

Commit:      49c03e1c524312652a0e400a7201a10b882efb64
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Wed May 22 22:50:26 2013 UTC

IMAP: work in progress of downloading the mail body.

* Most things are in place now, we just try to download the body to the
  wrong file, as the final location is currently unknown.
* Added local only kPartialMessage flag for mails, but it's not being
  used yet.

----------------------------------------------------------------------------

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 79ef13b..97add7b 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp
@@ -59,6 +59,11 @@ public:
                return fWorker._MailboxFor(folder);
        }
 
+       int32 BodyFetchLimit()
+       {
+               return fWorker.fSettings.BodyFetchLimit();
+       }
+
        status_t EnqueueCommand(WorkerCommand* command)
        {
                return fWorker._EnqueueCommand(command);
@@ -125,15 +130,78 @@ public:
 };
 
 
+class FetchBodiesCommand : public SyncCommand, public IMAP::FetchListener {
+public:
+       FetchBodiesCommand(IMAPFolder& folder, IMAPMailbox& mailbox,
+               std::vector<uint32>& entries)
+               :
+               fFolder(folder),
+               fMailbox(mailbox),
+               fEntries(entries)
+       {
+       }
+
+       virtual status_t Process(IMAPConnectionWorker& worker)
+       {
+               IMAP::Protocol& protocol = WorkerPrivate(worker).Protocol();
+
+               if (fEntries.empty())
+                       return B_OK;
+
+               fUID = *fEntries.begin();
+               fEntries.erase(fEntries.begin());
+
+               // TODO: check nextUID if we get one
+               status_t status = WorkerPrivate(worker).SelectMailbox(fFolder);
+               if (status != B_OK)
+                       return status;
+
+               printf("IMAP: fetch body for %lu\n", fUID);
+               // TODO: combine smaller messages together for faster retrieval
+               IMAP::FetchCommand fetch(fUID, fUID, IMAP::kFetchBody);
+               fetch.SetListener(this);
+
+               return protocol.ProcessCommand(fetch);
+       }
+
+       virtual bool IsDone() const
+       {
+               return fEntries.empty();
+       }
+
+       virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, size_t& 
length)
+       {
+               fFetchStatus = fFolder.StoreBody(fUID, stream, length, fRef, 
fFile);
+               return true;
+       }
+
+       virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags)
+       {
+               if (fFetchStatus == B_OK)
+                       fFolder.BodyStored(fRef, fFile, uid);
+       }
+
+private:
+       IMAPFolder&                             fFolder;
+       IMAPMailbox&                    fMailbox;
+       std::vector<uint32>             fEntries;
+       uint32                                  fUID;
+       entry_ref                               fRef;
+       BFile                                   fFile;
+       status_t                                fFetchStatus;
+};
+
+
 class FetchHeadersCommand : public SyncCommand, public IMAP::FetchListener {
 public:
        FetchHeadersCommand(IMAPFolder& folder, IMAPMailbox& mailbox,
-               uint32 from, uint32 to)
+               uint32 from, uint32 to, int32 bodyFetchLimit)
                :
                fFolder(folder),
                fMailbox(mailbox),
                fFrom(from),
-               fTo(to)
+               fTo(to),
+               fBodyFetchLimit(bodyFetchLimit)
        {
        }
 
@@ -152,8 +220,6 @@ public:
                if (to - fFrom >= kMaxFetchEntries)
                        to = fFrom + kMaxFetchEntries - 1;
 
-               // TODO: trigger download of mails for all messages below the
-               // body fetch limit
                printf("IMAP: fetch headers from %lu to %lu\n", fFrom, to);
                IMAP::FetchCommand fetch(fFrom, to,
                        IMAP::kFetchHeader | IMAP::kFetchFlags);
@@ -164,6 +230,13 @@ public:
                        return status;
 
                fFrom = to + 1;
+
+               if (IsDone() && !fFetchBodies.empty()) {
+                       // Enqueue command to fetch the message bodies
+                       WorkerPrivate(worker).EnqueueCommand(new 
FetchBodiesCommand(fFolder,
+                               fMailbox, fFetchBodies));
+               }
+
                return B_OK;
        }
 
@@ -174,15 +247,20 @@ public:
 
        virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, size_t& 
length)
        {
-               fFetchStatus = fFolder.StoreMessage(fFile, fetchFlags, stream,
-                       length, fRef);
+               fFetchStatus = fFolder.StoreMessage(fetchFlags, stream, length,
+                       fRef, fFile);
                return true;
        }
 
        virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags)
        {
-               if (fFetchStatus == B_OK)
+               if (fFetchStatus == B_OK) {
                        fFolder.MessageStored(fRef, fFile, fetchFlags, uid, 
flags);
+
+                       uint32 size = fMailbox.MessageSize(uid);
+                       if (fBodyFetchLimit < 0 || size < fBodyFetchLimit)
+                               fFetchBodies.push_back(uid);
+               }
        }
 
 private:
@@ -190,6 +268,8 @@ private:
        IMAPMailbox&                    fMailbox;
        uint32                                  fFrom;
        uint32                                  fTo;
+       uint32                                  fBodyFetchLimit;
+       std::vector<uint32>             fFetchBodies;
        entry_ref                               fRef;
        BFile                                   fFile;
        status_t                                fFetchStatus;
@@ -269,9 +349,13 @@ public:
                                return status;
 
                        // Determine how much we need to download
+                       // TODO: also retrieve the header size, and only take 
the body
+                       // size into account if it's below the limit
                        for (size_t i = 0; i < entries.size(); i++) {
                                printf("%10lu %8lu bytes, flags: %#lx\n", 
entries[i].uid,
                                        entries[i].size, entries[i].flags);
+                               fMailbox->AddMessageEntry(entries[i].uid, 
entries[i].flags,
+                                       entries[i].size);
                                fTotalBytes += entries[i].size;
                        }
                        fTotalEntries += entries.size();
@@ -283,7 +367,8 @@ public:
                                if (fMailboxEntries > 0) {
                                        // Add pending command to fetch the 
message headers
                                        WorkerCommand* command = new 
FetchHeadersCommand(*fFolder,
-                                               *fMailbox, fFirstUID, fNextUID);
+                                               *fMailbox, fFirstUID, fNextUID,
+                                               
WorkerPrivate(worker).BodyFetchLimit());
                                        if (!fFetchCommands.AddItem(command))
                                                delete command;
                                }
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 6cb060a..a7abf30 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp
@@ -132,7 +132,7 @@ IMAPFolder::IMAPFolder(IMAPProtocol& protocol, const 
BString& mailboxName,
                        uint32 uid = B_BENDIAN_TO_HOST_INT32(entries[i].uid);
                        uint32 flags = 
B_BENDIAN_TO_HOST_INT32(entries[i].flags);
 
-                       fUIDMap.insert(std::make_pair(uid, flags));
+                       fFlagsMap.insert(std::make_pair(uid, flags));
                }
        }
 
@@ -167,6 +167,29 @@ IMAPFolder::SetUIDValidity(uint32 uidValidity)
 }
 
 
+status_t
+IMAPFolder::GetMessageEntryRef(uint32 uid, entry_ref& ref) const
+{
+       UIDToRefMap::const_iterator found = fRefMap.find(uid);
+       if (found == fRefMap.end())
+               return B_ENTRY_NOT_FOUND;
+
+       ref = found->second;
+       return B_OK;
+}
+
+
+uint32
+IMAPFolder::MessageFlags(uint32 uid) const
+{
+       UIDToFlagsMap::const_iterator found = fFlagsMap.find(uid);
+       if (found == fFlagsMap.end())
+               return 0;
+
+       return found->second;
+}
+
+
 /*!    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
@@ -176,8 +199,8 @@ IMAPFolder::SetUIDValidity(uint32 uidValidity)
        were an error.
 */
 status_t
-IMAPFolder::StoreMessage(BFile& file, uint32 fetchFlags, BDataIO& stream,
-       size_t& length, entry_ref& ref)
+IMAPFolder::StoreMessage(uint32 fetchFlags, BDataIO& stream,
+       size_t& length, entry_ref& ref, BFile& file)
 {
        BPath path;
        status_t status = path.SetTo(&fRef);
@@ -189,26 +212,11 @@ IMAPFolder::StoreMessage(BFile& file, uint32 fetchFlags, 
BDataIO& stream,
        if (status != B_OK)
                return status;
 
-       char buffer[65535];
-       while (length > 0) {
-               ssize_t bytesRead = stream.Read(buffer,
-                       std::min(sizeof(buffer), length));
-               if (bytesRead < 0)
-                       return bytesRead;
-               if (bytesRead <= 0)
-                       break;
-
-               length -= bytesRead;
-
-               ssize_t bytesWritten = file.Write(buffer, bytesRead);
-               if (bytesWritten < 0)
-                       return bytesWritten;
-               if (bytesWritten != bytesRead)
-                       return B_IO_ERROR;
-       }
+       status = _WriteStream(file, stream, length);
+       if (status == B_OK)
+               temporaryFile.KeepFile();
 
-       temporaryFile.KeepFile();
-       return B_OK;
+       return status;
 }
 
 
@@ -223,29 +231,73 @@ 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
-       fProtocol.MessageStored(ref, file, fetchFlags);
+       // 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();
 
+       fRefMap.insert(std::make_pair(uid, ref));
+
        if (uid > fLastUID) {
                // Update last known UID
                fLastUID = uid;
 
                BNode directory(&fRef);
                status_t status = _WriteUInt32(directory, kLastUIDAttribute, 
uid);
-               if (status != B_OK)
+               if (status != B_OK) {
                        fprintf(stderr, "IMAP: Could not write last UID for 
mailbox "
                                "%s: %s\n", fMailboxName.String(), 
strerror(status));
+               }
        }
 }
 
 
+/*!    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.
+
+       \a length will reflect how many bytes are left to read in case there
+       were an error.
+*/
+status_t
+IMAPFolder::StoreBody(uint32 uid, BDataIO& stream, size_t& length,
+       entry_ref& ref, BFile& file)
+{
+       status_t status = GetMessageEntryRef(uid, ref);
+       if (status != B_OK)
+               return status;
+
+       status = file.SetTo(&ref, B_OPEN_AT_END | B_WRITE_ONLY);
+       if (status != B_OK)
+               return status;
+
+       BPath path(&ref);
+       printf("IMAP: write body to %s\n", path.Path());
+
+       return _WriteStream(file, stream, length);
+}
+
+
+/*!    Notifies the protocol that a body has been fetched.
+       This method also closes the \a file passed in.
+*/
+void
+IMAPFolder::BodyStored(entry_ref& ref, BFile& file, uint32 uid)
+{
+       fProtocol.MessageStored(*this, ref, file, IMAP::kFetchBody);
+       file.Unset();
+}
+
+
 void
 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)
 {
@@ -264,8 +316,8 @@ 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<uint32> lastUIDs;
-       UIDToFlagsMap::iterator iterator = fUIDMap.begin();
-       for (; iterator != fUIDMap.end(); iterator++)
+       UIDToFlagsMap::iterator iterator = fFlagsMap.begin();
+       for (; iterator != fFlagsMap.end(); iterator++)
                lastUIDs.insert(iterator->first);
 
        BDirectory directory(&fRef);
@@ -286,12 +338,11 @@ IMAPFolder::_InitializeFolderState()
                        // The message is still around
                        lastUIDs.erase(found);
 
-                       UIDToFlagsMap::iterator flagsFound = fUIDMap.find(uid);
-                       ASSERT(flagsFound != fUIDMap.end());
-                       if (flagsFound->second != flags) {
+                       uint32 flagsFound = MessageFlags(uid);
+                       if (flagsFound != flags) {
                                // Its flags have changed locally, and need to 
be updated
                                fListener->MessageFlagsChanged(_Token(uid), ref,
-                                       flagsFound->second, flags);
+                                       flagsFound, flags);
                        }
                } else {
                        // This is a new message
@@ -376,3 +427,28 @@ IMAPFolder::_WriteUInt32(BNode& node, const char* 
attribute, uint32 value)
 
        return bytesWritten < 0 ? bytesWritten : B_IO_ERROR;
 }
+
+
+status_t
+IMAPFolder::_WriteStream(BFile& file, BDataIO& stream, size_t& length)
+{
+       char buffer[65535];
+       while (length > 0) {
+               ssize_t bytesRead = stream.Read(buffer,
+                       std::min(sizeof(buffer), length));
+               if (bytesRead < 0)
+                       return bytesRead;
+               if (bytesRead <= 0)
+                       break;
+
+               length -= bytesRead;
+
+               ssize_t bytesWritten = file.Write(buffer, bytesRead);
+               if (bytesWritten < 0)
+                       return bytesWritten;
+               if (bytesWritten != bytesRead)
+                       return B_IO_ERROR;
+       }
+
+       return B_OK;
+}
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 6c9100e..997b65c 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h
@@ -24,6 +24,11 @@ struct MessageToken {
        uint32  uid;
 };
 
+// Additional local only message flags
+enum FolderMessageFlags {
+       kPartialMessage = 0x00010000,
+};
+
 
 class FolderListener {
 public:
@@ -51,13 +56,23 @@ public:
 
                        uint32                          LastUID() const { 
return fLastUID; }
 
-                       status_t                        StoreMessage(BFile& 
file, uint32 fetchFlags,
-                                                                       
BDataIO& stream, size_t& length,
-                                                                       
entry_ref& ref);
+                       status_t                        
GetMessageEntryRef(uint32 uid,
+                                                                       
entry_ref& ref) const;
+                       uint32                          MessageFlags(uint32 
uid) const;
+
+                       status_t                        StoreMessage(uint32 
fetchFlags, BDataIO& stream,
+                                                                       size_t& 
length, entry_ref& ref,
+                                                                       BFile& 
file);
                        void                            
MessageStored(entry_ref& ref, BFile& file,
                                                                        uint32 
fetchFlags, uint32 uid,
                                                                        uint32 
flags);
 
+                       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                            DeleteMessage(uint32 
uid);
                        void                            SetMessageFlags(uint32 
uid, uint32 flags);
 
@@ -75,6 +90,9 @@ private:
                        status_t                        _WriteUInt32(BNode& 
node,
                                                                        const 
char* attribute, uint32 value);
 
+                       status_t                        _WriteStream(BFile& 
file, BDataIO& stream,
+                                                                       size_t& 
length);
+
 private:
        typedef std::hash_map<uint32, uint32> UIDToFlagsMap;
        typedef std::hash_map<uint32, entry_ref> UIDToRefMap;
@@ -86,7 +104,7 @@ private:
                        uint32                          fLastUID;
                        FolderListener*         fListener;
                        UIDToRefMap                     fRefMap;
-                       UIDToFlagsMap           fUIDMap;
+                       UIDToFlagsMap           fFlagsMap;
 };
 
 
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 0703147..2c07be5 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp
@@ -24,6 +24,36 @@ IMAPMailbox::~IMAPMailbox()
 }
 
 
+void
+IMAPMailbox::AddMessageEntry(uint32 uid, uint32 flags, uint32 size)
+{
+       fMessageEntries.insert(
+               std::make_pair(uid, MessageFlagsAndSize(flags, size)));
+}
+
+
+uint32
+IMAPMailbox::MessageFlags(uint32 uid) const
+{
+       MessageEntryMap::const_iterator found = fMessageEntries.find(uid);
+       if (found == fMessageEntries.end())
+               return 0;
+
+       return found->second.flags;
+}
+
+
+uint32
+IMAPMailbox::MessageSize(uint32 uid) const
+{
+       MessageEntryMap::const_iterator found = fMessageEntries.find(uid);
+       if (found == fMessageEntries.end())
+               return 0;
+
+       return found->second.size;
+}
+
+
 uint32
 IMAPMailbox::MessageAdded(const MessageToken& fromToken, const entry_ref& ref)
 {
diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h 
b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h
index 46c1a04..352b2de 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h
@@ -22,6 +22,11 @@ public:
 
                        const BString&          MailboxName() const { return 
fMailboxName; }
 
+                       void                            AddMessageEntry(uint32 
uid, uint32 flags,
+                                                                       uint32 
size);
+                       uint32                          MessageFlags(uint32 
uid) const;
+                       uint32                          MessageSize(uint32 uid) 
const;
+
        // FolderListener interface
        virtual uint32                          MessageAdded(const 
MessageToken& fromToken,
                                                                        const 
entry_ref& ref);
@@ -32,8 +37,22 @@ public:
                                                                        uint32 
newFlags);
 
 protected:
+       struct MessageFlagsAndSize {
+               MessageFlagsAndSize(uint32 _flags, uint32 _size)
+                       :
+                       flags(_flags),
+                       size(_size)
+               {
+               }
+
+               uint32  flags;
+               uint32  size;
+       };
+       typedef std::hash_map<uint32, MessageFlagsAndSize> MessageEntryMap;
+
                        IMAP::Protocol&         fProtocol;
                        BString                         fMailboxName;
+                       MessageEntryMap         fMessageEntries;
 };
 
 
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 6b1c5e5..5499c06 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp
@@ -123,7 +123,8 @@ IMAPProtocol::WorkerQuit(IMAPConnectionWorker* worker)
 
 
 void
-IMAPProtocol::MessageStored(entry_ref& ref, BFile& stream, uint32 fetchFlags)
+IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, BFile& stream,
+       uint32 fetchFlags)
 {
        if ((fetchFlags & IMAP::kFetchHeader) != 0)
                NotifyHeaderFetched(ref, &stream);
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 c3c43a3..531b5c9 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h
@@ -34,7 +34,8 @@ public:
                                                                        
IMAP::Protocol& protocol, bool idle);
                        void                            
WorkerQuit(IMAPConnectionWorker* worker);
 
-                       void                            
MessageStored(entry_ref& ref, BFile& stream,
+                       void                            
MessageStored(IMAPFolder& folder,
+                                                                       
entry_ref& ref, BFile& stream,
                                                                        uint32 
fetchFlags);
 
        virtual status_t                        SyncMessages();
diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h 
b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h
index b47d194..634d2ec 100644
--- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h
+++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h
@@ -34,12 +34,14 @@ struct MessageEntry {
 typedef std::vector<MessageEntry> MessageEntryList;
 
 enum MessageFlags {
-       kSeen           = 0x01,
-       kAnswered       = 0x02,
-       kFlagged        = 0x04,
-       kDeleted        = 0x08,
-       kDraft          = 0x10
+       kSeen                           = 0x01,
+       kAnswered                       = 0x02,
+       kFlagged                        = 0x04,
+       kDeleted                        = 0x08,
+       kDraft                          = 0x10,
        // \Recent doesn't really have any useful meaning, so we just ignore it
+
+       kServerFlagsMask        = 0x0000ffff
 };
 
 


Other related posts:

  • » [haiku-commits] BRANCH axeld-github.imap [49c03e1] in src: add-ons/mail_daemon/inbound_protocols/imap servers/mail - axeld-github . imap