From a4bdd26d61967231469220573c4b5ee09e29dd49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 6 Apr 2013 01:32:39 +0200 Subject: [PATCH] imap: Work in progress of connection setup. * SelectCommand now correctly encodes the mailbox name again. * Hierarchy separators from the LIST/LSUB commands are now properly parsed, and taken into account. * Folders in the file system are now created for mailboxes on the server, supporting hierarchical mailbox names. * A connection worker now has an IMAPFolder that handles the local side of the mailbox, and an IMAPMailbox that handles the server side. * Connection workers are now created/deleted, and setup correctly. They will now also wait in case they don't have a mailbox until they get some. --- .../imap/FolderConfigWindow.cpp | 7 +- .../imap/IMAPConnectionWorker.cpp | 104 ++++++++++----- .../imap/IMAPConnectionWorker.h | 18 ++- .../inbound_protocols/imap/IMAPFolder.cpp | 22 +++- .../inbound_protocols/imap/IMAPFolder.h | 17 ++- .../inbound_protocols/imap/IMAPMailbox.cpp | 48 +++++++ .../inbound_protocols/imap/IMAPMailbox.h | 40 ++++++ .../inbound_protocols/imap/IMAPProtocol.cpp | 122 ++++++++++++++---- .../inbound_protocols/imap/IMAPProtocol.h | 15 ++- .../inbound_protocols/imap/Jamfile | 4 +- .../inbound_protocols/imap/Utilities.cpp | 21 +++ .../inbound_protocols/imap/Utilities.h | 15 +++ .../imap/imap_lib/Commands.cpp | 27 +++- .../imap/imap_lib/Commands.h | 11 +- .../imap/imap_lib/Protocol.cpp | 7 +- .../imap/imap_lib/Protocol.h | 6 +- 16 files changed, 382 insertions(+), 102 deletions(-) create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.cpp create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.h diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp index ded54729e3..b16bc18c7e 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp @@ -20,6 +20,7 @@ #include #include "Settings.h" +#include "Utilities.h" #undef B_TRANSLATION_CONTEXT @@ -332,10 +333,12 @@ FolderConfigWindow::_LoadFolders() // TODO: don't get all of them at once, but retrieve them level by level fFolderList.clear(); - fProtocol.GetFolders(fFolderList); + BString separator; + fProtocol.GetFolders(fFolderList, separator); for (size_t i = 0; i < fFolderList.size(); i++) { IMAP::FolderEntry& entry = fFolderList[i]; - CheckBoxItem* item = new CheckBoxItem(entry.folder, entry.subscribed); + CheckBoxItem* item = new CheckBoxItem( + MailboxToFolderName(entry.folder, separator), entry.subscribed); fFolderListView->AddItem(item); item->SetListView(fFolderListView); } 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 2f5318319d..9eeddd8a4b 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp @@ -8,6 +8,8 @@ #include +#include "IMAPFolder.h" +#include "IMAPMailbox.h" #include "IMAPProtocol.h" @@ -16,6 +18,7 @@ IMAPConnectionWorker::IMAPConnectionWorker(IMAPProtocol& owner, : fOwner(owner), fSettings(settings), + fIdleBox(NULL), fMain(main), fStopped(false) { @@ -27,55 +30,54 @@ IMAPConnectionWorker::~IMAPConnectionWorker() } +bool +IMAPConnectionWorker::HasMailboxes() const +{ + BAutolock locker(const_cast(this)->fLocker); + return !fMailboxes.empty(); +} + + uint32 IMAPConnectionWorker::CountMailboxes() const { BAutolock locker(const_cast(this)->fLocker); - return (fIdleBox.IsEmpty() ? 0 : 1) + fOtherBoxes.size(); + return fMailboxes.size(); } void -IMAPConnectionWorker::AddMailbox(const BString& name) +IMAPConnectionWorker::AddMailbox(IMAPFolder* folder) { BAutolock locker(fLocker); - if (fSettings.IdleMode() && fIdleBox.IsEmpty()) { - fIdleBox = name; - } else if (fSettings.IdleMode() && name == "INBOX") { - // Prefer to have the INBOX in idle mode over other mail boxes - fOtherBoxes.push_back(fIdleBox); - fIdleBox = name; - } else - fOtherBoxes.push_back(name); + fMailboxes.insert(std::make_pair(folder, (IMAPMailbox*)NULL)); + + // Prefer to have the INBOX in idle mode over other mail boxes + if (fIdleBox == NULL || folder->MailboxName().ICompare("INBOX") == 0) + fIdleBox = folder; } void -IMAPConnectionWorker::RemoveMailbox(const BString& name) +IMAPConnectionWorker::RemoveAllMailboxes() { BAutolock locker(fLocker); - if (fSettings.IdleMode() && fIdleBox == name) { - if (!fOtherBoxes.empty()) { - fIdleBox = fOtherBoxes[0]; - fOtherBoxes.erase(fOtherBoxes.begin()); - } else - fIdleBox.SetTo(NULL); - } else { - StringList::iterator iterator = fOtherBoxes.begin(); - for (; iterator != fOtherBoxes.end(); iterator++) { - if (*iterator == name) { - fOtherBoxes.erase(iterator); - break; - } - } + // Reset listeners, and delete the mailboxes + MailboxMap::iterator iterator = fMailboxes.begin(); + for (; iterator != fMailboxes.end(); iterator++) { + iterator->first->SetListener(NULL); + delete iterator->second; } + + fIdleBox = NULL; + fMailboxes.clear(); } status_t -IMAPConnectionWorker::Start() +IMAPConnectionWorker::Run() { fThread = spawn_thread(&_Worker, "imap connection worker", B_NORMAL_PRIORITY, this); @@ -88,7 +90,7 @@ IMAPConnectionWorker::Start() void -IMAPConnectionWorker::Stop() +IMAPConnectionWorker::Quit() { // TODO: we'll also need to interrupt listening to the socket fStopped = true; @@ -103,6 +105,10 @@ IMAPConnectionWorker::_Worker() if (status != B_OK) return status; + bool idle = fSettings.IdleMode() + && fProtocol.Capabilities().Contains("IDLE"); + bool initial = true; + while (!fStopped) { if (fMain) { // The main worker checks the subscribed folders, and creates @@ -112,14 +118,39 @@ IMAPConnectionWorker::_Worker() BAutolock locker(fLocker); - if (!fIdleBox.IsEmpty()) - printf("%p: IDLE: %s\n", this, fIdleBox.String()); - - StringList::iterator iterator = fOtherBoxes.begin(); - for (; iterator != fOtherBoxes.end(); iterator++) { - printf("%p: check: %s\n", this, iterator->String()); + if (!HasMailboxes()) { + locker.Unlock(); + _Wait(); + continue; } + if (!initial && idle && fIdleBox != NULL) { + printf("%p: IDLE: %s\n", this, fIdleBox->MailboxName().String()); + // TODO: enter IDLE mode + } + + MailboxMap::iterator iterator = fMailboxes.begin(); + for (; iterator != fMailboxes.end(); iterator++) { + IMAPFolder* folder = iterator->first; + if (!initial && idle && folder == fIdleBox) + continue; + + printf("%p: check: %s\n", this, folder->MailboxName().String()); + IMAPMailbox* mailbox = iterator->second; + if (mailbox == NULL) { + mailbox = new IMAPMailbox(fProtocol, folder->MailboxName()); + folder->SetListener(mailbox); + } + + IMAP::SelectCommand select(folder->MailboxName().String()); + status_t status = fProtocol.ProcessCommand(select); + if (status == B_OK) { + folder->SetUIDValidity(select.UIDValidity()); + // TODO: trigger download of mails until UIDNext() + } + } + + initial = false; // TODO: for now break; } @@ -128,6 +159,13 @@ IMAPConnectionWorker::_Worker() } +void +IMAPConnectionWorker::_Wait() +{ + while (acquire_sem(fOwner.FolderChangeSemaphore()) == B_INTERRUPTED); +} + + /*static*/ status_t IMAPConnectionWorker::_Worker(void* _self) { 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 de5763b07a..5475387f33 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h @@ -12,6 +12,8 @@ #include "Protocol.h" +class IMAPFolder; +class IMAPMailbox; class IMAPProtocol; class Settings; @@ -23,25 +25,29 @@ public: bool main = false); virtual ~IMAPConnectionWorker(); + bool HasMailboxes() const; uint32 CountMailboxes() const; - void AddMailbox(const BString& name); - void RemoveMailbox(const BString& name); + void AddMailbox(IMAPFolder* folder); + void RemoveAllMailboxes(); bool IsMain() const { return fMain; } - status_t Start(); - void Stop(); + status_t Run(); + void Quit(); private: status_t _Worker(); + void _Wait(); static status_t _Worker(void* self); private: + typedef std::map MailboxMap; + IMAPProtocol& fOwner; const Settings& fSettings; IMAP::Protocol fProtocol; - BString fIdleBox; - StringList fOtherBoxes; + IMAPFolder* fIdleBox; + MailboxMap fMailboxes; BLocker fLocker; thread_id fThread; 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 7b8b5c533f..4c3d40a64d 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, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2012-2013, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -21,10 +21,11 @@ static const char* kStateAttribute = "IMAP:state"; static const char* kUIDAttribute = "MAIL:unique_id"; -IMAPFolder::IMAPFolder(const entry_ref& ref, FolderListener& listener) +IMAPFolder::IMAPFolder(const BString& mailboxName, const entry_ref& ref) : fRef(ref), - fListener(listener) + fMailboxName(mailboxName), + fUIDValidity(UINT32_MAX) { // Initialize from folder attributes BNode node(&ref); @@ -81,8 +82,16 @@ IMAPFolder::~IMAPFolder() void -IMAPFolder::SetFolderID(const char* mailboxName, uint32 id) +IMAPFolder::SetListener(FolderListener* listener) { + fListener = listener; +} + + +void +IMAPFolder::SetUIDValidity(uint32 uidValidity) +{ + fUIDValidity = uidValidity; } @@ -132,6 +141,7 @@ IMAPFolder::_InitializeFolderState() 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 @@ -141,14 +151,14 @@ IMAPFolder::_InitializeFolderState() ASSERT(flagsFound != fUIDMap.end()); if (flagsFound->second != flags) { // Its flags have changed locally, and need to be updated - fListener.MessageFlagsChanged(_Token(uid), ref, + fListener->MessageFlagsChanged(_Token(uid), ref, flagsFound->second, flags); } } else { // This is a new message // TODO: the token must be the originating token! // TODO: uid might be udpated from the call - uid = fListener.MessageAdded(_Token(uid), ref); + uid = fListener->MessageAdded(_Token(uid), ref); } fRefMap.insert(std::make_pair(uid, ref)); 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 0fd4b8997f..11a69aaf10 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h @@ -6,7 +6,7 @@ #define IMAP_FOLDER_H -#include +#include #include #include @@ -36,11 +36,14 @@ public: class IMAPFolder : public BHandler { public: - IMAPFolder(const entry_ref& ref, - FolderListener& listener); + IMAPFolder(const BString& mailboxName, + const entry_ref& ref); virtual ~IMAPFolder(); - void SetFolderID(const char* mailboxName, uint32 id); + const BString& MailboxName() const { return fMailboxName; } + + void SetListener(FolderListener* listener); + void SetUIDValidity(uint32 uidValidity); void StoreMessage(uint32 uid, ...); void DeleteMessage(uint32 uid); @@ -55,13 +58,13 @@ private: uint32 _ReadFlags(BNode& node); private: - typedef std::map UIDToFlagsMap; - typedef std::map UIDToRefMap; + typedef std::hash_map UIDToFlagsMap; + typedef std::hash_map UIDToRefMap; const entry_ref fRef; BString fMailboxName; uint32 fUIDValidity; - FolderListener& fListener; + FolderListener* fListener; UIDToRefMap fRefMap; UIDToFlagsMap fUIDMap; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp new file mode 100644 index 0000000000..0703147ff3 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +/*! This class offers a high level look at an IMAP mailbox. +*/ + + +#include "IMAPMailbox.h" + + +IMAPMailbox::IMAPMailbox(IMAP::Protocol& protocol, const BString& mailboxName) + : + fProtocol(protocol), + fMailboxName(mailboxName) +{ +} + + +IMAPMailbox::~IMAPMailbox() +{ +} + + +uint32 +IMAPMailbox::MessageAdded(const MessageToken& fromToken, const entry_ref& ref) +{ + printf("IMAP: message added %s, uid %lu\n", ref.name, fromToken.uid); + return 0; +} + + +void +IMAPMailbox::MessageDeleted(const MessageToken& token) +{ + printf("IMAP: message deleted, uid %lu\n", token.uid); +} + + +void +IMAPMailbox::MessageFlagsChanged(const MessageToken& token, + const entry_ref& ref, uint32 oldFlags, uint32 newFlags) +{ + printf("IMAP: flags changed %s, uid %lu, from %lx to %lx\n", ref.name, + token.uid, oldFlags, newFlags); +} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h new file mode 100644 index 0000000000..46c1a04b0b --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPMailbox.h @@ -0,0 +1,40 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef IMAP_MAILBOX_H +#define IMAP_MAILBOX_H + + +#include "IMAPFolder.h" + + +namespace IMAP { + class Protocol; +}; + + +class IMAPMailbox : public FolderListener { +public: + IMAPMailbox(IMAP::Protocol& protocol, + const BString& mailboxName); + virtual ~IMAPMailbox(); + + const BString& MailboxName() const { return fMailboxName; } + + // FolderListener interface + virtual uint32 MessageAdded(const MessageToken& fromToken, + const entry_ref& ref); + virtual void MessageDeleted(const MessageToken& token); + + virtual void MessageFlagsChanged(const MessageToken& token, + const entry_ref& ref, uint32 oldFlags, + uint32 newFlags); + +protected: + IMAP::Protocol& fProtocol; + BString fMailboxName; +}; + + +#endif // IMAP_MAILBOX_H 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 ee3e24dd85..5476273096 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.cpp @@ -9,6 +9,8 @@ #include #include "IMAPConnectionWorker.h" +#include "IMAPFolder.h" +#include "Utilities.h" IMAPProtocol::IMAPProtocol(const BMailAccountSettings& settings) @@ -24,6 +26,10 @@ IMAPProtocol::IMAPProtocol(const BMailAccountSettings& settings) destination.Path(), strerror(status)); } + status = _CreateFolderChangeSemaphore(); + if (status != B_OK) + fprintf(stderr, "imap: Failed to create sem: %s\n", strerror(status)); + PostMessage(B_READY_TO_RUN); } @@ -38,51 +44,73 @@ IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol) { // Get list of subscribed folders - StringList folders; - status_t status = protocol.GetSubscribedFolders(folders); + StringList newFolders; + BString separator; + status_t status = protocol.GetSubscribedFolders(newFolders, separator); if (status != B_OK) return status; // Determine how many new mailboxes we have - StringList::iterator iterator = folders.begin(); - for (; iterator != folders.end(); iterator++) { - if (fKnownMailboxes.find(*iterator) != fKnownMailboxes.end()) - iterator = folders.erase(iterator); + StringList::iterator folderIterator = newFolders.begin(); + while (folderIterator != newFolders.end()) { + if (fFolders.find(*folderIterator) != fFolders.end()) + folderIterator = newFolders.erase(folderIterator); + else + folderIterator++; } - if (fSettings.IdleMode()) { - // Create connection workers as allowed + int32 totalMailboxes = fFolders.size() + newFolders.size(); + int32 workersWanted = 1; + if (fSettings.IdleMode()) + workersWanted = std::min(fSettings.MaxConnections(), totalMailboxes); - int32 totalMailboxes = fKnownMailboxes.size() + folders.size(); + if (newFolders.empty() && fWorkers.CountItems() == workersWanted) { + // Nothing to do - we've already distributed everything + return B_OK; + } - while (fWorkers.CountItems() < fSettings.MaxConnections() - && fWorkers.CountItems() < totalMailboxes) { - IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, - fSettings); - if (!fWorkers.AddItem(worker)) { - delete worker; - break; - } + // Remove mailboxes from workers + for (int32 i = 0; i < fWorkers.CountItems(); i++) { + fWorkers.ItemAt(i)->RemoveAllMailboxes(); + } - worker->Start(); + // Create/remove connection workers as allowed and needed + while (fWorkers.CountItems() < workersWanted) { + IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, + fSettings); + if (!fWorkers.AddItem(worker)) { + delete worker; + break; } + + worker->Run(); + } + while (fWorkers.CountItems() > workersWanted) { + IMAPConnectionWorker* worker + = fWorkers.RemoveItemAt(fWorkers.CountItems() - 1); + worker->Quit(); } - // Distribute the new mailboxes to the existing workers + // Update known mailboxes + folderIterator = newFolders.begin(); + for (; folderIterator != newFolders.end(); folderIterator++) { + const BString& mailbox = *folderIterator; + fFolders.insert(std::make_pair(mailbox, + _CreateFolder(mailbox, separator))); + } + // Distribute the mailboxes evenly to the workers + FolderMap::iterator iterator = fFolders.begin(); int32 index = 0; - while (!folders.empty()) { - BString folder = folders[0]; - folders.erase(folders.begin()); - - fWorkers.ItemAt(index)->AddMailbox(folder); - fKnownMailboxes.insert(folder); - + for (; iterator != fFolders.end(); iterator++) { + fWorkers.ItemAt(index)->AddMailbox(iterator->second); index = (index + 1) % fWorkers.CountItems(); } - return B_OK; + // Restart waiting workers + delete_sem(fFolderChangeSemaphore); + return _CreateFolderChangeSemaphore(); } @@ -100,7 +128,7 @@ IMAPProtocol::SyncMessages() return B_NO_MEMORY; } - return worker->Start(); + return worker->Run(); } return B_OK; @@ -163,6 +191,44 @@ IMAPProtocol::ReadyToRun() } +IMAPFolder* +IMAPProtocol::_CreateFolder(const BString& mailbox, const BString& separator) +{ + BString name = MailboxToFolderName(mailbox, separator); + + BPath path(fSettings.Destination()); + if (path.Append(name.String()) != B_OK) { + fprintf(stderr, "Could not append path: %s\n", name.String()); + return NULL; + } + + status_t status = create_directory(path.Path(), 0755); + if (status != B_OK) { + fprintf(stderr, "Could not create path %s: %s\n", path.Path(), + strerror(status)); + return NULL; + } + + entry_ref ref; + status = get_ref_for_path(path.Path(), &ref); + if (status != B_OK) { + fprintf(stderr, "Could not get ref for %s: %s\n", path.Path(), + strerror(status)); + return NULL; + } + + return new IMAPFolder(mailbox, ref); +} + + +status_t +IMAPProtocol::_CreateFolderChangeSemaphore() +{ + fFolderChangeSemaphore = create_sem(0, "imap folder change"); + return fFolderChangeSemaphore < 0 ? fFolderChangeSemaphore : B_OK; +} + + // #pragma mark - 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 dff40d3811..bdbb3c31a8 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPProtocol.h @@ -6,7 +6,7 @@ #define IMAP_PROTOCOL_H -#include +#include #include #include @@ -15,12 +15,13 @@ class IMAPConnectionWorker; +class IMAPFolder; namespace IMAP { class Protocol; } -typedef std::set StringSet; +typedef std::map FolderMap; class IMAPProtocol : public BInboundMailProtocol { @@ -31,6 +32,8 @@ public: status_t CheckSubscribedFolders( IMAP::Protocol& protocol); + sem_id FolderChangeSemaphore() const + { return fFolderChangeSemaphore; } virtual status_t SyncMessages(); virtual status_t FetchBody(const entry_ref& ref); @@ -44,10 +47,16 @@ public: protected: void ReadyToRun(); +private: + IMAPFolder* _CreateFolder(const BString& mailbox, + const BString& separator); + status_t _CreateFolderChangeSemaphore(); + protected: Settings fSettings; BObjectList fWorkers; - StringSet fKnownMailboxes; + FolderMap fFolders; + sem_id fFolderChangeSemaphore; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile index ff846fc482..c3a497bd25 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile @@ -16,14 +16,14 @@ UseLibraryHeaders linprog alm ; SubDirHdrs [ FDirName $(HAIKU_TOP) headers os add-ons mail_daemon ] ; local sources = -# IMAPInboundProtocol.cpp -# IMAPRootInboundProtocol.cpp IMAPProtocol.cpp ConfigView.cpp FolderConfigWindow.cpp IMAPFolder.cpp IMAPConnectionWorker.cpp + IMAPMailbox.cpp Settings.cpp + Utilities.cpp # imap_lib Commands.cpp diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.cpp new file mode 100644 index 0000000000..f1a74c27d6 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Utilities.h" + + +BString +MailboxToFolderName(const BString& mailbox, const BString& separator) +{ + if (separator == "/") + return mailbox; + + BString name = mailbox; + name.ReplaceAll('/', '_'); + name.ReplaceAll(separator.String(), "/"); + + return name; +} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.h b/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.h new file mode 100644 index 0000000000..944a1239a2 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Utilities.h @@ -0,0 +1,15 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UTILITIES_H +#define UTILITIES_H + + +#include + + +BString MailboxToFolderName(const BString& mailbox, const BString& separator); + + +#endif // UTILITIES_H 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 114b12b2bd..d8f14d276f 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, Haiku, Inc. All rights reserved. + * Copyright 2011-2013, Haiku, Inc. All rights reserved. * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. */ @@ -202,10 +202,10 @@ SelectCommand::SelectCommand() SelectCommand::SelectCommand(const char* name) : - fMailboxName(name), fNextUID(0), fUIDValidity(0) { + SetTo(name); } @@ -216,7 +216,6 @@ SelectCommand::CommandString() return ""; BString command = "SELECT \""; - // TODO: properly quote the string! command += fMailboxName; command += "\""; return command; @@ -243,6 +242,14 @@ SelectCommand::HandleUntagged(Response& response) } +void +SelectCommand::SetTo(const char* mailboxName) +{ + RFC3501Encoding encoding; + fMailboxName = encoding.Encode(mailboxName); +} + + // #pragma mark - @@ -654,10 +661,20 @@ ListCommand::CommandString() bool ListCommand::HandleUntagged(Response& response) { - if (response.IsCommand(_Command()) && response.IsStringAt(3)) { + if (response.IsCommand(_Command()) && response.IsStringAt(2) + && response.IsStringAt(3)) { + fSeparator = response.StringAt(2); + BString folder = response.StringAt(3); + if (folder == "") + return true; + try { - fFolders.push_back(fEncoding.Decode(folder)); + folder = fEncoding.Decode(folder); + // The folder INBOX is always case insensitive + if (folder.ICompare("INBOX") == 0) + folder = "Inbox"; + fFolders.push_back(folder); } catch (ParseException& exception) { // Decoding failed, just add the plain text fprintf(stderr, "Decoding \"%s\" failed: %s\n", folder.String(), 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 6b9d053ccf..ab37af938a 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 @@ -1,5 +1,5 @@ /* - * Copyright 2010-2011, Haiku Inc. All Rights Reserved. + * Copyright 2010-2013, Haiku Inc. All Rights Reserved. * Copyright 2010 Clemens Zeidler. All rights reserved. * * Distributed under the terms of the MIT License. @@ -97,8 +97,7 @@ public: virtual BString CommandString(); virtual bool HandleUntagged(Response& response); - void SetTo(const char* mailboxName) - { fMailboxName = mailboxName; } + void SetTo(const char* mailboxName); uint32 NextUID() { return fNextUID; } uint32 UIDValidity() { return fUIDValidity; } @@ -249,10 +248,11 @@ public: ListCommand(const char* prefix, bool subscribedOnly); - BString CommandString(); - bool HandleUntagged(Response& response); + virtual BString CommandString(); + virtual bool HandleUntagged(Response& response); const StringList& FolderList(); + const BString& Separator() { return fSeparator; } private: const char* _Command() const; @@ -261,6 +261,7 @@ private: RFC3501Encoding fEncoding; const char* fPrefix; StringList fFolders; + BString fSeparator; bool fSubscribedOnly; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp index e811dcb428..858932f41c 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp @@ -110,7 +110,7 @@ Protocol::IsConnected() status_t -Protocol::GetFolders(FolderList& folders) +Protocol::GetFolders(FolderList& folders, BString& separator) { StringList allFolders; status_t status = _GetAllFolders(allFolders); @@ -118,7 +118,7 @@ Protocol::GetFolders(FolderList& folders) return status; StringList subscribedFolders; - status = GetSubscribedFolders(subscribedFolders); + status = GetSubscribedFolders(subscribedFolders, separator); if (status != B_OK) return status; @@ -158,7 +158,7 @@ Protocol::GetFolders(FolderList& folders) status_t -Protocol::GetSubscribedFolders(StringList& folders) +Protocol::GetSubscribedFolders(StringList& folders, BString& separator) { ListCommand command(NULL, true); status_t status = ProcessCommand(command); @@ -166,6 +166,7 @@ Protocol::GetSubscribedFolders(StringList& folders) return status; folders = command.FolderList(); + separator = command.Separator(); return status; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h index 15fabf9203..3f65bc1632 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h @@ -66,8 +66,10 @@ public: ssize_t SendData(const char* buffer, uint32 length); // Some convenience methods - status_t GetFolders(FolderList& folders); - status_t GetSubscribedFolders(StringList& folders); + status_t GetFolders(FolderList& folders, + BString& separator); + status_t GetSubscribedFolders(StringList& folders, + BString& separator); status_t SubscribeFolder(const char* folder); status_t UnsubscribeFolder(const char* folder); status_t GetQuota(uint64& used, uint64& total);