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.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <StringForSize.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <Autolock.h>
|
||||
|
||||
#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<IMAPConnectionWorker*>(this)->fLocker);
|
||||
return !fMailboxes.empty();
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
IMAPConnectionWorker::CountMailboxes() const
|
||||
{
|
||||
BAutolock locker(const_cast<IMAPConnectionWorker*>(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)
|
||||
{
|
||||
|
||||
@@ -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<IMAPFolder*, IMAPMailbox*> MailboxMap;
|
||||
|
||||
IMAPProtocol& fOwner;
|
||||
const Settings& fSettings;
|
||||
IMAP::Protocol fProtocol;
|
||||
BString fIdleBox;
|
||||
StringList fOtherBoxes;
|
||||
IMAPFolder* fIdleBox;
|
||||
MailboxMap fMailboxes;
|
||||
|
||||
BLocker fLocker;
|
||||
thread_id fThread;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, Axel Dörfler, [email protected].
|
||||
* Copyright 2012-2013, Axel Dörfler, [email protected].
|
||||
* 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<uint32>::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));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define IMAP_FOLDER_H
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <hash_map>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <Entry.h>
|
||||
@@ -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<uint32, uint32> UIDToFlagsMap;
|
||||
typedef std::map<uint32, entry_ref> UIDToRefMap;
|
||||
typedef std::hash_map<uint32, uint32> UIDToFlagsMap;
|
||||
typedef std::hash_map<uint32, entry_ref> UIDToRefMap;
|
||||
|
||||
const entry_ref fRef;
|
||||
BString fMailboxName;
|
||||
uint32 fUIDValidity;
|
||||
FolderListener& fListener;
|
||||
FolderListener* fListener;
|
||||
UIDToRefMap fRefMap;
|
||||
UIDToFlagsMap fUIDMap;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2013, Axel Dörfler, [email protected].
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2013, Axel Dörfler, [email protected].
|
||||
* 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
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <Directory.h>
|
||||
|
||||
#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 -
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define IMAP_PROTOCOL_H
|
||||
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <MailProtocol.h>
|
||||
#include <ObjectList.h>
|
||||
@@ -15,12 +15,13 @@
|
||||
|
||||
|
||||
class IMAPConnectionWorker;
|
||||
class IMAPFolder;
|
||||
namespace IMAP {
|
||||
class Protocol;
|
||||
}
|
||||
|
||||
|
||||
typedef std::set<BString> StringSet;
|
||||
typedef std::map<BString, IMAPFolder*> 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<IMAPConnectionWorker> fWorkers;
|
||||
StringSet fKnownMailboxes;
|
||||
FolderMap fFolders;
|
||||
sem_id fFolderChangeSemaphore;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2013, Axel Dörfler, [email protected].
|
||||
* 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;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2013, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef UTILITIES_H
|
||||
#define UTILITIES_H
|
||||
|
||||
|
||||
#include <String.h>
|
||||
|
||||
|
||||
BString MailboxToFolderName(const BString& mailbox, const BString& separator);
|
||||
|
||||
|
||||
#endif // UTILITIES_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011-2013, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011, Clemens Zeidler <[email protected]>
|
||||
* 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(),
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user