diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp index a5c39b022c..cada937b37 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp @@ -329,9 +329,9 @@ FolderConfigWindow::_LoadFolders() delete[] passwd; } - fIMAPFolders.Connect(server, username, password, useSSL); + fProtocol.Connect(server, username, password, useSSL); fFolderList.clear(); - fIMAPFolders.GetFolders(fFolderList); + fProtocol.GetFolders(fFolderList); for (unsigned int i = 0; i < fFolderList.size(); i++) { FolderInfo& info = fFolderList[i]; CheckBoxItem* item = new CheckBoxItem(info.folder, info.subscribed); @@ -340,7 +340,7 @@ FolderConfigWindow::_LoadFolders() } uint64 used, total; - if (fIMAPFolders.GetQuota(used, total) == B_OK) { + if (fProtocol.GetQuota(used, total) == B_OK) { char buffer[256]; BString quotaString = "Server storage: "; quotaString += string_for_size(used, buffer, 256); @@ -377,9 +377,9 @@ FolderConfigWindow::_ApplyChanges() FolderInfo& info = fFolderList[i]; CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i); if (info.subscribed && !item->Checked()) - fIMAPFolders.UnsubscribeFolder(info.folder); + fProtocol.UnsubscribeFolder(info.folder); else if (!info.subscribed && item->Checked()) - fIMAPFolders.SubscribeFolder(info.folder); + fProtocol.SubscribeFolder(info.folder); } status->PostMessage(B_QUIT_REQUESTED); diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h index f6ae3da5c7..f9a8fde127 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h @@ -14,7 +14,7 @@ #include -#include "IMAPFolders.h" +#include "Protocol.h" class FolderConfigWindow : public BWindow { @@ -28,11 +28,11 @@ private: void _LoadFolders(); void _ApplyChanges(); - IMAPFolders fIMAPFolders; + IMAP::Protocol fProtocol; BListView* fFolderListView; BButton* fApplyButton; const BMessage fSettings; - FolderList fFolderList; + IMAP::FolderList fFolderList; BStringView* fQuotaView; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPInboundProtocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPInboundProtocol.h index 954a1fc685..9b3eda7db3 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPInboundProtocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPInboundProtocol.h @@ -15,7 +15,7 @@ #include "MailSettings.h" -#include "IMAPMailbox.h" +#include "Protocol.h" #include "IMAPStorage.h" diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPRootInboundProtocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPRootInboundProtocol.cpp index b7e49275d8..544d927cf5 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPRootInboundProtocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPRootInboundProtocol.cpp @@ -9,8 +9,6 @@ #include -#include "IMAPFolders.h" - IMAPRootInboundProtocol::IMAPRootInboundProtocol(BMailAccountSettings* settings) : @@ -34,9 +32,8 @@ IMAPRootInboundProtocol::Connect(const char* server, const char* username, if (status != B_OK) return status; - IMAPFolders folder(fIMAPMailbox); FolderList folders; - folder.GetFolders(folders); + fIMAPMailbox.GetFolders(folders); for (unsigned int i = 0; i < folders.size(); i++) { if (!folders[i].subscribed || folders[i].folder == "INBOX") continue; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile index d89f9221d2..17a83c8df8 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile @@ -21,12 +21,10 @@ local sources = IMAPRootInboundProtocol.cpp IMAPFolderConfig.cpp # imap_lib - IMAPFolders.cpp - IMAPHandler.cpp - IMAPMailbox.cpp - IMAPParser.cpp - IMAPProtocol.cpp + Commands.cpp + Protocol.cpp IMAPStorage.cpp + Response.cpp ; AddResources IMAP : IMAP.rdef ; @@ -46,8 +44,8 @@ Addon IMAP libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ] ; -SEARCH on [ FGristFiles IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp - IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.cpp ServerConnection.cpp ] +SEARCH on [ FGristFiles Commands.cpp IMAPMailbox.cpp + IMAPProtocol.cpp IMAPStorage.cpp Response.cpp ] = [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap imap_lib ] ; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp similarity index 69% rename from src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.cpp rename to src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp index 695f8693fc..afcd7ed16c 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp @@ -5,16 +5,12 @@ */ -#include "IMAPHandler.h" +#include "Commands.h" #include #include -#include "IMAPMailbox.h" -#include "IMAPParser.h" -#include "IMAPStorage.h" - #define DEBUG_IMAP_HANDLER #ifdef DEBUG_IMAP_HANDLER @@ -28,28 +24,82 @@ using namespace BPrivate; -IMAPCommand::~IMAPCommand() -{ -} +namespace IMAP { -BString -IMAPCommand::Command() -{ - return ""; -} +static HandlerListener sEmptyHandler; -IMAPMailboxCommand::IMAPMailboxCommand(IMAPMailbox& mailbox) +Handler::Handler() : - fIMAPMailbox(mailbox), - fStorage(mailbox.GetStorage()), - fConnectionReader(mailbox.GetConnectionReader()) + fListener(&sEmptyHandler) { } -IMAPMailboxCommand::~IMAPMailboxCommand() +Handler::~Handler() +{ +} + + +void +Handler::SetListener(HandlerListener& listener) +{ + fListener = &listener; +} + + +IMAP::LiteralHandler* +Handler::LiteralHandler() +{ + return NULL; +} + + +// #pragma mark - + + +Command::~Command() +{ +} + + +status_t +Command::HandleTagged(Response& response) +{ + if (response.StringAt(0) == "OK") + return B_OK; + if (response.StringAt(0) == "BAD") + return B_BAD_VALUE; + if (response.StringAt(0) == "NO") + return B_NOT_ALLOWED; + + return B_ERROR; +} + + +// #pragma mark - + + +HandlerListener::~HandlerListener() +{ +} + + +void +HandlerListener::ExpungeReceived(int32 number) +{ +} + + +void +HandlerListener::ExistsReceived(int32 number) +{ +} + + +void +HandlerListener::FetchBody(Command& command, int32 size) { } @@ -57,19 +107,83 @@ IMAPMailboxCommand::~IMAPMailboxCommand() // #pragma mark - -MailboxSelectHandler::MailboxSelectHandler(IMAPMailbox& mailbox) +RawCommand::RawCommand(const BString& command) : - IMAPMailboxCommand(mailbox), - - fMailboxName(""), - fNextUID(-1), - fUIDValidity(-1) + fCommand(command) { } BString -MailboxSelectHandler::Command() +RawCommand::CommandString() +{ + return fCommand; +} + + +// #pragma mark - + + +LoginCommand::LoginCommand(const char* user, const char* password) + : + fUser(user), + fPassword(password) +{ +} + + +BString +LoginCommand::CommandString() +{ + BString command = "LOGIN "; + command << "\"" << fUser << "\" " << "\"" << fPassword << "\""; + + return command; +} + + +bool +LoginCommand::HandleUntagged(Response& response) +{ + if (!response.EqualsAt(0, "OK") || !response.IsListAt(1, '[')) + return false; + + // TODO: we only support capabilities at the moment + ArgumentList& list = response.ListAt(1); + if (!list.EqualsAt(0, "CAPABILITY")) + return false; + + fCapabilities.MakeEmpty(); + while (list.CountItems() > 1) + fCapabilities.AddItem(list.RemoveItemAt(1)); + + TRACE("CAPABILITY: %s\n", fCapabilities.ToString().String()); + return true; +} + + +// #pragma mark - + + +SelectCommand::SelectCommand() + : + fNextUID(0), + fUIDValidity(0) +{ +} + + +SelectCommand::SelectCommand(const char* name) + : + fMailboxName(name), + fNextUID(0), + fUIDValidity(0) +{ +} + + +BString +SelectCommand::CommandString() { if (fMailboxName == "") return ""; @@ -82,21 +196,19 @@ MailboxSelectHandler::Command() bool -MailboxSelectHandler::Handle(const BString& response) +SelectCommand::HandleUntagged(Response& response) { - BString extracted = IMAPParser::ExtractStringAfter(response, - "* OK [UIDVALIDITY"); - if (extracted != "") { - fUIDValidity = IMAPParser::RemoveIntegerFromLeft(extracted); - TRACE("UIDValidity %i\n", (int)fUIDValidity); - return true; - } - - extracted = IMAPParser::ExtractStringAfter(response, "* OK [UIDNEXT"); - if (extracted != "") { - fNextUID = IMAPParser::RemoveIntegerFromLeft(extracted); - TRACE("NextUID %i\n", (int)fNextUID); - return true; + if (response.EqualsAt(0, "OK") && response.IsListAt(1, '[')) { + const ArgumentList& arguments = response.ListAt(1); + if (arguments.EqualsAt(0, "UIDVALIDITY") + && arguments.IsNumberAt(1)) { + fUIDValidity = arguments.NumberAt(1); + return true; + } else if (arguments.EqualsAt(0, "UIDNEXT") + && arguments.IsNumberAt(1)) { + fNextUID = arguments.NumberAt(1); + return true; + } } return false; @@ -106,42 +218,94 @@ MailboxSelectHandler::Handle(const BString& response) // #pragma mark - -CapabilityHandler::CapabilityHandler() - : - fCapabilities("") -{ -} - - BString -CapabilityHandler::Command() +CapabilityHandler::CommandString() { return "CAPABILITY"; } bool -CapabilityHandler::Handle(const BString& response) +CapabilityHandler::HandleUntagged(Response& response) { - BString cap = IMAPParser::ExtractStringAfter(response, "* CAPABILITY"); - if (cap == "") + if (!response.IsCommand("CAPABILITY")) return false; - fCapabilities = cap; - TRACE("CAPABILITY: %s\n", fCapabilities.String()); + + fCapabilities.MakeEmpty(); + while (response.CountItems() > 1) + fCapabilities.AddItem(response.RemoveItemAt(1)); + + TRACE("CAPABILITY: %s\n", fCapabilities.ToString().String()); return true; } -BString& -CapabilityHandler::Capabilities() -{ - return fCapabilities; -} - - // #pragma mark - +FetchMessageEntriesCommand::FetchMessageEntriesCommand( + MessageEntryList& entries, uint32 from, uint32 to) + : + fEntries(entries), + fFrom(from), + fTo(to) +{ +} + + +BString +FetchMessageEntriesCommand::CommandString() +{ + BString command = "UID FETCH "; + command << fFrom << ":" << fTo << " FLAGS"; + + return command; +} + + +bool +FetchMessageEntriesCommand::HandleUntagged(Response& response) +{ + if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2)) + return false; + + MessageEntry entry; + + ArgumentList& list = response.ListAt(2); + for (int32 i = 0; i < list.CountItems(); i += 2) { + if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1)) + entry.uid = list.NumberAt(i + 1); + else if (list.EqualsAt(i, "FLAGS") && list.IsListAt(i + 1)) { + // Parse flags + ArgumentList& flags = list.ListAt(i + 1); + printf("flags: %s\n", flags.ToString().String()); + for (int32 j = 0; j < flags.CountItems(); j++) { + if (flags.EqualsAt(j, "\\Seen")) + entry.flags |= kSeen; + else if (flags.EqualsAt(j, "\\Answered")) + entry.flags |= kAnswered; + else if (flags.EqualsAt(j, "\\Flagged")) + entry.flags |= kFlagged; + else if (flags.EqualsAt(j, "\\Deleted")) + entry.flags |= kDeleted; + else if (flags.EqualsAt(j, "\\Draft")) + entry.flags |= kDraft; + } + } + } + + if (entry.uid == 0) + return false; + + fEntries.push_back(entry); + return true; +} + + +// #pragma mark - + + +#if 0 FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox, int32 message, MinMessageList* list, BPositionIO** data) : @@ -170,7 +334,7 @@ FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox, BString -FetchMinMessageCommand::Command() +FetchMinMessageCommand::CommandString() { if (fMessage <= 0) return ""; @@ -186,7 +350,7 @@ FetchMinMessageCommand::Command() bool -FetchMinMessageCommand::Handle(const BString& response) +FetchMinMessageCommand::HandleUntagged(const BString& response) { BString extracted = response; int32 message; @@ -256,47 +420,6 @@ FetchMinMessageCommand::ExtractFlags(const BString& response) // #pragma mark - -FetchMessageListCommand::FetchMessageListCommand(IMAPMailbox& mailbox, - MinMessageList* list, int32 nextId) - : - IMAPMailboxCommand(mailbox), - - fMinMessageList(list), - fNextId(nextId) -{ -} - - -BString -FetchMessageListCommand::Command() -{ - BString command = "UID FETCH 1:"; - command << fNextId - 1; - command << " FLAGS"; - return command; -} - - -bool -FetchMessageListCommand::Handle(const BString& response) -{ - BString extracted = response; - int32 message; - if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message)) - return false; - - MinMessage minMessage; - if (!FetchMinMessageCommand::ParseMinMessage(extracted, minMessage)) - return false; - - fMinMessageList->push_back(minMessage); - return true; -} - - -// #pragma mark - - - FetchMessageCommand::FetchMessageCommand(IMAPMailbox& mailbox, int32 message, BPositionIO* data, int32 fetchBodyLimit) : @@ -335,7 +458,7 @@ FetchMessageCommand::~FetchMessageCommand() BString -FetchMessageCommand::Command() +FetchMessageCommand::CommandString() { BString command = "FETCH "; command << fMessage; @@ -349,7 +472,7 @@ FetchMessageCommand::Command() bool -FetchMessageCommand::Handle(const BString& response) +FetchMessageCommand::HandleUntagged(const BString& response) { BString extracted = response; int32 message; @@ -454,7 +577,7 @@ FetchBodyCommand::~FetchBodyCommand() BString -FetchBodyCommand::Command() +FetchBodyCommand::CommandString() { BString command = "FETCH "; command << fMessage; @@ -464,7 +587,7 @@ FetchBodyCommand::Command() bool -FetchBodyCommand::Handle(const BString& response) +FetchBodyCommand::HandleUntagged(const BString& response) { if (response.FindFirst("FETCH") < 0) return false; @@ -521,7 +644,7 @@ SetFlagsCommand::SetFlagsCommand(IMAPMailbox& mailbox, int32 message, BString -SetFlagsCommand::Command() +SetFlagsCommand::CommandString() { BString command = "STORE "; command << fMessage; @@ -533,7 +656,7 @@ SetFlagsCommand::Command() bool -SetFlagsCommand::Handle(const BString& response) +SetFlagsCommand::HandleUntagged(const BString& response) { return false; } @@ -576,7 +699,7 @@ AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message, BString -AppendCommand::Command() +AppendCommand::CommandString() { BString command = "APPEND "; command << fIMAPMailbox.Mailbox(); @@ -591,7 +714,7 @@ AppendCommand::Command() bool -AppendCommand::Handle(const BString& response) +AppendCommand::HandleUntagged(const BString& response) { if (response.FindFirst("+") != 0) return false; @@ -614,21 +737,27 @@ AppendCommand::Handle(const BString& response) fIMAPMailbox.SendRawData(CRLF, strlen(CRLF)); return true; } +#endif // #pragma mark - -ExistsHandler::ExistsHandler(IMAPMailbox& mailbox) - : - IMAPMailboxCommand(mailbox) +ExistsHandler::ExistsHandler() { } bool -ExistsHandler::Handle(const BString& response) +ExistsHandler::HandleUntagged(Response& response) { + if (!response.EqualsAt(1, "EXISTS") || response.IsNumberAt(0)) + return false; + + int32 expunge = response.NumberAt(0); + Listener().ExistsReceived(expunge); + +#if 0 if (response.FindFirst("EXISTS") < 0) return false; @@ -654,6 +783,7 @@ ExistsHandler::Handle(const BString& response) TRACE("EXISTS %i\n", (int)exists); fIMAPMailbox.SendRawCommand("DONE"); +#endif return true; } @@ -662,47 +792,36 @@ ExistsHandler::Handle(const BString& response) // #pragma mark - -ExpungeCommmand::ExpungeCommmand(IMAPMailbox& mailbox) - : - IMAPMailboxCommand(mailbox) +ExpungeCommand::ExpungeCommand() { } BString -ExpungeCommmand::Command() +ExpungeCommand::CommandString() { return "EXPUNGE"; } -bool -ExpungeCommmand::Handle(const BString& response) -{ - return false; -} - - // #pragma mark - -ExpungeHandler::ExpungeHandler(IMAPMailbox& mailbox) - : - IMAPMailboxCommand(mailbox) +ExpungeHandler::ExpungeHandler() { } bool -ExpungeHandler::Handle(const BString& response) +ExpungeHandler::HandleUntagged(Response& response) { - if (response.FindFirst("EXPUNGE") < 0) + if (!response.EqualsAt(1, "EXPUNGE") || response.IsNumberAt(0)) return false; - int32 expunge = 0; - if (!IMAPParser::ExtractUntagedFromLeft(response, "EXPUNGE", expunge)) - return false; + int32 expunge = response.NumberAt(0); + Listener().ExpungeReceived(expunge); +#if 0 // remove from storage IMAPStorage& storage = fIMAPMailbox.GetStorage(); storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge)); @@ -717,6 +836,7 @@ ExpungeHandler::Handle(const BString& response) // the watching loop restarts again, we need to watch again to because // some IDLE implementation stop sending notifications fIMAPMailbox.SendRawCommand("DONE"); +#endif return true; } @@ -724,6 +844,7 @@ ExpungeHandler::Handle(const BString& response) // #pragma mark - +#if 0 FlagsHandler::FlagsHandler(IMAPMailbox& mailbox) : IMAPMailboxCommand(mailbox) @@ -732,7 +853,7 @@ FlagsHandler::FlagsHandler(IMAPMailbox& mailbox) bool -FlagsHandler::Handle(const BString& response) +FlagsHandler::HandleUntagged(const BString& response) { if (response.FindFirst("FETCH") < 0) return false; @@ -749,13 +870,14 @@ FlagsHandler::Handle(const BString& response) return true; } +#endif // #pragma mark - BString -ListCommand::Command() +ListCommand::CommandString() { fFolders.clear(); return "LIST \"\" \"*\""; @@ -763,9 +885,14 @@ ListCommand::Command() bool -ListCommand::Handle(const BString& response) +ListCommand::HandleUntagged(Response& response) { - return ParseList("LIST", response, fFolders); + if (response.IsCommand("LIST") && response.IsStringAt(3)) { + fFolders.push_back(response.StringAt(3)); + return true; + } + + return false; } @@ -776,41 +903,11 @@ ListCommand::FolderList() } -bool -ListCommand::ParseList(const char* command, const BString& response, - StringList& list) -{ - int32 textPos = response.FindFirst(command); - if (textPos < 0) - return false; - BString extracted = response; - - extracted.Remove(0, textPos + strlen(command) + 1); - extracted.Trim(); - if (extracted[0] == '(') { - BString flags = IMAPParser::ExtractBetweenBrackets(extracted, "(", ")"); - if (flags.IFindFirst("\\Noselect") >= 0) - return true; - textPos = extracted.FindFirst(")"); - extracted.Remove(0, textPos + 1); - } - - IMAPParser::RemovePrimitiveFromLeft(extracted); - extracted.Trim(); - // remove quotation marks - extracted.Remove(0, 1); - extracted.Truncate(extracted.Length() - 1); - - list.push_back(extracted); - return true; -} - - // #pragma mark - BString -ListSubscribedCommand::Command() +ListSubscribedCommand::CommandString() { fFolders.clear(); return "LSUB \"\" \"*\""; @@ -818,9 +915,14 @@ ListSubscribedCommand::Command() bool -ListSubscribedCommand::Handle(const BString& response) +ListSubscribedCommand::HandleUntagged(Response& response) { - return ListCommand::ParseList("LSUB", response, fFolders); + if (response.IsCommand("LSUB") && response.IsStringAt(3)) { + fFolders.push_back(response.StringAt(3)); + return true; + } + + return false; } @@ -842,7 +944,7 @@ SubscribeCommand::SubscribeCommand(const char* mailboxName) BString -SubscribeCommand::Command() +SubscribeCommand::CommandString() { BString command = "SUBSCRIBE \""; command += fMailboxName; @@ -851,13 +953,6 @@ SubscribeCommand::Command() } -bool -SubscribeCommand::Handle(const BString& response) -{ - return false; -} - - // #pragma mark - @@ -869,7 +964,7 @@ UnsubscribeCommand::UnsubscribeCommand(const char* mailboxName) BString -UnsubscribeCommand::Command() +UnsubscribeCommand::CommandString() { BString command = "UNSUBSCRIBE \""; command += fMailboxName; @@ -878,13 +973,6 @@ UnsubscribeCommand::Command() } -bool -UnsubscribeCommand::Handle(const BString& response) -{ - return false; -} - - // #pragma mark - @@ -898,7 +986,7 @@ GetQuotaCommand::GetQuotaCommand(const char* mailboxName) BString -GetQuotaCommand::Command() +GetQuotaCommand::CommandString() { BString command = "GETQUOTA \""; command += fMailboxName; @@ -908,15 +996,14 @@ GetQuotaCommand::Command() bool -GetQuotaCommand::Handle(const BString& response) +GetQuotaCommand::HandleUntagged(Response& response) { - if (response.FindFirst("QUOTA") < 0) + if (!response.IsCommand("QUOTA") || response.IsListAt(1)) return false; - BString data = IMAPParser::ExtractBetweenBrackets(response, "(", ")"); - IMAPParser::RemovePrimitiveFromLeft(data); - fUsedStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024; - fTotalStorage = (uint64)IMAPParser::RemoveIntegerFromLeft(data) * 1024; + const ArgumentList& arguments = response.ListAt(1); + fUsedStorage = (uint64)arguments.NumberAt(0) * 1024; + fTotalStorage = (uint64)arguments.NumberAt(1) * 1024; return true; } @@ -934,3 +1021,6 @@ GetQuotaCommand::TotalStorage() { return fTotalStorage; } + + +} // namespace diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h new file mode 100644 index 0000000000..8a6e828d8e --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h @@ -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 + +#include "Response.h" + + +typedef std::vector StringList; + + +namespace IMAP { + + +class ConnectionReader; +class HandlerListener; + + +struct MessageEntry { + MessageEntry() + : + uid(0), + flags(0) + { + } + + uint32 uid; + uint32 flags; +}; +typedef std::vector 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 diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.cpp deleted file mode 100644 index 6d16ab2bf2..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2011, Haiku, Inc. All rights reserved. - * Copyright 2011, Clemens Zeidler - * 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; -} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.h deleted file mode 100644 index 8f230b02bc..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPFolders.h +++ /dev/null @@ -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 - -#include "IMAPHandler.h" -#include "IMAPProtocol.h" - - -class FolderInfo { -public: - FolderInfo() - : - subscribed(false) - { - } - - BString folder; - bool subscribed; -}; - - -typedef std::vector 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 diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.h deleted file mode 100644 index ed322db076..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPHandler.h +++ /dev/null @@ -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 - -#include -#include - - -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 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 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 diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.cpp index 2da4cfc655..96f80f4d02 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.cpp @@ -43,7 +43,6 @@ IMAPMailbox::IMAPMailbox(IMAPStorage& storage) fFetchBodyLimit(0) { - fHandlerList.AddItem(&fCapabilityHandler); fIMAPMailboxListener = &fNULLListener; } @@ -64,27 +63,6 @@ IMAPMailbox::SetListener(IMAPMailboxListener* listener) } -status_t -IMAPMailbox::SelectMailbox(const char* mailbox) -{ - TRACE("SELECT %s\n", mailbox); - fMailboxSelectHandler.SetTo(mailbox); - status_t status = ProcessCommand(&fMailboxSelectHandler); - if (status != B_OK) - return status; - fSelectedMailbox = mailbox; - - if (fCapabilityHandler.Capabilities() != "") - return status; - //else get them - status = ProcessCommand(fCapabilityHandler.Command()); - if (status != B_OK) - return status; - - return B_OK; -} - - BString IMAPMailbox::Mailbox() { @@ -239,7 +217,7 @@ IMAPMailbox::FetchMessages(int32 firstMessage, int32 lastMessage) status_t IMAPMailbox::FetchBody(int32 messageNumber) { - if (fStorage.BodyFetched(MessageNumberToUID(messageNumber))) + if (fStorage.IsBodyFetched(MessageNumberToUID(messageNumber))) return B_BAD_VALUE; BPositionIO* file; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h index b8c53dcd76..afb6e1c9f1 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPMailbox.h @@ -30,7 +30,7 @@ public: class IMAPStorage; -class IMAPMailbox : public IMAPProtocol { +class IMAPMailbox : public IMAP::Protocol { public: IMAPMailbox(IMAPStorage& storage); ~IMAPMailbox(); @@ -39,7 +39,6 @@ public: IMAPMailboxListener& Listener() { return *fIMAPMailboxListener; } /*! Select mailbox and sync with the storage. */ - status_t SelectMailbox(const char* mailbox); BString Mailbox(); status_t Sync(); @@ -68,7 +67,7 @@ public: int32 GetCurrentMessageCount() { return fMessageList.size(); } - const MinMessageList& GetMessageList() { return fMessageList; } + const IMAP::MinMessageList& GetMessageList() { return fMessageList; } IMAPStorage& GetStorage() { return fStorage; } int32 UIDToMessageNumber(int32 uid); @@ -78,17 +77,15 @@ public: private: void _InstallUnsolicitedHandler(bool install); - MinMessageList fMessageList; + IMAP::MinMessageList fMessageList; IMAPStorage& fStorage; IMAPMailboxListener* fIMAPMailboxListener; IMAPMailboxListener fNULLListener; - MailboxSelectHandler fMailboxSelectHandler; - CapabilityHandler fCapabilityHandler; - ExistsHandler fExistsHandler; - ExpungeHandler fExpungeHandler; - FlagsHandler fFlagsHandler; + IMAP::ExistsHandler fExistsHandler; + IMAP::ExpungeHandler fExpungeHandler; +// FlagsHandler fFlagsHandler; int32 fWatching; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.cpp deleted file mode 100644 index 5ea949701f..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.cpp +++ /dev/null @@ -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 - - -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); -} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.h deleted file mode 100644 index 91590f1d50..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPParser.h +++ /dev/null @@ -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 - - -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 diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.cpp deleted file mode 100644 index 8297b9de54..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.cpp +++ /dev/null @@ -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 -# 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::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(); -} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h deleted file mode 100644 index bd236fa71a..0000000000 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPProtocol.h +++ /dev/null @@ -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 - -#include -#include -#include -#include - - -#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 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 fOngoingCommands; - - BString fCommandError; - - int32 fStopNow; - - bool fIsConnected; -}; - - -#endif // IMAP_PROTOCOL_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.cpp index 762fad56f3..a2444e3f7e 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.cpp @@ -36,7 +36,7 @@ IMAPMailboxSync::Sync(IMAPStorage& storage, IMAPMailbox& mailbox) const MinMessageList& messages = mailbox.GetMessageList(); for (MailEntryMap::const_iterator it = files.begin(); it != files.end(); - it++) { + it++) { const StorageMailEntry& mailEntry = (*it).second; bool found = false; for (unsigned int a = 0; a < messages.size(); a++) { @@ -352,7 +352,7 @@ IMAPStorage::GetEntryForRef(const node_ref& ref) bool -IMAPStorage::BodyFetched(int32 uid) +IMAPStorage::IsBodyFetched(int32 uid) { MailEntryMap::iterator it = fMailEntryMap.find(uid); if (it == fMailEntryMap.end()) @@ -365,9 +365,8 @@ IMAPStorage::BodyFetched(int32 uid) char buffer[B_MIME_TYPE_LENGTH]; BNodeInfo info(&node); info.GetType(buffer); - if (strcmp(buffer, B_MAIL_TYPE) == 0) - return true; - return false; + + return strcmp(buffer, B_MAIL_TYPE) == 0; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.h index d402e5e166..8f63a2a182 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/IMAPStorage.h @@ -16,17 +16,6 @@ #include #include -#include "IMAPHandler.h" - - -enum FileFlags { - kSeen = 0x01, - kAnswered = 0x02, - kFlagged = 0x04, - kDeleted = 0x08, - kDraft = 0x10 -}; - struct StorageMailEntry { int32 uid; @@ -73,7 +62,7 @@ public: status_t SetCompleteMessageSize(int32 uid, int32 size); - bool BodyFetched(int32 uid); + bool IsBodyFetched(int32 uid); StorageMailEntry* GetEntryForRef(const node_ref& ref); int32 RefToUID(const entry_ref& ref); diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp new file mode 100644 index 0000000000..76be8d92c9 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp @@ -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 +# 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(&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(arguments.ItemAt(i))) + fCapabilities.AddItem(new StringArgument(*argument)); + } + + TRACE("capabilities: %s\n", fCapabilities.ToString().String()); +} + + +} // namespace IMAP diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h new file mode 100644 index 0000000000..1b1b9bc14c --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h @@ -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 + +#include +#include +#include +#include +#include + +#include "Commands.h" + + +#define xEOF 236 +const bigtime_t kIMAP4ClientTimeout = 1000000 * 60; // 60 sec + + +namespace IMAP { + + +class Command; +class Handler; + + +typedef BObjectList CommandList; +typedef BObjectList HandlerList; +typedef std::map 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 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 diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp index de3a2ea19e..a49df18b24 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp @@ -6,6 +6,19 @@ #include "Response.h" +#include + +#include "Protocol.h" + // TODO: remove again once the ConnectionReader is out + + +#define TRACE_IMAP +#ifdef TRACE_IMAP +# define TRACE(...) printf(__VA_ARGS__) +#else +# define TRACE(...) ; +#endif + namespace IMAP { @@ -82,11 +95,8 @@ ArgumentList::ListAt(int32 index) const bool ArgumentList::IsListAt(int32 index) const { - if (index >= 0 && index < CountItems()) { - if (ListArgument* argument = dynamic_cast(ItemAt(index))) - return true; - } - return false; + return index >= 0 && index < CountItems() + && dynamic_cast(ItemAt(index)) != NULL; } @@ -101,15 +111,15 @@ ArgumentList::IsListAt(int32 index, char kind) const } -int32 -ArgumentList::IntegerAt(int32 index) const +uint32 +ArgumentList::NumberAt(int32 index) const { - return atoi(StringAt(index).String()); + return atoul(StringAt(index).String()); } bool -ArgumentList::IsIntegerAt(int32 index) const +ArgumentList::IsNumberAt(int32 index) const { BString string = StringAt(index); for (int32 i = 0; i < string.Length(); i++) { @@ -209,11 +219,6 @@ ParseException::ParseException(const char* message) } -ParseException::~ParseException() -{ -} - - // #pragma mark - @@ -228,6 +233,19 @@ ExpectedParseException::ExpectedParseException(char expected, char instead) // #pragma mark - +LiteralHandler::LiteralHandler() +{ +} + + +LiteralHandler::~LiteralHandler() +{ +} + + +// #pragma mark - + + Response::Response() : fTag(0), @@ -242,9 +260,12 @@ Response::~Response() void -Response::SetTo(const char* line) throw(ParseException) +Response::Parse(ConnectionReader& reader, const char* line, + LiteralHandler* handler) throw(ParseException) { MakeEmpty(); + fReader = &reader; + fLiteralHandler = handler; fTag = 0; fContinuation = false; @@ -384,8 +405,24 @@ Response::ParseQuoted(ArgumentList& arguments, const char*& line) void Response::ParseLiteral(ArgumentList& arguments, const char*& line) { - // TODO! - throw ParseException("Literals are not yet supported!"); + Consume(line, '{'); + off_t size = atoll(ExtractString(line)); + Consume(line, '}'); + Consume(line, '\r'); + Consume(line, '\n'); + + if (fLiteralHandler != NULL) + fLiteralHandler->HandleLiteral(*fReader, size); + else { + // The default implementation just throws the data away + BMallocIO stream; + TRACE("Trying to read literal with %llu bytes.\n", size); + status_t status = fReader->ReadToStream(size, stream); + if (status == B_OK) { + TRACE("LITERAL: %-*s\n", (int)size, (char*)stream.Buffer()); + } else + TRACE("Reading literal failed: %s\n", strerror(status)); + } } @@ -401,6 +438,7 @@ Response::ExtractString(const char*& line) { const char* start = line; + // TODO: parse modified UTF-7 as described in RFC 3501, 5.1.3 while (line[0] != '\0') { char c = line[0]; if (c <= ' ' || strchr("()[]{}\"", c) != NULL) @@ -413,4 +451,52 @@ Response::ExtractString(const char*& line) } +// #pragma mark - + + +ResponseParser::ResponseParser(ConnectionReader& reader) + : + fLiteralHandler(NULL) +{ + SetTo(reader); +} + + +ResponseParser::~ResponseParser() +{ +} + + +void +ResponseParser::SetTo(ConnectionReader& reader) +{ + fReader = &reader; +} + + +void +ResponseParser::SetLiteralHandler(LiteralHandler* handler) +{ + fLiteralHandler = handler; +} + + +status_t +ResponseParser::NextResponse(Response& response, bigtime_t timeout) + throw(ParseException) +{ + BString line; + status_t status = fReader->GetNextLine(line, timeout); + if (status != B_OK) { + TRACE("S: read error %s", line.String()); + return status; + } + + TRACE("S: %s", line.String()); + response.Parse(*fReader, line, fLiteralHandler); + + return B_OK; +} + + } // namespace IMAP diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h index 7ca0916ef2..5593fabcee 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h @@ -16,6 +16,7 @@ namespace IMAP { class Argument; +class ConnectionReader; class ArgumentList : public BObjectList { @@ -33,8 +34,8 @@ public: bool IsListAt(int32 index) const; bool IsListAt(int32 index, char kind) const; - int32 IntegerAt(int32 index) const; - bool IsIntegerAt(int32 index) const; + uint32 NumberAt(int32 index) const; + bool IsNumberAt(int32 index) const; BString ToString() const; }; @@ -82,7 +83,6 @@ class ParseException : public std::exception { public: ParseException(); ParseException(const char* message); - virtual ~ParseException(); const char* Message() const { return fMessage; } @@ -91,7 +91,7 @@ protected: }; -class ExpectedParseException : ParseException { +class ExpectedParseException : public ParseException { public: ExpectedParseException(char expected, char instead); @@ -101,12 +101,24 @@ protected: }; +class LiteralHandler { +public: + LiteralHandler(); + virtual ~LiteralHandler(); + + virtual void HandleLiteral(ConnectionReader& reader, + off_t length) = 0; +}; + + class Response : public ArgumentList { public: Response(); ~Response(); - void SetTo(const char* line) throw(ParseException); + void Parse(ConnectionReader& reader, + const char* line, LiteralHandler* handler) + throw(ParseException); bool IsUntagged() const { return fTag == 0; } int32 Tag() const { return fTag; } @@ -128,11 +140,30 @@ protected: BString ExtractString(const char*& line); protected: + ConnectionReader* fReader; + LiteralHandler* fLiteralHandler; int32 fTag; bool fContinuation; }; +class ResponseParser { +public: + ResponseParser(ConnectionReader& reader); + ~ResponseParser(); + + void SetTo(ConnectionReader& reader); + void SetLiteralHandler(LiteralHandler* handler); + + status_t NextResponse(Response& response, + bigtime_t timeout) throw(ParseException); + +protected: + ConnectionReader* fReader; + LiteralHandler* fLiteralHandler; +}; + + } // namespace IMAP diff --git a/src/tests/add-ons/mail/imap/Jamfile b/src/tests/add-ons/mail/imap/Jamfile index 65e2387470..4dc4f1a7bb 100644 --- a/src/tests/add-ons/mail/imap/Jamfile +++ b/src/tests/add-ons/mail/imap/Jamfile @@ -8,8 +8,20 @@ SubDirHdrs [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap imap_lib ] ; -local libSources = IMAPFolders.cpp IMAPHandler.cpp IMAPMailbox.cpp - IMAPParser.cpp IMAPProtocol.cpp IMAPStorage.cpp ; +local libSources = Commands.cpp Protocol.cpp Response.cpp ; +#IMAPStorage.cpp + +# use OpenSSL, if enabled +if $(HAIKU_OPENSSL_ENABLED) { + SubDirC++Flags -DUSE_SSL ; + SubDirSysHdrs $(HAIKU_OPENSSL_HEADERS) ; + Includes [ FGristFiles $(sources) ] : $(HAIKU_OPENSSL_HEADERS_DEPENDENCY) ; + # Dependency needed to trigger downloading/unzipping the package before + # compiling the files. + SetupFeatureObjectsDir ssl ; +} else { + SetupFeatureObjectsDir no-ssl ; +} SimpleTest imap_tester : imap_tester.cpp @@ -18,7 +30,7 @@ SimpleTest imap_tester : # from fs_shell argv.c - : be [ TargetLibsupc++ ] mail + : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] bnetapi mail ; SEARCH on [ FGristFiles $(libSources) ] diff --git a/src/tests/add-ons/mail/imap/imap_tester.cpp b/src/tests/add-ons/mail/imap/imap_tester.cpp index 188178f2e3..667e6625a0 100644 --- a/src/tests/add-ons/mail/imap/imap_tester.cpp +++ b/src/tests/add-ons/mail/imap/imap_tester.cpp @@ -1,14 +1,22 @@ -#include "IMAPFolders.h" -#include "IMAPMailbox.h" -#include "IMAPStorage.h" +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +//#include "IMAPStorage.h" +#include "Protocol.h" +#include "Response.h" #include "argv.h" struct cmd_entry { - char* name; - void (*func)(int argc, char **argv); - char* help; + const char* name; + void (*func)(int argc, char **argv); + const char* help; }; @@ -18,8 +26,8 @@ static void do_help(int argc, char** argv); extern const char* __progname; static const char* kProgramName = __progname; -static IMAPStorage sStorage; -static IMAPMailbox sMailbox(sStorage); +//static IMAPStorage sStorage; +static IMAP::Protocol sMailbox;//(/*sStorage*/); static void @@ -56,11 +64,13 @@ do_select(int argc, char** argv) static void do_folders(int argc, char** argv) { - IMAPFolders folder(sMailbox); - FolderList folders; - status_t status = folder.GetFolders(folders); - if (status != B_OK) + IMAP::FolderList folders; + + status_t status = sMailbox.GetFolders(folders); + if (status != B_OK) { error("folders", status); + return; + } for (size_t i = 0; i < folders.size(); i++) { printf(" %s %s\n", folders[i].subscribed ? "*" : " ", @@ -69,6 +79,34 @@ do_folders(int argc, char** argv) } +static void +do_flags(int argc, char** argv) +{ + uint32 from = 1; + uint32 to; + if (argc < 2) { + printf("usage: %s [] []\n", argv[0]); + return; + } + if (argc > 2) { + from = atoul(argv[1]); + to = atoul(argv[2]); + } else + to = atoul(argv[1]); + + IMAP::MessageEntryList entries; + IMAP::FetchMessageEntriesCommand command(entries, from, to); + status_t status = sMailbox.ProcessCommand(command); + if (status != B_OK) { + error("flags", status); + return; + } + + for (size_t i = 0; i < entries.size(); i++) + printf(" %lu %lx\n", entries[i].uid, entries[i].flags); +} + + static void do_raw(int argc, char** argv) { @@ -82,7 +120,7 @@ do_raw(int argc, char** argv) strlcat(command, argv[i], sizeof(command)); } - class RawCommand : public IMAPCommand { + class RawCommand : public IMAP::Command, public IMAP::Handler { public: RawCommand(const char* command) : @@ -90,13 +128,18 @@ do_raw(int argc, char** argv) { } - BString Command() + BString CommandString() { return fCommand; } - bool Handle(const BString& response) + bool HandleUntagged(IMAP::Response& response) { + if (response.IsCommand(fCommand)) { + printf("-> %s\n", response.ToString().String()); + return true; + } + return false; } @@ -104,7 +147,7 @@ do_raw(int argc, char** argv) const char* fCommand; }; RawCommand rawCommand(command); - status_t status = sMailbox.ProcessCommand(&rawCommand, 60 * 1000); + status_t status = sMailbox.ProcessCommand(rawCommand); if (status != B_OK) error("raw", status); } @@ -113,6 +156,8 @@ do_raw(int argc, char** argv) static cmd_entry sBuiltinCommands[] = { {"select", do_select, "Selects a mailbox, defaults to INBOX"}, {"folders", do_folders, "List of existing folders"}, + {"flags", do_flags, + "List of all mail UIDs in the mailbox with their flags"}, {"raw", do_raw, "Issue a raw command to the server"}, {"help", do_help, "prints this help text"}, {"quit", NULL, "exits the application"}, @@ -145,11 +190,13 @@ main(int argc, char** argv) const char* user = argv[2]; const char* password = argv[3]; bool useSSL = argc > 4; - uint16 port = useSSL ? 995 : 143; + uint16 port = useSSL ? 993 : 143; - printf("Connecting to \"%s\" as %s\n", server, user); + BNetworkAddress address(AF_INET, server, port); + printf("Connecting to \"%s\" as %s%s, port %u\n", server, user, + useSSL ? " with SSL" : "", address.Port()); - status_t status = sMailbox.Connect(server, user, password, useSSL, port); + status_t status = sMailbox.Connect(address, user, password, useSSL); if (status != B_OK) { error("connect", status); return 1;