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:
parent
a517047070
commit
db0a4f2c00
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue