diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp index afcd7ed16c..20734f6770 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp @@ -24,15 +24,62 @@ using namespace BPrivate; +static void +PutFlag(BString& string, const char* flag) +{ + if (!string.IsEmpty()) + string += " "; + string += flag; +} + + +static BString +GenerateFlagString(uint32 flags) +{ + BString string; + + if ((flags & IMAP::kSeen) != 0) + PutFlag(string, "\\Seen "); + if ((flags & IMAP::kAnswered) != 0) + PutFlag(string, "\\Answered "); + if ((flags & IMAP::kFlagged) != 0) + PutFlag(string, "\\Flagged "); + if ((flags & IMAP::kDeleted) != 0) + PutFlag(string, "\\Deleted "); + if ((flags & IMAP::kDraft) != 0) + PutFlag(string, "\\Draft "); + + return string; +} + + +static uint32 +ParseFlags(IMAP::ArgumentList& list) +{ + uint32 flags = 0; + for (int32 i = 0; i < list.CountItems(); i++) { + if (list.EqualsAt(i, "\\Seen")) + flags |= IMAP::kSeen; + else if (list.EqualsAt(i, "\\Answered")) + flags |= IMAP::kAnswered; + else if (list.EqualsAt(i, "\\Flagged")) + flags |= IMAP::kFlagged; + else if (list.EqualsAt(i, "\\Deleted")) + flags |= IMAP::kDeleted; + else if (list.EqualsAt(i, "\\Draft")) + flags |= IMAP::kDraft; + } + return flags; +} + + +// #pragma mark - + + namespace IMAP { -static HandlerListener sEmptyHandler; - - Handler::Handler() - : - fListener(&sEmptyHandler) { } @@ -42,20 +89,6 @@ Handler::~Handler() } -void -Handler::SetListener(HandlerListener& listener) -{ - fListener = &listener; -} - - -IMAP::LiteralHandler* -Handler::LiteralHandler() -{ - return NULL; -} - - // #pragma mark - @@ -80,7 +113,7 @@ Command::HandleTagged(Response& response) // #pragma mark - - +#if 0 HandlerListener::~HandlerListener() { } @@ -96,13 +129,7 @@ void HandlerListener::ExistsReceived(int32 number) { } - - -void -HandlerListener::FetchBody(Command& command, int32 size) -{ -} - +#endif // #pragma mark - @@ -257,7 +284,7 @@ BString FetchMessageEntriesCommand::CommandString() { BString command = "UID FETCH "; - command << fFrom << ":" << fTo << " FLAGS"; + command << fFrom << ":" << fTo << " (FLAGS RFC822.SIZE)"; return command; } @@ -275,22 +302,12 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response) 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, "RFC822.SIZE") && list.IsNumberAt(i + 1)) + entry.size = 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; - } + entry.flags = ParseFlags(flags); } } @@ -305,339 +322,93 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response) // #pragma mark - -#if 0 -FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox, - int32 message, MinMessageList* list, BPositionIO** data) +FetchCommand::FetchCommand(uint32 from, uint32 to, + FetchMode mode) : - IMAPMailboxCommand(mailbox), - - fMessage(message), - fEndMessage(-1), - fMinMessageList(list), - fData(data) + fFrom(from), + fTo(to), + fMode(mode) { } -FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox, - int32 firstMessage, int32 lastMessage, MinMessageList* list, - BPositionIO** data) - : - IMAPMailboxCommand(mailbox), - - fMessage(firstMessage), - fEndMessage(lastMessage), - fMinMessageList(list), - fData(data) +void +FetchCommand::SetListener(FetchListener* listener) { + fListener = listener; } BString -FetchMinMessageCommand::CommandString() +FetchCommand::CommandString() { - if (fMessage <= 0) - return ""; - BString command = "FETCH "; - command << fMessage; - if (fEndMessage > 0) { - command += ":"; - command << fEndMessage; - } - command += " (UID FLAGS)"; - return command; -} + BString command = "UID FETCH "; + command << fFrom; + if (fFrom != fTo) + command << ":" << fTo; - -bool -FetchMinMessageCommand::HandleUntagged(const BString& response) -{ - BString extracted = response; - int32 message; - if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message)) - return false; - - // check if we requested this message - int32 end = message; - if (fEndMessage > 0) - end = fEndMessage; - if (message < fMessage && message > end) - return false; - - MinMessage minMessage; - if (!ParseMinMessage(extracted, minMessage)) - return false; - - fMinMessageList->push_back(minMessage); - fStorage.AddNewMessage(minMessage.uid, minMessage.flags, fData); - return true; -} - - -bool -FetchMinMessageCommand::ParseMinMessage(const BString& response, - MinMessage& minMessage) -{ - BString extracted = IMAPParser::ExtractNextElement(response); - BString uid = IMAPParser::ExtractElementAfter(extracted, "UID"); - if (uid == "") - return false; - minMessage.uid = atoi(uid); - - int32 flags = ExtractFlags(extracted); - minMessage.flags = flags; - - return true; -} - - -int32 -FetchMinMessageCommand::ExtractFlags(const BString& response) -{ - int32 flags = 0; - BString flagsString = IMAPParser::ExtractElementAfter(response, "FLAGS"); - - while (true) { - BString flag = IMAPParser::RemovePrimitiveFromLeft(flagsString); - if (flag == "") + command += " (UID "; + switch (fMode) { + case kFetchHeader: + command += "RFC822.HEADER"; + break; + case kFetchBody: + command += "BODY.PEEK[TEXT]"; + break; + case kFetchAll: + command += "BODY.PEEK[]"; break; - - if (flag == "\\Seen") - flags |= kSeen; - else if (flag == "\\Answered") - flags |= kAnswered; - else if (flag == "\\Flagged") - flags |= kFlagged; - else if (flag == "\\Deleted") - flags |= kDeleted; - else if (flag == "\\Draft") - flags |= kDraft; } - return flags; -} + command += ")"; - -// #pragma mark - - - -FetchMessageCommand::FetchMessageCommand(IMAPMailbox& mailbox, int32 message, - BPositionIO* data, int32 fetchBodyLimit) - : - IMAPMailboxCommand(mailbox), - - fMessage(message), - fEndMessage(-1), - fOutData(data), - fFetchBodyLimit(fetchBodyLimit) -{ -} - - -FetchMessageCommand::FetchMessageCommand(IMAPMailbox& mailbox, - int32 firstMessage, int32 lastMessage, int32 fetchBodyLimit) - : - IMAPMailboxCommand(mailbox), - - fMessage(firstMessage), - fEndMessage(lastMessage), - fOutData(NULL), - fFetchBodyLimit(fetchBodyLimit) -{ - if (fEndMessage > 0) - fUnhandled = fEndMessage - fMessage + 1; - else - fUnhandled = 1; -} - - -FetchMessageCommand::~FetchMessageCommand() -{ - for (int32 i = 0; i < fUnhandled; i++) - fIMAPMailbox.Listener().FetchEnd(); -} - - -BString -FetchMessageCommand::CommandString() -{ - BString command = "FETCH "; - command << fMessage; - if (fEndMessage > 0) { - command += ":"; - command << fEndMessage; - } - command += " (RFC822.SIZE RFC822.HEADER)"; return command; } bool -FetchMessageCommand::HandleUntagged(const BString& response) +FetchCommand::HandleUntagged(Response& response) { - BString extracted = response; - int32 message; - if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message)) + if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2)) return false; - // check if we requested this message - int32 end = message; - if (fEndMessage > 0) - end = fEndMessage; - if (message < fMessage && message > end) + // We don't need to parse anything here - all the data is processed via + // HandleLiteral(). + return true; +} + + +bool +FetchCommand::HandleLiteral(Response& response, BDataIO& stream, + size_t length) +{ + if (fListener == NULL || !response.EqualsAt(1, "FETCH") + || !response.IsListAt(2)) return false; - const MinMessageList& list = fIMAPMailbox.GetMessageList(); - int32 index = message - 1; - if (index < 0 || index >= (int32)list.size()) - return false; - const MinMessage& minMessage = list[index]; + uint32 uid = 0; - BPositionIO* data = fOutData; - ObjectDeleter deleter; - if (!data) { - status_t status = fStorage.OpenMessage(minMessage.uid, &data); - if (status != B_OK) { - status = fStorage.AddNewMessage(minMessage.uid, minMessage.flags, - &data); + // Get current UID + ArgumentList& list = response.ListAt(2); + for (int32 i = 0; i < list.CountItems(); i += 2) { + if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1)) { + uid = list.NumberAt(i + 1); + break; } - if (status != B_OK) - return false; - deleter.SetTo(data); } - // read message size - BString messageSizeString = IMAPParser::ExtractElementAfter(extracted, - "RFC822.SIZE"); - int32 messageSize = atoi(messageSizeString); - fStorage.SetCompleteMessageSize(minMessage.uid, messageSize); - - // read header - int32 headerPos = extracted.FindFirst("RFC822.HEADER"); - if (headerPos < 0) { - if (!fOutData) - fStorage.DeleteMessage(minMessage.uid); + if (uid == 0) return false; - } - extracted.Remove(0, headerPos + strlen("RFC822.HEADER") + 1); - BString headerSize = IMAPParser::RemovePrimitiveFromLeft(extracted); - headerSize = IMAPParser::ExtractNextElement(headerSize); - int32 size = atoi(headerSize); - status_t status = fConnectionReader.ReadToFile(size, data); - if (status != B_OK) { - if (!fOutData) - fStorage.DeleteMessage(minMessage.uid); - return false; - } - - // read last ")" line - BString lastLine; - fConnectionReader.GetNextLine(lastLine); - - fUnhandled--; - - bool bodyIsComing = true; - if (fFetchBodyLimit >= 0 && fFetchBodyLimit <= messageSize) - bodyIsComing = false; - - int32 uid = fIMAPMailbox.MessageNumberToUID(message); - if (uid >= 0) - fIMAPMailbox.Listener().HeaderFetched(uid, data, bodyIsComing); - - if (!bodyIsComing) - return true; - - deleter.Detach(); - FetchBodyCommand* bodyCommand = new FetchBodyCommand(fIMAPMailbox, message, - data); - fIMAPMailbox.AddAfterQuakeCommand(bodyCommand); - - return true; + return fListener->FetchData(response, uid, fMode, stream, length); } // #pragma mark - -FetchBodyCommand::FetchBodyCommand(IMAPMailbox& mailbox, int32 message, - BPositionIO* data) +SetFlagsCommand::SetFlagsCommand(uint32 uid, uint32 flags) : - IMAPMailboxCommand(mailbox), - - fMessage(message), - fOutData(data) -{ -} - - -FetchBodyCommand::~FetchBodyCommand() -{ - delete fOutData; -} - - -BString -FetchBodyCommand::CommandString() -{ - BString command = "FETCH "; - command << fMessage; - command += " (FLAGS BODY.PEEK[TEXT])"; - return command; -} - - -bool -FetchBodyCommand::HandleUntagged(const BString& response) -{ - if (response.FindFirst("FETCH") < 0) - return false; - - BString extracted = response; - int32 message; - if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message)) - return false; - if (message != fMessage) - return false; - - int32 flags = FetchMinMessageCommand::ExtractFlags(extracted); - fStorage.SetFlags(fIMAPMailbox.MessageNumberToUID(message), flags); - - int32 textPos = extracted.FindFirst("BODY[TEXT]"); - if (textPos < 0) - return false; - extracted.Remove(0, textPos + strlen("BODY[TEXT]") + 1); - BString bodySize = IMAPParser::ExtractBetweenBrackets(extracted, "{", "}"); - bodySize = IMAPParser::ExtractNextElement(bodySize); - int32 size = atoi(bodySize); - TRACE("Body size %i\n", (int)size); - fOutData->Seek(0, SEEK_END); - status_t status = fConnectionReader.ReadToFile(size, fOutData); - if (status != B_OK) - return false; - - // read last ")" line - BString lastLine; - fConnectionReader.GetNextLine(lastLine); - - int32 uid = fIMAPMailbox.MessageNumberToUID(message); - if (uid >= 0) - fIMAPMailbox.Listener().BodyFetched(uid, fOutData); - else - fIMAPMailbox.Listener().FetchEnd(); - - return true; -} - - -// #pragma mark - - - -SetFlagsCommand::SetFlagsCommand(IMAPMailbox& mailbox, int32 message, - int32 flags) - : - IMAPMailboxCommand(mailbox), - - fMessage(message), + fUID(uid), fFlags(flags) { } @@ -647,44 +418,24 @@ BString SetFlagsCommand::CommandString() { BString command = "STORE "; - command << fMessage; - command += " FLAGS ("; - command += GenerateFlagList(fFlags); - command += ")"; + command << fUID << " FLAGS (" << GenerateFlagString(fFlags) << ")"; + return command; } bool -SetFlagsCommand::HandleUntagged(const BString& response) +SetFlagsCommand::HandleUntagged(Response& response) { - return false; -} - - -BString -SetFlagsCommand::GenerateFlagList(int32 flags) -{ - BString flagList; - - if ((flags & kSeen) != 0) - flagList += "\\Seen "; - if ((flags & kAnswered) != 0) - flagList += "\\Answered "; - if ((flags & kFlagged) != 0) - flagList += "\\Flagged "; - if ((flags & kDeleted) != 0) - flagList += "\\Deleted "; - if ((flags & kDraft) != 0) - flagList += "\\Draft "; - - return flagList.Trim(); + // We're not that interested in the outcome, apparently + return response.EqualsAt(1, "FETCH"); } // #pragma mark - +#if 0 AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message, off_t size, int32 flags, time_t time) : @@ -754,10 +505,10 @@ ExistsHandler::HandleUntagged(Response& response) if (!response.EqualsAt(1, "EXISTS") || response.IsNumberAt(0)) return false; - int32 expunge = response.NumberAt(0); +// int32 expunge = response.NumberAt(0); +#if 0 Listener().ExistsReceived(expunge); -#if 0 if (response.FindFirst("EXISTS") < 0) return false; @@ -818,10 +569,10 @@ ExpungeHandler::HandleUntagged(Response& response) if (!response.EqualsAt(1, "EXPUNGE") || response.IsNumberAt(0)) return false; - int32 expunge = response.NumberAt(0); +// int32 expunge = response.NumberAt(0); +#if 0 Listener().ExpungeReceived(expunge); -#if 0 // remove from storage IMAPStorage& storage = fIMAPMailbox.GetStorage(); storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge)); 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 index 5f3f66c485..08d8f66467 100644 --- 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 @@ -19,9 +19,6 @@ typedef std::vector StringList; namespace IMAP { -class HandlerListener; - - struct MessageEntry { MessageEntry() : @@ -32,6 +29,7 @@ struct MessageEntry { uint32 uid; uint32 flags; + uint32 size; }; typedef std::vector MessageEntryList; @@ -49,14 +47,7 @@ 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; }; @@ -69,16 +60,6 @@ public: }; -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); @@ -112,8 +93,8 @@ public: SelectCommand(); SelectCommand(const char* mailboxName); - BString CommandString(); - bool HandleUntagged(Response& response); + virtual BString CommandString(); + virtual bool HandleUntagged(Response& response); void SetTo(const char* mailboxName) { fMailboxName = mailboxName; } @@ -154,88 +135,58 @@ private: uint32 fTo; }; + +enum FetchMode { + kFetchHeader, + kFetchBody, + kFetchAll +}; + + +class FetchListener { +public: + virtual bool FetchData(Response& reponse, uint32 uid, + FetchMode mode, BDataIO& stream, + size_t length) = 0; +}; + + +class FetchCommand : public Command, public Handler, + public LiteralHandler { +public: + FetchCommand(uint32 from, uint32 to, + FetchMode mode); + + void SetListener(FetchListener* listener); + FetchListener* Listener() const { return fListener; } + + virtual BString CommandString(); + virtual bool HandleUntagged(Response& response); + virtual bool HandleLiteral(Response& response, + BDataIO& stream, size_t length); + +private: + uint32 fFrom; + uint32 fTo; + FetchMode fMode; + FetchListener* fListener; +}; + + +class SetFlagsCommand : public Command, public Handler { +public: + SetFlagsCommand(uint32 uid, uint32 flags); + + virtual BString CommandString(); + virtual bool HandleUntagged(Response& response); + +private: + uint32 fUID; + uint32 fFlags; +}; + + #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, 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 index b7ef6f82d1..dbd3d6f737 100644 --- 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 @@ -236,6 +236,8 @@ Protocol::SendCommand(int32 id, const char* command) else length = snprintf(buffer, sizeof(buffer), "%s\r\n", command); + TRACE("C: %s", buffer); + ssize_t bytesWritten = fSocket->Write(buffer, length); if (bytesWritten < 0) return bytesWritten; 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 752197239e..372831fa4e 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 @@ -412,9 +412,11 @@ Response::ParseLiteral(ArgumentList& arguments, BDataIO& stream) Consume(stream, '\r'); Consume(stream, '\n'); + bool handled = false; if (fLiteralHandler != NULL) - fLiteralHandler->HandleLiteral(stream, size); - else { + handled = fLiteralHandler->HandleLiteral(*this, stream, size); + + if (!handled) { // The default implementation just adds the data as a string TRACE("Trying to read literal with %" B_PRIuSIZE " bytes.\n", size); BString string; 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 b5f1663fc1..6797f15b95 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 @@ -17,6 +17,7 @@ namespace IMAP { class Argument; +class Response; class ArgumentList : public BObjectList { @@ -112,8 +113,8 @@ public: LiteralHandler(); virtual ~LiteralHandler(); - virtual void HandleLiteral(BDataIO& stream, - size_t length) = 0; + virtual bool HandleLiteral(Response& response, + BDataIO& stream, size_t length) = 0; }; diff --git a/src/tests/add-ons/mail/imap/imap_tester.cpp b/src/tests/add-ons/mail/imap/imap_tester.cpp index 667e6625a0..702c649860 100644 --- a/src/tests/add-ons/mail/imap/imap_tester.cpp +++ b/src/tests/add-ons/mail/imap/imap_tester.cpp @@ -6,7 +6,6 @@ #include -//#include "IMAPStorage.h" #include "Protocol.h" #include "Response.h" @@ -26,8 +25,7 @@ static void do_help(int argc, char** argv); extern const char* __progname; static const char* kProgramName = __progname; -//static IMAPStorage sStorage; -static IMAP::Protocol sMailbox;//(/*sStorage*/); +static IMAP::Protocol sProtocol; static void @@ -55,7 +53,7 @@ do_select(int argc, char** argv) if (argc > 1) folder = argv[1]; - status_t status = sMailbox.SelectMailbox(folder); + status_t status = sProtocol.SelectMailbox(folder); if (status != B_OK) error("select", status); } @@ -66,7 +64,7 @@ do_folders(int argc, char** argv) { IMAP::FolderList folders; - status_t status = sMailbox.GetFolders(folders); + status_t status = sProtocol.GetFolders(folders); if (status != B_OK) { error("folders", status); return; @@ -79,6 +77,40 @@ do_folders(int argc, char** argv) } +static void +do_fetch(int argc, char** argv) +{ + uint32 from = 1; + uint32 to; + IMAP::FetchMode mode = IMAP::kFetchAll; + if (argc < 2) { + printf("usage: %s [] [] [header|body]\n", argv[0]); + return; + } + if (argc > 2) { + if (!strcasecmp(argv[argc - 1], "header")) { + mode = IMAP::kFetchHeader; + argc--; + } else if (!strcasecmp(argv[argc - 1], "body")) { + mode = IMAP::kFetchBody; + argc--; + } + } + if (argc > 2) { + from = atoul(argv[1]); + to = atoul(argv[2]); + } else + from = to = atoul(argv[1]); + + IMAP::FetchCommand command(from, to, mode); + status_t status = sProtocol.ProcessCommand(command); + if (status != B_OK) { + error("fetch", status); + return; + } +} + + static void do_flags(int argc, char** argv) { @@ -96,14 +128,26 @@ do_flags(int argc, char** argv) IMAP::MessageEntryList entries; IMAP::FetchMessageEntriesCommand command(entries, from, to); - status_t status = sMailbox.ProcessCommand(command); + status_t status = sProtocol.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); + for (size_t i = 0; i < entries.size(); i++) { + printf("%10lu %8lu bytes, flags: %#lx\n", entries[i].uid, + entries[i].size, entries[i].flags); + } +} + + +static void +do_noop(int argc, char** argv) +{ + IMAP::RawCommand command("NOOP"); + status_t status = sProtocol.ProcessCommand(command); + if (status != B_OK) + error("noop", status); } @@ -147,7 +191,7 @@ do_raw(int argc, char** argv) const char* fCommand; }; RawCommand rawCommand(command); - status_t status = sMailbox.ProcessCommand(rawCommand); + status_t status = sProtocol.ProcessCommand(rawCommand); if (status != B_OK) error("raw", status); } @@ -158,6 +202,9 @@ static cmd_entry sBuiltinCommands[] = { {"folders", do_folders, "List of existing folders"}, {"flags", do_flags, "List of all mail UIDs in the mailbox with their flags"}, + {"fetch", do_fetch, + "Fetch mails via UIDs"}, + {"noop", do_noop, "Issue a NOOP command (will report new messages)"}, {"raw", do_raw, "Issue a raw command to the server"}, {"help", do_help, "prints this help text"}, {"quit", NULL, "exits the application"}, @@ -196,7 +243,7 @@ main(int argc, char** argv) printf("Connecting to \"%s\" as %s%s, port %u\n", server, user, useSSL ? " with SSL" : "", address.Port()); - status_t status = sMailbox.Connect(address, user, password, useSSL); + status_t status = sProtocol.Connect(address, user, password, useSSL); if (status != B_OK) { error("connect", status); return 1;