More work in progress of the IMAP rework.

* Implemented FetchCommand, and some more.
* Improved and extended the imap_tester.
* The base to implement the new InboundProtocol on is now mostly done, at least
  for a start.
This commit is contained in:
Axel Dörfler 2011-12-02 00:15:53 +01:00
parent a517047070
commit db0a4f2c00
6 changed files with 237 additions and 483 deletions

View File

@ -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<BPositionIO> 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));

View File

@ -19,9 +19,6 @@ typedef std::vector<BString> StringList;
namespace IMAP {
class HandlerListener;
struct MessageEntry {
MessageEntry()
:
@ -32,6 +29,7 @@ struct MessageEntry {
uint32 uid;
uint32 flags;
uint32 size;
};
typedef std::vector<MessageEntry> 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,

View File

@ -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;

View File

@ -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;

View File

@ -17,6 +17,7 @@ namespace IMAP {
class Argument;
class Response;
class ArgumentList : public BObjectList<Argument> {
@ -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;
};

View File

@ -6,7 +6,6 @@
#include <stdlib.h>
//#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 [<from>] [<to>] [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;