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;
|
delete[] passwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fIMAPFolders.Connect(server, username, password, useSSL);
|
fProtocol.Connect(server, username, password, useSSL);
|
||||||
fFolderList.clear();
|
fFolderList.clear();
|
||||||
fIMAPFolders.GetFolders(fFolderList);
|
fProtocol.GetFolders(fFolderList);
|
||||||
for (unsigned int i = 0; i < fFolderList.size(); i++) {
|
for (unsigned int i = 0; i < fFolderList.size(); i++) {
|
||||||
FolderInfo& info = fFolderList[i];
|
FolderInfo& info = fFolderList[i];
|
||||||
CheckBoxItem* item = new CheckBoxItem(info.folder, info.subscribed);
|
CheckBoxItem* item = new CheckBoxItem(info.folder, info.subscribed);
|
||||||
@@ -340,7 +340,7 @@ FolderConfigWindow::_LoadFolders()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64 used, total;
|
uint64 used, total;
|
||||||
if (fIMAPFolders.GetQuota(used, total) == B_OK) {
|
if (fProtocol.GetQuota(used, total) == B_OK) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
BString quotaString = "Server storage: ";
|
BString quotaString = "Server storage: ";
|
||||||
quotaString += string_for_size(used, buffer, 256);
|
quotaString += string_for_size(used, buffer, 256);
|
||||||
@@ -377,9 +377,9 @@ FolderConfigWindow::_ApplyChanges()
|
|||||||
FolderInfo& info = fFolderList[i];
|
FolderInfo& info = fFolderList[i];
|
||||||
CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i);
|
CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i);
|
||||||
if (info.subscribed && !item->Checked())
|
if (info.subscribed && !item->Checked())
|
||||||
fIMAPFolders.UnsubscribeFolder(info.folder);
|
fProtocol.UnsubscribeFolder(info.folder);
|
||||||
else if (!info.subscribed && item->Checked())
|
else if (!info.subscribed && item->Checked())
|
||||||
fIMAPFolders.SubscribeFolder(info.folder);
|
fProtocol.SubscribeFolder(info.folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
status->PostMessage(B_QUIT_REQUESTED);
|
status->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include <MailSettings.h>
|
#include <MailSettings.h>
|
||||||
|
|
||||||
#include "IMAPFolders.h"
|
#include "Protocol.h"
|
||||||
|
|
||||||
|
|
||||||
class FolderConfigWindow : public BWindow {
|
class FolderConfigWindow : public BWindow {
|
||||||
@@ -28,11 +28,11 @@ private:
|
|||||||
void _LoadFolders();
|
void _LoadFolders();
|
||||||
void _ApplyChanges();
|
void _ApplyChanges();
|
||||||
|
|
||||||
IMAPFolders fIMAPFolders;
|
IMAP::Protocol fProtocol;
|
||||||
BListView* fFolderListView;
|
BListView* fFolderListView;
|
||||||
BButton* fApplyButton;
|
BButton* fApplyButton;
|
||||||
const BMessage fSettings;
|
const BMessage fSettings;
|
||||||
FolderList fFolderList;
|
IMAP::FolderList fFolderList;
|
||||||
|
|
||||||
BStringView* fQuotaView;
|
BStringView* fQuotaView;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include "MailSettings.h"
|
#include "MailSettings.h"
|
||||||
|
|
||||||
#include "IMAPMailbox.h"
|
#include "Protocol.h"
|
||||||
#include "IMAPStorage.h"
|
#include "IMAPStorage.h"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
|
||||||
#include "IMAPFolders.h"
|
|
||||||
|
|
||||||
|
|
||||||
IMAPRootInboundProtocol::IMAPRootInboundProtocol(BMailAccountSettings* settings)
|
IMAPRootInboundProtocol::IMAPRootInboundProtocol(BMailAccountSettings* settings)
|
||||||
:
|
:
|
||||||
@@ -34,9 +32,8 @@ IMAPRootInboundProtocol::Connect(const char* server, const char* username,
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
IMAPFolders folder(fIMAPMailbox);
|
|
||||||
FolderList folders;
|
FolderList folders;
|
||||||
folder.GetFolders(folders);
|
fIMAPMailbox.GetFolders(folders);
|
||||||
for (unsigned int i = 0; i < folders.size(); i++) {
|
for (unsigned int i = 0; i < folders.size(); i++) {
|
||||||
if (!folders[i].subscribed || folders[i].folder == "INBOX")
|
if (!folders[i].subscribed || folders[i].folder == "INBOX")
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ local sources =
|
|||||||
IMAPRootInboundProtocol.cpp
|
IMAPRootInboundProtocol.cpp
|
||||||
IMAPFolderConfig.cpp
|
IMAPFolderConfig.cpp
|
||||||
# imap_lib
|
# imap_lib
|
||||||
IMAPFolders.cpp
|
Commands.cpp
|
||||||
IMAPHandler.cpp
|
Protocol.cpp
|
||||||
IMAPMailbox.cpp
|
|
||||||
IMAPParser.cpp
|
|
||||||
IMAPProtocol.cpp
|
|
||||||
IMAPStorage.cpp
|
IMAPStorage.cpp
|
||||||
|
Response.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
AddResources IMAP : IMAP.rdef ;
|
AddResources IMAP : IMAP.rdef ;
|
||||||
@@ -46,8 +44,8 @@ Addon IMAP
|
|||||||
libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ]
|
libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ]
|
||||||
;
|
;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp
|
SEARCH on [ FGristFiles Commands.cpp IMAPMailbox.cpp
|
||||||
IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.cpp ServerConnection.cpp ]
|
IMAPProtocol.cpp IMAPStorage.cpp Response.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap
|
= [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap
|
||||||
imap_lib ] ;
|
imap_lib ] ;
|
||||||
|
|
||||||
|
|||||||
+283
-193
@@ -5,16 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "IMAPHandler.h"
|
#include "Commands.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include "IMAPMailbox.h"
|
|
||||||
#include "IMAPParser.h"
|
|
||||||
#include "IMAPStorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG_IMAP_HANDLER
|
#define DEBUG_IMAP_HANDLER
|
||||||
#ifdef DEBUG_IMAP_HANDLER
|
#ifdef DEBUG_IMAP_HANDLER
|
||||||
@@ -28,28 +24,82 @@
|
|||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
|
||||||
IMAPCommand::~IMAPCommand()
|
namespace IMAP {
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BString
|
static HandlerListener sEmptyHandler;
|
||||||
IMAPCommand::Command()
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IMAPMailboxCommand::IMAPMailboxCommand(IMAPMailbox& mailbox)
|
Handler::Handler()
|
||||||
:
|
:
|
||||||
fIMAPMailbox(mailbox),
|
fListener(&sEmptyHandler)
|
||||||
fStorage(mailbox.GetStorage()),
|
|
||||||
fConnectionReader(mailbox.GetConnectionReader())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
MailboxSelectHandler::MailboxSelectHandler(IMAPMailbox& mailbox)
|
RawCommand::RawCommand(const BString& command)
|
||||||
:
|
:
|
||||||
IMAPMailboxCommand(mailbox),
|
fCommand(command)
|
||||||
|
|
||||||
fMailboxName(""),
|
|
||||||
fNextUID(-1),
|
|
||||||
fUIDValidity(-1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BString
|
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 == "")
|
if (fMailboxName == "")
|
||||||
return "";
|
return "";
|
||||||
@@ -82,21 +196,19 @@ MailboxSelectHandler::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MailboxSelectHandler::Handle(const BString& response)
|
SelectCommand::HandleUntagged(Response& response)
|
||||||
{
|
{
|
||||||
BString extracted = IMAPParser::ExtractStringAfter(response,
|
if (response.EqualsAt(0, "OK") && response.IsListAt(1, '[')) {
|
||||||
"* OK [UIDVALIDITY");
|
const ArgumentList& arguments = response.ListAt(1);
|
||||||
if (extracted != "") {
|
if (arguments.EqualsAt(0, "UIDVALIDITY")
|
||||||
fUIDValidity = IMAPParser::RemoveIntegerFromLeft(extracted);
|
&& arguments.IsNumberAt(1)) {
|
||||||
TRACE("UIDValidity %i\n", (int)fUIDValidity);
|
fUIDValidity = arguments.NumberAt(1);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (arguments.EqualsAt(0, "UIDNEXT")
|
||||||
|
&& arguments.IsNumberAt(1)) {
|
||||||
extracted = IMAPParser::ExtractStringAfter(response, "* OK [UIDNEXT");
|
fNextUID = arguments.NumberAt(1);
|
||||||
if (extracted != "") {
|
return true;
|
||||||
fNextUID = IMAPParser::RemoveIntegerFromLeft(extracted);
|
}
|
||||||
TRACE("NextUID %i\n", (int)fNextUID);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -106,42 +218,94 @@ MailboxSelectHandler::Handle(const BString& response)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
CapabilityHandler::CapabilityHandler()
|
|
||||||
:
|
|
||||||
fCapabilities("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
CapabilityHandler::Command()
|
CapabilityHandler::CommandString()
|
||||||
{
|
{
|
||||||
return "CAPABILITY";
|
return "CAPABILITY";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CapabilityHandler::Handle(const BString& response)
|
CapabilityHandler::HandleUntagged(Response& response)
|
||||||
{
|
{
|
||||||
BString cap = IMAPParser::ExtractStringAfter(response, "* CAPABILITY");
|
if (!response.IsCommand("CAPABILITY"))
|
||||||
if (cap == "")
|
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BString&
|
|
||||||
CapabilityHandler::Capabilities()
|
|
||||||
{
|
|
||||||
return fCapabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #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,
|
FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
||||||
int32 message, MinMessageList* list, BPositionIO** data)
|
int32 message, MinMessageList* list, BPositionIO** data)
|
||||||
:
|
:
|
||||||
@@ -170,7 +334,7 @@ FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
FetchMinMessageCommand::Command()
|
FetchMinMessageCommand::CommandString()
|
||||||
{
|
{
|
||||||
if (fMessage <= 0)
|
if (fMessage <= 0)
|
||||||
return "";
|
return "";
|
||||||
@@ -186,7 +350,7 @@ FetchMinMessageCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FetchMinMessageCommand::Handle(const BString& response)
|
FetchMinMessageCommand::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
BString extracted = response;
|
BString extracted = response;
|
||||||
int32 message;
|
int32 message;
|
||||||
@@ -256,47 +420,6 @@ FetchMinMessageCommand::ExtractFlags(const BString& response)
|
|||||||
// #pragma mark -
|
// #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,
|
FetchMessageCommand::FetchMessageCommand(IMAPMailbox& mailbox, int32 message,
|
||||||
BPositionIO* data, int32 fetchBodyLimit)
|
BPositionIO* data, int32 fetchBodyLimit)
|
||||||
:
|
:
|
||||||
@@ -335,7 +458,7 @@ FetchMessageCommand::~FetchMessageCommand()
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
FetchMessageCommand::Command()
|
FetchMessageCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "FETCH ";
|
BString command = "FETCH ";
|
||||||
command << fMessage;
|
command << fMessage;
|
||||||
@@ -349,7 +472,7 @@ FetchMessageCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FetchMessageCommand::Handle(const BString& response)
|
FetchMessageCommand::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
BString extracted = response;
|
BString extracted = response;
|
||||||
int32 message;
|
int32 message;
|
||||||
@@ -454,7 +577,7 @@ FetchBodyCommand::~FetchBodyCommand()
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
FetchBodyCommand::Command()
|
FetchBodyCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "FETCH ";
|
BString command = "FETCH ";
|
||||||
command << fMessage;
|
command << fMessage;
|
||||||
@@ -464,7 +587,7 @@ FetchBodyCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FetchBodyCommand::Handle(const BString& response)
|
FetchBodyCommand::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
if (response.FindFirst("FETCH") < 0)
|
if (response.FindFirst("FETCH") < 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -521,7 +644,7 @@ SetFlagsCommand::SetFlagsCommand(IMAPMailbox& mailbox, int32 message,
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
SetFlagsCommand::Command()
|
SetFlagsCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "STORE ";
|
BString command = "STORE ";
|
||||||
command << fMessage;
|
command << fMessage;
|
||||||
@@ -533,7 +656,7 @@ SetFlagsCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SetFlagsCommand::Handle(const BString& response)
|
SetFlagsCommand::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -576,7 +699,7 @@ AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message,
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
AppendCommand::Command()
|
AppendCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "APPEND ";
|
BString command = "APPEND ";
|
||||||
command << fIMAPMailbox.Mailbox();
|
command << fIMAPMailbox.Mailbox();
|
||||||
@@ -591,7 +714,7 @@ AppendCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AppendCommand::Handle(const BString& response)
|
AppendCommand::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
if (response.FindFirst("+") != 0)
|
if (response.FindFirst("+") != 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -614,21 +737,27 @@ AppendCommand::Handle(const BString& response)
|
|||||||
fIMAPMailbox.SendRawData(CRLF, strlen(CRLF));
|
fIMAPMailbox.SendRawData(CRLF, strlen(CRLF));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
ExistsHandler::ExistsHandler(IMAPMailbox& mailbox)
|
ExistsHandler::ExistsHandler()
|
||||||
:
|
|
||||||
IMAPMailboxCommand(mailbox)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
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)
|
if (response.FindFirst("EXISTS") < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -654,6 +783,7 @@ ExistsHandler::Handle(const BString& response)
|
|||||||
|
|
||||||
TRACE("EXISTS %i\n", (int)exists);
|
TRACE("EXISTS %i\n", (int)exists);
|
||||||
fIMAPMailbox.SendRawCommand("DONE");
|
fIMAPMailbox.SendRawCommand("DONE");
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -662,47 +792,36 @@ ExistsHandler::Handle(const BString& response)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
ExpungeCommmand::ExpungeCommmand(IMAPMailbox& mailbox)
|
ExpungeCommand::ExpungeCommand()
|
||||||
:
|
|
||||||
IMAPMailboxCommand(mailbox)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
ExpungeCommmand::Command()
|
ExpungeCommand::CommandString()
|
||||||
{
|
{
|
||||||
return "EXPUNGE";
|
return "EXPUNGE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
ExpungeCommmand::Handle(const BString& response)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
ExpungeHandler::ExpungeHandler(IMAPMailbox& mailbox)
|
ExpungeHandler::ExpungeHandler()
|
||||||
:
|
|
||||||
IMAPMailboxCommand(mailbox)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
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;
|
return false;
|
||||||
|
|
||||||
int32 expunge = 0;
|
int32 expunge = response.NumberAt(0);
|
||||||
if (!IMAPParser::ExtractUntagedFromLeft(response, "EXPUNGE", expunge))
|
Listener().ExpungeReceived(expunge);
|
||||||
return false;
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
// remove from storage
|
// remove from storage
|
||||||
IMAPStorage& storage = fIMAPMailbox.GetStorage();
|
IMAPStorage& storage = fIMAPMailbox.GetStorage();
|
||||||
storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge));
|
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
|
// the watching loop restarts again, we need to watch again to because
|
||||||
// some IDLE implementation stop sending notifications
|
// some IDLE implementation stop sending notifications
|
||||||
fIMAPMailbox.SendRawCommand("DONE");
|
fIMAPMailbox.SendRawCommand("DONE");
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,6 +844,7 @@ ExpungeHandler::Handle(const BString& response)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
FlagsHandler::FlagsHandler(IMAPMailbox& mailbox)
|
FlagsHandler::FlagsHandler(IMAPMailbox& mailbox)
|
||||||
:
|
:
|
||||||
IMAPMailboxCommand(mailbox)
|
IMAPMailboxCommand(mailbox)
|
||||||
@@ -732,7 +853,7 @@ FlagsHandler::FlagsHandler(IMAPMailbox& mailbox)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FlagsHandler::Handle(const BString& response)
|
FlagsHandler::HandleUntagged(const BString& response)
|
||||||
{
|
{
|
||||||
if (response.FindFirst("FETCH") < 0)
|
if (response.FindFirst("FETCH") < 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -749,13 +870,14 @@ FlagsHandler::Handle(const BString& response)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
ListCommand::Command()
|
ListCommand::CommandString()
|
||||||
{
|
{
|
||||||
fFolders.clear();
|
fFolders.clear();
|
||||||
return "LIST \"\" \"*\"";
|
return "LIST \"\" \"*\"";
|
||||||
@@ -763,9 +885,14 @@ ListCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
ListSubscribedCommand::Command()
|
ListSubscribedCommand::CommandString()
|
||||||
{
|
{
|
||||||
fFolders.clear();
|
fFolders.clear();
|
||||||
return "LSUB \"\" \"*\"";
|
return "LSUB \"\" \"*\"";
|
||||||
@@ -818,9 +915,14 @@ ListSubscribedCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
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
|
BString
|
||||||
SubscribeCommand::Command()
|
SubscribeCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "SUBSCRIBE \"";
|
BString command = "SUBSCRIBE \"";
|
||||||
command += fMailboxName;
|
command += fMailboxName;
|
||||||
@@ -851,13 +953,6 @@ SubscribeCommand::Command()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
SubscribeCommand::Handle(const BString& response)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -869,7 +964,7 @@ UnsubscribeCommand::UnsubscribeCommand(const char* mailboxName)
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
UnsubscribeCommand::Command()
|
UnsubscribeCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "UNSUBSCRIBE \"";
|
BString command = "UNSUBSCRIBE \"";
|
||||||
command += fMailboxName;
|
command += fMailboxName;
|
||||||
@@ -878,13 +973,6 @@ UnsubscribeCommand::Command()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
UnsubscribeCommand::Handle(const BString& response)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -898,7 +986,7 @@ GetQuotaCommand::GetQuotaCommand(const char* mailboxName)
|
|||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
GetQuotaCommand::Command()
|
GetQuotaCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "GETQUOTA \"";
|
BString command = "GETQUOTA \"";
|
||||||
command += fMailboxName;
|
command += fMailboxName;
|
||||||
@@ -908,15 +996,14 @@ GetQuotaCommand::Command()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetQuotaCommand::Handle(const BString& response)
|
GetQuotaCommand::HandleUntagged(Response& response)
|
||||||
{
|
{
|
||||||
if (response.FindFirst("QUOTA") < 0)
|
if (!response.IsCommand("QUOTA") || response.IsListAt(1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
BString data = IMAPParser::ExtractBetweenBrackets(response, "(", ")");
|
const ArgumentList& arguments = response.ListAt(1);
|
||||||
IMAPParser::RemovePrimitiveFromLeft(data);
|
fUsedStorage = (uint64)arguments.NumberAt(0) * 1024;
|
||||||
fUsedStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024;
|
fTotalStorage = (uint64)arguments.NumberAt(1) * 1024;
|
||||||
fTotalStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -934,3 +1021,6 @@ GetQuotaCommand::TotalStorage()
|
|||||||
{
|
{
|
||||||
return fTotalStorage;
|
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)
|
fFetchBodyLimit(0)
|
||||||
{
|
{
|
||||||
fHandlerList.AddItem(&fCapabilityHandler);
|
|
||||||
fIMAPMailboxListener = &fNULLListener;
|
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
|
BString
|
||||||
IMAPMailbox::Mailbox()
|
IMAPMailbox::Mailbox()
|
||||||
{
|
{
|
||||||
@@ -239,7 +217,7 @@ IMAPMailbox::FetchMessages(int32 firstMessage, int32 lastMessage)
|
|||||||
status_t
|
status_t
|
||||||
IMAPMailbox::FetchBody(int32 messageNumber)
|
IMAPMailbox::FetchBody(int32 messageNumber)
|
||||||
{
|
{
|
||||||
if (fStorage.BodyFetched(MessageNumberToUID(messageNumber)))
|
if (fStorage.IsBodyFetched(MessageNumberToUID(messageNumber)))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
BPositionIO* file;
|
BPositionIO* file;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
class IMAPStorage;
|
class IMAPStorage;
|
||||||
|
|
||||||
|
|
||||||
class IMAPMailbox : public IMAPProtocol {
|
class IMAPMailbox : public IMAP::Protocol {
|
||||||
public:
|
public:
|
||||||
IMAPMailbox(IMAPStorage& storage);
|
IMAPMailbox(IMAPStorage& storage);
|
||||||
~IMAPMailbox();
|
~IMAPMailbox();
|
||||||
@@ -39,7 +39,6 @@ public:
|
|||||||
IMAPMailboxListener& Listener() { return *fIMAPMailboxListener; }
|
IMAPMailboxListener& Listener() { return *fIMAPMailboxListener; }
|
||||||
|
|
||||||
/*! Select mailbox and sync with the storage. */
|
/*! Select mailbox and sync with the storage. */
|
||||||
status_t SelectMailbox(const char* mailbox);
|
|
||||||
BString Mailbox();
|
BString Mailbox();
|
||||||
status_t Sync();
|
status_t Sync();
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ public:
|
|||||||
|
|
||||||
int32 GetCurrentMessageCount()
|
int32 GetCurrentMessageCount()
|
||||||
{ return fMessageList.size(); }
|
{ return fMessageList.size(); }
|
||||||
const MinMessageList& GetMessageList() { return fMessageList; }
|
const IMAP::MinMessageList& GetMessageList() { return fMessageList; }
|
||||||
IMAPStorage& GetStorage() { return fStorage; }
|
IMAPStorage& GetStorage() { return fStorage; }
|
||||||
|
|
||||||
int32 UIDToMessageNumber(int32 uid);
|
int32 UIDToMessageNumber(int32 uid);
|
||||||
@@ -78,17 +77,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
void _InstallUnsolicitedHandler(bool install);
|
void _InstallUnsolicitedHandler(bool install);
|
||||||
|
|
||||||
MinMessageList fMessageList;
|
IMAP::MinMessageList fMessageList;
|
||||||
|
|
||||||
IMAPStorage& fStorage;
|
IMAPStorage& fStorage;
|
||||||
IMAPMailboxListener* fIMAPMailboxListener;
|
IMAPMailboxListener* fIMAPMailboxListener;
|
||||||
IMAPMailboxListener fNULLListener;
|
IMAPMailboxListener fNULLListener;
|
||||||
|
|
||||||
MailboxSelectHandler fMailboxSelectHandler;
|
IMAP::ExistsHandler fExistsHandler;
|
||||||
CapabilityHandler fCapabilityHandler;
|
IMAP::ExpungeHandler fExpungeHandler;
|
||||||
ExistsHandler fExistsHandler;
|
// FlagsHandler fFlagsHandler;
|
||||||
ExpungeHandler fExpungeHandler;
|
|
||||||
FlagsHandler fFlagsHandler;
|
|
||||||
|
|
||||||
int32 fWatching;
|
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();
|
const MinMessageList& messages = mailbox.GetMessageList();
|
||||||
|
|
||||||
for (MailEntryMap::const_iterator it = files.begin(); it != files.end();
|
for (MailEntryMap::const_iterator it = files.begin(); it != files.end();
|
||||||
it++) {
|
it++) {
|
||||||
const StorageMailEntry& mailEntry = (*it).second;
|
const StorageMailEntry& mailEntry = (*it).second;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (unsigned int a = 0; a < messages.size(); a++) {
|
for (unsigned int a = 0; a < messages.size(); a++) {
|
||||||
@@ -352,7 +352,7 @@ IMAPStorage::GetEntryForRef(const node_ref& ref)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IMAPStorage::BodyFetched(int32 uid)
|
IMAPStorage::IsBodyFetched(int32 uid)
|
||||||
{
|
{
|
||||||
MailEntryMap::iterator it = fMailEntryMap.find(uid);
|
MailEntryMap::iterator it = fMailEntryMap.find(uid);
|
||||||
if (it == fMailEntryMap.end())
|
if (it == fMailEntryMap.end())
|
||||||
@@ -365,9 +365,8 @@ IMAPStorage::BodyFetched(int32 uid)
|
|||||||
char buffer[B_MIME_TYPE_LENGTH];
|
char buffer[B_MIME_TYPE_LENGTH];
|
||||||
BNodeInfo info(&node);
|
BNodeInfo info(&node);
|
||||||
info.GetType(buffer);
|
info.GetType(buffer);
|
||||||
if (strcmp(buffer, B_MAIL_TYPE) == 0)
|
|
||||||
return true;
|
return strcmp(buffer, B_MAIL_TYPE) == 0;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,17 +16,6 @@
|
|||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include "IMAPHandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum FileFlags {
|
|
||||||
kSeen = 0x01,
|
|
||||||
kAnswered = 0x02,
|
|
||||||
kFlagged = 0x04,
|
|
||||||
kDeleted = 0x08,
|
|
||||||
kDraft = 0x10
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct StorageMailEntry {
|
struct StorageMailEntry {
|
||||||
int32 uid;
|
int32 uid;
|
||||||
@@ -73,7 +62,7 @@ public:
|
|||||||
|
|
||||||
status_t SetCompleteMessageSize(int32 uid, int32 size);
|
status_t SetCompleteMessageSize(int32 uid, int32 size);
|
||||||
|
|
||||||
bool BodyFetched(int32 uid);
|
bool IsBodyFetched(int32 uid);
|
||||||
|
|
||||||
StorageMailEntry* GetEntryForRef(const node_ref& ref);
|
StorageMailEntry* GetEntryForRef(const node_ref& ref);
|
||||||
int32 RefToUID(const entry_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 "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 {
|
namespace IMAP {
|
||||||
|
|
||||||
@@ -82,11 +95,8 @@ ArgumentList::ListAt(int32 index) const
|
|||||||
bool
|
bool
|
||||||
ArgumentList::IsListAt(int32 index) const
|
ArgumentList::IsListAt(int32 index) const
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < CountItems()) {
|
return index >= 0 && index < CountItems()
|
||||||
if (ListArgument* argument = dynamic_cast<ListArgument*>(ItemAt(index)))
|
&& dynamic_cast<ListArgument*>(ItemAt(index)) != NULL;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -101,15 +111,15 @@ ArgumentList::IsListAt(int32 index, char kind) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
uint32
|
||||||
ArgumentList::IntegerAt(int32 index) const
|
ArgumentList::NumberAt(int32 index) const
|
||||||
{
|
{
|
||||||
return atoi(StringAt(index).String());
|
return atoul(StringAt(index).String());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ArgumentList::IsIntegerAt(int32 index) const
|
ArgumentList::IsNumberAt(int32 index) const
|
||||||
{
|
{
|
||||||
BString string = StringAt(index);
|
BString string = StringAt(index);
|
||||||
for (int32 i = 0; i < string.Length(); i++) {
|
for (int32 i = 0; i < string.Length(); i++) {
|
||||||
@@ -209,11 +219,6 @@ ParseException::ParseException(const char* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ParseException::~ParseException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -228,6 +233,19 @@ ExpectedParseException::ExpectedParseException(char expected, char instead)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
LiteralHandler::LiteralHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LiteralHandler::~LiteralHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
Response::Response()
|
Response::Response()
|
||||||
:
|
:
|
||||||
fTag(0),
|
fTag(0),
|
||||||
@@ -242,9 +260,12 @@ Response::~Response()
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Response::SetTo(const char* line) throw(ParseException)
|
Response::Parse(ConnectionReader& reader, const char* line,
|
||||||
|
LiteralHandler* handler) throw(ParseException)
|
||||||
{
|
{
|
||||||
MakeEmpty();
|
MakeEmpty();
|
||||||
|
fReader = &reader;
|
||||||
|
fLiteralHandler = handler;
|
||||||
fTag = 0;
|
fTag = 0;
|
||||||
fContinuation = false;
|
fContinuation = false;
|
||||||
|
|
||||||
@@ -384,8 +405,24 @@ Response::ParseQuoted(ArgumentList& arguments, const char*& line)
|
|||||||
void
|
void
|
||||||
Response::ParseLiteral(ArgumentList& arguments, const char*& line)
|
Response::ParseLiteral(ArgumentList& arguments, const char*& line)
|
||||||
{
|
{
|
||||||
// TODO!
|
Consume(line, '{');
|
||||||
throw ParseException("Literals are not yet supported!");
|
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;
|
const char* start = line;
|
||||||
|
|
||||||
|
// TODO: parse modified UTF-7 as described in RFC 3501, 5.1.3
|
||||||
while (line[0] != '\0') {
|
while (line[0] != '\0') {
|
||||||
char c = line[0];
|
char c = line[0];
|
||||||
if (c <= ' ' || strchr("()[]{}\"", c) != NULL)
|
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
|
} // namespace IMAP
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace IMAP {
|
|||||||
|
|
||||||
|
|
||||||
class Argument;
|
class Argument;
|
||||||
|
class ConnectionReader;
|
||||||
|
|
||||||
|
|
||||||
class ArgumentList : public BObjectList<Argument> {
|
class ArgumentList : public BObjectList<Argument> {
|
||||||
@@ -33,8 +34,8 @@ public:
|
|||||||
bool IsListAt(int32 index) const;
|
bool IsListAt(int32 index) const;
|
||||||
bool IsListAt(int32 index, char kind) const;
|
bool IsListAt(int32 index, char kind) const;
|
||||||
|
|
||||||
int32 IntegerAt(int32 index) const;
|
uint32 NumberAt(int32 index) const;
|
||||||
bool IsIntegerAt(int32 index) const;
|
bool IsNumberAt(int32 index) const;
|
||||||
|
|
||||||
BString ToString() const;
|
BString ToString() const;
|
||||||
};
|
};
|
||||||
@@ -82,7 +83,6 @@ class ParseException : public std::exception {
|
|||||||
public:
|
public:
|
||||||
ParseException();
|
ParseException();
|
||||||
ParseException(const char* message);
|
ParseException(const char* message);
|
||||||
virtual ~ParseException();
|
|
||||||
|
|
||||||
const char* Message() const { return fMessage; }
|
const char* Message() const { return fMessage; }
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ExpectedParseException : ParseException {
|
class ExpectedParseException : public ParseException {
|
||||||
public:
|
public:
|
||||||
ExpectedParseException(char expected,
|
ExpectedParseException(char expected,
|
||||||
char instead);
|
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 {
|
class Response : public ArgumentList {
|
||||||
public:
|
public:
|
||||||
Response();
|
Response();
|
||||||
~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; }
|
bool IsUntagged() const { return fTag == 0; }
|
||||||
int32 Tag() const { return fTag; }
|
int32 Tag() const { return fTag; }
|
||||||
@@ -128,11 +140,30 @@ protected:
|
|||||||
BString ExtractString(const char*& line);
|
BString ExtractString(const char*& line);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ConnectionReader* fReader;
|
||||||
|
LiteralHandler* fLiteralHandler;
|
||||||
int32 fTag;
|
int32 fTag;
|
||||||
bool fContinuation;
|
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
|
} // 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
|
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols
|
||||||
imap imap_lib ] ;
|
imap imap_lib ] ;
|
||||||
|
|
||||||
local libSources = IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp
|
local libSources = Commands.cpp Protocol.cpp Response.cpp ;
|
||||||
IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.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 :
|
SimpleTest imap_tester :
|
||||||
imap_tester.cpp
|
imap_tester.cpp
|
||||||
@@ -18,7 +30,7 @@ SimpleTest imap_tester :
|
|||||||
# from fs_shell
|
# from fs_shell
|
||||||
argv.c
|
argv.c
|
||||||
|
|
||||||
: be [ TargetLibsupc++ ] mail
|
: be [ TargetLibstdc++ ] [ TargetLibsupc++ ] bnetapi mail
|
||||||
;
|
;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles $(libSources) ]
|
SEARCH on [ FGristFiles $(libSources) ]
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
#include "IMAPFolders.h"
|
/*
|
||||||
#include "IMAPMailbox.h"
|
* Copyright 2011, Axel Dörfler, [email protected].
|
||||||
#include "IMAPStorage.h"
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//#include "IMAPStorage.h"
|
||||||
|
#include "Protocol.h"
|
||||||
|
#include "Response.h"
|
||||||
|
|
||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
|
|
||||||
|
|
||||||
struct cmd_entry {
|
struct cmd_entry {
|
||||||
char* name;
|
const char* name;
|
||||||
void (*func)(int argc, char **argv);
|
void (*func)(int argc, char **argv);
|
||||||
char* help;
|
const char* help;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -18,8 +26,8 @@ static void do_help(int argc, char** argv);
|
|||||||
extern const char* __progname;
|
extern const char* __progname;
|
||||||
static const char* kProgramName = __progname;
|
static const char* kProgramName = __progname;
|
||||||
|
|
||||||
static IMAPStorage sStorage;
|
//static IMAPStorage sStorage;
|
||||||
static IMAPMailbox sMailbox(sStorage);
|
static IMAP::Protocol sMailbox;//(/*sStorage*/);
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -56,11 +64,13 @@ do_select(int argc, char** argv)
|
|||||||
static void
|
static void
|
||||||
do_folders(int argc, char** argv)
|
do_folders(int argc, char** argv)
|
||||||
{
|
{
|
||||||
IMAPFolders folder(sMailbox);
|
IMAP::FolderList folders;
|
||||||
FolderList folders;
|
|
||||||
status_t status = folder.GetFolders(folders);
|
status_t status = sMailbox.GetFolders(folders);
|
||||||
if (status != B_OK)
|
if (status != B_OK) {
|
||||||
error("folders", status);
|
error("folders", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < folders.size(); i++) {
|
for (size_t i = 0; i < folders.size(); i++) {
|
||||||
printf(" %s %s\n", folders[i].subscribed ? "*" : " ",
|
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
|
static void
|
||||||
do_raw(int argc, char** argv)
|
do_raw(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@@ -82,7 +120,7 @@ do_raw(int argc, char** argv)
|
|||||||
strlcat(command, argv[i], sizeof(command));
|
strlcat(command, argv[i], sizeof(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
class RawCommand : public IMAPCommand {
|
class RawCommand : public IMAP::Command, public IMAP::Handler {
|
||||||
public:
|
public:
|
||||||
RawCommand(const char* command)
|
RawCommand(const char* command)
|
||||||
:
|
:
|
||||||
@@ -90,13 +128,18 @@ do_raw(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BString Command()
|
BString CommandString()
|
||||||
{
|
{
|
||||||
return fCommand;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +147,7 @@ do_raw(int argc, char** argv)
|
|||||||
const char* fCommand;
|
const char* fCommand;
|
||||||
};
|
};
|
||||||
RawCommand rawCommand(command);
|
RawCommand rawCommand(command);
|
||||||
status_t status = sMailbox.ProcessCommand(&rawCommand, 60 * 1000);
|
status_t status = sMailbox.ProcessCommand(rawCommand);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
error("raw", status);
|
error("raw", status);
|
||||||
}
|
}
|
||||||
@@ -113,6 +156,8 @@ do_raw(int argc, char** argv)
|
|||||||
static cmd_entry sBuiltinCommands[] = {
|
static cmd_entry sBuiltinCommands[] = {
|
||||||
{"select", do_select, "Selects a mailbox, defaults to INBOX"},
|
{"select", do_select, "Selects a mailbox, defaults to INBOX"},
|
||||||
{"folders", do_folders, "List of existing folders"},
|
{"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"},
|
{"raw", do_raw, "Issue a raw command to the server"},
|
||||||
{"help", do_help, "prints this help text"},
|
{"help", do_help, "prints this help text"},
|
||||||
{"quit", NULL, "exits the application"},
|
{"quit", NULL, "exits the application"},
|
||||||
@@ -145,11 +190,13 @@ main(int argc, char** argv)
|
|||||||
const char* user = argv[2];
|
const char* user = argv[2];
|
||||||
const char* password = argv[3];
|
const char* password = argv[3];
|
||||||
bool useSSL = argc > 4;
|
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) {
|
if (status != B_OK) {
|
||||||
error("connect", status);
|
error("connect", status);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user