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:
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user