From f06916d5726232b9e535ef50a5b7e860b793be6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 9 Aug 2012 13:33:24 +0200 Subject: [PATCH] Initial work on a class that manages an IMAP folder on disk. --- .../inbound_protocols/imap/IMAPFolder.cpp | 188 ++++++++++++++++++ .../inbound_protocols/imap/IMAPFolder.h | 69 +++++++ .../inbound_protocols/imap/Jamfile | 1 + 3 files changed, 258 insertions(+) create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp new file mode 100644 index 0000000000..7b8b5c533f --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2012, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "IMAPFolder.h" + +#include + +#include +#include +#include +#include +#include + + +static const char* kMailboxNameAttribute = "IMAP:mailbox"; +static const char* kUIDValidityAttribute = "IMAP:uidvalidity"; +static const char* kStateAttribute = "IMAP:state"; +static const char* kUIDAttribute = "MAIL:unique_id"; + + +IMAPFolder::IMAPFolder(const entry_ref& ref, FolderListener& listener) + : + fRef(ref), + fListener(listener) +{ + // Initialize from folder attributes + BNode node(&ref); + if (node.InitCheck() != B_OK) + return; + + if (node.ReadAttrString(kMailboxNameAttribute, &fMailboxName) != B_OK) + return; + + uint32 uidValidity; + if (node.ReadAttr(kUIDValidityAttribute, B_UINT32_TYPE, 0, &uidValidity, + sizeof(uint32)) != sizeof(uint32)) + return; + + fUIDValidity = B_BENDIAN_TO_HOST_INT32(uidValidity); + + attr_info info; + status_t 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; + } + + 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; + } + + for (size_t i = 0; i < info.size / sizeof(entry); i++) { + 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)); + } + } + + // Initialize current state from actual folder + // TODO: this should be done in another thread + _InitializeFolderState(); +} + + +IMAPFolder::~IMAPFolder() +{ +} + + +void +IMAPFolder::SetFolderID(const char* mailboxName, uint32 id) +{ +} + + +void +IMAPFolder::StoreMessage(uint32 uid, ...) +{ +} + + +void +IMAPFolder::DeleteMessage(uint32 uid) +{ +} + + +void +IMAPFolder::SetMessageFlags(uint32 uid, uint32 flags) +{ +} + + +void +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 = fUIDMap.begin(); + for (; iterator != fUIDMap.end(); iterator++) + lastUIDs.insert(iterator->first); + + BDirectory directory(&fRef); + BEntry entry; + while (directory.GetNextEntry(&entry) == B_OK) { + entry_ref ref; + BNode node; + if (!entry.IsFile() || entry.GetRef(&ref) != B_OK + || node.SetTo(&entry) != B_OK) + continue; + + uint32 uid = _ReadUniqueID(node); + uint32 flags = _ReadFlags(node); + + std::set::iterator found = lastUIDs.find(uid); + if (found != lastUIDs.end()) { + // The message is still around + lastUIDs.erase(found); + + UIDToFlagsMap::iterator flagsFound = fUIDMap.find(uid); + ASSERT(flagsFound != fUIDMap.end()); + if (flagsFound->second != flags) { + // Its flags have changed locally, and need to be updated + 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); + } + + fRefMap.insert(std::make_pair(uid, ref)); + } +} + + +const MessageToken +IMAPFolder::_Token(uint32 uid) const +{ + MessageToken token; + token.mailboxName = fMailboxName; + token.uidValidity = fUIDValidity; + token.uid = uid; + + return token; +} + + +uint32 +IMAPFolder::_ReadUniqueID(BNode& node) +{ + // For compatibility we must assume that the UID is stored as a string + BString string; + if (node.ReadAttrString(kUIDAttribute, &string) != B_OK) + return 0; + + return strtoul(string.String(), NULL, 0); +} + + +uint32 +IMAPFolder::_ReadFlags(BNode& node) +{ + // TODO! + return 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 new file mode 100644 index 0000000000..75d2982ec0 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h @@ -0,0 +1,69 @@ +/* + * Copyright 2012, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef IMAP_FOLDER_H +#define IMAP_FOLDER_H + + +#include +#include + +#include +#include +#include + + +struct MessageToken { + BString mailboxName; + uint32 uidValidity; + uint32 uid; +}; + + +class FolderListener { +public: + 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); +}; + + +class IMAPFolder : public BHandler { +public: + IMAPFolder(const entry_ref& ref, + FolderListener& listener); + virtual ~IMAPFolder(); + + void SetFolderID(const char* mailboxName, uint32 id); + + void StoreMessage(uint32 uid, ...); + 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); + uint32 _ReadFlags(BNode& node); + +private: + typedef std::map UIDToFlagsMap; + typedef std::map UIDToRefMap; + + const entry_ref fRef; + BString fMailboxName; + uint32 fUIDValidity; + FolderListener& fListener; + UIDToRefMap fRefMap; + UIDToFlagsMap fUIDMap; +}; + + +#endif // IMAP_FOLDER_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile index 40b980b70f..8345f8b5a8 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile @@ -20,6 +20,7 @@ local sources = # IMAPRootInboundProtocol.cpp ConfigView.cpp FolderConfigWindow.cpp + IMAPFolder.cpp IMAPConnectionWorker.cpp Settings.cpp