mirror of
https://review.haiku-os.org/haiku
synced 2025-01-22 22:34:48 +01:00
Initial work on a class that manages an IMAP folder on disk.
This commit is contained in:
parent
077338a9b8
commit
f06916d572
188
src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp
Normal file
188
src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp
Normal file
@ -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 <set>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <Debug.h>
|
||||
#include <Directory.h>
|
||||
#include <fs_attr.h>
|
||||
#include <Node.h>
|
||||
|
||||
|
||||
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<uint32> 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<uint32>::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;
|
||||
}
|
69
src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h
Normal file
69
src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h
Normal file
@ -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 <map>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <Handler.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
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<uint32, uint32> UIDToFlagsMap;
|
||||
typedef std::map<uint32, entry_ref> UIDToRefMap;
|
||||
|
||||
const entry_ref fRef;
|
||||
BString fMailboxName;
|
||||
uint32 fUIDValidity;
|
||||
FolderListener& fListener;
|
||||
UIDToRefMap fRefMap;
|
||||
UIDToFlagsMap fUIDMap;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAP_FOLDER_H
|
@ -20,6 +20,7 @@ local sources =
|
||||
# IMAPRootInboundProtocol.cpp
|
||||
ConfigView.cpp
|
||||
FolderConfigWindow.cpp
|
||||
IMAPFolder.cpp
|
||||
IMAPConnectionWorker.cpp
|
||||
Settings.cpp
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user