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:
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;
};
@@ -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)
}
void
IMAPFolder::StoreMessage(uint32 uid, ...)
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 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 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);
@@ -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);
}
@@ -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;
};
@@ -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;
}
@@ -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
@@ -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;
};
+24 -11
View File
@@ -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);