IMAP: removed superfluous files from the old implementation.
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user