Work in progress of rewrite; IMAP doesn't even compile at this point.
This commit is contained in:
@@ -329,9 +329,9 @@ FolderConfigWindow::_LoadFolders()
|
||||
delete[] passwd;
|
||||
}
|
||||
|
||||
fIMAPFolders.Connect(server, username, password, useSSL);
|
||||
fProtocol.Connect(server, username, password, useSSL);
|
||||
fFolderList.clear();
|
||||
fIMAPFolders.GetFolders(fFolderList);
|
||||
fProtocol.GetFolders(fFolderList);
|
||||
for (unsigned int i = 0; i < fFolderList.size(); i++) {
|
||||
FolderInfo& info = fFolderList[i];
|
||||
CheckBoxItem* item = new CheckBoxItem(info.folder, info.subscribed);
|
||||
@@ -340,7 +340,7 @@ FolderConfigWindow::_LoadFolders()
|
||||
}
|
||||
|
||||
uint64 used, total;
|
||||
if (fIMAPFolders.GetQuota(used, total) == B_OK) {
|
||||
if (fProtocol.GetQuota(used, total) == B_OK) {
|
||||
char buffer[256];
|
||||
BString quotaString = "Server storage: ";
|
||||
quotaString += string_for_size(used, buffer, 256);
|
||||
@@ -377,9 +377,9 @@ FolderConfigWindow::_ApplyChanges()
|
||||
FolderInfo& info = fFolderList[i];
|
||||
CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i);
|
||||
if (info.subscribed && !item->Checked())
|
||||
fIMAPFolders.UnsubscribeFolder(info.folder);
|
||||
fProtocol.UnsubscribeFolder(info.folder);
|
||||
else if (!info.subscribed && item->Checked())
|
||||
fIMAPFolders.SubscribeFolder(info.folder);
|
||||
fProtocol.SubscribeFolder(info.folder);
|
||||
}
|
||||
|
||||
status->PostMessage(B_QUIT_REQUESTED);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <MailSettings.h>
|
||||
|
||||
#include "IMAPFolders.h"
|
||||
#include "Protocol.h"
|
||||
|
||||
|
||||
class FolderConfigWindow : public BWindow {
|
||||
@@ -28,11 +28,11 @@ private:
|
||||
void _LoadFolders();
|
||||
void _ApplyChanges();
|
||||
|
||||
IMAPFolders fIMAPFolders;
|
||||
IMAP::Protocol fProtocol;
|
||||
BListView* fFolderListView;
|
||||
BButton* fApplyButton;
|
||||
const BMessage fSettings;
|
||||
FolderList fFolderList;
|
||||
IMAP::FolderList fFolderList;
|
||||
|
||||
BStringView* fQuotaView;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "MailSettings.h"
|
||||
|
||||
#include "IMAPMailbox.h"
|
||||
#include "Protocol.h"
|
||||
#include "IMAPStorage.h"
|
||||
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#include <Messenger.h>
|
||||
|
||||
#include "IMAPFolders.h"
|
||||
|
||||
|
||||
IMAPRootInboundProtocol::IMAPRootInboundProtocol(BMailAccountSettings* settings)
|
||||
:
|
||||
@@ -34,9 +32,8 @@ IMAPRootInboundProtocol::Connect(const char* server, const char* username,
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
IMAPFolders folder(fIMAPMailbox);
|
||||
FolderList folders;
|
||||
folder.GetFolders(folders);
|
||||
fIMAPMailbox.GetFolders(folders);
|
||||
for (unsigned int i = 0; i < folders.size(); i++) {
|
||||
if (!folders[i].subscribed || folders[i].folder == "INBOX")
|
||||
continue;
|
||||
|
||||
@@ -21,12 +21,10 @@ local sources =
|
||||
IMAPRootInboundProtocol.cpp
|
||||
IMAPFolderConfig.cpp
|
||||
# imap_lib
|
||||
IMAPFolders.cpp
|
||||
IMAPHandler.cpp
|
||||
IMAPMailbox.cpp
|
||||
IMAPParser.cpp
|
||||
IMAPProtocol.cpp
|
||||
Commands.cpp
|
||||
Protocol.cpp
|
||||
IMAPStorage.cpp
|
||||
Response.cpp
|
||||
;
|
||||
|
||||
AddResources IMAP : IMAP.rdef ;
|
||||
@@ -46,8 +44,8 @@ Addon IMAP
|
||||
libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ]
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp
|
||||
IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.cpp ServerConnection.cpp ]
|
||||
SEARCH on [ FGristFiles Commands.cpp IMAPMailbox.cpp
|
||||
IMAPProtocol.cpp IMAPStorage.cpp Response.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap
|
||||
imap_lib ] ;
|
||||
|
||||
|
||||
+283
-193
@@ -5,16 +5,12 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "IMAPHandler.h"
|
||||
#include "Commands.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include "IMAPMailbox.h"
|
||||
#include "IMAPParser.h"
|
||||
#include "IMAPStorage.h"
|
||||
|
||||
|
||||
#define DEBUG_IMAP_HANDLER
|
||||
#ifdef DEBUG_IMAP_HANDLER
|
||||
@@ -28,28 +24,82 @@
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
IMAPCommand::~IMAPCommand()
|
||||
{
|
||||
}
|
||||
namespace IMAP {
|
||||
|
||||
|
||||
BString
|
||||
IMAPCommand::Command()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
static HandlerListener sEmptyHandler;
|
||||
|
||||
|
||||
IMAPMailboxCommand::IMAPMailboxCommand(IMAPMailbox& mailbox)
|
||||
Handler::Handler()
|
||||
:
|
||||
fIMAPMailbox(mailbox),
|
||||
fStorage(mailbox.GetStorage()),
|
||||
fConnectionReader(mailbox.GetConnectionReader())
|
||||
fListener(&sEmptyHandler)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IMAPMailboxCommand::~IMAPMailboxCommand()
|
||||
Handler::~Handler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Handler::SetListener(HandlerListener& listener)
|
||||
{
|
||||
fListener = &listener;
|
||||
}
|
||||
|
||||
|
||||
IMAP::LiteralHandler*
|
||||
Handler::LiteralHandler()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Command::HandleTagged(Response& response)
|
||||
{
|
||||
if (response.StringAt(0) == "OK")
|
||||
return B_OK;
|
||||
if (response.StringAt(0) == "BAD")
|
||||
return B_BAD_VALUE;
|
||||
if (response.StringAt(0) == "NO")
|
||||
return B_NOT_ALLOWED;
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
HandlerListener::~HandlerListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HandlerListener::ExpungeReceived(int32 number)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HandlerListener::ExistsReceived(int32 number)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HandlerListener::FetchBody(Command& command, int32 size)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -57,19 +107,83 @@ IMAPMailboxCommand::~IMAPMailboxCommand()
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
MailboxSelectHandler::MailboxSelectHandler(IMAPMailbox& mailbox)
|
||||
RawCommand::RawCommand(const BString& command)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox),
|
||||
|
||||
fMailboxName(""),
|
||||
fNextUID(-1),
|
||||
fUIDValidity(-1)
|
||||
fCommand(command)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
MailboxSelectHandler::Command()
|
||||
RawCommand::CommandString()
|
||||
{
|
||||
return fCommand;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
LoginCommand::LoginCommand(const char* user, const char* password)
|
||||
:
|
||||
fUser(user),
|
||||
fPassword(password)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
LoginCommand::CommandString()
|
||||
{
|
||||
BString command = "LOGIN ";
|
||||
command << "\"" << fUser << "\" " << "\"" << fPassword << "\"";
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LoginCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
if (!response.EqualsAt(0, "OK") || !response.IsListAt(1, '['))
|
||||
return false;
|
||||
|
||||
// TODO: we only support capabilities at the moment
|
||||
ArgumentList& list = response.ListAt(1);
|
||||
if (!list.EqualsAt(0, "CAPABILITY"))
|
||||
return false;
|
||||
|
||||
fCapabilities.MakeEmpty();
|
||||
while (list.CountItems() > 1)
|
||||
fCapabilities.AddItem(list.RemoveItemAt(1));
|
||||
|
||||
TRACE("CAPABILITY: %s\n", fCapabilities.ToString().String());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
SelectCommand::SelectCommand()
|
||||
:
|
||||
fNextUID(0),
|
||||
fUIDValidity(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SelectCommand::SelectCommand(const char* name)
|
||||
:
|
||||
fMailboxName(name),
|
||||
fNextUID(0),
|
||||
fUIDValidity(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
SelectCommand::CommandString()
|
||||
{
|
||||
if (fMailboxName == "")
|
||||
return "";
|
||||
@@ -82,21 +196,19 @@ MailboxSelectHandler::Command()
|
||||
|
||||
|
||||
bool
|
||||
MailboxSelectHandler::Handle(const BString& response)
|
||||
SelectCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
BString extracted = IMAPParser::ExtractStringAfter(response,
|
||||
"* OK [UIDVALIDITY");
|
||||
if (extracted != "") {
|
||||
fUIDValidity = IMAPParser::RemoveIntegerFromLeft(extracted);
|
||||
TRACE("UIDValidity %i\n", (int)fUIDValidity);
|
||||
return true;
|
||||
}
|
||||
|
||||
extracted = IMAPParser::ExtractStringAfter(response, "* OK [UIDNEXT");
|
||||
if (extracted != "") {
|
||||
fNextUID = IMAPParser::RemoveIntegerFromLeft(extracted);
|
||||
TRACE("NextUID %i\n", (int)fNextUID);
|
||||
return true;
|
||||
if (response.EqualsAt(0, "OK") && response.IsListAt(1, '[')) {
|
||||
const ArgumentList& arguments = response.ListAt(1);
|
||||
if (arguments.EqualsAt(0, "UIDVALIDITY")
|
||||
&& arguments.IsNumberAt(1)) {
|
||||
fUIDValidity = arguments.NumberAt(1);
|
||||
return true;
|
||||
} else if (arguments.EqualsAt(0, "UIDNEXT")
|
||||
&& arguments.IsNumberAt(1)) {
|
||||
fNextUID = arguments.NumberAt(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -106,42 +218,94 @@ MailboxSelectHandler::Handle(const BString& response)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
CapabilityHandler::CapabilityHandler()
|
||||
:
|
||||
fCapabilities("")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
CapabilityHandler::Command()
|
||||
CapabilityHandler::CommandString()
|
||||
{
|
||||
return "CAPABILITY";
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CapabilityHandler::Handle(const BString& response)
|
||||
CapabilityHandler::HandleUntagged(Response& response)
|
||||
{
|
||||
BString cap = IMAPParser::ExtractStringAfter(response, "* CAPABILITY");
|
||||
if (cap == "")
|
||||
if (!response.IsCommand("CAPABILITY"))
|
||||
return false;
|
||||
fCapabilities = cap;
|
||||
TRACE("CAPABILITY: %s\n", fCapabilities.String());
|
||||
|
||||
fCapabilities.MakeEmpty();
|
||||
while (response.CountItems() > 1)
|
||||
fCapabilities.AddItem(response.RemoveItemAt(1));
|
||||
|
||||
TRACE("CAPABILITY: %s\n", fCapabilities.ToString().String());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BString&
|
||||
CapabilityHandler::Capabilities()
|
||||
{
|
||||
return fCapabilities;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
FetchMessageEntriesCommand::FetchMessageEntriesCommand(
|
||||
MessageEntryList& entries, uint32 from, uint32 to)
|
||||
:
|
||||
fEntries(entries),
|
||||
fFrom(from),
|
||||
fTo(to)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
FetchMessageEntriesCommand::CommandString()
|
||||
{
|
||||
BString command = "UID FETCH ";
|
||||
command << fFrom << ":" << fTo << " FLAGS";
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
FetchMessageEntriesCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2))
|
||||
return false;
|
||||
|
||||
MessageEntry entry;
|
||||
|
||||
ArgumentList& list = response.ListAt(2);
|
||||
for (int32 i = 0; i < list.CountItems(); i += 2) {
|
||||
if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1))
|
||||
entry.uid = list.NumberAt(i + 1);
|
||||
else if (list.EqualsAt(i, "FLAGS") && list.IsListAt(i + 1)) {
|
||||
// Parse flags
|
||||
ArgumentList& flags = list.ListAt(i + 1);
|
||||
printf("flags: %s\n", flags.ToString().String());
|
||||
for (int32 j = 0; j < flags.CountItems(); j++) {
|
||||
if (flags.EqualsAt(j, "\\Seen"))
|
||||
entry.flags |= kSeen;
|
||||
else if (flags.EqualsAt(j, "\\Answered"))
|
||||
entry.flags |= kAnswered;
|
||||
else if (flags.EqualsAt(j, "\\Flagged"))
|
||||
entry.flags |= kFlagged;
|
||||
else if (flags.EqualsAt(j, "\\Deleted"))
|
||||
entry.flags |= kDeleted;
|
||||
else if (flags.EqualsAt(j, "\\Draft"))
|
||||
entry.flags |= kDraft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.uid == 0)
|
||||
return false;
|
||||
|
||||
fEntries.push_back(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
#if 0
|
||||
FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 message, MinMessageList* list, BPositionIO** data)
|
||||
:
|
||||
@@ -170,7 +334,7 @@ FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
|
||||
|
||||
BString
|
||||
FetchMinMessageCommand::Command()
|
||||
FetchMinMessageCommand::CommandString()
|
||||
{
|
||||
if (fMessage <= 0)
|
||||
return "";
|
||||
@@ -186,7 +350,7 @@ FetchMinMessageCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
FetchMinMessageCommand::Handle(const BString& response)
|
||||
FetchMinMessageCommand::HandleUntagged(const BString& response)
|
||||
{
|
||||
BString extracted = response;
|
||||
int32 message;
|
||||
@@ -256,47 +420,6 @@ FetchMinMessageCommand::ExtractFlags(const BString& response)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
FetchMessageListCommand::FetchMessageListCommand(IMAPMailbox& mailbox,
|
||||
MinMessageList* list, int32 nextId)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox),
|
||||
|
||||
fMinMessageList(list),
|
||||
fNextId(nextId)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
FetchMessageListCommand::Command()
|
||||
{
|
||||
BString command = "UID FETCH 1:";
|
||||
command << fNextId - 1;
|
||||
command << " FLAGS";
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
FetchMessageListCommand::Handle(const BString& response)
|
||||
{
|
||||
BString extracted = response;
|
||||
int32 message;
|
||||
if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message))
|
||||
return false;
|
||||
|
||||
MinMessage minMessage;
|
||||
if (!FetchMinMessageCommand::ParseMinMessage(extracted, minMessage))
|
||||
return false;
|
||||
|
||||
fMinMessageList->push_back(minMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
FetchMessageCommand::FetchMessageCommand(IMAPMailbox& mailbox, int32 message,
|
||||
BPositionIO* data, int32 fetchBodyLimit)
|
||||
:
|
||||
@@ -335,7 +458,7 @@ FetchMessageCommand::~FetchMessageCommand()
|
||||
|
||||
|
||||
BString
|
||||
FetchMessageCommand::Command()
|
||||
FetchMessageCommand::CommandString()
|
||||
{
|
||||
BString command = "FETCH ";
|
||||
command << fMessage;
|
||||
@@ -349,7 +472,7 @@ FetchMessageCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
FetchMessageCommand::Handle(const BString& response)
|
||||
FetchMessageCommand::HandleUntagged(const BString& response)
|
||||
{
|
||||
BString extracted = response;
|
||||
int32 message;
|
||||
@@ -454,7 +577,7 @@ FetchBodyCommand::~FetchBodyCommand()
|
||||
|
||||
|
||||
BString
|
||||
FetchBodyCommand::Command()
|
||||
FetchBodyCommand::CommandString()
|
||||
{
|
||||
BString command = "FETCH ";
|
||||
command << fMessage;
|
||||
@@ -464,7 +587,7 @@ FetchBodyCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
FetchBodyCommand::Handle(const BString& response)
|
||||
FetchBodyCommand::HandleUntagged(const BString& response)
|
||||
{
|
||||
if (response.FindFirst("FETCH") < 0)
|
||||
return false;
|
||||
@@ -521,7 +644,7 @@ SetFlagsCommand::SetFlagsCommand(IMAPMailbox& mailbox, int32 message,
|
||||
|
||||
|
||||
BString
|
||||
SetFlagsCommand::Command()
|
||||
SetFlagsCommand::CommandString()
|
||||
{
|
||||
BString command = "STORE ";
|
||||
command << fMessage;
|
||||
@@ -533,7 +656,7 @@ SetFlagsCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
SetFlagsCommand::Handle(const BString& response)
|
||||
SetFlagsCommand::HandleUntagged(const BString& response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -576,7 +699,7 @@ AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message,
|
||||
|
||||
|
||||
BString
|
||||
AppendCommand::Command()
|
||||
AppendCommand::CommandString()
|
||||
{
|
||||
BString command = "APPEND ";
|
||||
command << fIMAPMailbox.Mailbox();
|
||||
@@ -591,7 +714,7 @@ AppendCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
AppendCommand::Handle(const BString& response)
|
||||
AppendCommand::HandleUntagged(const BString& response)
|
||||
{
|
||||
if (response.FindFirst("+") != 0)
|
||||
return false;
|
||||
@@ -614,21 +737,27 @@ AppendCommand::Handle(const BString& response)
|
||||
fIMAPMailbox.SendRawData(CRLF, strlen(CRLF));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ExistsHandler::ExistsHandler(IMAPMailbox& mailbox)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox)
|
||||
ExistsHandler::ExistsHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ExistsHandler::Handle(const BString& response)
|
||||
ExistsHandler::HandleUntagged(Response& response)
|
||||
{
|
||||
if (!response.EqualsAt(1, "EXISTS") || response.IsNumberAt(0))
|
||||
return false;
|
||||
|
||||
int32 expunge = response.NumberAt(0);
|
||||
Listener().ExistsReceived(expunge);
|
||||
|
||||
#if 0
|
||||
if (response.FindFirst("EXISTS") < 0)
|
||||
return false;
|
||||
|
||||
@@ -654,6 +783,7 @@ ExistsHandler::Handle(const BString& response)
|
||||
|
||||
TRACE("EXISTS %i\n", (int)exists);
|
||||
fIMAPMailbox.SendRawCommand("DONE");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -662,47 +792,36 @@ ExistsHandler::Handle(const BString& response)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ExpungeCommmand::ExpungeCommmand(IMAPMailbox& mailbox)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox)
|
||||
ExpungeCommand::ExpungeCommand()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
ExpungeCommmand::Command()
|
||||
ExpungeCommand::CommandString()
|
||||
{
|
||||
return "EXPUNGE";
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ExpungeCommmand::Handle(const BString& response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ExpungeHandler::ExpungeHandler(IMAPMailbox& mailbox)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox)
|
||||
ExpungeHandler::ExpungeHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ExpungeHandler::Handle(const BString& response)
|
||||
ExpungeHandler::HandleUntagged(Response& response)
|
||||
{
|
||||
if (response.FindFirst("EXPUNGE") < 0)
|
||||
if (!response.EqualsAt(1, "EXPUNGE") || response.IsNumberAt(0))
|
||||
return false;
|
||||
|
||||
int32 expunge = 0;
|
||||
if (!IMAPParser::ExtractUntagedFromLeft(response, "EXPUNGE", expunge))
|
||||
return false;
|
||||
int32 expunge = response.NumberAt(0);
|
||||
Listener().ExpungeReceived(expunge);
|
||||
|
||||
#if 0
|
||||
// remove from storage
|
||||
IMAPStorage& storage = fIMAPMailbox.GetStorage();
|
||||
storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge));
|
||||
@@ -717,6 +836,7 @@ ExpungeHandler::Handle(const BString& response)
|
||||
// the watching loop restarts again, we need to watch again to because
|
||||
// some IDLE implementation stop sending notifications
|
||||
fIMAPMailbox.SendRawCommand("DONE");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -724,6 +844,7 @@ ExpungeHandler::Handle(const BString& response)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
#if 0
|
||||
FlagsHandler::FlagsHandler(IMAPMailbox& mailbox)
|
||||
:
|
||||
IMAPMailboxCommand(mailbox)
|
||||
@@ -732,7 +853,7 @@ FlagsHandler::FlagsHandler(IMAPMailbox& mailbox)
|
||||
|
||||
|
||||
bool
|
||||
FlagsHandler::Handle(const BString& response)
|
||||
FlagsHandler::HandleUntagged(const BString& response)
|
||||
{
|
||||
if (response.FindFirst("FETCH") < 0)
|
||||
return false;
|
||||
@@ -749,13 +870,14 @@ FlagsHandler::Handle(const BString& response)
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BString
|
||||
ListCommand::Command()
|
||||
ListCommand::CommandString()
|
||||
{
|
||||
fFolders.clear();
|
||||
return "LIST \"\" \"*\"";
|
||||
@@ -763,9 +885,14 @@ ListCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
ListCommand::Handle(const BString& response)
|
||||
ListCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
return ParseList("LIST", response, fFolders);
|
||||
if (response.IsCommand("LIST") && response.IsStringAt(3)) {
|
||||
fFolders.push_back(response.StringAt(3));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -776,41 +903,11 @@ ListCommand::FolderList()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ListCommand::ParseList(const char* command, const BString& response,
|
||||
StringList& list)
|
||||
{
|
||||
int32 textPos = response.FindFirst(command);
|
||||
if (textPos < 0)
|
||||
return false;
|
||||
BString extracted = response;
|
||||
|
||||
extracted.Remove(0, textPos + strlen(command) + 1);
|
||||
extracted.Trim();
|
||||
if (extracted[0] == '(') {
|
||||
BString flags = IMAPParser::ExtractBetweenBrackets(extracted, "(", ")");
|
||||
if (flags.IFindFirst("\\Noselect") >= 0)
|
||||
return true;
|
||||
textPos = extracted.FindFirst(")");
|
||||
extracted.Remove(0, textPos + 1);
|
||||
}
|
||||
|
||||
IMAPParser::RemovePrimitiveFromLeft(extracted);
|
||||
extracted.Trim();
|
||||
// remove quotation marks
|
||||
extracted.Remove(0, 1);
|
||||
extracted.Truncate(extracted.Length() - 1);
|
||||
|
||||
list.push_back(extracted);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BString
|
||||
ListSubscribedCommand::Command()
|
||||
ListSubscribedCommand::CommandString()
|
||||
{
|
||||
fFolders.clear();
|
||||
return "LSUB \"\" \"*\"";
|
||||
@@ -818,9 +915,14 @@ ListSubscribedCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
ListSubscribedCommand::Handle(const BString& response)
|
||||
ListSubscribedCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
return ListCommand::ParseList("LSUB", response, fFolders);
|
||||
if (response.IsCommand("LSUB") && response.IsStringAt(3)) {
|
||||
fFolders.push_back(response.StringAt(3));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -842,7 +944,7 @@ SubscribeCommand::SubscribeCommand(const char* mailboxName)
|
||||
|
||||
|
||||
BString
|
||||
SubscribeCommand::Command()
|
||||
SubscribeCommand::CommandString()
|
||||
{
|
||||
BString command = "SUBSCRIBE \"";
|
||||
command += fMailboxName;
|
||||
@@ -851,13 +953,6 @@ SubscribeCommand::Command()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SubscribeCommand::Handle(const BString& response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@@ -869,7 +964,7 @@ UnsubscribeCommand::UnsubscribeCommand(const char* mailboxName)
|
||||
|
||||
|
||||
BString
|
||||
UnsubscribeCommand::Command()
|
||||
UnsubscribeCommand::CommandString()
|
||||
{
|
||||
BString command = "UNSUBSCRIBE \"";
|
||||
command += fMailboxName;
|
||||
@@ -878,13 +973,6 @@ UnsubscribeCommand::Command()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UnsubscribeCommand::Handle(const BString& response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@@ -898,7 +986,7 @@ GetQuotaCommand::GetQuotaCommand(const char* mailboxName)
|
||||
|
||||
|
||||
BString
|
||||
GetQuotaCommand::Command()
|
||||
GetQuotaCommand::CommandString()
|
||||
{
|
||||
BString command = "GETQUOTA \"";
|
||||
command += fMailboxName;
|
||||
@@ -908,15 +996,14 @@ GetQuotaCommand::Command()
|
||||
|
||||
|
||||
bool
|
||||
GetQuotaCommand::Handle(const BString& response)
|
||||
GetQuotaCommand::HandleUntagged(Response& response)
|
||||
{
|
||||
if (response.FindFirst("QUOTA") < 0)
|
||||
if (!response.IsCommand("QUOTA") || response.IsListAt(1))
|
||||
return false;
|
||||
|
||||
BString data = IMAPParser::ExtractBetweenBrackets(response, "(", ")");
|
||||
IMAPParser::RemovePrimitiveFromLeft(data);
|
||||
fUsedStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024;
|
||||
fTotalStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024;
|
||||
const ArgumentList& arguments = response.ListAt(1);
|
||||
fUsedStorage = (uint64)arguments.NumberAt(0) * 1024;
|
||||
fTotalStorage = (uint64)arguments.NumberAt(1) * 1024;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -934,3 +1021,6 @@ GetQuotaCommand::TotalStorage()
|
||||
{
|
||||
return fTotalStorage;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright 2010-2011, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2010 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef COMMANDS_H
|
||||
#define COMMANDS_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Response.h"
|
||||
|
||||
|
||||
typedef std::vector<BString> StringList;
|
||||
|
||||
|
||||
namespace IMAP {
|
||||
|
||||
|
||||
class ConnectionReader;
|
||||
class HandlerListener;
|
||||
|
||||
|
||||
struct MessageEntry {
|
||||
MessageEntry()
|
||||
:
|
||||
uid(0),
|
||||
flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 uid;
|
||||
uint32 flags;
|
||||
};
|
||||
typedef std::vector<MessageEntry> MessageEntryList;
|
||||
|
||||
enum MessageFlags {
|
||||
kSeen = 0x01,
|
||||
kAnswered = 0x02,
|
||||
kFlagged = 0x04,
|
||||
kDeleted = 0x08,
|
||||
kDraft = 0x10
|
||||
};
|
||||
|
||||
|
||||
class Handler {
|
||||
public:
|
||||
Handler();
|
||||
virtual ~Handler();
|
||||
|
||||
void SetListener(HandlerListener& listener);
|
||||
HandlerListener& Listener() { return *fListener; }
|
||||
|
||||
virtual bool HandleUntagged(Response& response) = 0;
|
||||
virtual IMAP::LiteralHandler* LiteralHandler();
|
||||
|
||||
protected:
|
||||
HandlerListener* fListener;
|
||||
};
|
||||
|
||||
|
||||
class Command {
|
||||
public:
|
||||
virtual ~Command();
|
||||
|
||||
virtual BString CommandString() = 0;
|
||||
virtual status_t HandleTagged(Response& response);
|
||||
};
|
||||
|
||||
|
||||
class HandlerListener {
|
||||
public:
|
||||
virtual ~HandlerListener();
|
||||
|
||||
virtual void ExpungeReceived(int32 number);
|
||||
virtual void ExistsReceived(int32 number);
|
||||
virtual void FetchBody(Command& command, int32 size);
|
||||
};
|
||||
|
||||
|
||||
class RawCommand : public Command {
|
||||
public:
|
||||
RawCommand(const BString& command);
|
||||
|
||||
virtual BString CommandString();
|
||||
|
||||
private:
|
||||
BString fCommand;
|
||||
};
|
||||
|
||||
|
||||
class LoginCommand : public Command, public Handler {
|
||||
public:
|
||||
LoginCommand(const char* user,
|
||||
const char* password);
|
||||
|
||||
virtual BString CommandString();
|
||||
virtual bool HandleUntagged(Response& response);
|
||||
|
||||
const ArgumentList& Capabilities() const { return fCapabilities; }
|
||||
|
||||
private:
|
||||
const char* fUser;
|
||||
const char* fPassword;
|
||||
ArgumentList fCapabilities;
|
||||
};
|
||||
|
||||
|
||||
class SelectCommand : public Command, public Handler {
|
||||
public:
|
||||
SelectCommand();
|
||||
SelectCommand(const char* mailboxName);
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(Response& response);
|
||||
|
||||
void SetTo(const char* mailboxName)
|
||||
{ fMailboxName = mailboxName; }
|
||||
uint32 NextUID() { return fNextUID; }
|
||||
uint32 UIDValidity() { return fUIDValidity; }
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
uint32 fNextUID;
|
||||
uint32 fUIDValidity;
|
||||
};
|
||||
|
||||
|
||||
class CapabilityHandler : public Command, public Handler {
|
||||
public:
|
||||
virtual BString CommandString();
|
||||
virtual bool HandleUntagged(Response& response);
|
||||
|
||||
const ArgumentList& Capabilities() const { return fCapabilities; }
|
||||
|
||||
private:
|
||||
ArgumentList fCapabilities;
|
||||
};
|
||||
|
||||
|
||||
class FetchMessageEntriesCommand : public Command, public Handler {
|
||||
public:
|
||||
FetchMessageEntriesCommand(
|
||||
MessageEntryList& entries, uint32 from,
|
||||
uint32 to);
|
||||
|
||||
BString CommandString();
|
||||
virtual bool HandleUntagged(Response& response);
|
||||
|
||||
private:
|
||||
MessageEntryList& fEntries;
|
||||
uint32 fFrom;
|
||||
uint32 fTo;
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
class FetchMinMessageCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 message, MinMessageList* list,
|
||||
BPositionIO** data);
|
||||
FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 firstMessage, int32 lastMessage,
|
||||
MinMessageList* list, BPositionIO** data);
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(const BString& response);
|
||||
|
||||
static bool ParseMinMessage(const BString& response,
|
||||
MinMessage& minMessage);
|
||||
static int32 ExtractFlags(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fEndMessage;
|
||||
MinMessageList* fMinMessageList;
|
||||
BPositionIO** fData;
|
||||
};
|
||||
|
||||
|
||||
class FetchMessageCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
FetchMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 message, BPositionIO* data,
|
||||
int32 fetchBodyLimit = -1);
|
||||
/*! Fetch multiple message within a range. */
|
||||
FetchMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 firstMessage, int32 lastMessage,
|
||||
int32 fetchBodyLimit = -1);
|
||||
~FetchMessageCommand();
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fEndMessage;
|
||||
BPositionIO* fOutData;
|
||||
int32 fFetchBodyLimit;
|
||||
int32 fUnhandled;
|
||||
};
|
||||
|
||||
|
||||
class FetchBodyCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
/*! takes ownership of the data */
|
||||
FetchBodyCommand(IMAPMailbox& mailbox,
|
||||
int32 message, BPositionIO* data);
|
||||
~FetchBodyCommand();
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
BPositionIO* fOutData;
|
||||
};
|
||||
|
||||
|
||||
class SetFlagsCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
SetFlagsCommand(IMAPMailbox& mailbox,
|
||||
int32 message, int32 flags);
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(const BString& response);
|
||||
|
||||
static BString GenerateFlagList(int32 flags);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fFlags;
|
||||
};
|
||||
|
||||
|
||||
class AppendCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
AppendCommand(IMAPMailbox& mailbox,
|
||||
BPositionIO& message, off_t size,
|
||||
int32 flags, time_t time);
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(const BString& response);
|
||||
|
||||
private:
|
||||
BPositionIO& fMessageData;
|
||||
off_t fDataSize;
|
||||
int32 fFlags;
|
||||
time_t fTime;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class ExistsHandler : public Handler {
|
||||
public:
|
||||
ExistsHandler();
|
||||
|
||||
bool HandleUntagged(Response& response);
|
||||
};
|
||||
|
||||
|
||||
/*! Just send a expunge command to delete kDeleted flagged messages. The
|
||||
response is handled by the unsolicited ExpungeHandler which is installed
|
||||
all the time.
|
||||
*/
|
||||
class ExpungeCommand : public Command {
|
||||
public:
|
||||
ExpungeCommand();
|
||||
|
||||
BString CommandString();
|
||||
};
|
||||
|
||||
|
||||
class ExpungeHandler : public Handler {
|
||||
public:
|
||||
ExpungeHandler();
|
||||
|
||||
bool HandleUntagged(Response& response);
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
class FlagsHandler : public Handler {
|
||||
public:
|
||||
FlagsHandler(IMAPMailbox& mailbox);
|
||||
|
||||
bool HandleUntagged(const BString& response);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class ListCommand : public Command, public Handler {
|
||||
public:
|
||||
BString CommandString();
|
||||
bool HandleUntagged(Response& response);
|
||||
|
||||
const StringList& FolderList();
|
||||
|
||||
private:
|
||||
StringList fFolders;
|
||||
};
|
||||
|
||||
|
||||
class ListSubscribedCommand : public Command, public Handler {
|
||||
public:
|
||||
BString CommandString();
|
||||
bool HandleUntagged(Response& response);
|
||||
|
||||
const StringList& FolderList();
|
||||
|
||||
private:
|
||||
StringList fFolders;
|
||||
};
|
||||
|
||||
|
||||
class SubscribeCommand : public Command {
|
||||
public:
|
||||
SubscribeCommand(const char* mailboxName);
|
||||
|
||||
BString CommandString();
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
};
|
||||
|
||||
|
||||
class UnsubscribeCommand : public Command {
|
||||
public:
|
||||
UnsubscribeCommand(const char* mailboxName);
|
||||
|
||||
BString CommandString();
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
};
|
||||
|
||||
|
||||
class GetQuotaCommand : public Command, public Handler {
|
||||
public:
|
||||
GetQuotaCommand(const char* mailboxName = "");
|
||||
|
||||
BString CommandString();
|
||||
bool HandleUntagged(Response& response);
|
||||
|
||||
uint64 UsedStorage();
|
||||
uint64 TotalStorage();
|
||||
private:
|
||||
BString fMailboxName;
|
||||
|
||||
uint64 fUsedStorage;
|
||||
uint64 fTotalStorage;
|
||||
};
|
||||
|
||||
|
||||
} // namespace IMAP
|
||||
|
||||
|
||||
#endif // COMMANDS_H
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2011, Clemens Zeidler <[email protected]>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "IMAPFolders.h"
|
||||
|
||||
|
||||
IMAPFolders::IMAPFolders()
|
||||
{
|
||||
fHandlerList.AddItem(&fCapabilityHandler);
|
||||
}
|
||||
|
||||
|
||||
IMAPFolders::IMAPFolders(IMAPProtocol& connection)
|
||||
:
|
||||
IMAPProtocol(connection)
|
||||
{
|
||||
fHandlerList.AddItem(&fCapabilityHandler);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::GetFolders(FolderList& folders)
|
||||
{
|
||||
StringList allFolders;
|
||||
status_t status = _GetAllFolders(allFolders);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
StringList subscribedFolders;
|
||||
status = _GetSubscribedFolders(subscribedFolders);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (unsigned int i = 0; i < allFolders.size(); i++) {
|
||||
FolderInfo info;
|
||||
info.folder = allFolders[i];
|
||||
for (unsigned int a = 0; a < subscribedFolders.size(); a++) {
|
||||
if (allFolders[i] == subscribedFolders[a]
|
||||
|| allFolders[i].ICompare("INBOX") == 0) {
|
||||
info.subscribed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
folders.push_back(info);
|
||||
}
|
||||
|
||||
// you could be subscribed to a folder which not exist currently, add them:
|
||||
for (unsigned int a = 0; a < subscribedFolders.size(); a++) {
|
||||
bool isInlist = false;
|
||||
for (unsigned int i = 0; i < allFolders.size(); i++) {
|
||||
if (subscribedFolders[a] == allFolders[i]) {
|
||||
isInlist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isInlist)
|
||||
continue;
|
||||
|
||||
FolderInfo info;
|
||||
info.folder = subscribedFolders[a];
|
||||
info.subscribed = true;
|
||||
folders.push_back(info);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::SubscribeFolder(const char* folder)
|
||||
{
|
||||
SubscribeCommand command(folder);
|
||||
return ProcessCommand(&command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::UnsubscribeFolder(const char* folder)
|
||||
{
|
||||
UnsubscribeCommand command(folder);
|
||||
return ProcessCommand(&command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::GetQuota(uint64& used, uint64& total)
|
||||
{
|
||||
if (fCapabilityHandler.Capabilities() == "")
|
||||
ProcessCommand(fCapabilityHandler.Command());
|
||||
if (fCapabilityHandler.Capabilities().FindFirst("QUOTA") < 0)
|
||||
return B_ERROR;
|
||||
|
||||
GetQuotaCommand quotaCommand;
|
||||
status_t status = ProcessCommand("aCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
used = quotaCommand.UsedStorage();
|
||||
total = quotaCommand.TotalStorage();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::_GetAllFolders(StringList& folders)
|
||||
{
|
||||
ListCommand listCommand;
|
||||
status_t status = ProcessCommand(&listCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
folders = listCommand.FolderList();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPFolders::_GetSubscribedFolders(StringList& folders)
|
||||
{
|
||||
ListSubscribedCommand listSubscribedCommand;
|
||||
status_t status = ProcessCommand(&listSubscribedCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
folders = listSubscribedCommand.FolderList();
|
||||
return status;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2011 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef IMAP_FOLDERS_H
|
||||
#define IMAP_FOLDERS_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "IMAPHandler.h"
|
||||
#include "IMAPProtocol.h"
|
||||
|
||||
|
||||
class FolderInfo {
|
||||
public:
|
||||
FolderInfo()
|
||||
:
|
||||
subscribed(false)
|
||||
{
|
||||
}
|
||||
|
||||
BString folder;
|
||||
bool subscribed;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<FolderInfo> FolderList;
|
||||
|
||||
|
||||
class IMAPFolders : public IMAPProtocol {
|
||||
public:
|
||||
IMAPFolders();
|
||||
IMAPFolders(IMAPProtocol& connection);
|
||||
|
||||
status_t GetFolders(FolderList& folders);
|
||||
status_t SubscribeFolder(const char* folder);
|
||||
status_t UnsubscribeFolder(const char* folder);
|
||||
|
||||
status_t GetQuota(uint64& used, uint64& total);
|
||||
private:
|
||||
status_t _GetAllFolders(StringList& folders);
|
||||
status_t _GetSubscribedFolders(StringList& folders);
|
||||
|
||||
CapabilityHandler fCapabilityHandler;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAP_FOLDERS_H
|
||||
@@ -1,303 +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.
|
||||
*/
|
||||
#ifndef IMAP_HANDLER_H
|
||||
#define IMAP_HANDLER_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class ConnectionReader;
|
||||
class IMAPMailbox;
|
||||
class IMAPStorage;
|
||||
|
||||
|
||||
class IMAPCommand {
|
||||
public:
|
||||
virtual ~IMAPCommand();
|
||||
|
||||
virtual BString Command();
|
||||
virtual bool Handle(const BString& response) = 0;
|
||||
};
|
||||
|
||||
|
||||
class IMAPMailboxCommand : public IMAPCommand{
|
||||
public:
|
||||
IMAPMailboxCommand(IMAPMailbox& mailbox);
|
||||
virtual ~IMAPMailboxCommand();
|
||||
|
||||
protected:
|
||||
IMAPMailbox& fIMAPMailbox;
|
||||
IMAPStorage& fStorage;
|
||||
ConnectionReader& fConnectionReader;
|
||||
};
|
||||
|
||||
|
||||
class MailboxSelectHandler : public IMAPMailboxCommand {
|
||||
public:
|
||||
MailboxSelectHandler(IMAPMailbox& mailbox);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
void SetTo(const char* mailboxName)
|
||||
{ fMailboxName = mailboxName; }
|
||||
int32 NextUID() { return fNextUID; }
|
||||
int32 UIDValidity() { return fUIDValidity; }
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
int32 fNextUID;
|
||||
int32 fUIDValidity;
|
||||
};
|
||||
|
||||
|
||||
class CapabilityHandler : public IMAPCommand {
|
||||
public:
|
||||
CapabilityHandler();
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
BString& Capabilities();
|
||||
|
||||
private:
|
||||
BString fCapabilities;
|
||||
};
|
||||
|
||||
|
||||
struct MinMessage {
|
||||
MinMessage();
|
||||
|
||||
int32 uid;
|
||||
int32 flags;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<MinMessage> MinMessageList;
|
||||
|
||||
|
||||
class FetchMinMessageCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 message, MinMessageList* list,
|
||||
BPositionIO** data);
|
||||
FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 firstMessage, int32 lastMessage,
|
||||
MinMessageList* list, BPositionIO** data);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
static bool ParseMinMessage(const BString& response,
|
||||
MinMessage& minMessage);
|
||||
static int32 ExtractFlags(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fEndMessage;
|
||||
MinMessageList* fMinMessageList;
|
||||
BPositionIO** fData;
|
||||
};
|
||||
|
||||
|
||||
class FetchMessageListCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
FetchMessageListCommand(IMAPMailbox& mailbox,
|
||||
MinMessageList* list, int32 nextId);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
MinMessageList* fMinMessageList;
|
||||
int32 fNextId;
|
||||
};
|
||||
|
||||
|
||||
class FetchMessageCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
FetchMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 message, BPositionIO* data,
|
||||
int32 fetchBodyLimit = -1);
|
||||
/*! Fetch multiple message within a range. */
|
||||
FetchMessageCommand(IMAPMailbox& mailbox,
|
||||
int32 firstMessage, int32 lastMessage,
|
||||
int32 fetchBodyLimit = -1);
|
||||
~FetchMessageCommand();
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fEndMessage;
|
||||
BPositionIO* fOutData;
|
||||
int32 fFetchBodyLimit;
|
||||
int32 fUnhandled;
|
||||
};
|
||||
|
||||
|
||||
class FetchBodyCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
/*! takes ownership of the data */
|
||||
FetchBodyCommand(IMAPMailbox& mailbox,
|
||||
int32 message, BPositionIO* data);
|
||||
~FetchBodyCommand();
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
BPositionIO* fOutData;
|
||||
};
|
||||
|
||||
|
||||
class SetFlagsCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
SetFlagsCommand(IMAPMailbox& mailbox,
|
||||
int32 message, int32 flags);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
static BString GenerateFlagList(int32 flags);
|
||||
|
||||
private:
|
||||
int32 fMessage;
|
||||
int32 fFlags;
|
||||
};
|
||||
|
||||
|
||||
class AppendCommand : public IMAPMailboxCommand {
|
||||
public:
|
||||
AppendCommand(IMAPMailbox& mailbox,
|
||||
BPositionIO& message, off_t size,
|
||||
int32 flags, time_t time);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
BPositionIO& fMessageData;
|
||||
off_t fDataSize;
|
||||
int32 fFlags;
|
||||
time_t fTime;
|
||||
};
|
||||
|
||||
|
||||
class ExistsHandler : public IMAPMailboxCommand {
|
||||
public:
|
||||
ExistsHandler(IMAPMailbox& mailbox);
|
||||
|
||||
bool Handle(const BString& response);
|
||||
};
|
||||
|
||||
|
||||
/*! Just send a expunge command to delete kDeleted flagged messages. The
|
||||
response is handled by the unsolicited ExpungeHandler which is installed all
|
||||
the time. */
|
||||
class ExpungeCommmand : public IMAPMailboxCommand {
|
||||
public:
|
||||
ExpungeCommmand(IMAPMailbox& mailbox);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
};
|
||||
|
||||
|
||||
class ExpungeHandler : public IMAPMailboxCommand {
|
||||
public:
|
||||
ExpungeHandler(IMAPMailbox& mailbox);
|
||||
|
||||
bool Handle(const BString& response);
|
||||
};
|
||||
|
||||
|
||||
class FlagsHandler : public IMAPMailboxCommand {
|
||||
public:
|
||||
FlagsHandler(IMAPMailbox& mailbox);
|
||||
|
||||
bool Handle(const BString& response);
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<BString> StringList;
|
||||
|
||||
|
||||
class ListCommand : public IMAPCommand {
|
||||
public:
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
const StringList& FolderList();
|
||||
|
||||
static bool ParseList(const char* command,
|
||||
const BString& response, StringList& list);
|
||||
private:
|
||||
StringList fFolders;
|
||||
};
|
||||
|
||||
|
||||
class ListSubscribedCommand : public IMAPCommand {
|
||||
public:
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
const StringList& FolderList();
|
||||
|
||||
private:
|
||||
StringList fFolders;
|
||||
};
|
||||
|
||||
|
||||
class SubscribeCommand : public IMAPCommand {
|
||||
public:
|
||||
SubscribeCommand(const char* mailboxName);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
};
|
||||
|
||||
|
||||
class UnsubscribeCommand : public IMAPCommand {
|
||||
public:
|
||||
UnsubscribeCommand(const char* mailboxName);
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
private:
|
||||
BString fMailboxName;
|
||||
};
|
||||
|
||||
|
||||
class GetQuotaCommand : public IMAPCommand {
|
||||
public:
|
||||
GetQuotaCommand(const char* mailboxName = "");
|
||||
|
||||
BString Command();
|
||||
bool Handle(const BString& response);
|
||||
|
||||
uint64 UsedStorage();
|
||||
uint64 TotalStorage();
|
||||
private:
|
||||
BString fMailboxName;
|
||||
|
||||
uint64 fUsedStorage;
|
||||
uint64 fTotalStorage;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAP_HANDLER_H
|
||||
@@ -43,7 +43,6 @@ IMAPMailbox::IMAPMailbox(IMAPStorage& storage)
|
||||
|
||||
fFetchBodyLimit(0)
|
||||
{
|
||||
fHandlerList.AddItem(&fCapabilityHandler);
|
||||
fIMAPMailboxListener = &fNULLListener;
|
||||
}
|
||||
|
||||
@@ -64,27 +63,6 @@ IMAPMailbox::SetListener(IMAPMailboxListener* listener)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPMailbox::SelectMailbox(const char* mailbox)
|
||||
{
|
||||
TRACE("SELECT %s\n", mailbox);
|
||||
fMailboxSelectHandler.SetTo(mailbox);
|
||||
status_t status = ProcessCommand(&fMailboxSelectHandler);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
fSelectedMailbox = mailbox;
|
||||
|
||||
if (fCapabilityHandler.Capabilities() != "")
|
||||
return status;
|
||||
//else get them
|
||||
status = ProcessCommand(fCapabilityHandler.Command());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
IMAPMailbox::Mailbox()
|
||||
{
|
||||
@@ -239,7 +217,7 @@ IMAPMailbox::FetchMessages(int32 firstMessage, int32 lastMessage)
|
||||
status_t
|
||||
IMAPMailbox::FetchBody(int32 messageNumber)
|
||||
{
|
||||
if (fStorage.BodyFetched(MessageNumberToUID(messageNumber)))
|
||||
if (fStorage.IsBodyFetched(MessageNumberToUID(messageNumber)))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BPositionIO* file;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
class IMAPStorage;
|
||||
|
||||
|
||||
class IMAPMailbox : public IMAPProtocol {
|
||||
class IMAPMailbox : public IMAP::Protocol {
|
||||
public:
|
||||
IMAPMailbox(IMAPStorage& storage);
|
||||
~IMAPMailbox();
|
||||
@@ -39,7 +39,6 @@ public:
|
||||
IMAPMailboxListener& Listener() { return *fIMAPMailboxListener; }
|
||||
|
||||
/*! Select mailbox and sync with the storage. */
|
||||
status_t SelectMailbox(const char* mailbox);
|
||||
BString Mailbox();
|
||||
status_t Sync();
|
||||
|
||||
@@ -68,7 +67,7 @@ public:
|
||||
|
||||
int32 GetCurrentMessageCount()
|
||||
{ return fMessageList.size(); }
|
||||
const MinMessageList& GetMessageList() { return fMessageList; }
|
||||
const IMAP::MinMessageList& GetMessageList() { return fMessageList; }
|
||||
IMAPStorage& GetStorage() { return fStorage; }
|
||||
|
||||
int32 UIDToMessageNumber(int32 uid);
|
||||
@@ -78,17 +77,15 @@ public:
|
||||
private:
|
||||
void _InstallUnsolicitedHandler(bool install);
|
||||
|
||||
MinMessageList fMessageList;
|
||||
IMAP::MinMessageList fMessageList;
|
||||
|
||||
IMAPStorage& fStorage;
|
||||
IMAPMailboxListener* fIMAPMailboxListener;
|
||||
IMAPMailboxListener fNULLListener;
|
||||
|
||||
MailboxSelectHandler fMailboxSelectHandler;
|
||||
CapabilityHandler fCapabilityHandler;
|
||||
ExistsHandler fExistsHandler;
|
||||
ExpungeHandler fExpungeHandler;
|
||||
FlagsHandler fFlagsHandler;
|
||||
IMAP::ExistsHandler fExistsHandler;
|
||||
IMAP::ExpungeHandler fExpungeHandler;
|
||||
// FlagsHandler fFlagsHandler;
|
||||
|
||||
int32 fWatching;
|
||||
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2010 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "IMAPParser.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::ExtractStringAfter(const BString& string, const char* after)
|
||||
{
|
||||
int32 pos = string.FindFirst(after);
|
||||
if (pos < 0)
|
||||
return "";
|
||||
|
||||
BString extractedString = string;
|
||||
extractedString.Remove(0, pos + strlen(after));
|
||||
|
||||
return extractedString.Trim();
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::ExtractFirstPrimitive(const BString& string)
|
||||
{
|
||||
BString extractedString = string;
|
||||
extractedString.Trim();
|
||||
int32 end = extractedString.FindFirst(" ");
|
||||
if (end < 0)
|
||||
return extractedString;
|
||||
return extractedString.Truncate(end);
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::ExtractBetweenBrackets(const BString& string, const char* start,
|
||||
const char* end)
|
||||
{
|
||||
BString outString = string;
|
||||
int32 startPos = outString.FindFirst(start);
|
||||
if (startPos < 0)
|
||||
return "";
|
||||
outString.Remove(0, startPos + 1);
|
||||
|
||||
int32 searchPos = 0;
|
||||
while (true) {
|
||||
int32 endPos = outString.FindFirst(end, searchPos);
|
||||
if (endPos < 0)
|
||||
return "";
|
||||
int32 nextStartPos = outString.FindFirst(start, searchPos);
|
||||
if (nextStartPos < 0 || nextStartPos > endPos)
|
||||
return outString.Truncate(endPos);
|
||||
searchPos = endPos + 1;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::ExtractNextElement(const BString& string)
|
||||
{
|
||||
if (string[0] == '(')
|
||||
return ExtractBetweenBrackets(string, "(", ")");
|
||||
else if (string[0] == '[')
|
||||
return ExtractBetweenBrackets(string, "[", "]");
|
||||
else if (string[0] == '{')
|
||||
return ExtractBetweenBrackets(string, "{", "}");
|
||||
else
|
||||
return ExtractFirstPrimitive(string);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::ExtractElementAfter(const BString& string, const char* after)
|
||||
{
|
||||
BString rest = ExtractStringAfter(string, after);
|
||||
if (rest == "")
|
||||
return rest;
|
||||
return ExtractNextElement(rest);
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
IMAPParser::RemovePrimitiveFromLeft(BString& string)
|
||||
{
|
||||
BString extracted;
|
||||
string.Trim();
|
||||
int32 end = string.FindFirst(" ");
|
||||
if (end < 0) {
|
||||
extracted = string;
|
||||
string = "";
|
||||
} else {
|
||||
string.MoveInto(extracted, 0, end);
|
||||
string.Trim();
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
IMAPParser::RemoveIntegerFromLeft(BString& string)
|
||||
{
|
||||
BString extracted = RemovePrimitiveFromLeft(string);
|
||||
return atoi(extracted);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IMAPParser::RemoveUntagedFromLeft(BString& string, const char* keyword,
|
||||
int32& number)
|
||||
{
|
||||
BString result = RemovePrimitiveFromLeft(string);
|
||||
if (result != "*")
|
||||
return false;
|
||||
number = RemoveIntegerFromLeft(string);
|
||||
if (number == 0)
|
||||
return false;
|
||||
result = RemovePrimitiveFromLeft(string);
|
||||
if (result != keyword)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IMAPParser::ExtractUntagedFromLeft(const BString& string, const char* keyword,
|
||||
int32& number)
|
||||
{
|
||||
//TODO: could be more efficient without copy the string
|
||||
BString copy = string;
|
||||
return RemoveUntagedFromLeft(copy, keyword, number);
|
||||
}
|
||||
@@ -1,35 +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_PARSER_H
|
||||
#define IMAP_PARSER_H
|
||||
|
||||
|
||||
#include <String.h>
|
||||
|
||||
|
||||
namespace IMAPParser {
|
||||
|
||||
BString ExtractStringAfter(const BString& string, const char* after);
|
||||
BString ExtractFirstPrimitive(const BString& string);
|
||||
BString ExtractBetweenBrackets(const BString& string, const char* start,
|
||||
const char* end);
|
||||
BString ExtractNextElement(const BString& string);
|
||||
BString ExtractElementAfter(const BString& string, const char* after);
|
||||
|
||||
BString RemovePrimitiveFromLeft(BString& string);
|
||||
int RemoveIntegerFromLeft(BString& string);
|
||||
|
||||
// remove the part like "* 234 FETCH " where FETCH is the keyword
|
||||
bool RemoveUntagedFromLeft(BString& string, const char* keyword,
|
||||
int32& number);
|
||||
bool ExtractUntagedFromLeft(const BString& string, const char* keyword,
|
||||
int32& number);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // IMAP_PARSER_H
|
||||
@@ -1,433 +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 "IMAPProtocol.h"
|
||||
|
||||
#include "IMAPHandler.h"
|
||||
#include "IMAPParser.h"
|
||||
|
||||
|
||||
#define DEBUG_IMAP_PROTOCOL
|
||||
#ifdef DEBUG_IMAP_PROTOCOL
|
||||
# include <stdio.h>
|
||||
# define TRACE(x...) printf(x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
ConnectionReader::ConnectionReader(ServerConnection* connection)
|
||||
:
|
||||
fServerConnection(connection)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::GetNextLine(BString& line, bigtime_t timeout,
|
||||
int32 maxUnfinishedLine)
|
||||
{
|
||||
line.SetTo((const char*)NULL, 0);
|
||||
|
||||
while (true) {
|
||||
status_t status = _GetNextDataBunch(line, timeout);
|
||||
if (status == B_OK)
|
||||
return status;
|
||||
if (status == B_NAME_NOT_FOUND) {
|
||||
if (maxUnfinishedLine < 0 || line.Length() < maxUnfinishedLine)
|
||||
continue;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::FinishLine(BString& line)
|
||||
{
|
||||
while (true) {
|
||||
status_t status = _GetNextDataBunch(line, B_INFINITE_TIMEOUT);
|
||||
if (status == B_OK)
|
||||
return status;
|
||||
if (status == B_NAME_NOT_FOUND)
|
||||
continue;
|
||||
return status;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::ReadToFile(int32 size, BPositionIO* out)
|
||||
{
|
||||
const int32 kBunchSize = 1024; // 1Kb
|
||||
char buffer[kBunchSize];
|
||||
|
||||
int32 readSize = size - fStringBuffer.Length();
|
||||
int32 readed = fStringBuffer.Length();
|
||||
if (readSize < 0) {
|
||||
readed = size;
|
||||
}
|
||||
out->Write(fStringBuffer.String(), readed);
|
||||
fStringBuffer.Remove(0, readed);
|
||||
|
||||
while (readSize > 0) {
|
||||
int32 bunchSize = readSize < kBunchSize ? readSize : kBunchSize;
|
||||
int nReaded = fServerConnection->Read(buffer, bunchSize);
|
||||
if (nReaded < 0)
|
||||
return B_ERROR;
|
||||
readSize -= nReaded;
|
||||
out->Write(buffer, nReaded);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::_GetNextDataBunch(BString& line, bigtime_t timeout,
|
||||
uint32 maxNewLength)
|
||||
{
|
||||
if (_ExtractTillEndOfLine(line))
|
||||
return B_OK;
|
||||
|
||||
char buffer[maxNewLength];
|
||||
|
||||
if (timeout != B_INFINITE_TIMEOUT) {
|
||||
status_t status = fServerConnection->WaitForData(timeout);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
int nReaded = fServerConnection->Read(buffer, maxNewLength);
|
||||
if (nReaded <= 0)
|
||||
return B_ERROR;
|
||||
|
||||
fStringBuffer.SetTo(buffer, nReaded);
|
||||
if (_ExtractTillEndOfLine(line))
|
||||
return B_OK;
|
||||
return B_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ConnectionReader::_ExtractTillEndOfLine(BString& out)
|
||||
{
|
||||
int32 endPos = fStringBuffer.FindFirst('\n');
|
||||
if (endPos == B_ERROR) {
|
||||
endPos = fStringBuffer.FindFirst(xEOF);
|
||||
if (endPos == B_ERROR) {
|
||||
out += fStringBuffer;
|
||||
fStringBuffer.SetTo((const char*)NULL, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
out.Append(fStringBuffer, endPos + 1);
|
||||
fStringBuffer.Remove(0, endPos + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
IMAPProtocol::IMAPProtocol()
|
||||
:
|
||||
fServerConnection(&fOwnServerConnection),
|
||||
fConnectionReader(fServerConnection),
|
||||
fCommandID(0),
|
||||
fStopNow(0),
|
||||
fIsConnected(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IMAPProtocol::IMAPProtocol(IMAPProtocol& connection)
|
||||
:
|
||||
fServerConnection(connection.fServerConnection),
|
||||
fConnectionReader(fServerConnection),
|
||||
fCommandID(0),
|
||||
fStopNow(0),
|
||||
fIsConnected(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IMAPProtocol::~IMAPProtocol()
|
||||
{
|
||||
for (int32 i = 0; i < fAfterQuackCommands.CountItems(); i++)
|
||||
delete fAfterQuackCommands.ItemAt(i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
IMAPProtocol::SetStopNow()
|
||||
{
|
||||
atomic_set(&fStopNow, 1);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IMAPProtocol::StopNow()
|
||||
{
|
||||
return (atomic_get(&fStopNow) != 0);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::Connect(const char* server, const char* username,
|
||||
const char* password, bool useSSL, int32 port)
|
||||
{
|
||||
TRACE("Connect\n");
|
||||
status_t status = B_ERROR;
|
||||
if (useSSL) {
|
||||
if (port >= 0)
|
||||
status = fServerConnection->ConnectSSL(server, port);
|
||||
else
|
||||
status = fServerConnection->ConnectSSL(server);
|
||||
} else {
|
||||
if (port >= 0)
|
||||
status = fServerConnection->ConnectSocket(server, port);
|
||||
else
|
||||
status = fServerConnection->ConnectSocket(server);
|
||||
}
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
TRACE("Login\n");
|
||||
|
||||
fIsConnected = true;
|
||||
|
||||
BString command = "LOGIN ";
|
||||
command << "\"" << username << "\" ";
|
||||
command << "\"" << password << "\"";
|
||||
status = ProcessCommand(command);
|
||||
if (status != B_OK) {
|
||||
_Disconnect();
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::Disconnect()
|
||||
{
|
||||
ProcessCommand("LOGOUT");
|
||||
return _Disconnect();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IMAPProtocol::IsConnected()
|
||||
{
|
||||
return fIsConnected;
|
||||
}
|
||||
|
||||
|
||||
ConnectionReader&
|
||||
IMAPProtocol::GetConnectionReader()
|
||||
{
|
||||
return fConnectionReader;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::SendRawCommand(const char* command)
|
||||
{
|
||||
static char cmd[256];
|
||||
::sprintf(cmd, "%s"CRLF, command);
|
||||
int32 commandLength = strlen(cmd);
|
||||
|
||||
if (fServerConnection->Write(cmd, commandLength) != commandLength)
|
||||
return B_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
IMAPProtocol::SendRawData(const char* buffer, uint32 nBytes)
|
||||
{
|
||||
return fServerConnection->Write(buffer, nBytes);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::AddAfterQuakeCommand(IMAPCommand* command)
|
||||
{
|
||||
return fAfterQuackCommands.AddItem(command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::ProcessCommand(IMAPCommand* command, bigtime_t timeout)
|
||||
{
|
||||
status_t status = _ProcessCommandWithoutAfterQuake(command, timeout);
|
||||
|
||||
ProcessAfterQuacks(timeout);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::ProcessCommand(const char* command, bigtime_t timeout)
|
||||
{
|
||||
status_t status = _ProcessCommandWithoutAfterQuake(command, timeout);
|
||||
|
||||
ProcessAfterQuacks(timeout);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::SendCommand(const char* command, int32 commandID)
|
||||
{
|
||||
if (strlen(command) + 10 > 256)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
static char cmd[256];
|
||||
::sprintf(cmd, "A%.7" B_PRId32 " %s"CRLF, commandID, command);
|
||||
|
||||
TRACE("_SendCommand: %s\n", cmd);
|
||||
int commandLength = strlen(cmd);
|
||||
if (fServerConnection->Write(cmd, commandLength) != commandLength) {
|
||||
// we might lost the connection, clear the connection state
|
||||
_Disconnect();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fOngoingCommands.push_back(commandID);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::HandleResponse(int32 commandID, bigtime_t timeout,
|
||||
bool disconnectOnTimeout)
|
||||
{
|
||||
status_t commandStatus = B_ERROR;
|
||||
|
||||
bool done = false;
|
||||
while (done != true) {
|
||||
BString line;
|
||||
status_t status = fConnectionReader.GetNextLine(line, timeout);
|
||||
if (status != B_OK) {
|
||||
// we might lost the connection, clear the connection state
|
||||
if (status != B_TIMED_OUT) {
|
||||
TRACE("S:read error %s", line.String());
|
||||
_Disconnect();
|
||||
} else if (disconnectOnTimeout) {
|
||||
_Disconnect();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
//TRACE("S: %s", line.String());
|
||||
|
||||
bool handled = false;
|
||||
for (int i = 0; i < fHandlerList.CountItems(); i++) {
|
||||
if (fHandlerList.ItemAt(i)->Handle(line) == true) {
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (handled == true)
|
||||
continue;
|
||||
|
||||
for (std::vector<int32>::iterator it = fOngoingCommands.begin();
|
||||
it != fOngoingCommands.end(); it++) {
|
||||
static char idString[8];
|
||||
::sprintf(idString, "A%.7" B_PRId32, *it);
|
||||
if (line.FindFirst(idString) >= 0) {
|
||||
if (*it == commandID) {
|
||||
BString result = IMAPParser::ExtractElementAfter(line,
|
||||
idString);
|
||||
if (result == "OK")
|
||||
commandStatus = B_OK;
|
||||
else {
|
||||
fCommandError = IMAPParser::ExtractStringAfter(line,
|
||||
idString);
|
||||
TRACE("Command Error %s\n", fCommandError.String());
|
||||
}
|
||||
}
|
||||
fOngoingCommands.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fOngoingCommands.size() == 0)
|
||||
done = true;
|
||||
|
||||
TRACE("Unhandled S: %s", line.String());
|
||||
}
|
||||
|
||||
return commandStatus;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IMAPProtocol::ProcessAfterQuacks(bigtime_t timeout)
|
||||
{
|
||||
while (fAfterQuackCommands.CountItems() != 0) {
|
||||
IMAPCommand* currentCommand = fAfterQuackCommands.RemoveItemAt(0);
|
||||
_ProcessCommandWithoutAfterQuake(currentCommand, timeout);
|
||||
delete currentCommand;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
IMAPProtocol::NextCommandID()
|
||||
{
|
||||
fCommandID++;
|
||||
return fCommandID;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::_ProcessCommandWithoutAfterQuake(IMAPCommand* command,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
BString cmd = command->Command();
|
||||
if (cmd == "")
|
||||
return B_BAD_VALUE;
|
||||
if (!fHandlerList.AddItem(command, 0))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = _ProcessCommandWithoutAfterQuake(cmd, timeout);
|
||||
|
||||
fHandlerList.RemoveItem(command);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::_ProcessCommandWithoutAfterQuake(const char* command,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
int32 commandID = NextCommandID();
|
||||
status_t status = SendCommand(command, commandID);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return HandleResponse(commandID, timeout);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
IMAPProtocol::_Disconnect()
|
||||
{
|
||||
fOngoingCommands.clear();
|
||||
fIsConnected = false;
|
||||
return fOwnServerConnection.Disconnect();
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001-2002, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
* Copyright 2010 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef IMAP_PROTOCOL_H
|
||||
#define IMAP_PROTOCOL_H
|
||||
|
||||
|
||||
#include "ServerConnection.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <ObjectList.h>
|
||||
#include <OS.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
#define CRLF "\r\n"
|
||||
#define xEOF 236
|
||||
const bigtime_t kIMAP4ClientTimeout = 1000000 * 60; // 60 sec
|
||||
|
||||
|
||||
class ConnectionReader {
|
||||
public:
|
||||
ConnectionReader(ServerConnection* connection);
|
||||
|
||||
/*! Try to read line. If no end of line is found at least
|
||||
minUnfinishedLine characters are returned. */
|
||||
status_t GetNextLine(BString& line,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout,
|
||||
int32 maxUnfinishedLine = -1);
|
||||
/*! Read data and append it to line till the end of file is
|
||||
reached. */
|
||||
status_t FinishLine(BString& line);
|
||||
|
||||
status_t ReadToFile(int32 size, BPositionIO* out);
|
||||
|
||||
private:
|
||||
/*! Try to read till the end of line is reached. To do so maximal
|
||||
maxNewLength bytes are read from the server if needed. */
|
||||
status_t _GetNextDataBunch(BString& line,
|
||||
bigtime_t timeout,
|
||||
uint32 maxNewLength = 256);
|
||||
bool _ExtractTillEndOfLine(BString& out);
|
||||
|
||||
ServerConnection* fServerConnection;
|
||||
|
||||
BString fStringBuffer;
|
||||
};
|
||||
|
||||
|
||||
class IMAPCommand;
|
||||
|
||||
|
||||
typedef BObjectList<IMAPCommand> IMAPCommandList;
|
||||
|
||||
|
||||
class IMAPProtocol {
|
||||
public:
|
||||
IMAPProtocol();
|
||||
/*! Use the server connection from another protocol. */
|
||||
IMAPProtocol(IMAPProtocol& connection);
|
||||
~IMAPProtocol();
|
||||
|
||||
/*! Indicates that the current action should be interrupted because
|
||||
we are going to be deleted. */
|
||||
void SetStopNow();
|
||||
bool StopNow();
|
||||
|
||||
status_t Connect(const char* server,
|
||||
const char* username, const char* password,
|
||||
bool useSSL = true, int32 port = -1);
|
||||
status_t Disconnect();
|
||||
bool IsConnected();
|
||||
|
||||
ConnectionReader& GetConnectionReader();
|
||||
status_t SendRawCommand(const char* command);
|
||||
int32 SendRawData(const char* buffer, uint32 nBytes);
|
||||
|
||||
status_t AddAfterQuakeCommand(IMAPCommand* command);
|
||||
|
||||
const BString& CommandError() { return fCommandError; }
|
||||
protected:
|
||||
/*! Install a temporary handler at first position in the handler
|
||||
list. */
|
||||
status_t ProcessCommand(IMAPCommand* command,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout);
|
||||
status_t ProcessCommand(const char* command,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout);
|
||||
status_t SendCommand(const char* command,
|
||||
int32 commandId);
|
||||
status_t HandleResponse(int32 commandId,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout,
|
||||
bool disconnectOnTimeout = true);
|
||||
void ProcessAfterQuacks(bigtime_t timeout);
|
||||
int32 NextCommandID();
|
||||
|
||||
ServerConnection* fServerConnection;
|
||||
ServerConnection fOwnServerConnection;
|
||||
ConnectionReader fConnectionReader;
|
||||
|
||||
IMAPCommandList fHandlerList;
|
||||
IMAPCommandList fAfterQuackCommands;
|
||||
|
||||
private:
|
||||
/*! Same as ProccessCommand but AfterShockCommands are not send. */
|
||||
status_t _ProcessCommandWithoutAfterQuake(
|
||||
IMAPCommand* command, bigtime_t timeout);
|
||||
status_t _ProcessCommandWithoutAfterQuake(
|
||||
const char* command,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout);
|
||||
status_t _Disconnect();
|
||||
|
||||
int32 fCommandID;
|
||||
std::vector<int32> fOngoingCommands;
|
||||
|
||||
BString fCommandError;
|
||||
|
||||
int32 fStopNow;
|
||||
|
||||
bool fIsConnected;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAP_PROTOCOL_H
|
||||
@@ -36,7 +36,7 @@ IMAPMailboxSync::Sync(IMAPStorage& storage, IMAPMailbox& mailbox)
|
||||
const MinMessageList& messages = mailbox.GetMessageList();
|
||||
|
||||
for (MailEntryMap::const_iterator it = files.begin(); it != files.end();
|
||||
it++) {
|
||||
it++) {
|
||||
const StorageMailEntry& mailEntry = (*it).second;
|
||||
bool found = false;
|
||||
for (unsigned int a = 0; a < messages.size(); a++) {
|
||||
@@ -352,7 +352,7 @@ IMAPStorage::GetEntryForRef(const node_ref& ref)
|
||||
|
||||
|
||||
bool
|
||||
IMAPStorage::BodyFetched(int32 uid)
|
||||
IMAPStorage::IsBodyFetched(int32 uid)
|
||||
{
|
||||
MailEntryMap::iterator it = fMailEntryMap.find(uid);
|
||||
if (it == fMailEntryMap.end())
|
||||
@@ -365,9 +365,8 @@ IMAPStorage::BodyFetched(int32 uid)
|
||||
char buffer[B_MIME_TYPE_LENGTH];
|
||||
BNodeInfo info(&node);
|
||||
info.GetType(buffer);
|
||||
if (strcmp(buffer, B_MAIL_TYPE) == 0)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
return strcmp(buffer, B_MAIL_TYPE) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,17 +16,6 @@
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "IMAPHandler.h"
|
||||
|
||||
|
||||
enum FileFlags {
|
||||
kSeen = 0x01,
|
||||
kAnswered = 0x02,
|
||||
kFlagged = 0x04,
|
||||
kDeleted = 0x08,
|
||||
kDraft = 0x10
|
||||
};
|
||||
|
||||
|
||||
struct StorageMailEntry {
|
||||
int32 uid;
|
||||
@@ -73,7 +62,7 @@ public:
|
||||
|
||||
status_t SetCompleteMessageSize(int32 uid, int32 size);
|
||||
|
||||
bool BodyFetched(int32 uid);
|
||||
bool IsBodyFetched(int32 uid);
|
||||
|
||||
StorageMailEntry* GetEntryForRef(const node_ref& ref);
|
||||
int32 RefToUID(const entry_ref& ref);
|
||||
|
||||
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright 2010-2011, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2010 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Protocol.h"
|
||||
|
||||
#include "Commands.h"
|
||||
|
||||
|
||||
#define DEBUG_IMAP_PROTOCOL
|
||||
#ifdef DEBUG_IMAP_PROTOCOL
|
||||
# include <stdio.h>
|
||||
# define TRACE(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
# define TRACE(...) ;
|
||||
#endif
|
||||
|
||||
|
||||
namespace IMAP {
|
||||
|
||||
|
||||
ConnectionReader::ConnectionReader()
|
||||
:
|
||||
fSocket(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConnectionReader::SetTo(BSocket& socket)
|
||||
{
|
||||
fSocket = &socket;
|
||||
fBufferedSocket = new BBufferedDataIO(socket, 32768, false, true);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::GetNextLine(BString& line, bigtime_t timeout,
|
||||
int32 maxUnfinishedLine)
|
||||
{
|
||||
line.SetTo((const char*)NULL, 0);
|
||||
|
||||
while (true) {
|
||||
status_t status = _GetNextDataBunch(line, timeout);
|
||||
if (status == B_OK)
|
||||
return status;
|
||||
if (status == B_NAME_NOT_FOUND) {
|
||||
if (maxUnfinishedLine < 0 || line.Length() < maxUnfinishedLine)
|
||||
continue;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::FinishLine(BString& line)
|
||||
{
|
||||
while (true) {
|
||||
status_t status = _GetNextDataBunch(line, B_INFINITE_TIMEOUT);
|
||||
if (status == B_OK)
|
||||
return status;
|
||||
if (status == B_NAME_NOT_FOUND)
|
||||
continue;
|
||||
return status;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::ReadToStream(int32 size, BDataIO& out)
|
||||
{
|
||||
const int32 kBunchSize = 1024; // 1Kb
|
||||
char buffer[kBunchSize];
|
||||
|
||||
int32 readSize = size - fStringBuffer.Length();
|
||||
int32 readed = fStringBuffer.Length();
|
||||
if (readSize < 0) {
|
||||
readed = size;
|
||||
}
|
||||
out.Write(fStringBuffer.String(), readed);
|
||||
fStringBuffer.Remove(0, readed);
|
||||
|
||||
while (readSize > 0) {
|
||||
int32 bunchSize = readSize < kBunchSize ? readSize : kBunchSize;
|
||||
int nReaded = fBufferedSocket->Read(buffer, bunchSize);
|
||||
if (nReaded < 0)
|
||||
return B_ERROR;
|
||||
readSize -= nReaded;
|
||||
out.Write(buffer, nReaded);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ConnectionReader::_GetNextDataBunch(BString& line, bigtime_t timeout,
|
||||
uint32 maxNewLength)
|
||||
{
|
||||
if (_ExtractTillEndOfLine(line))
|
||||
return B_OK;
|
||||
|
||||
char buffer[maxNewLength];
|
||||
//
|
||||
// if (timeout != B_INFINITE_TIMEOUT) {
|
||||
// status_t status = fSocket->WaitForReadable(timeout);
|
||||
// if (status != B_OK)
|
||||
// return status;
|
||||
// }
|
||||
|
||||
int nReaded = fBufferedSocket->Read(buffer, maxNewLength);
|
||||
if (nReaded <= 0)
|
||||
return B_ERROR;
|
||||
|
||||
fStringBuffer.SetTo(buffer, nReaded);
|
||||
if (_ExtractTillEndOfLine(line))
|
||||
return B_OK;
|
||||
return B_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ConnectionReader::_ExtractTillEndOfLine(BString& out)
|
||||
{
|
||||
int32 endPos = fStringBuffer.FindFirst('\n');
|
||||
if (endPos == B_ERROR) {
|
||||
endPos = fStringBuffer.FindFirst(xEOF);
|
||||
if (endPos == B_ERROR) {
|
||||
out += fStringBuffer;
|
||||
fStringBuffer.SetTo((const char*)NULL, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
out.Append(fStringBuffer, endPos + 1);
|
||||
fStringBuffer.Remove(0, endPos + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Protocol::Protocol()
|
||||
:
|
||||
fSocket(NULL),
|
||||
fBufferedSocket(NULL),
|
||||
fCommandID(0),
|
||||
fStopNow(0),
|
||||
fIsConnected(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Protocol::~Protocol()
|
||||
{
|
||||
for (int32 i = 0; i < fAfterQuackCommands.CountItems(); i++)
|
||||
delete fAfterQuackCommands.ItemAt(i);
|
||||
|
||||
delete fSocket;
|
||||
delete fBufferedSocket;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Protocol::SetStopNow()
|
||||
{
|
||||
atomic_set(&fStopNow, 1);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Protocol::StopNow()
|
||||
{
|
||||
return (atomic_get(&fStopNow) != 0);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::Connect(const BNetworkAddress& address, const char* username,
|
||||
const char* password, bool useSSL)
|
||||
{
|
||||
TRACE("Connect\n");
|
||||
if (useSSL)
|
||||
fSocket = new(std::nothrow) BSecureSocket(address);
|
||||
else
|
||||
fSocket = new(std::nothrow) BSocket(address);
|
||||
|
||||
if (fSocket == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = fSocket->InitCheck();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
fBufferedSocket = new(std::nothrow) BBufferedDataIO(*fSocket, 32768, false,
|
||||
true);
|
||||
if (fBufferedSocket == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE("Login\n");
|
||||
|
||||
fConnectionReader.SetTo(*fSocket);
|
||||
fIsConnected = true;
|
||||
|
||||
LoginCommand login(username, password);
|
||||
status = ProcessCommand(login);
|
||||
if (status != B_OK) {
|
||||
_Disconnect();
|
||||
return status;
|
||||
}
|
||||
|
||||
_ParseCapabilities(login.Capabilities());
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::Disconnect()
|
||||
{
|
||||
if (IsConnected()) {
|
||||
RawCommand command("LOGOUT");
|
||||
ProcessCommand(command);
|
||||
}
|
||||
return _Disconnect();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Protocol::IsConnected()
|
||||
{
|
||||
return fIsConnected;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::GetFolders(FolderList& folders)
|
||||
{
|
||||
StringList allFolders;
|
||||
status_t status = _GetAllFolders(allFolders);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
StringList subscribedFolders;
|
||||
status = _GetSubscribedFolders(subscribedFolders);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (unsigned int i = 0; i < allFolders.size(); i++) {
|
||||
FolderInfo info;
|
||||
info.folder = allFolders[i];
|
||||
for (unsigned int a = 0; a < subscribedFolders.size(); a++) {
|
||||
if (allFolders[i] == subscribedFolders[a]
|
||||
|| allFolders[i].ICompare("INBOX") == 0) {
|
||||
info.subscribed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
folders.push_back(info);
|
||||
}
|
||||
|
||||
// you could be subscribed to a folder which not exist currently, add them:
|
||||
for (unsigned int a = 0; a < subscribedFolders.size(); a++) {
|
||||
bool isInlist = false;
|
||||
for (unsigned int i = 0; i < allFolders.size(); i++) {
|
||||
if (subscribedFolders[a] == allFolders[i]) {
|
||||
isInlist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isInlist)
|
||||
continue;
|
||||
|
||||
FolderInfo info;
|
||||
info.folder = subscribedFolders[a];
|
||||
info.subscribed = true;
|
||||
folders.push_back(info);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::SubscribeFolder(const char* folder)
|
||||
{
|
||||
SubscribeCommand command(folder);
|
||||
return ProcessCommand(command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::UnsubscribeFolder(const char* folder)
|
||||
{
|
||||
UnsubscribeCommand command(folder);
|
||||
return ProcessCommand(command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::SelectMailbox(const char* mailbox)
|
||||
{
|
||||
TRACE("SELECT %s\n", mailbox);
|
||||
SelectCommand command(mailbox);
|
||||
status_t status = ProcessCommand(command);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (fCapabilities.IsEmpty()) {
|
||||
CapabilityHandler capabilityHandler;
|
||||
status = ProcessCommand(capabilityHandler);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
_ParseCapabilities(capabilityHandler.Capabilities());
|
||||
}
|
||||
|
||||
fMailbox = mailbox;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::GetQuota(uint64& used, uint64& total)
|
||||
{
|
||||
if (!Capabilities().Contains("QUOTA"))
|
||||
return B_ERROR;
|
||||
|
||||
GetQuotaCommand quotaCommand;
|
||||
status_t status = ProcessCommand(quotaCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
used = quotaCommand.UsedStorage();
|
||||
total = quotaCommand.TotalStorage();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::SendCommand(const char* command)
|
||||
{
|
||||
return SendCommand(0, command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::SendCommand(int32 id, const char* command)
|
||||
{
|
||||
char buffer[2048];
|
||||
int32 length;
|
||||
if (id > 0)
|
||||
length = snprintf(buffer, sizeof(buffer), "A%.7ld %s\r\n", id, command);
|
||||
else
|
||||
length = snprintf(buffer, sizeof(buffer), "%s\r\n", command);
|
||||
|
||||
ssize_t bytesWritten = fSocket->Write(buffer, length);
|
||||
if (bytesWritten < 0)
|
||||
return bytesWritten;
|
||||
|
||||
return bytesWritten == length ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Protocol::SendData(const char* buffer, uint32 length)
|
||||
{
|
||||
return fSocket->Write(buffer, length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::AddAfterQuakeCommand(Command* command)
|
||||
{
|
||||
return fAfterQuackCommands.AddItem(command);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::ProcessCommand(Command& command, bigtime_t timeout)
|
||||
{
|
||||
status_t status = _ProcessCommandWithoutAfterQuake(command, timeout);
|
||||
|
||||
ProcessAfterQuacks(timeout);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::HandleResponse(bigtime_t timeout, bool disconnectOnTimeout)
|
||||
{
|
||||
status_t commandStatus = B_OK;
|
||||
IMAP::ResponseParser parser(fConnectionReader);
|
||||
IMAP::Response response;
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
status_t status = parser.NextResponse(response, timeout);
|
||||
if (status != B_OK) {
|
||||
// we might have lost the connection, clear the connection state
|
||||
if (status != B_TIMED_OUT || disconnectOnTimeout)
|
||||
_Disconnect();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (response.IsUntagged() || response.IsContinuation()) {
|
||||
bool handled = false;
|
||||
for (int i = 0; i < fHandlerList.CountItems(); i++) {
|
||||
if (fHandlerList.ItemAt(i)->HandleUntagged(response)) {
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!handled)
|
||||
printf("Unhandled S: %s\n", response.ToString().String());
|
||||
} else {
|
||||
CommandIDMap::iterator found
|
||||
= fOngoingCommands.find(response.Tag());
|
||||
if (found != fOngoingCommands.end()) {
|
||||
status_t status = found->second->HandleTagged(response);
|
||||
if (status != B_OK)
|
||||
commandStatus = status;
|
||||
|
||||
fOngoingCommands.erase(found);
|
||||
} else
|
||||
printf("Unknown tag S: %s\n", response.ToString().String());
|
||||
}
|
||||
} catch (IMAP::ParseException& exception) {
|
||||
printf("Error during parsing: %s\n", exception.Message());
|
||||
}
|
||||
|
||||
if (fOngoingCommands.size() == 0)
|
||||
done = true;
|
||||
}
|
||||
|
||||
return commandStatus;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Protocol::ProcessAfterQuacks(bigtime_t timeout)
|
||||
{
|
||||
while (fAfterQuackCommands.CountItems() != 0) {
|
||||
Command* currentCommand = fAfterQuackCommands.RemoveItemAt(0);
|
||||
_ProcessCommandWithoutAfterQuake(*currentCommand, timeout);
|
||||
delete currentCommand;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Protocol::NextCommandID()
|
||||
{
|
||||
fCommandID++;
|
||||
return fCommandID;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::_ProcessCommandWithoutAfterQuake(Command& command, bigtime_t timeout)
|
||||
{
|
||||
BString commandString = command.CommandString();
|
||||
if (commandString.IsEmpty())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
Handler* handler = dynamic_cast<Handler*>(&command);
|
||||
if (handler != NULL && !fHandlerList.AddItem(handler, 0))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
int32 commandID = NextCommandID();
|
||||
status_t status = SendCommand(commandID, commandString.String());
|
||||
if (status == B_OK) {
|
||||
fOngoingCommands[commandID] = &command;
|
||||
status = HandleResponse(timeout);
|
||||
}
|
||||
|
||||
if (handler != NULL)
|
||||
fHandlerList.RemoveItem(handler);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::_Disconnect()
|
||||
{
|
||||
fOngoingCommands.clear();
|
||||
fIsConnected = false;
|
||||
delete fSocket;
|
||||
fSocket = NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::_GetAllFolders(StringList& folders)
|
||||
{
|
||||
ListCommand listCommand;
|
||||
status_t status = ProcessCommand(listCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
folders = listCommand.FolderList();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Protocol::_GetSubscribedFolders(StringList& folders)
|
||||
{
|
||||
ListSubscribedCommand listSubscribedCommand;
|
||||
status_t status = ProcessCommand(listSubscribedCommand);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
folders = listSubscribedCommand.FolderList();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Protocol::_ParseCapabilities(const ArgumentList& arguments)
|
||||
{
|
||||
fCapabilities.MakeEmpty();
|
||||
|
||||
for (int32 i = 0; i < arguments.CountItems(); i++) {
|
||||
if (StringArgument* argument
|
||||
= dynamic_cast<StringArgument*>(arguments.ItemAt(i)))
|
||||
fCapabilities.AddItem(new StringArgument(*argument));
|
||||
}
|
||||
|
||||
TRACE("capabilities: %s\n", fCapabilities.ToString().String());
|
||||
}
|
||||
|
||||
|
||||
} // namespace IMAP
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2001-2011, Haiku Inc. All Rights Reserved.
|
||||
* Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
* Copyright 2010 Clemens Zeidler. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <BufferedDataIO.h>
|
||||
#include <ObjectList.h>
|
||||
#include <OS.h>
|
||||
#include <SecureSocket.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "Commands.h"
|
||||
|
||||
|
||||
#define xEOF 236
|
||||
const bigtime_t kIMAP4ClientTimeout = 1000000 * 60; // 60 sec
|
||||
|
||||
|
||||
namespace IMAP {
|
||||
|
||||
|
||||
class Command;
|
||||
class Handler;
|
||||
|
||||
|
||||
typedef BObjectList<Command> CommandList;
|
||||
typedef BObjectList<Handler> HandlerList;
|
||||
typedef std::map<int32, Command*> CommandIDMap;
|
||||
|
||||
|
||||
// TODO: throw this class away, and just use a BBufferedDataIO instead.
|
||||
class ConnectionReader {
|
||||
public:
|
||||
ConnectionReader();
|
||||
|
||||
void SetTo(BSocket& socket);
|
||||
|
||||
/*! Try to read line. If no end of line is found at least
|
||||
minUnfinishedLine characters are returned. */
|
||||
status_t GetNextLine(BString& line,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout,
|
||||
int32 maxUnfinishedLine = -1);
|
||||
/*! Read data and append it to line till the end of file is
|
||||
reached. */
|
||||
status_t FinishLine(BString& line);
|
||||
|
||||
status_t ReadToStream(int32 size, BDataIO& out);
|
||||
|
||||
private:
|
||||
/*! Try to read till the end of line is reached. To do so maximal
|
||||
maxNewLength bytes are read from the server if needed. */
|
||||
status_t _GetNextDataBunch(BString& line,
|
||||
bigtime_t timeout,
|
||||
uint32 maxNewLength = 256);
|
||||
bool _ExtractTillEndOfLine(BString& out);
|
||||
|
||||
private:
|
||||
BSocket* fSocket;
|
||||
BBufferedDataIO* fBufferedSocket;
|
||||
BString fStringBuffer;
|
||||
};
|
||||
|
||||
|
||||
class FolderInfo {
|
||||
public:
|
||||
FolderInfo()
|
||||
:
|
||||
subscribed(false)
|
||||
{
|
||||
}
|
||||
|
||||
BString folder;
|
||||
bool subscribed;
|
||||
};
|
||||
typedef std::vector<FolderInfo> FolderList;
|
||||
|
||||
|
||||
class Protocol {
|
||||
public:
|
||||
Protocol();
|
||||
~Protocol();
|
||||
|
||||
/*! Indicates that the current action should be interrupted because
|
||||
we are going to be deleted. */
|
||||
void SetStopNow();
|
||||
bool StopNow();
|
||||
|
||||
status_t Connect(const BNetworkAddress& address,
|
||||
const char* username, const char* password,
|
||||
bool useSSL = true);
|
||||
status_t Disconnect();
|
||||
bool IsConnected();
|
||||
|
||||
status_t SendCommand(const char* command);
|
||||
status_t SendCommand(int32 id, const char* command);
|
||||
ssize_t SendData(const char* buffer, uint32 length);
|
||||
|
||||
status_t GetFolders(FolderList& folders);
|
||||
status_t SubscribeFolder(const char* folder);
|
||||
status_t UnsubscribeFolder(const char* folder);
|
||||
|
||||
status_t SelectMailbox(const char* mailbox);
|
||||
const BString& Mailbox() const { return fMailbox; }
|
||||
|
||||
status_t GetQuota(uint64& used, uint64& total);
|
||||
|
||||
/*! Install a temporary handler at first position in the handler
|
||||
list. */
|
||||
status_t ProcessCommand(Command& command,
|
||||
bigtime_t timeout = kIMAP4ClientTimeout);
|
||||
|
||||
ArgumentList& Capabilities() { return fCapabilities; }
|
||||
const ArgumentList& Capabilities() const { return fCapabilities; }
|
||||
|
||||
status_t AddAfterQuakeCommand(Command* command);
|
||||
|
||||
const BString& CommandError() { return fCommandError; }
|
||||
|
||||
protected:
|
||||
status_t HandleResponse(
|
||||
bigtime_t timeout = kIMAP4ClientTimeout,
|
||||
bool disconnectOnTimeout = true);
|
||||
void ProcessAfterQuacks(bigtime_t timeout);
|
||||
int32 NextCommandID();
|
||||
|
||||
private:
|
||||
/*! Same as ProccessCommand but AfterShockCommands are not send. */
|
||||
status_t _ProcessCommandWithoutAfterQuake(
|
||||
Command& command, bigtime_t timeout);
|
||||
status_t _Disconnect();
|
||||
status_t _GetAllFolders(StringList& folders);
|
||||
status_t _GetSubscribedFolders(StringList& folders);
|
||||
void _ParseCapabilities(
|
||||
const ArgumentList& arguments);
|
||||
|
||||
protected:
|
||||
BSocket* fSocket;
|
||||
BBufferedDataIO* fBufferedSocket;
|
||||
ConnectionReader fConnectionReader;
|
||||
|
||||
HandlerList fHandlerList;
|
||||
CommandList fAfterQuackCommands;
|
||||
ArgumentList fCapabilities;
|
||||
|
||||
private:
|
||||
BString fMailbox;
|
||||
int32 fCommandID;
|
||||
CommandIDMap fOngoingCommands;
|
||||
BString fCommandError;
|
||||
|
||||
vint32 fStopNow;
|
||||
bool fIsConnected;
|
||||
};
|
||||
|
||||
|
||||
} // namespace IMAP
|
||||
|
||||
|
||||
#endif // PROTOCOL_H
|
||||
@@ -6,6 +6,19 @@
|
||||
|
||||
#include "Response.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Protocol.h"
|
||||
// TODO: remove again once the ConnectionReader is out
|
||||
|
||||
|
||||
#define TRACE_IMAP
|
||||
#ifdef TRACE_IMAP
|
||||
# define TRACE(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
# define TRACE(...) ;
|
||||
#endif
|
||||
|
||||
|
||||
namespace IMAP {
|
||||
|
||||
@@ -82,11 +95,8 @@ ArgumentList::ListAt(int32 index) const
|
||||
bool
|
||||
ArgumentList::IsListAt(int32 index) const
|
||||
{
|
||||
if (index >= 0 && index < CountItems()) {
|
||||
if (ListArgument* argument = dynamic_cast<ListArgument*>(ItemAt(index)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return index >= 0 && index < CountItems()
|
||||
&& dynamic_cast<ListArgument*>(ItemAt(index)) != NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,15 +111,15 @@ ArgumentList::IsListAt(int32 index, char kind) const
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ArgumentList::IntegerAt(int32 index) const
|
||||
uint32
|
||||
ArgumentList::NumberAt(int32 index) const
|
||||
{
|
||||
return atoi(StringAt(index).String());
|
||||
return atoul(StringAt(index).String());
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ArgumentList::IsIntegerAt(int32 index) const
|
||||
ArgumentList::IsNumberAt(int32 index) const
|
||||
{
|
||||
BString string = StringAt(index);
|
||||
for (int32 i = 0; i < string.Length(); i++) {
|
||||
@@ -209,11 +219,6 @@ ParseException::ParseException(const char* message)
|
||||
}
|
||||
|
||||
|
||||
ParseException::~ParseException()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@@ -228,6 +233,19 @@ ExpectedParseException::ExpectedParseException(char expected, char instead)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
LiteralHandler::LiteralHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LiteralHandler::~LiteralHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Response::Response()
|
||||
:
|
||||
fTag(0),
|
||||
@@ -242,9 +260,12 @@ Response::~Response()
|
||||
|
||||
|
||||
void
|
||||
Response::SetTo(const char* line) throw(ParseException)
|
||||
Response::Parse(ConnectionReader& reader, const char* line,
|
||||
LiteralHandler* handler) throw(ParseException)
|
||||
{
|
||||
MakeEmpty();
|
||||
fReader = &reader;
|
||||
fLiteralHandler = handler;
|
||||
fTag = 0;
|
||||
fContinuation = false;
|
||||
|
||||
@@ -384,8 +405,24 @@ Response::ParseQuoted(ArgumentList& arguments, const char*& line)
|
||||
void
|
||||
Response::ParseLiteral(ArgumentList& arguments, const char*& line)
|
||||
{
|
||||
// TODO!
|
||||
throw ParseException("Literals are not yet supported!");
|
||||
Consume(line, '{');
|
||||
off_t size = atoll(ExtractString(line));
|
||||
Consume(line, '}');
|
||||
Consume(line, '\r');
|
||||
Consume(line, '\n');
|
||||
|
||||
if (fLiteralHandler != NULL)
|
||||
fLiteralHandler->HandleLiteral(*fReader, size);
|
||||
else {
|
||||
// The default implementation just throws the data away
|
||||
BMallocIO stream;
|
||||
TRACE("Trying to read literal with %llu bytes.\n", size);
|
||||
status_t status = fReader->ReadToStream(size, stream);
|
||||
if (status == B_OK) {
|
||||
TRACE("LITERAL: %-*s\n", (int)size, (char*)stream.Buffer());
|
||||
} else
|
||||
TRACE("Reading literal failed: %s\n", strerror(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -401,6 +438,7 @@ Response::ExtractString(const char*& line)
|
||||
{
|
||||
const char* start = line;
|
||||
|
||||
// TODO: parse modified UTF-7 as described in RFC 3501, 5.1.3
|
||||
while (line[0] != '\0') {
|
||||
char c = line[0];
|
||||
if (c <= ' ' || strchr("()[]{}\"", c) != NULL)
|
||||
@@ -413,4 +451,52 @@ Response::ExtractString(const char*& line)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ResponseParser::ResponseParser(ConnectionReader& reader)
|
||||
:
|
||||
fLiteralHandler(NULL)
|
||||
{
|
||||
SetTo(reader);
|
||||
}
|
||||
|
||||
|
||||
ResponseParser::~ResponseParser()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ResponseParser::SetTo(ConnectionReader& reader)
|
||||
{
|
||||
fReader = &reader;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ResponseParser::SetLiteralHandler(LiteralHandler* handler)
|
||||
{
|
||||
fLiteralHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ResponseParser::NextResponse(Response& response, bigtime_t timeout)
|
||||
throw(ParseException)
|
||||
{
|
||||
BString line;
|
||||
status_t status = fReader->GetNextLine(line, timeout);
|
||||
if (status != B_OK) {
|
||||
TRACE("S: read error %s", line.String());
|
||||
return status;
|
||||
}
|
||||
|
||||
TRACE("S: %s", line.String());
|
||||
response.Parse(*fReader, line, fLiteralHandler);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
} // namespace IMAP
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace IMAP {
|
||||
|
||||
|
||||
class Argument;
|
||||
class ConnectionReader;
|
||||
|
||||
|
||||
class ArgumentList : public BObjectList<Argument> {
|
||||
@@ -33,8 +34,8 @@ public:
|
||||
bool IsListAt(int32 index) const;
|
||||
bool IsListAt(int32 index, char kind) const;
|
||||
|
||||
int32 IntegerAt(int32 index) const;
|
||||
bool IsIntegerAt(int32 index) const;
|
||||
uint32 NumberAt(int32 index) const;
|
||||
bool IsNumberAt(int32 index) const;
|
||||
|
||||
BString ToString() const;
|
||||
};
|
||||
@@ -82,7 +83,6 @@ class ParseException : public std::exception {
|
||||
public:
|
||||
ParseException();
|
||||
ParseException(const char* message);
|
||||
virtual ~ParseException();
|
||||
|
||||
const char* Message() const { return fMessage; }
|
||||
|
||||
@@ -91,7 +91,7 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class ExpectedParseException : ParseException {
|
||||
class ExpectedParseException : public ParseException {
|
||||
public:
|
||||
ExpectedParseException(char expected,
|
||||
char instead);
|
||||
@@ -101,12 +101,24 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class LiteralHandler {
|
||||
public:
|
||||
LiteralHandler();
|
||||
virtual ~LiteralHandler();
|
||||
|
||||
virtual void HandleLiteral(ConnectionReader& reader,
|
||||
off_t length) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Response : public ArgumentList {
|
||||
public:
|
||||
Response();
|
||||
~Response();
|
||||
|
||||
void SetTo(const char* line) throw(ParseException);
|
||||
void Parse(ConnectionReader& reader,
|
||||
const char* line, LiteralHandler* handler)
|
||||
throw(ParseException);
|
||||
|
||||
bool IsUntagged() const { return fTag == 0; }
|
||||
int32 Tag() const { return fTag; }
|
||||
@@ -128,11 +140,30 @@ protected:
|
||||
BString ExtractString(const char*& line);
|
||||
|
||||
protected:
|
||||
ConnectionReader* fReader;
|
||||
LiteralHandler* fLiteralHandler;
|
||||
int32 fTag;
|
||||
bool fContinuation;
|
||||
};
|
||||
|
||||
|
||||
class ResponseParser {
|
||||
public:
|
||||
ResponseParser(ConnectionReader& reader);
|
||||
~ResponseParser();
|
||||
|
||||
void SetTo(ConnectionReader& reader);
|
||||
void SetLiteralHandler(LiteralHandler* handler);
|
||||
|
||||
status_t NextResponse(Response& response,
|
||||
bigtime_t timeout) throw(ParseException);
|
||||
|
||||
protected:
|
||||
ConnectionReader* fReader;
|
||||
LiteralHandler* fLiteralHandler;
|
||||
};
|
||||
|
||||
|
||||
} // namespace IMAP
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,20 @@ SubDirHdrs [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols
|
||||
imap imap_lib ] ;
|
||||
|
||||
local libSources = IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp
|
||||
IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.cpp ;
|
||||
local libSources = Commands.cpp Protocol.cpp Response.cpp ;
|
||||
#IMAPStorage.cpp
|
||||
|
||||
# use OpenSSL, if enabled
|
||||
if $(HAIKU_OPENSSL_ENABLED) {
|
||||
SubDirC++Flags -DUSE_SSL ;
|
||||
SubDirSysHdrs $(HAIKU_OPENSSL_HEADERS) ;
|
||||
Includes [ FGristFiles $(sources) ] : $(HAIKU_OPENSSL_HEADERS_DEPENDENCY) ;
|
||||
# Dependency needed to trigger downloading/unzipping the package before
|
||||
# compiling the files.
|
||||
SetupFeatureObjectsDir ssl ;
|
||||
} else {
|
||||
SetupFeatureObjectsDir no-ssl ;
|
||||
}
|
||||
|
||||
SimpleTest imap_tester :
|
||||
imap_tester.cpp
|
||||
@@ -18,7 +30,7 @@ SimpleTest imap_tester :
|
||||
# from fs_shell
|
||||
argv.c
|
||||
|
||||
: be [ TargetLibsupc++ ] mail
|
||||
: be [ TargetLibstdc++ ] [ TargetLibsupc++ ] bnetapi mail
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles $(libSources) ]
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
#include "IMAPFolders.h"
|
||||
#include "IMAPMailbox.h"
|
||||
#include "IMAPStorage.h"
|
||||
/*
|
||||
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//#include "IMAPStorage.h"
|
||||
#include "Protocol.h"
|
||||
#include "Response.h"
|
||||
|
||||
#include "argv.h"
|
||||
|
||||
|
||||
struct cmd_entry {
|
||||
char* name;
|
||||
void (*func)(int argc, char **argv);
|
||||
char* help;
|
||||
const char* name;
|
||||
void (*func)(int argc, char **argv);
|
||||
const char* help;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,8 +26,8 @@ static void do_help(int argc, char** argv);
|
||||
extern const char* __progname;
|
||||
static const char* kProgramName = __progname;
|
||||
|
||||
static IMAPStorage sStorage;
|
||||
static IMAPMailbox sMailbox(sStorage);
|
||||
//static IMAPStorage sStorage;
|
||||
static IMAP::Protocol sMailbox;//(/*sStorage*/);
|
||||
|
||||
|
||||
static void
|
||||
@@ -56,11 +64,13 @@ do_select(int argc, char** argv)
|
||||
static void
|
||||
do_folders(int argc, char** argv)
|
||||
{
|
||||
IMAPFolders folder(sMailbox);
|
||||
FolderList folders;
|
||||
status_t status = folder.GetFolders(folders);
|
||||
if (status != B_OK)
|
||||
IMAP::FolderList folders;
|
||||
|
||||
status_t status = sMailbox.GetFolders(folders);
|
||||
if (status != B_OK) {
|
||||
error("folders", status);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < folders.size(); i++) {
|
||||
printf(" %s %s\n", folders[i].subscribed ? "*" : " ",
|
||||
@@ -69,6 +79,34 @@ do_folders(int argc, char** argv)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_flags(int argc, char** argv)
|
||||
{
|
||||
uint32 from = 1;
|
||||
uint32 to;
|
||||
if (argc < 2) {
|
||||
printf("usage: %s [<from>] [<to>]\n", argv[0]);
|
||||
return;
|
||||
}
|
||||
if (argc > 2) {
|
||||
from = atoul(argv[1]);
|
||||
to = atoul(argv[2]);
|
||||
} else
|
||||
to = atoul(argv[1]);
|
||||
|
||||
IMAP::MessageEntryList entries;
|
||||
IMAP::FetchMessageEntriesCommand command(entries, from, to);
|
||||
status_t status = sMailbox.ProcessCommand(command);
|
||||
if (status != B_OK) {
|
||||
error("flags", status);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entries.size(); i++)
|
||||
printf(" %lu %lx\n", entries[i].uid, entries[i].flags);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_raw(int argc, char** argv)
|
||||
{
|
||||
@@ -82,7 +120,7 @@ do_raw(int argc, char** argv)
|
||||
strlcat(command, argv[i], sizeof(command));
|
||||
}
|
||||
|
||||
class RawCommand : public IMAPCommand {
|
||||
class RawCommand : public IMAP::Command, public IMAP::Handler {
|
||||
public:
|
||||
RawCommand(const char* command)
|
||||
:
|
||||
@@ -90,13 +128,18 @@ do_raw(int argc, char** argv)
|
||||
{
|
||||
}
|
||||
|
||||
BString Command()
|
||||
BString CommandString()
|
||||
{
|
||||
return fCommand;
|
||||
}
|
||||
|
||||
bool Handle(const BString& response)
|
||||
bool HandleUntagged(IMAP::Response& response)
|
||||
{
|
||||
if (response.IsCommand(fCommand)) {
|
||||
printf("-> %s\n", response.ToString().String());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -104,7 +147,7 @@ do_raw(int argc, char** argv)
|
||||
const char* fCommand;
|
||||
};
|
||||
RawCommand rawCommand(command);
|
||||
status_t status = sMailbox.ProcessCommand(&rawCommand, 60 * 1000);
|
||||
status_t status = sMailbox.ProcessCommand(rawCommand);
|
||||
if (status != B_OK)
|
||||
error("raw", status);
|
||||
}
|
||||
@@ -113,6 +156,8 @@ do_raw(int argc, char** argv)
|
||||
static cmd_entry sBuiltinCommands[] = {
|
||||
{"select", do_select, "Selects a mailbox, defaults to INBOX"},
|
||||
{"folders", do_folders, "List of existing folders"},
|
||||
{"flags", do_flags,
|
||||
"List of all mail UIDs in the mailbox with their flags"},
|
||||
{"raw", do_raw, "Issue a raw command to the server"},
|
||||
{"help", do_help, "prints this help text"},
|
||||
{"quit", NULL, "exits the application"},
|
||||
@@ -145,11 +190,13 @@ main(int argc, char** argv)
|
||||
const char* user = argv[2];
|
||||
const char* password = argv[3];
|
||||
bool useSSL = argc > 4;
|
||||
uint16 port = useSSL ? 995 : 143;
|
||||
uint16 port = useSSL ? 993 : 143;
|
||||
|
||||
printf("Connecting to \"%s\" as %s\n", server, user);
|
||||
BNetworkAddress address(AF_INET, server, port);
|
||||
printf("Connecting to \"%s\" as %s%s, port %u\n", server, user,
|
||||
useSSL ? " with SSL" : "", address.Port());
|
||||
|
||||
status_t status = sMailbox.Connect(server, user, password, useSSL, port);
|
||||
status_t status = sMailbox.Connect(address, user, password, useSSL);
|
||||
if (status != B_OK) {
|
||||
error("connect", status);
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user