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.
This commit is contained in:
Axel Dörfler
2015-01-06 15:25:33 +01:00
parent 9234fd439e
commit 3302df142e
9 changed files with 171 additions and 51 deletions
@@ -112,7 +112,7 @@ public:
}; };
class FetchHeadersCommand : public WorkerCommand { class FetchHeadersCommand : public WorkerCommand, public IMAP::FetchListener {
public: public:
FetchHeadersCommand(IMAPFolder& folder, IMAPMailbox& mailbox, FetchHeadersCommand(IMAPFolder& folder, IMAPMailbox& mailbox,
uint32 from, uint32 to) uint32 from, uint32 to)
@@ -133,11 +133,11 @@ public:
if (status != B_OK) if (status != B_OK)
return status; return status;
// TODO: create messages!
// TODO: trigger download of mails for all messages below the // TODO: trigger download of mails for all messages below the
// body fetch limit // body fetch limit
// TODO: we would really like to have the message flags at this point
IMAP::FetchCommand fetch(fFrom, fTo, IMAP::kFetchHeader); IMAP::FetchCommand fetch(fFrom, fTo, IMAP::kFetchHeader);
fetch.SetListener(this);
status = protocol.ProcessCommand(fetch); status = protocol.ProcessCommand(fetch);
if (status != B_OK) if (status != B_OK)
return status; return status;
@@ -145,11 +145,26 @@ public:
return B_OK; 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: private:
IMAPFolder& fFolder; IMAPFolder& fFolder;
IMAPMailbox& fMailbox; IMAPMailbox& fMailbox;
uint32 fFrom; uint32 fFrom;
uint32 fTo; uint32 fTo;
entry_ref fRef;
status_t fFetchStatus;
}; };
@@ -11,8 +11,10 @@
#include <ByteOrder.h> #include <ByteOrder.h>
#include <Debug.h> #include <Debug.h>
#include <Directory.h> #include <Directory.h>
#include <File.h>
#include <fs_attr.h> #include <fs_attr.h>
#include <Node.h> #include <Node.h>
#include <Path.h>
static const char* kMailboxNameAttribute = "IMAP:mailbox"; static const char* kMailboxNameAttribute = "IMAP:mailbox";
@@ -95,9 +97,57 @@ IMAPFolder::SetUIDValidity(uint32 uidValidity)
} }
void status_t
IMAPFolder::StoreMessage(uint32 uid, ...) 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 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;
} }
@@ -45,7 +45,13 @@ public:
void SetListener(FolderListener* listener); void SetListener(FolderListener* listener);
void SetUIDValidity(uint32 uidValidity); 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 DeleteMessage(uint32 uid);
void SetMessageFlags(uint32 uid, uint32 flags); void SetMessageFlags(uint32 uid, uint32 flags);
@@ -330,11 +330,11 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response)
// #pragma mark - // #pragma mark -
FetchCommand::FetchCommand(uint32 from, uint32 to, FetchMode mode) FetchCommand::FetchCommand(uint32 from, uint32 to, uint32 flags)
: :
fFrom(from), fFrom(from),
fTo(to), fTo(to),
fMode(mode) fFlags(flags)
{ {
} }
@@ -355,7 +355,9 @@ FetchCommand::CommandString()
command << ":" << fTo; command << ":" << fTo;
command += " (UID "; command += " (UID ";
switch (fMode) { if ((fFlags & kFetchFlags) != 0)
command += "FLAGS ";
switch (fFlags & kFetchAll) {
case kFetchHeader: case kFetchHeader:
command += "RFC822.HEADER"; command += "RFC822.HEADER";
break; break;
@@ -378,35 +380,35 @@ FetchCommand::HandleUntagged(Response& response)
if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2)) if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2))
return false; return false;
// We don't need to parse anything here - all the data is processed via ArgumentList& list = response.ListAt(2);
// HandleLiteral(). 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; return true;
} }
bool bool
FetchCommand::HandleLiteral(Response& response, BDataIO& stream, FetchCommand::HandleLiteral(Response& response, ArgumentList& arguments,
size_t length) BDataIO& stream, size_t length)
{ {
if (fListener == NULL || !response.EqualsAt(1, "FETCH") if (fListener == NULL || !response.EqualsAt(1, "FETCH")
|| !response.IsListAt(2)) || !response.IsListAt(2))
return false; return false;
uint32 uid = 0; return fListener->FetchData(fFlags, stream, length);
// 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);
} }
@@ -136,18 +136,20 @@ private:
}; };
enum FetchMode { enum FetchFlags {
kFetchHeader, kFetchHeader = 0x01,
kFetchBody, kFetchBody = 0x02,
kFetchAll kFetchAll = kFetchHeader | kFetchBody,
kFetchFlags = 0x04,
}; };
class FetchListener { class FetchListener {
public: public:
virtual bool FetchData(Response& reponse, uint32 uid, virtual bool FetchData(uint32 fetchFlags, BDataIO& stream,
FetchMode mode, BDataIO& stream,
size_t length) = 0; 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 LiteralHandler {
public: public:
FetchCommand(uint32 from, uint32 to, FetchCommand(uint32 from, uint32 to,
FetchMode mode); uint32 fetchFlags);
void SetListener(FetchListener* listener); void SetListener(FetchListener* listener);
FetchListener* Listener() const { return fListener; } FetchListener* Listener() const { return fListener; }
@@ -163,12 +165,13 @@ public:
virtual BString CommandString(); virtual BString CommandString();
virtual bool HandleUntagged(Response& response); virtual bool HandleUntagged(Response& response);
virtual bool HandleLiteral(Response& response, virtual bool HandleLiteral(Response& response,
BDataIO& stream, size_t length); ArgumentList& arguments, BDataIO& stream,
size_t length);
private: private:
uint32 fFrom; uint32 fFrom;
uint32 fTo; uint32 fTo;
FetchMode fMode; uint32 fFlags;
FetchListener* fListener; FetchListener* fListener;
}; };
@@ -85,6 +85,34 @@ Protocol::Connect(const BNetworkAddress& address, const char* username,
_ParseCapabilities(capabilityHandler.Capabilities()); _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; return B_OK;
} }
@@ -583,8 +583,10 @@ Response::ParseLiteral(ArgumentList& arguments, BDataIO& stream)
Consume(stream, '\n'); Consume(stream, '\n');
bool handled = false; bool handled = false;
if (fLiteralHandler != NULL) if (fLiteralHandler != NULL) {
handled = fLiteralHandler->HandleLiteral(*this, stream, size); handled = fLiteralHandler->HandleLiteral(*this, arguments, stream,
size);
}
if (!handled) { if (!handled) {
// The default implementation just adds the data as a string // The default implementation just adds the data as a string
@@ -129,7 +129,8 @@ public:
virtual ~LiteralHandler(); virtual ~LiteralHandler();
virtual bool HandleLiteral(Response& response, virtual bool HandleLiteral(Response& response,
BDataIO& stream, size_t length) = 0; ArgumentList& arguments, BDataIO& stream,
size_t length) = 0;
}; };
+24 -11
View File
@@ -87,17 +87,17 @@ do_fetch(int argc, char** argv)
{ {
uint32 from = 1; uint32 from = 1;
uint32 to; uint32 to;
IMAP::FetchMode mode = IMAP::kFetchAll; uint32 flags = IMAP::kFetchAll;
if (argc < 2) { if (argc < 2) {
printf("usage: %s [<from>] [<to>] [header|body]\n", argv[0]); printf("usage: %s [<from>] [<to>] [header|body]\n", argv[0]);
return; return;
} }
if (argc > 2) { if (argc > 2) {
if (!strcasecmp(argv[argc - 1], "header")) { if (!strcasecmp(argv[argc - 1], "header")) {
mode = IMAP::kFetchHeader; flags = IMAP::kFetchHeader;
argc--; argc--;
} else if (!strcasecmp(argv[argc - 1], "body")) { } else if (!strcasecmp(argv[argc - 1], "body")) {
mode = IMAP::kFetchBody; flags = IMAP::kFetchBody;
argc--; argc--;
} }
} }
@@ -107,15 +107,20 @@ do_fetch(int argc, char** argv)
} else } else
from = to = atoul(argv[1]); 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 // A fetch listener that dumps everything to stdout
class Listener : public IMAP::FetchListener { class Listener : public IMAP::FetchListener {
public: public:
virtual bool FetchData(IMAP::Response& reponse, uint32 uid, virtual ~Listener()
IMAP::FetchMode mode, BDataIO& stream, size_t length)
{ {
BMallocIO copy; }
virtual bool FetchData(uint32 fetchFlags, BDataIO& stream,
size_t length)
{
fBuffer.SetSize(0);
char buffer[65535]; char buffer[65535];
while (length > 0) { while (length > 0) {
ssize_t bytesRead = stream.Read(buffer, ssize_t bytesRead = stream.Read(buffer,
@@ -123,18 +128,26 @@ do_fetch(int argc, char** argv)
if (bytesRead <= 0) if (bytesRead <= 0)
break; break;
copy.Write(buffer, bytesRead); fBuffer.Write(buffer, bytesRead);
length -= bytesRead; length -= bytesRead;
} }
// Null terminate the buffer // Null terminate the buffer
char null = '\0'; char null = '\0';
copy.Write(&null, 1); fBuffer.Write(&null, 1);
printf("================= UID %ld =================\n", uid);
puts((const char*)copy.Buffer());
return true; 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; } listener;
command.SetListener(&listener); command.SetListener(&listener);