IMAP: removed superfluous files from the old implementation.

This commit is contained in:
Axel Dörfler
2015-12-22 19:35:08 +01:00
parent 958bf09770
commit 184619e625
9 changed files with 0 additions and 2154 deletions
@@ -1,143 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_H
#define IMAP_H
#include "MailProtocol.h"
#include <Handler.h>
#include <Locker.h>
#include <Message.h>
#include "MailSettings.h"
#include "Protocol.h"
#include "IMAPStorage.h"
class DispatcherIMAPListener : public IMAPMailboxListener {
public:
DispatcherIMAPListener(MailProtocol& protocol,
IMAPStorage& storage);
bool Lock();
void Unlock();
void HeaderFetched(int32 uid, BPositionIO* data,
bool bodyIsComming);
void BodyFetched(int32 uid, BPositionIO* data);
void NewMessagesToFetch(int32 nMessages);
void FetchEnd();
private:
MailProtocol& fProtocol;
IMAPStorage& fStorage;
};
class IMAPInboundProtocol;
/*! Just wait for a IDLE (watching) IMAP response in this thread. */
class IMAPMailboxThread {
public:
IMAPMailboxThread(IMAPInboundProtocol& protocol,
IMAPMailbox& mailbox);
~IMAPMailboxThread();
bool IsWatching();
status_t SyncAndStartWatchingMailbox();
status_t StopWatchingMailbox();
private:
static status_t _WatchThreadFunction(void* data);
void _Watch();
private:
IMAPInboundProtocol& fProtocol;
IMAPMailbox& fIMAPMailbox;
BLocker fLock;
bool fIsWatching;
thread_id fThread;
sem_id fWatchSyncSem;
};
class IMAPInboundProtocol;
class MailboxWatcher : public BHandler {
public:
MailboxWatcher(IMAPInboundProtocol* protocol);
~MailboxWatcher();
void StartWatching(const char* mailboxDir);
void MessageReceived(BMessage* message);
private:
node_ref fWatchDir;
IMAPInboundProtocol* fProtocol;
};
class IMAPInboundProtocol : public InboundProtocol {
public:
IMAPInboundProtocol(
BMailAccountSettings* settings,
const char* mailbox);
virtual ~IMAPInboundProtocol();
//! thread safe interface
virtual status_t Connect(const char* server,
const char* username, const char* password,
bool useSSL = true, int32 port = -1);
virtual status_t Disconnect();
status_t Reconnect();
bool IsConnected();
virtual void SetStopNow();
void AddedToLooper();
void UpdateSettings(const BMessage& settings);
bool InterestingEntry(const entry_ref& ref);
virtual status_t SyncMessages();
virtual status_t FetchBody(const entry_ref& ref);
virtual status_t MarkMessageAsRead(const entry_ref& ref,
read_flags flag = B_READ);
virtual status_t DeleteMessage(const entry_ref& ref);
virtual status_t AppendMessage(const entry_ref& ref);
virtual status_t DeleteMessage(node_ref& node);
//! these should be thread save
virtual void FileRenamed(const entry_ref& from,
const entry_ref& to);
virtual void FileDeleted(const node_ref& node);
protected:
BString fServer;
BString fUsername;
BString fPassword;
bool fUseSSL;
bool fIsConnected;
BString fMailboxName;
BPath fMailboxPath;
IMAPStorage fStorage;
IMAPMailbox fIMAPMailbox;
DispatcherIMAPListener fDispatcherIMAPListener;
MailboxWatcher* fINBOXWatcher;
IMAPMailboxThread* fIMAPMailboxThread;
};
#endif // IMAP_H
@@ -1,615 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#include "IMAPInboundProtocol.h"
#include <stdlib.h>
#include <Autolock.h>
#include <Directory.h>
#include <Messenger.h>
#include <NodeMonitor.h>
#include <crypt.h>
const uint32 kMsgStartWatching = '&StW';
DispatcherIMAPListener::DispatcherIMAPListener(MailProtocol& protocol,
IMAPStorage& storage)
:
fProtocol(protocol),
fStorage(storage)
{
}
void
DispatcherIMAPListener::HeaderFetched(int32 uid, BPositionIO* data,
bool bodyIsComing)
{
BFile* file = dynamic_cast<BFile*>(data);
if (file == NULL)
return;
entry_ref ref;
if (!fStorage.UIDToRef(uid, ref))
return;
fProtocol.NotifyHeaderFetched(ref, file);
if (!bodyIsComing)
fProtocol.ReportProgress(0, 1);
}
void
DispatcherIMAPListener::BodyFetched(int32 uid, BPositionIO* data)
{
BFile* file = dynamic_cast<BFile*>(data);
if (file == NULL)
return;
entry_ref ref;
if (!fStorage.UIDToRef(uid, ref))
return;
fProtocol.NotifyBodyFetched(ref, file);
fProtocol.ReportProgress(0, 1);
}
void
DispatcherIMAPListener::NewMessagesToFetch(int32 nMessages)
{
fProtocol.NotifyNewMessagesToFetch(nMessages);
}
void
DispatcherIMAPListener::FetchEnd()
{
fProtocol.ReportProgress(0, 1);
}
// #pragma mark -
IMAPMailboxThread::IMAPMailboxThread(IMAPInboundProtocol& protocol,
IMAPMailbox& mailbox)
:
fProtocol(protocol),
fIMAPMailbox(mailbox),
fIsWatching(false),
fThread(-1)
{
fWatchSyncSem = create_sem(0, "watch sync sem");
}
IMAPMailboxThread::~IMAPMailboxThread()
{
delete_sem(fWatchSyncSem);
}
bool
IMAPMailboxThread::IsWatching()
{
BAutolock _(fLock);
return fIsWatching;
}
status_t
IMAPMailboxThread::SyncAndStartWatchingMailbox()
{
if (!fProtocol.IsConnected())
return B_ERROR;
if (fIMAPMailbox.SupportWatching()) {
BAutolock autolock(fLock);
if (fIsWatching)
return B_OK;
fThread = spawn_thread(_WatchThreadFunction, "IMAPMailboxThread",
B_LOW_PRIORITY, this);
if (resume_thread(fThread) != B_OK) {
fThread = -1;
return B_ERROR;
}
acquire_sem(fWatchSyncSem);
fIsWatching = true;
} else {
status_t status = fIMAPMailbox.CheckMailbox();
// if we lost connection reconnect and try again
if (status != B_OK)
status = fProtocol.Reconnect();
if (status != B_OK)
return status;
status = fIMAPMailbox.CheckMailbox();
if (status != B_OK)
return status;
}
return B_OK;
}
status_t
IMAPMailboxThread::StopWatchingMailbox()
{
status_t status = fIMAPMailbox.StopWatchingMailbox();
if (status != B_OK)
return status;
// wait till watching stopped
status_t exitCode;
return wait_for_thread(fThread, &exitCode);
}
/*static*/ status_t
IMAPMailboxThread::_WatchThreadFunction(void* data)
{
((IMAPMailboxThread*)data)->_Watch();
return B_OK;
}
void
IMAPMailboxThread::_Watch()
{
status_t status = fIMAPMailbox.StartWatchingMailbox(fWatchSyncSem);
if (status != B_OK)
fProtocol.Disconnect();
fLock.Lock();
fIsWatching = false;
fLock.Unlock();
fThread = -1;
}
// #pragma mark -
MailboxWatcher::MailboxWatcher(IMAPInboundProtocol* protocol)
:
fProtocol(protocol)
{
}
MailboxWatcher::~MailboxWatcher()
{
stop_watching(this);
}
void
MailboxWatcher::StartWatching(const char* mailboxDir)
{
create_directory(mailboxDir, 0755);
BDirectory dir(mailboxDir);
dir.GetNodeRef(&fWatchDir);
watch_node(&fWatchDir, B_WATCH_DIRECTORY, this);
}
void
MailboxWatcher::MessageReceived(BMessage* message)
{
int32 opcode;
entry_ref ref;
node_ref nref;
const char* name;
switch (message->what) {
case B_NODE_MONITOR:
if (message->FindInt32("opcode", &opcode) != B_OK)
break;
switch (opcode) {
case B_ENTRY_CREATED:
break;
message->FindInt32("device", &ref.device);
message->FindInt64("directory", &ref.directory);
message->FindString("name", &name);
ref.set_name(name);
fProtocol->AppendMessage(ref);
break;
case B_ENTRY_REMOVED:
message->FindInt32("device", &nref.device);
message->FindInt64("node", &nref.node);
fProtocol->DeleteMessage(nref);
break;
case B_ENTRY_MOVED:
{
break;
entry_ref from;
entry_ref to;
ino_t toDirectory = -1;
ino_t fromDirectory = -2;
message->FindInt64("to directory", &toDirectory);
message->FindInt64("from directory", &fromDirectory);
if (toDirectory != fromDirectory)
break;
message->FindInt32("device", &to.device);
message->FindInt64("directory", &to.directory);
message->FindString("name", &name);
to.set_name(name);
from.device = to.device;
from.directory = to.directory;
from.set_name(message->FindString("from name"));
fProtocol->Looper()->TriggerFileRenamed(from, to);
break;
if (fWatchDir.node == toDirectory) {
// append
message->FindInt32("device", &ref.device);
ref.directory = toDirectory;
message->FindString("name", &name);
ref.set_name(name);
fProtocol->AppendMessage(ref);
} else {
// delete
message->FindInt32("device", &nref.device);
message->FindInt64("node", &nref.node);
fProtocol->DeleteMessage(nref);
}
break;
}
}
default:
BHandler::MessageReceived(message);
}
}
// #pragma mark -
IMAPInboundProtocol::IMAPInboundProtocol(BMailAccountSettings* settings,
const char* mailbox)
:
InboundProtocol(settings),
fIsConnected(false),
fMailboxName(mailbox),
fIMAPMailbox(fStorage),
fDispatcherIMAPListener(*this, fStorage),
fINBOXWatcher(NULL)
{
const BMessage& settingsMsg = fAccountSettings.InboundSettings().Settings();
int32 bodyLimit = 0;
if (settingsMsg.HasInt32("partial_download_limit"))
bodyLimit = settingsMsg.FindInt32("partial_download_limit");
BString tempString;
if (settingsMsg.FindString("destination", &tempString) != B_OK) {
tempString = "/boot/home/mail/";
tempString += settings->Name();
}
fMailboxPath.SetTo(tempString);
fMailboxPath.Append(fMailboxName);
fStorage.SetTo(fMailboxPath.Path());
fIMAPMailbox.SetListener(&fDispatcherIMAPListener);
fIMAPMailbox.SetFetchBodyLimit(bodyLimit);
fIMAPMailboxThread = new IMAPMailboxThread(*this, fIMAPMailbox);
// set watch directory
fINBOXWatcher = new MailboxWatcher(this);
AddHandler(fINBOXWatcher);
}
IMAPInboundProtocol::~IMAPInboundProtocol()
{
fIMAPMailboxThread->StopWatchingMailbox();
RemoveHandler(fINBOXWatcher);
delete fINBOXWatcher;
delete fIMAPMailboxThread;
}
status_t
IMAPInboundProtocol::Connect(const char* server, const char* username,
const char* password, bool useSSL, int32 port)
{
if (fIsConnected)
return B_OK;
BString statusMessage;
statusMessage = "Connect to: ";
statusMessage += username;
SetTotalItems(5);
ReportProgress(0, 1, statusMessage);
status_t status = fIMAPMailbox.Connect(server, username, password, useSSL,
port);
if (status != B_OK) {
if (fIMAPMailbox.CommandError().CountChars() > 0) {
// This was a IMAP error
statusMessage = "Failed to login: ";
statusMessage += fIMAPMailbox.CommandError();
} else {
// Probably a connection error
statusMessage = "Connection error: ";
statusMessage += strerror(status);
}
ShowError(statusMessage);
ResetProgress();
return status;
}
ReportProgress(0, 1, "Load database");
fStorage.StartReadDatabase();
status = fIMAPMailbox.SelectMailbox(fMailboxName);
if (status != B_OK) {
fStorage.WaitForDatabaseRead();
statusMessage = "Failed to select mailbox (";
statusMessage += fMailboxName;
statusMessage += "): ";
statusMessage += fIMAPMailbox.CommandError();
ShowError(statusMessage);
ResetProgress();
return status;
}
ReportProgress(0, 1, "Fetch message list");
status = fIMAPMailbox.Sync();
if (status != B_OK) {
fStorage.WaitForDatabaseRead();
ShowError("Failed to sync mailbox");
ResetProgress();
return status;
}
ReportProgress(0, 1, "Read local message list");
status = fStorage.WaitForDatabaseRead();
if (status != B_OK) {
ShowError("Can't read database");
ResetProgress();
return status;
}
ReportProgress(0, 1, "Sync mailbox");
IMAPMailboxSync mailboxSync;
status = mailboxSync.Sync(fStorage, fIMAPMailbox);
ResetProgress();
if (status == B_OK)
fIsConnected = true;
else
Disconnect();
return status;
}
status_t
IMAPInboundProtocol::Disconnect()
{
fIsConnected = false;
return fIMAPMailbox.Disconnect();
}
status_t
IMAPInboundProtocol::Reconnect()
{
Disconnect();
return Connect(fServer, fUsername, fPassword, fUseSSL, -1);
}
bool
IMAPInboundProtocol::IsConnected()
{
if (!fIsConnected)
return false;
if (fIMAPMailbox.IsConnected())
return true;
Disconnect();
return false;
}
void
IMAPInboundProtocol::SetStopNow()
{
fIMAPMailbox.SetStopNow();
}
void
IMAPInboundProtocol::AddedToLooper()
{
fINBOXWatcher->StartWatching(fMailboxPath.Path());
const BMessage& settingsMsg = fAccountSettings.InboundSettings().Settings();
UpdateSettings(settingsMsg);
}
void
IMAPInboundProtocol::UpdateSettings(const BMessage& settings)
{
settings.FindString("server", &fServer);
int32 ssl;
settings.FindInt32("flavor", &ssl);
if (ssl == 1)
fUseSSL = true;
else
fUseSSL = false;
settings.FindString("username", &fUsername);
char* passwd = get_passwd(&settings, "cpasswd");
if (passwd) {
fPassword = passwd;
delete[] passwd;
}
SyncMessages();
}
bool
IMAPInboundProtocol::InterestingEntry(const entry_ref& ref)
{
BEntry entry(&ref);
return BDirectory(fMailboxPath.Path()).Contains(&entry, B_FILE_NODE);
}
status_t
IMAPInboundProtocol::SyncMessages()
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
return fIMAPMailboxThread->SyncAndStartWatchingMailbox();
}
status_t
IMAPInboundProtocol::FetchBody(const entry_ref& ref)
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
fIMAPMailboxThread->StopWatchingMailbox();
int32 uid = fStorage.RefToUID(ref);
ResetProgress("Fetch body");
SetTotalItems(1);
status_t status = fIMAPMailbox.FetchBody(fIMAPMailbox.UIDToMessageNumber(
uid));
ResetProgress();
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return status;
}
status_t
IMAPInboundProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flag)
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
fIMAPMailboxThread->StopWatchingMailbox();
int32 uid = fStorage.RefToUID(ref);
int32 flags = fStorage.GetFlags(uid);
if (flag == B_READ)
flags |= kSeen;
else
flags &= ~kSeen;
status_t status = fIMAPMailbox.SetFlags(
fIMAPMailbox.UIDToMessageNumber(uid), flags);
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
if (status != B_OK)
return status;
return InboundProtocol::MarkMessageAsRead(ref, flag);
}
status_t
IMAPInboundProtocol::DeleteMessage(const entry_ref& ref)
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
fIMAPMailboxThread->StopWatchingMailbox();
int32 uid = fStorage.RefToUID(ref);
status_t status = fIMAPMailbox.DeleteMessage(uid, false);
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return status;
}
void
IMAPInboundProtocol::FileRenamed(const entry_ref& from, const entry_ref& to)
{
fStorage.FileRenamed(from, to);
}
void
IMAPInboundProtocol::FileDeleted(const node_ref& node)
{
//TODO
}
status_t
IMAPInboundProtocol::AppendMessage(const entry_ref& ref)
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
fIMAPMailboxThread->StopWatchingMailbox();
BFile file(&ref, B_READ_ONLY);
off_t size;
file.GetSize(&size);
// check if file is already known
int32 uid = -1;
file.ReadAttr("MAIL:unique_id", B_INT32_TYPE, 0, &uid, sizeof(int32));
if (fStorage.HasFile(uid)) {
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return B_BAD_VALUE;
}
int32 flags = 0;
file.ReadAttr("MAIL:server_flags", B_INT32_TYPE, 0, &flags, sizeof(int32));
status_t status = fIMAPMailbox.AppendMessage(file, size, flags);
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return status;
}
status_t
IMAPInboundProtocol::DeleteMessage(node_ref& node)
{
if (!IsConnected())
Connect(fServer, fUsername, fPassword, fUseSSL);
fIMAPMailboxThread->StopWatchingMailbox();
StorageMailEntry* entry = fStorage.GetEntryForRef(node);
if (entry == NULL) {
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return B_BAD_VALUE;
}
int32 uid = entry->uid;
status_t status = fIMAPMailbox.DeleteMessage(uid, false);
fIMAPMailboxThread->SyncAndStartWatchingMailbox();
return status;
}
@@ -1,143 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_INBOUND_PROTOCOL_H
#define IMAP_INBOUND_PROTOCOL_H
#include "MailProtocol.h"
#include <Handler.h>
#include <Locker.h>
#include <Message.h>
#include "MailSettings.h"
#include "Protocol.h"
#include "IMAPStorage.h"
class DispatcherIMAPListener : public IMAPMailboxListener {
public:
DispatcherIMAPListener(MailProtocol& protocol,
IMAPStorage& storage);
bool Lock();
void Unlock();
void HeaderFetched(int32 uid, BPositionIO* data,
bool bodyIsComming);
void BodyFetched(int32 uid, BPositionIO* data);
void NewMessagesToFetch(int32 nMessages);
void FetchEnd();
private:
MailProtocol& fProtocol;
IMAPStorage& fStorage;
};
class IMAPInboundProtocol;
/*! Just wait for a IDLE (watching) IMAP response in this thread. */
class IMAPMailboxThread {
public:
IMAPMailboxThread(IMAPInboundProtocol& protocol,
IMAPMailbox& mailbox);
~IMAPMailboxThread();
bool IsWatching();
status_t SyncAndStartWatchingMailbox();
status_t StopWatchingMailbox();
private:
static status_t _WatchThreadFunction(void* data);
void _Watch();
private:
IMAPInboundProtocol& fProtocol;
IMAPMailbox& fIMAPMailbox;
BLocker fLock;
bool fIsWatching;
thread_id fThread;
sem_id fWatchSyncSem;
};
class IMAPInboundProtocol;
class MailboxWatcher : public BHandler {
public:
MailboxWatcher(IMAPInboundProtocol* protocol);
~MailboxWatcher();
void StartWatching(const char* mailboxDir);
void MessageReceived(BMessage* message);
private:
node_ref fWatchDir;
IMAPInboundProtocol* fProtocol;
};
class IMAPInboundProtocol : public InboundProtocol {
public:
IMAPInboundProtocol(
BMailAccountSettings* settings,
const char* mailbox);
virtual ~IMAPInboundProtocol();
//! thread safe interface
virtual status_t Connect(const char* server,
const char* username, const char* password,
bool useSSL = true, int32 port = -1);
virtual status_t Disconnect();
status_t Reconnect();
bool IsConnected();
virtual void SetStopNow();
void AddedToLooper();
void UpdateSettings(const BMessage& settings);
bool InterestingEntry(const entry_ref& ref);
virtual status_t SyncMessages();
virtual status_t FetchBody(const entry_ref& ref);
virtual status_t MarkMessageAsRead(const entry_ref& ref,
read_flags flag = B_READ);
virtual status_t DeleteMessage(const entry_ref& ref);
virtual status_t AppendMessage(const entry_ref& ref);
virtual status_t DeleteMessage(node_ref& node);
//! these should be thread save
virtual void FileRenamed(const entry_ref& from,
const entry_ref& to);
virtual void FileDeleted(const node_ref& node);
protected:
BString fServer;
BString fUsername;
BString fPassword;
bool fUseSSL;
bool fIsConnected;
BString fMailboxName;
BPath fMailboxPath;
IMAPStorage fStorage;
IMAPMailbox fIMAPMailbox;
DispatcherIMAPListener fDispatcherIMAPListener;
MailboxWatcher* fINBOXWatcher;
IMAPMailboxThread* fIMAPMailboxThread;
};
#endif // IMAP_INBOUND_PROTOCOL_H
@@ -1,185 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#include "IMAPRootInboundProtocol.h"
#include <Messenger.h>
IMAPRootInboundProtocol::IMAPRootInboundProtocol(BMailAccountSettings* settings)
:
IMAPInboundProtocol(settings, "INBOX")
{
}
IMAPRootInboundProtocol::~IMAPRootInboundProtocol()
{
_ShutdownChilds();
}
status_t
IMAPRootInboundProtocol::Connect(const char* server, const char* username,
const char* password, bool useSSL, int32 port)
{
status_t status = IMAPInboundProtocol::Connect(server, username, password,
useSSL, port);
if (status != B_OK)
return status;
FolderList folders;
fIMAPMailbox.GetFolders(folders);
for (unsigned int i = 0; i < folders.size(); i++) {
if (!folders[i].subscribed || folders[i].folder == "INBOX")
continue;
IMAPInboundProtocol* inboundProtocol = new IMAPInboundProtocol(
&fAccountSettings, folders[i].folder);
inboundProtocol->SetMailNotifier(fMailNotifier->Clone());
InboundProtocolThread* inboundThread = new InboundProtocolThread(
inboundProtocol);
inboundThread->Run();
fProtocolThreadList.AddItem(inboundThread);
}
return status;
}
status_t
IMAPRootInboundProtocol::Disconnect()
{
status_t status = IMAPInboundProtocol::Disconnect();
_ShutdownChilds();
return status;
}
void
IMAPRootInboundProtocol::SetStopNow()
{
for (int32 i = 0; i < fProtocolThreadList.CountItems(); i++)
fProtocolThreadList.ItemAt(i)->SetStopNow();
IMAPInboundProtocol::SetStopNow();
}
status_t
IMAPRootInboundProtocol::SyncMessages()
{
for (int32 i = 0; i < fProtocolThreadList.CountItems(); i++)
fProtocolThreadList.ItemAt(i)->SyncMessages();
return IMAPInboundProtocol::SyncMessages();
}
status_t
IMAPRootInboundProtocol::FetchBody(const entry_ref& ref)
{
if (InterestingEntry(ref))
return IMAPInboundProtocol::FetchBody(ref);
InboundProtocolThread* thread = _FindThreadFor(ref);
if (!thread)
return B_BAD_VALUE;
thread->FetchBody(ref);
return B_OK;
}
status_t
IMAPRootInboundProtocol::MarkMessageAsRead(const entry_ref& ref,
read_flags flag)
{
if (InterestingEntry(ref))
return IMAPInboundProtocol::MarkMessageAsRead(ref, flag);
InboundProtocolThread* thread = _FindThreadFor(ref);
if (!thread)
return B_BAD_VALUE;
thread->MarkMessageAsRead(ref, flag);
return B_OK;
}
status_t
IMAPRootInboundProtocol::DeleteMessage(const entry_ref& ref)
{
if (InterestingEntry(ref))
return IMAPInboundProtocol::DeleteMessage(ref);
InboundProtocolThread* thread = _FindThreadFor(ref);
if (!thread)
return B_BAD_VALUE;
thread->DeleteMessage(ref);
return B_OK;
}
status_t
IMAPRootInboundProtocol::AppendMessage(const entry_ref& ref)
{
if (InterestingEntry(ref))
return IMAPInboundProtocol::AppendMessage(ref);
InboundProtocolThread* thread = _FindThreadFor(ref);
if (!thread)
return B_BAD_VALUE;
thread->AppendMessage(ref);
return B_OK;
}
status_t
IMAPRootInboundProtocol::DeleteMessage(node_ref& node)
{
status_t status = IMAPInboundProtocol::DeleteMessage(node);
if (status == B_OK)
return status;
for (int32 i = 0; i < fProtocolThreadList.CountItems(); i++)
fProtocolThreadList.ItemAt(i)->TriggerFileDeleted(node);
return B_OK;
}
void
IMAPRootInboundProtocol::_ShutdownChilds()
{
BMessage reply;
for (int32 i = 0; i < fProtocolThreadList.CountItems(); i++) {
InboundProtocolThread* thread = fProtocolThreadList.ItemAt(i);
MailProtocol* protocol = thread->Protocol();
thread->SetStopNow();
BMessenger(thread).SendMessage(B_QUIT_REQUESTED, &reply);
delete protocol;
}
fProtocolThreadList.MakeEmpty();
}
InboundProtocolThread*
IMAPRootInboundProtocol::_FindThreadFor(const entry_ref& ref)
{
for (int32 i = 0; i < fProtocolThreadList.CountItems(); i++) {
InboundProtocolThread* thread = fProtocolThreadList.ItemAt(i);
IMAPInboundProtocol* protocol
= (IMAPInboundProtocol*)thread->Protocol();
if (protocol->InterestingEntry(ref))
return thread;
}
return NULL;
}
// #pragma mark -
InboundProtocol*
instantiate_inbound_protocol(BMailAccountSettings* settings)
{
return new IMAPRootInboundProtocol(settings);
}
@@ -1,51 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_ROOT_INBOUND_PROTOCOL_H
#define IMAP_ROOT_INBOUND_PROTOCOL_H
#include "IMAPInboundProtocol.h"
#include "MailAddon.h"
typedef BObjectList<InboundProtocolThread> ProtocolThreadList;
/*! Hold the main INBOX mailbox and manage all the other other mailboxes. */
class IMAPRootInboundProtocol : public IMAPInboundProtocol {
public:
IMAPRootInboundProtocol(
BMailAccountSettings* settings);
~IMAPRootInboundProtocol();
//! thread safe interface
status_t Connect(const char* server,
const char* username, const char* password,
bool useSSL = true, int32 port = -1);
status_t Disconnect();
void SetStopNow();
status_t SyncMessages();
status_t FetchBody(const entry_ref& ref);
status_t MarkMessageAsRead(const entry_ref& ref,
read_flags flag = B_READ);
status_t DeleteMessage(const entry_ref& ref);
status_t AppendMessage(const entry_ref& ref);
status_t DeleteMessage(node_ref& node);
private:
void _ShutdownChilds();
InboundProtocolThread* _FindThreadFor(const entry_ref& ref);
ProtocolThreadList fProtocolThreadList;
};
#endif // IMAP_ROOT_INBOUND_PROTOCOL_H
@@ -1,304 +0,0 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#include "IMAPMailbox.h"
#include "IMAPHandler.h"
#include "IMAPStorage.h"
#define DEBUG_IMAP_MAILBOX
#ifdef DEBUG_IMAP_MAILBOX
# include <stdio.h>
# define TRACE(x...) printf(x)
#else
# define TRACE(x...) ;
#endif
MinMessage::MinMessage()
{
uid = 0;
flags = 0;
}
// #pragma mark -
IMAPMailbox::IMAPMailbox(IMAPStorage& storage)
:
fStorage(storage),
fMailboxSelectHandler(*this),
fExistsHandler(*this),
fExpungeHandler(*this),
fFlagsHandler(*this),
fWatching(0),
fFetchBodyLimit(0)
{
fIMAPMailboxListener = &fNULLListener;
}
IMAPMailbox::~IMAPMailbox()
{
Disconnect();
}
void
IMAPMailbox::SetListener(IMAPMailboxListener* listener)
{
if (listener == NULL)
fIMAPMailboxListener = &fNULLListener;
else
fIMAPMailboxListener = listener;
}
BString
IMAPMailbox::Mailbox()
{
return fSelectedMailbox;
}
status_t
IMAPMailbox::Sync()
{
TRACE("Sync\n");
if (fMailboxSelectHandler.NextUID() <= 1)
return B_OK;
_InstallUnsolicitedHandler(false);
fMessageList.clear();
FetchMessageListCommand fetchMessageListCommand(*this, &fMessageList,
fMailboxSelectHandler.NextUID());
status_t status = ProcessCommand(&fetchMessageListCommand);
if (status != B_OK)
return status;
_InstallUnsolicitedHandler(true);
return B_OK;
}
bool
IMAPMailbox::SupportWatching()
{
if (fCapabilityHandler.Capabilities().FindFirst("IDLE") < 0)
return false;
return true;
}
status_t
IMAPMailbox::StartWatchingMailbox(sem_id startedSem)
{
atomic_set(&fWatching, 1);
bool firstIDLE = true;
// refresh every 29 min
bigtime_t timeout = 1000 * 1000 * 60 * 29; // 29 min
status_t status;
while (true) {
int32 commandID = NextCommandID();
TRACE("IDLE ...\n");
status = SendCommand("IDLE", commandID);
if (firstIDLE) {
release_sem(startedSem);
firstIDLE = false;
}
if (status != B_OK)
break;
status = HandleResponse(commandID, timeout, false);
ProcessAfterQuacks(kIMAP4ClientTimeout);
if (atomic_get(&fWatching) == 0)
break;
if (status == B_TIMED_OUT) {
TRACE("Renew IDLE connection.\n");
status = SendRawCommand("DONE");
if (status != B_OK)
break;
// handle IDLE response and more
status = ProcessCommand("NOOP");
if (status != B_OK)
break;
else
continue;
}
if (status != B_OK)
break;
}
atomic_set(&fWatching, 0);
return status;
}
status_t
IMAPMailbox::StopWatchingMailbox()
{
if (atomic_get(&fWatching) == 0)
return B_OK;
atomic_set(&fWatching, 0);
return SendRawCommand("DONE");
}
status_t
IMAPMailbox::CheckMailbox()
{
return ProcessCommand("NOOP");
}
status_t
IMAPMailbox::FetchMinMessage(int32 messageNumber, BPositionIO** data)
{
if (messageNumber <= 0)
return B_BAD_VALUE;
FetchMinMessageCommand fetchMinMessageCommand(*this, messageNumber,
&fMessageList, data);
return ProcessCommand(&fetchMinMessageCommand);
}
status_t
IMAPMailbox::FetchBody(int32 messageNumber, BPositionIO* data)
{
if (data == NULL || messageNumber <= 0) {
delete data;
return B_BAD_VALUE;
}
FetchBodyCommand fetchBodyCommand(*this, messageNumber, data);
status_t status = ProcessCommand(&fetchBodyCommand);
return status;
}
void
IMAPMailbox::SetFetchBodyLimit(int32 limit)
{
fFetchBodyLimit = limit;
}
status_t
IMAPMailbox::FetchMessage(int32 messageNumber)
{
return FetchMessages(messageNumber, -1);
}
status_t
IMAPMailbox::FetchMessages(int32 firstMessage, int32 lastMessage)
{
FetchMessageCommand fetchCommand(*this, firstMessage, lastMessage,
fFetchBodyLimit);
return ProcessCommand(&fetchCommand);
}
status_t
IMAPMailbox::FetchBody(int32 messageNumber)
{
if (fStorage.IsBodyFetched(MessageNumberToUID(messageNumber)))
return B_BAD_VALUE;
BPositionIO* file;
status_t status = fStorage.OpenMessage(MessageNumberToUID(messageNumber),
&file);
if (status != B_OK)
return status;
// fetch command deletes the file
status = FetchBody(messageNumber, file);
return status;
}
status_t
IMAPMailbox::SetFlags(int32 messageNumber, int32 flags)
{
if (messageNumber <= 0)
return B_BAD_VALUE;
SetFlagsCommand setFlagsCommand(*this, messageNumber, flags);
return ProcessCommand(&setFlagsCommand);
}
status_t
IMAPMailbox::AppendMessage(BPositionIO& message, off_t size, int32 flags,
time_t time)
{
AppendCommand appendCommand(*this, message, size, flags, time);
return ProcessCommand(&appendCommand);
}
int32
IMAPMailbox::UIDToMessageNumber(int32 uid)
{
for (unsigned int i = 0; i < fMessageList.size(); i++) {
if (fMessageList[i].uid == uid)
return i + 1;
}
return -1;
}
int32
IMAPMailbox::MessageNumberToUID(int32 messageNumber)
{
int32 index = messageNumber - 1;
if (index < 0 || index >= (int32)fMessageList.size())
return -1;
return fMessageList[index].uid;
}
status_t
IMAPMailbox::DeleteMessage(int32 uid, bool permanently)
{
int32 flags = fStorage.GetFlags(uid);
flags |= kDeleted;
status_t status = SetFlags(UIDToMessageNumber(uid), flags);
if (!permanently || status != B_OK)
return status;
// delete permanently by invoking expunge
ExpungeCommmand expungeCommand(*this);
return ProcessCommand(&expungeCommand);
}
void
IMAPMailbox::_InstallUnsolicitedHandler(bool install)
{
if (install) {
fHandlerList.AddItem(&fFlagsHandler, 0);
fHandlerList.AddItem(&fExpungeHandler, 0);
fHandlerList.AddItem(&fExistsHandler, 0);
} else {
fHandlerList.RemoveItem(&fFlagsHandler);
fHandlerList.RemoveItem(&fExpungeHandler);
fHandlerList.RemoveItem(&fExistsHandler);
}
}
@@ -1,98 +0,0 @@
/*
* Copyright 2010, Haiku Inc. All Rights Reserved.
* Copyright 2010 Clemens Zeidler. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_MAILBOX_H
#define IMAP_MAILBOX_H
#include <DataIO.h>
#include "IMAPHandler.h"
#include "IMAPProtocol.h"
class IMAPMailboxListener {
public:
virtual ~IMAPMailboxListener() {}
virtual void HeaderFetched(int32 uid, BPositionIO* data,
bool bodyIsComing) {}
virtual void BodyFetched(int32 uid, BPositionIO* data) {}
virtual void NewMessagesToFetch(int32 nMessages) {}
virtual void FetchEnd() {}
};
class IMAPStorage;
class IMAPMailbox : public IMAP::Protocol {
public:
IMAPMailbox(IMAPStorage& storage);
~IMAPMailbox();
void SetListener(IMAPMailboxListener* listener);
IMAPMailboxListener& Listener() { return *fIMAPMailboxListener; }
/*! Select mailbox and sync with the storage. */
BString Mailbox();
status_t Sync();
bool SupportWatching();
status_t StartWatchingMailbox(sem_id startedSem = -1);
status_t StopWatchingMailbox();
status_t CheckMailbox();
//! Low level fetch functions.
status_t FetchMinMessage(int32 messageNumber,
BPositionIO** data = NULL);
status_t FetchBody(int32 messageNumber,
BPositionIO* data);
void SetFetchBodyLimit(int32 limit);
int32 FetchBodyLimit() { return fFetchBodyLimit; }
status_t FetchMessage(int32 messageNumber);
status_t FetchMessages(int32 firstMessage,
int32 lastMessage);
status_t FetchBody(int32 messageNumber);
status_t SetFlags(int32 messageNumber, int32 flags);
status_t AppendMessage(BPositionIO& message, off_t size,
int32 flags = 0, time_t time = -1);
int32 GetCurrentMessageCount()
{ return fMessageList.size(); }
const IMAP::MinMessageList& GetMessageList() { return fMessageList; }
IMAPStorage& GetStorage() { return fStorage; }
int32 UIDToMessageNumber(int32 uid);
int32 MessageNumberToUID(int32 messageNumber);
status_t DeleteMessage(int32 uid, bool permanently);
private:
void _InstallUnsolicitedHandler(bool install);
IMAP::MinMessageList fMessageList;
IMAPStorage& fStorage;
IMAPMailboxListener* fIMAPMailboxListener;
IMAPMailboxListener fNULLListener;
IMAP::ExistsHandler fExistsHandler;
IMAP::ExpungeHandler fExpungeHandler;
// FlagsHandler fFlagsHandler;
int32 fWatching;
BString fSelectedMailbox;
int32 fFetchBodyLimit;
};
#endif // IMAP_MAILBOX_H
@@ -1,513 +0,0 @@
/*
* Copyright 2010-2011, Haiku Inc. All Rights Reserved.
* Copyright 2010 Clemens Zeidler. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include "IMAPStorage.h"
#include <stdlib.h>
#include <Directory.h>
#include <Entry.h>
#include <NodeInfo.h>
#include <OS.h>
#include <mail_util.h>
#include "IMAPMailbox.h"
#define DEBUG_IMAP_STORAGE
#ifdef DEBUG_IMAP_STORAGE
# include <stdio.h>
# define TRACE(x...) printf(x)
#else
# define TRACE(x...) /* nothing */
#endif
status_t
IMAPMailboxSync::Sync(IMAPStorage& storage, IMAPMailbox& mailbox)
{
const MailEntryMap& files = storage.GetFiles();
const MinMessageList& messages = mailbox.GetMessageList();
for (MailEntryMap::const_iterator it = files.begin(); it != files.end();
it++) {
const StorageMailEntry& mailEntry = (*it).second;
bool found = false;
for (unsigned int a = 0; a < messages.size(); a++) {
const MinMessage& minMessage = messages[a];
if (mailEntry.uid == minMessage.uid) {
found = true;
if (mailEntry.flags != minMessage.flags)
storage.SetFlags(mailEntry.uid, minMessage.flags);
break;
}
}
if (!found)
storage.DeleteMessage(mailEntry.uid);
}
for (unsigned int i = 0; i < messages.size(); i++) {
const MinMessage& minMessage = messages[i];
bool found = false;
for (MailEntryMap::const_iterator it = files.begin(); it != files.end();
it++) {
const StorageMailEntry& mailEntry = (*it).second;
if (mailEntry.uid == minMessage.uid) {
found = true;
break;
}
}
if (!found)
fToFetchList.push_back(i + 1);
}
mailbox.Listener().NewMessagesToFetch(fToFetchList.size());
// fetch headers in big bunches if possible
int32 fetchCount = 0;
int32 start = -1;
int32 end = -1;
int32 lastId = -1;
for (unsigned int i = 0; i < fToFetchList.size(); i++) {
if (mailbox.StopNow())
return B_ERROR;
int32 current = fToFetchList[i];
fetchCount++;
if (start < 0) {
start = current;
lastId = current;
continue;
}
if (current - 1 == lastId) {
end = current;
lastId = current;
// limit to a fix number to make it interruptable see StopNow()
if (fetchCount < 250)
continue;
}
fetchCount = 0;
mailbox.FetchMessages(start, end);
start = -1;
end = -1;
}
if (start > 0)
mailbox.FetchMessages(start, end);
return B_OK;
}
// #pragma mark -
IMAPStorage::IMAPStorage()
{
fLoadDatabaseLock = create_sem(1, "sync lock");
}
IMAPStorage::~IMAPStorage()
{
delete_sem(fLoadDatabaseLock);
}
void
IMAPStorage::SetTo(const char* dir)
{
fMailboxPath.SetTo(dir);
}
status_t
IMAPStorage::StartReadDatabase()
{
status_t status = create_directory(fMailboxPath.Path(), 0755);
if (status != B_OK)
return status;
thread_id id = spawn_thread(_ReadFilesThreadFunction, "read mailbox",
B_LOW_PRIORITY, this);
if (id < 0)
return id;
// will be unlocked from thread
acquire_sem(fLoadDatabaseLock);
status = resume_thread(id);
if (status != B_OK)
release_sem(fLoadDatabaseLock);
return status;
}
status_t
IMAPStorage::WaitForDatabaseRead()
{
// just wait for thread
if (acquire_sem(fLoadDatabaseLock) != B_OK)
return B_ERROR;
release_sem(fLoadDatabaseLock);
return B_OK;
}
status_t
IMAPStorage::AddNewMessage(int32 uid, int32 flags, BPositionIO** file)
{
if (file != NULL)
*file = NULL;
// TODO: make sure there is not a valid mail with this name
BString fileName = "Downloading file... uid: ";
fileName << uid;
BPath filePath = fMailboxPath;
filePath.Append(fileName);
TRACE("AddNewMessage %s\n", filePath.Path());
BFile* newFile = new BFile(filePath.Path(), B_READ_WRITE | B_CREATE_FILE
| B_ERASE_FILE);
if (newFile == NULL)
return B_NO_MEMORY;
StorageMailEntry storageEntry;
storageEntry.uid = uid;
storageEntry.flags = flags;
storageEntry.fileName = fileName;
newFile->GetNodeRef(&storageEntry.nodeRef);
if (_WriteUniqueID(*newFile, uid) != B_OK) {
delete newFile;
return B_ERROR;
}
status_t status = _WriteFlags(flags, *newFile);
if (status != B_OK) {
delete newFile;
return status;
}
if (file)
*file = newFile;
else
delete newFile;
fMailEntryMap[uid] = storageEntry;
return B_OK;
}
status_t
IMAPStorage::OpenMessage(int32 uid, BPositionIO** file)
{
*file = NULL;
MailEntryMap::const_iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return B_BAD_VALUE;
const StorageMailEntry& storageEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(storageEntry.fileName);
BFile* ourFile = new BFile(filePath.Path(), B_READ_WRITE);
if (!ourFile)
return B_NO_MEMORY;
status_t status = ourFile->InitCheck();
if (status != B_OK) {
delete *file;
return status;
}
*file = ourFile;
return B_OK;
}
status_t
IMAPStorage::DeleteMessage(int32 uid)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return B_ENTRY_NOT_FOUND;
const StorageMailEntry& storageEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(storageEntry.fileName);
BEntry entry(filePath.Path());
TRACE("IMAPStorage::DeleteMessage %s, %" B_PRId32 "\n", filePath.Path(), uid);
status_t status = entry.Remove();
if (status != B_OK)
return status;
fMailEntryMap.erase(it);
return B_OK;
}
status_t
IMAPStorage::SetFlags(int32 uid, int32 flags)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return B_ENTRY_NOT_FOUND;
StorageMailEntry& entry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(entry.fileName);
BNode node(filePath.Path());
status_t status = _WriteFlags(flags, node);
if (status != B_OK)
return status;
entry.flags = flags;
return B_OK;
}
int32
IMAPStorage::GetFlags(int32 uid)
{
MailEntryMap::const_iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return -1;
const StorageMailEntry& entry = (*it).second;
return entry.flags;
}
status_t
IMAPStorage::SetFileName(int32 uid, const BString& name)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return -1;
StorageMailEntry& storageEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(storageEntry.fileName);
BEntry entry(filePath.Path());
status_t status = entry.Rename(name);
if (status != B_OK)
return status;
storageEntry.fileName = name;
return B_OK;
}
status_t
IMAPStorage::FileRenamed(const entry_ref& from, const entry_ref& to)
{
int32 uid = RefToUID(from);
if (uid < 0)
return B_BAD_VALUE;
fMailEntryMap[uid].fileName = to.name;
return B_OK;
}
bool
IMAPStorage::HasFile(int32 uid)
{
MailEntryMap::const_iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return false;
return true;
}
status_t
IMAPStorage::SetCompleteMessageSize(int32 uid, int32 size)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return false;
StorageMailEntry& storageEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(storageEntry.fileName);
BNode node(filePath.Path());
if (node.WriteAttr("MAIL:size", B_INT32_TYPE, 0, &size, sizeof(int32)) < 0)
return B_ERROR;
return B_OK;
}
StorageMailEntry*
IMAPStorage::GetEntryForRef(const node_ref& ref)
{
for (MailEntryMap::iterator it = fMailEntryMap.begin();
it != fMailEntryMap.end(); it++) {
StorageMailEntry& mailEntry = (*it).second;
if (mailEntry.nodeRef == ref)
return &mailEntry;
}
return NULL;
}
bool
IMAPStorage::IsBodyFetched(int32 uid)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return false;
StorageMailEntry& storageEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(storageEntry.fileName);
BNode node(filePath.Path());
char buffer[B_MIME_TYPE_LENGTH];
BNodeInfo info(&node);
info.GetType(buffer);
return strcmp(buffer, B_MAIL_TYPE) == 0;
}
int32
IMAPStorage::RefToUID(const entry_ref& ref)
{
for (MailEntryMap::iterator it = fMailEntryMap.begin();
it != fMailEntryMap.end(); it++) {
StorageMailEntry& mailEntry = (*it).second;
if (mailEntry.fileName == ref.name)
return mailEntry.uid;
}
// not found try to fix internal name
BDirectory dir(fMailboxPath.Path());
if (!dir.Contains(ref.name))
return -1;
BNode node(&ref);
int32 uid;
if (ReadUniqueID(node, uid) != B_OK)
return -1;
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return -1;
it->second.fileName = ref.name;
return uid;
}
bool
IMAPStorage::UIDToRef(int32 uid, entry_ref& ref)
{
MailEntryMap::iterator it = fMailEntryMap.find(uid);
if (it == fMailEntryMap.end())
return false;
StorageMailEntry& mailEntry = (*it).second;
BPath filePath = fMailboxPath;
filePath.Append(mailEntry.fileName);
BEntry entry(filePath.Path());
if (entry.GetRef(&ref) == B_OK)
return true;
return false;
}
status_t
IMAPStorage::_ReadFilesThreadFunction(void* data)
{
IMAPStorage* storage = (IMAPStorage*)data;
return storage->_ReadFiles();
}
status_t
IMAPStorage::_ReadFiles()
{
fMailEntryMap.clear();
BDirectory directory(fMailboxPath.Path());
entry_ref ref;
while (directory.GetNextRef(&ref) != B_ENTRY_NOT_FOUND) {
BNode node(&ref);
if (node.InitCheck() != B_OK || !node.IsFile())
continue;
char buffer[B_MIME_TYPE_LENGTH];
BNodeInfo info(&node);
info.GetType(buffer);
// maybe interrupted downloads ignore them
if (strcmp(buffer, "text/x-partial-email") != 0
&& strcmp(buffer, B_MAIL_TYPE) != 0)
continue;
StorageMailEntry entry;
entry.fileName = ref.name;
if (ReadUniqueID(node, entry.uid) != B_OK) {
TRACE("IMAPStorage::_ReadFilesThread() failed to read uid %s\n",
ref.name);
continue;
}
if (node.ReadAttr("MAIL:server_flags", B_INT32_TYPE, 0, &entry.flags,
sizeof(int32)) != sizeof(int32))
continue;
node.GetNodeRef(&entry.nodeRef);
fMailEntryMap[entry.uid] = entry;
}
release_sem(fLoadDatabaseLock);
return B_OK;
}
status_t
IMAPStorage::_WriteFlags(int32 flags, BNode& node)
{
if ((flags & kSeen) != 0)
write_read_attr(node, B_READ);
else
write_read_attr(node, B_UNREAD);
ssize_t writen = node.WriteAttr("MAIL:server_flags", B_INT32_TYPE, 0,
&flags, sizeof(int32));
if (writen != sizeof(int32))
return writen;
return B_OK;
}
status_t
IMAPStorage::ReadUniqueID(BNode& node, int32& uid)
{
const uint32 kMaxUniqueLength = 32;
char uidString[kMaxUniqueLength];
memset(uidString, 0, kMaxUniqueLength);
if (node.ReadAttr("MAIL:unique_id", B_STRING_TYPE, 0, uidString,
kMaxUniqueLength) < 0)
return B_ERROR;
uid = atoi(uidString);
return B_OK;
}
status_t
IMAPStorage::_WriteUniqueID(BNode& node, int32 uid)
{
BString uidString;
uidString << uid;
ssize_t written = node.WriteAttr("MAIL:unique_id", B_STRING_TYPE, 0,
uidString.String(), uidString.Length());
if (written < 0)
return written;
return B_OK;
}
@@ -1,102 +0,0 @@
/*
* Copyright 2010, Haiku Inc. All Rights Reserved.
* Copyright 2010 Clemens Zeidler. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_STORAGE_H
#define IMAP_STORAGE_H
#include <map>
#include <string.h>
#include <File.h>
#include <kernel/OS.h>
#include <Path.h>
#include <String.h>
struct StorageMailEntry {
int32 uid;
int32 flags;
node_ref nodeRef;
BString fileName;
};
typedef std::map<int32, StorageMailEntry> MailEntryMap;
class IMAPStorage {
public:
enum MessageState {
kHeaderDownloaded = 0x01,
kBodyDownloaded = 0x02
};
IMAPStorage();
~IMAPStorage();
void SetTo(const char* dir);
status_t StartReadDatabase();
status_t WaitForDatabaseRead();
status_t AddNewMessage(int32 uid, int32 flags,
BPositionIO** file = NULL);
status_t OpenMessage(int32 uid, BPositionIO** file);
/*! Remove the message from the storage. */
status_t DeleteMessage(int32 uid);
status_t SetFlags(int32 uid, int32 flags);
int32 GetFlags(int32 uid);
status_t SetFileName(int32 uid, const BString& name);
status_t FileRenamed(const entry_ref& from,
const entry_ref& to);
const MailEntryMap& GetFiles() { return fMailEntryMap; }
bool HasFile(int32 uid);
status_t SetCompleteMessageSize(int32 uid, int32 size);
bool IsBodyFetched(int32 uid);
StorageMailEntry* GetEntryForRef(const node_ref& ref);
int32 RefToUID(const entry_ref& ref);
bool UIDToRef(int32 uid, entry_ref& ref);
status_t ReadUniqueID(BNode& node, int32& uid);
private:
static status_t _ReadFilesThreadFunction(void* data);
status_t _ReadFiles();
status_t _WriteFlags(int32 flags, BNode& node);
status_t _WriteUniqueID(BNode& node, int32 uid);
private:
BPath fMailboxPath;
sem_id fLoadDatabaseLock;
MailEntryMap fMailEntryMap;
};
class IMAPMailbox;
typedef std::vector<int32> MessageNumberList;
class IMAPMailboxSync {
public:
status_t Sync(IMAPStorage& storage,
IMAPMailbox& mailbox);
const MessageNumberList& ToFetchList() { return fToFetchList; }
private:
MessageNumberList fToFetchList;
};
#endif // IMAP_STORAGE_H