added 1 changeset to branch 'refs/remotes/axeld-github/imap' old head: f79e74cddf027a87ca86cede7974e54ccc73d3d1 new head: d10b838e460a596c57968f5fd12ee5d9818e84aa overview: https://github.com/axeld/haiku/compare/f79e74c...d10b838 ---------------------------------------------------------------------------- d10b838: imap: WIP of getting fetching headers to work. * Changed the FetchListener mechanism quite a bit. * Doesn't seem to work correctly yet, although most pieces are in place now. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: d10b838e460a596c57968f5fd12ee5d9818e84aa Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Fri Apr 19 21:29:34 2013 UTC ---------------------------------------------------------------------------- 9 files changed, 170 insertions(+), 50 deletions(-) .../imap/IMAPConnectionWorker.cpp | 21 ++++++-- .../inbound_protocols/imap/IMAPFolder.cpp | 52 +++++++++++++++++++- .../inbound_protocols/imap/IMAPFolder.h | 8 ++- .../inbound_protocols/imap/imap_lib/Commands.cpp | 46 ++++++++--------- .../inbound_protocols/imap/imap_lib/Commands.h | 21 ++++---- .../inbound_protocols/imap/imap_lib/Protocol.cpp | 28 +++++++++++ .../inbound_protocols/imap/imap_lib/Response.cpp | 6 ++- .../inbound_protocols/imap/imap_lib/Response.h | 3 +- src/tests/add-ons/mail/imap/imap_tester.cpp | 35 ++++++++----- ---------------------------------------------------------------------------- diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp index eea0214..746226f 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp @@ -112,7 +112,7 @@ public: }; -class FetchHeadersCommand : public WorkerCommand { +class FetchHeadersCommand : public WorkerCommand, public IMAP::FetchListener { public: FetchHeadersCommand(IMAPFolder& folder, IMAPMailbox& mailbox, uint32 from, uint32 to) @@ -133,11 +133,11 @@ public: if (status != B_OK) return status; - // TODO: create messages! // TODO: trigger download of mails for all messages below the // body fetch limit - // TODO: we would really like to have the message flags at this point IMAP::FetchCommand fetch(fFrom, fTo, IMAP::kFetchHeader); + fetch.SetListener(this); + status = protocol.ProcessCommand(fetch); if (status != B_OK) return status; @@ -145,11 +145,26 @@ public: return B_OK; } + virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, size_t length) + { + fFetchStatus = fFolder.StoreTemporaryMessage(fetchFlags, stream, + length, fRef); + return true; + } + + virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags) + { + if (fFetchStatus == B_OK) + fFolder.StoreMessage(fetchFlags, uid, flags, fRef); + } + private: IMAPFolder& fFolder; IMAPMailbox& fMailbox; uint32 fFrom; uint32 fTo; + entry_ref fRef; + status_t fFetchStatus; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp index 4c3d40a..3b7cda6 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.cpp @@ -11,8 +11,10 @@ #include <ByteOrder.h> #include <Debug.h> #include <Directory.h> +#include <File.h> #include <fs_attr.h> #include <Node.h> +#include <Path.h> static const char* kMailboxNameAttribute = "IMAP:mailbox"; @@ -95,9 +97,57 @@ IMAPFolder::SetUIDValidity(uint32 uidValidity) } +status_t +IMAPFolder::StoreTemporaryMessage(uint32 fetchFlags, BDataIO& stream, + size_t length, entry_ref& ref) +{ + BPath path; + status_t status = path.SetTo(&fRef); + if (status != B_OK) + return status; + + path.Append("tmp1234"); + + BFile file; + status = (path.Path(), B_CREATE_FILE); + if (status != B_OK) + return status; + + get_ref_for_path(path.Path(), &ref); + + char buffer[65535]; + while (length > 0) { + ssize_t bytesRead = stream.Read(buffer, + min_c(sizeof(buffer), length)); + if (bytesRead <= 0) + break; + + file.Write(buffer, bytesRead); + length -= bytesRead; + } + + return B_OK; +} + + void -IMAPFolder::StoreMessage(uint32 uid, ...) +IMAPFolder::StoreMessage(uint32 fetchFlags, uint32 uid, uint32 flags, + entry_ref& ref) +{ + BString name = "mail-"; + name << uid; + + // TODO: remove renaming as its superfluous here + BEntry entry(&ref); + entry.Rename(name.String()); +} + + +status_t +IMAPFolder::StoreMessage(uint32 fetchFlags, uint32 uid, BDataIO& stream, + size_t length) { + return B_ERROR; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h index 11a69aa..1b8b2e5 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolder.h @@ -45,7 +45,13 @@ public: void SetListener(FolderListener* listener); void SetUIDValidity(uint32 uidValidity); - void StoreMessage(uint32 uid, ...); + status_t StoreTemporaryMessage(uint32 fetchFlags, + BDataIO& stream, size_t length, + entry_ref& ref); + void StoreMessage(uint32 fetchFlags, uint32 uid, + uint32 flags, entry_ref& ref); + status_t StoreMessage(uint32 fetchFlags, uint32 uid, + BDataIO& stream, size_t length); void DeleteMessage(uint32 uid); void SetMessageFlags(uint32 uid, uint32 flags); 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 e7adfab..0a60206 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 @@ -330,11 +330,11 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response) // #pragma mark - -FetchCommand::FetchCommand(uint32 from, uint32 to, FetchMode mode) +FetchCommand::FetchCommand(uint32 from, uint32 to, uint32 flags) : fFrom(from), fTo(to), - fMode(mode) + fFlags(flags) { } @@ -355,7 +355,9 @@ FetchCommand::CommandString() command << ":" << fTo; command += " (UID "; - switch (fMode) { + if ((fFlags & kFetchFlags) != 0) + command += "FLAGS "; + switch (fFlags & kFetchAll) { case kFetchHeader: command += "RFC822.HEADER"; break; @@ -378,35 +380,35 @@ FetchCommand::HandleUntagged(Response& response) if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2)) return false; - // We don't need to parse anything here - all the data is processed via - // HandleLiteral(). + ArgumentList& list = response.ListAt(2); + uint32 uid = 0; + uint32 flags = 0; + + for (int32 i = 0; i < list.CountItems(); i += 2) { + if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1)) + uid = list.NumberAt(i + 1); + else if (list.EqualsAt(i, "FLAGS") && list.IsListAt(i + 1)) { + // Parse flags + ArgumentList& flagList = list.ListAt(i + 1); + flags = ParseFlags(flagList); + } + } + + if (fListener != NULL) + fListener->FetchedData(fFlags, uid, flags); return true; } bool -FetchCommand::HandleLiteral(Response& response, BDataIO& stream, - size_t length) +FetchCommand::HandleLiteral(Response& response, ArgumentList& arguments, + BDataIO& stream, size_t length) { if (fListener == NULL || !response.EqualsAt(1, "FETCH") || !response.IsListAt(2)) return false; - uint32 uid = 0; - - // 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 (uid == 0) - return false; - - return fListener->FetchData(response, uid, fMode, stream, length); + return fListener->FetchData(fFlags, stream, length); } 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 8a547bc..4284409 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 @@ -136,18 +136,20 @@ private: }; -enum FetchMode { - kFetchHeader, - kFetchBody, - kFetchAll +enum FetchFlags { + kFetchHeader = 0x01, + kFetchBody = 0x02, + kFetchAll = kFetchHeader | kFetchBody, + kFetchFlags = 0x04, }; class FetchListener { public: - virtual bool FetchData(Response& reponse, uint32 uid, - FetchMode mode, BDataIO& stream, + virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, size_t length) = 0; + virtual void FetchedData(uint32 fetchFlags, uint32 uid, + uint32 flags) = 0; }; @@ -155,7 +157,7 @@ class FetchCommand : public Command, public Handler, public LiteralHandler { public: FetchCommand(uint32 from, uint32 to, - FetchMode mode); + uint32 fetchFlags); void SetListener(FetchListener* listener); FetchListener* Listener() const { return fListener; } @@ -163,12 +165,13 @@ public: virtual BString CommandString(); virtual bool HandleUntagged(Response& response); virtual bool HandleLiteral(Response& response, - BDataIO& stream, size_t length); + ArgumentList& arguments, BDataIO& stream, + size_t length); private: uint32 fFrom; uint32 fTo; - FetchMode fMode; + uint32 fFlags; FetchListener* fListener; }; 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 88adcad..9a50cf1 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 @@ -85,6 +85,34 @@ Protocol::Connect(const BNetworkAddress& address, const char* username, _ParseCapabilities(capabilityHandler.Capabilities()); } + if (Capabilities().Contains("ID")) { + // Get the server's ID into our log + class IDCommand : public IMAP::Command, public IMAP::Handler { + public: + BString CommandString() + { + return "ID NIL"; + } + + bool HandleUntagged(IMAP::Response& response) + { + if (response.IsCommand("ID") && response.IsListAt(1)) { + puts("Server:"); + ArgumentList& list = response.ListAt(1); + for (int32 i = 0; i < list.CountItems(); i += 2) { + printf(" %s: %s\n", + list.ItemAt(i)->ToString().String(), + list.ItemAt(i + 1)->ToString().String()); + } + return true; + } + + return false; + } + }; + IDCommand idCommand; + ProcessCommand(idCommand); + } return B_OK; } 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 d27b4c4..446d2c1 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 @@ -583,8 +583,10 @@ Response::ParseLiteral(ArgumentList& arguments, BDataIO& stream) Consume(stream, '\n'); bool handled = false; - if (fLiteralHandler != NULL) - handled = fLiteralHandler->HandleLiteral(*this, stream, size); + if (fLiteralHandler != NULL) { + handled = fLiteralHandler->HandleLiteral(*this, arguments, stream, + size); + } if (!handled) { // The default implementation just adds the data as a 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 7460cf4..584ce6c 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 @@ -129,7 +129,8 @@ public: virtual ~LiteralHandler(); virtual bool HandleLiteral(Response& response, - BDataIO& stream, size_t length) = 0; + ArgumentList& arguments, 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 c77c912..95ddc86 100644 --- a/src/tests/add-ons/mail/imap/imap_tester.cpp +++ b/src/tests/add-ons/mail/imap/imap_tester.cpp @@ -87,17 +87,17 @@ do_fetch(int argc, char** argv) { uint32 from = 1; uint32 to; - IMAP::FetchMode mode = IMAP::kFetchAll; + uint32 flags = IMAP::kFetchAll; if (argc < 2) { printf("usage: %s [<from>] [<to>] [header|body]\n", argv[0]); return; } if (argc > 2) { if (!strcasecmp(argv[argc - 1], "header")) { - mode = IMAP::kFetchHeader; + flags = IMAP::kFetchHeader; argc--; } else if (!strcasecmp(argv[argc - 1], "body")) { - mode = IMAP::kFetchBody; + flags = IMAP::kFetchBody; argc--; } } @@ -107,15 +107,20 @@ do_fetch(int argc, char** argv) } else from = to = atoul(argv[1]); - IMAP::FetchCommand command(from, to, mode); + IMAP::FetchCommand command(from, to, flags | IMAP::kFetchFlags); // A fetch listener that dumps everything to stdout class Listener : public IMAP::FetchListener { public: - virtual bool FetchData(IMAP::Response& reponse, uint32 uid, - IMAP::FetchMode mode, BDataIO& stream, size_t length) + virtual ~Listener() { - BMallocIO copy; + } + + virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, + size_t length) + { + fBuffer.SetSize(0); + char buffer[65535]; while (length > 0) { ssize_t bytesRead = stream.Read(buffer, @@ -123,18 +128,26 @@ do_fetch(int argc, char** argv) if (bytesRead <= 0) break; - copy.Write(buffer, bytesRead); + fBuffer.Write(buffer, bytesRead); length -= bytesRead; } // Null terminate the buffer char null = '\0'; - copy.Write(&null, 1); + fBuffer.Write(&null, 1); - printf("================= UID %ld =================\n", uid); - puts((const char*)copy.Buffer()); return true; } + + virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags) + { + printf("================= UID %ld, flags %lx =================\n", + uid, flags); + puts((const char*)fBuffer.Buffer()); + } + + private: + BMallocIO fBuffer; } listener; command.SetListener(&listener);