IMAP: setting flags, and body fetching works now.
* The direct methods in BMailProtocol now forward the request to the looper; it's no longer the mail_daemon's responsibility to know anything about that protocol. * It's in desperate need of refactoring, but it doesn't hurt to add it to the repository as is.
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013, Axel Dörfler, [email protected].
|
||||
* Copyright 2011-2016, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "IMAPConnectionWorker.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <Messenger.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
@@ -141,12 +142,13 @@ public:
|
||||
class FetchBodiesCommand : public SyncCommand, public IMAP::FetchListener {
|
||||
public:
|
||||
FetchBodiesCommand(IMAPFolder& folder, IMAPMailbox& mailbox,
|
||||
std::vector<uint32>& 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<uint32> 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<uint32> 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<uint32> 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);
|
||||
|
||||
@@ -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 <Locker.h>
|
||||
#include <String.h>
|
||||
|
||||
//#include "Commands.h"
|
||||
#include "Protocol.h"
|
||||
|
||||
|
||||
@@ -20,7 +19,6 @@ class Settings;
|
||||
class WorkerCommand;
|
||||
class WorkerPrivate;
|
||||
|
||||
|
||||
typedef BObjectList<WorkerCommand> 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);
|
||||
|
||||
@@ -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 <Directory.h>
|
||||
#include <File.h>
|
||||
#include <fs_attr.h>
|
||||
#include <Messenger.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include "Commands.h"
|
||||
#include <NodeMessage.h>
|
||||
|
||||
#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<uint32> 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<uint32>::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<uint32>::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) {
|
||||
|
||||
@@ -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 <Handler.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <locks.h>
|
||||
|
||||
#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<BMessenger> MessengerList;
|
||||
#if __GNUC__ >= 4
|
||||
typedef __gnu_cxx::hash_map<uint32, uint32> UIDToFlagsMap;
|
||||
typedef __gnu_cxx::hash_map<uint32, entry_ref> UIDToRefMap;
|
||||
typedef __gnu_cxx::hash_map<uint32, MessengerList> MessengerMap;
|
||||
#else
|
||||
typedef std::hash_map<uint32, uint32> UIDToFlagsMap;
|
||||
typedef std::hash_map<uint32, entry_ref> UIDToRefMap;
|
||||
typedef std::hash_map<uint32, MessengerList> 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 <Directory.h>
|
||||
#include <Messenger.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 <MailProtocol.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include <locks.h>
|
||||
|
||||
#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<IMAPFolder*, IMAPConnectionWorker*> WorkerMap;
|
||||
typedef std::map<ino_t, IMAPFolder*> FolderNodeMap;
|
||||
|
||||
Settings fSettings;
|
||||
mutex fWorkerLock;
|
||||
BObjectList<IMAPConnectionWorker> fWorkers;
|
||||
WorkerMap fWorkerMap;
|
||||
FolderMap fFolders;
|
||||
FolderNodeMap fFolderNodeMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011-2016, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
|
||||
* 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;
|
||||
|
||||
@@ -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 <haiku@clemens-zeidler.de>
|
||||
*
|
||||
@@ -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)
|
||||
|
||||
@@ -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 <haiku@clemens-zeidler.de>
|
||||
*
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 <haiku@clemens-zeidler.de>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user