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:
@@ -24,15 +24,62 @@
|
|||||||
using namespace BPrivate;
|
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 {
|
namespace IMAP {
|
||||||
|
|
||||||
|
|
||||||
static HandlerListener sEmptyHandler;
|
|
||||||
|
|
||||||
|
|
||||||
Handler::Handler()
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +113,7 @@ Command::HandleTagged(Response& response)
|
|||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
#if 0
|
||||||
HandlerListener::~HandlerListener()
|
HandlerListener::~HandlerListener()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -96,13 +129,7 @@ void
|
|||||||
HandlerListener::ExistsReceived(int32 number)
|
HandlerListener::ExistsReceived(int32 number)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
|
||||||
HandlerListener::FetchBody(Command& command, int32 size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
@@ -257,7 +284,7 @@ BString
|
|||||||
FetchMessageEntriesCommand::CommandString()
|
FetchMessageEntriesCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "UID FETCH ";
|
BString command = "UID FETCH ";
|
||||||
command << fFrom << ":" << fTo << " FLAGS";
|
command << fFrom << ":" << fTo << " (FLAGS RFC822.SIZE)";
|
||||||
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
@@ -275,22 +302,12 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response)
|
|||||||
for (int32 i = 0; i < list.CountItems(); i += 2) {
|
for (int32 i = 0; i < list.CountItems(); i += 2) {
|
||||||
if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1))
|
if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1))
|
||||||
entry.uid = list.NumberAt(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)) {
|
else if (list.EqualsAt(i, "FLAGS") && list.IsListAt(i + 1)) {
|
||||||
// Parse flags
|
// Parse flags
|
||||||
ArgumentList& flags = list.ListAt(i + 1);
|
ArgumentList& flags = list.ListAt(i + 1);
|
||||||
printf("flags: %s\n", flags.ToString().String());
|
entry.flags = ParseFlags(flags);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,339 +322,93 @@ FetchMessageEntriesCommand::HandleUntagged(Response& response)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
FetchCommand::FetchCommand(uint32 from, uint32 to,
|
||||||
FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
FetchMode mode)
|
||||||
int32 message, MinMessageList* list, BPositionIO** data)
|
|
||||||
:
|
:
|
||||||
IMAPMailboxCommand(mailbox),
|
fFrom(from),
|
||||||
|
fTo(to),
|
||||||
fMessage(message),
|
fMode(mode)
|
||||||
fEndMessage(-1),
|
|
||||||
fMinMessageList(list),
|
|
||||||
fData(data)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FetchMinMessageCommand::FetchMinMessageCommand(IMAPMailbox& mailbox,
|
void
|
||||||
int32 firstMessage, int32 lastMessage, MinMessageList* list,
|
FetchCommand::SetListener(FetchListener* listener)
|
||||||
BPositionIO** data)
|
|
||||||
:
|
|
||||||
IMAPMailboxCommand(mailbox),
|
|
||||||
|
|
||||||
fMessage(firstMessage),
|
|
||||||
fEndMessage(lastMessage),
|
|
||||||
fMinMessageList(list),
|
|
||||||
fData(data)
|
|
||||||
{
|
{
|
||||||
|
fListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BString
|
BString
|
||||||
FetchMinMessageCommand::CommandString()
|
FetchCommand::CommandString()
|
||||||
{
|
{
|
||||||
if (fMessage <= 0)
|
BString command = "UID FETCH ";
|
||||||
return "";
|
command << fFrom;
|
||||||
BString command = "FETCH ";
|
if (fFrom != fTo)
|
||||||
command << fMessage;
|
command << ":" << fTo;
|
||||||
if (fEndMessage > 0) {
|
|
||||||
command += ":";
|
|
||||||
command << fEndMessage;
|
|
||||||
}
|
|
||||||
command += " (UID FLAGS)";
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
command += " (UID ";
|
||||||
bool
|
switch (fMode) {
|
||||||
FetchMinMessageCommand::HandleUntagged(const BString& response)
|
case kFetchHeader:
|
||||||
{
|
command += "RFC822.HEADER";
|
||||||
BString extracted = response;
|
break;
|
||||||
int32 message;
|
case kFetchBody:
|
||||||
if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message))
|
command += "BODY.PEEK[TEXT]";
|
||||||
return false;
|
break;
|
||||||
|
case kFetchAll:
|
||||||
// check if we requested this message
|
command += "BODY.PEEK[]";
|
||||||
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 == "")
|
|
||||||
break;
|
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;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FetchMessageCommand::HandleUntagged(const BString& response)
|
FetchCommand::HandleUntagged(Response& response)
|
||||||
{
|
{
|
||||||
BString extracted = response;
|
if (!response.EqualsAt(1, "FETCH") || !response.IsListAt(2))
|
||||||
int32 message;
|
|
||||||
if (!IMAPParser::RemoveUntagedFromLeft(extracted, "FETCH", message))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check if we requested this message
|
// We don't need to parse anything here - all the data is processed via
|
||||||
int32 end = message;
|
// HandleLiteral().
|
||||||
if (fEndMessage > 0)
|
return true;
|
||||||
end = fEndMessage;
|
}
|
||||||
if (message < fMessage && message > end)
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FetchCommand::HandleLiteral(Response& response, BDataIO& stream,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (fListener == NULL || !response.EqualsAt(1, "FETCH")
|
||||||
|
|| !response.IsListAt(2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const MinMessageList& list = fIMAPMailbox.GetMessageList();
|
uint32 uid = 0;
|
||||||
int32 index = message - 1;
|
|
||||||
if (index < 0 || index >= (int32)list.size())
|
|
||||||
return false;
|
|
||||||
const MinMessage& minMessage = list[index];
|
|
||||||
|
|
||||||
BPositionIO* data = fOutData;
|
// Get current UID
|
||||||
ObjectDeleter<BPositionIO> deleter;
|
ArgumentList& list = response.ListAt(2);
|
||||||
if (!data) {
|
for (int32 i = 0; i < list.CountItems(); i += 2) {
|
||||||
status_t status = fStorage.OpenMessage(minMessage.uid, &data);
|
if (list.EqualsAt(i, "UID") && list.IsNumberAt(i + 1)) {
|
||||||
if (status != B_OK) {
|
uid = list.NumberAt(i + 1);
|
||||||
status = fStorage.AddNewMessage(minMessage.uid, minMessage.flags,
|
break;
|
||||||
&data);
|
|
||||||
}
|
}
|
||||||
if (status != B_OK)
|
|
||||||
return false;
|
|
||||||
deleter.SetTo(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// read message size
|
if (uid == 0)
|
||||||
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);
|
|
||||||
return false;
|
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);
|
return fListener->FetchData(response, uid, fMode, stream, length);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
FetchBodyCommand::FetchBodyCommand(IMAPMailbox& mailbox, int32 message,
|
SetFlagsCommand::SetFlagsCommand(uint32 uid, uint32 flags)
|
||||||
BPositionIO* data)
|
|
||||||
:
|
:
|
||||||
IMAPMailboxCommand(mailbox),
|
fUID(uid),
|
||||||
|
|
||||||
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),
|
|
||||||
fFlags(flags)
|
fFlags(flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -647,44 +418,24 @@ BString
|
|||||||
SetFlagsCommand::CommandString()
|
SetFlagsCommand::CommandString()
|
||||||
{
|
{
|
||||||
BString command = "STORE ";
|
BString command = "STORE ";
|
||||||
command << fMessage;
|
command << fUID << " FLAGS (" << GenerateFlagString(fFlags) << ")";
|
||||||
command += " FLAGS (";
|
|
||||||
command += GenerateFlagList(fFlags);
|
|
||||||
command += ")";
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SetFlagsCommand::HandleUntagged(const BString& response)
|
SetFlagsCommand::HandleUntagged(Response& response)
|
||||||
{
|
{
|
||||||
return false;
|
// We're not that interested in the outcome, apparently
|
||||||
}
|
return response.EqualsAt(1, "FETCH");
|
||||||
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message,
|
AppendCommand::AppendCommand(IMAPMailbox& mailbox, BPositionIO& message,
|
||||||
off_t size, int32 flags, time_t time)
|
off_t size, int32 flags, time_t time)
|
||||||
:
|
:
|
||||||
@@ -754,10 +505,10 @@ ExistsHandler::HandleUntagged(Response& response)
|
|||||||
if (!response.EqualsAt(1, "EXISTS") || response.IsNumberAt(0))
|
if (!response.EqualsAt(1, "EXISTS") || response.IsNumberAt(0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int32 expunge = response.NumberAt(0);
|
// int32 expunge = response.NumberAt(0);
|
||||||
|
#if 0
|
||||||
Listener().ExistsReceived(expunge);
|
Listener().ExistsReceived(expunge);
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (response.FindFirst("EXISTS") < 0)
|
if (response.FindFirst("EXISTS") < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -818,10 +569,10 @@ ExpungeHandler::HandleUntagged(Response& response)
|
|||||||
if (!response.EqualsAt(1, "EXPUNGE") || response.IsNumberAt(0))
|
if (!response.EqualsAt(1, "EXPUNGE") || response.IsNumberAt(0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int32 expunge = response.NumberAt(0);
|
// int32 expunge = response.NumberAt(0);
|
||||||
|
#if 0
|
||||||
Listener().ExpungeReceived(expunge);
|
Listener().ExpungeReceived(expunge);
|
||||||
|
|
||||||
#if 0
|
|
||||||
// remove from storage
|
// remove from storage
|
||||||
IMAPStorage& storage = fIMAPMailbox.GetStorage();
|
IMAPStorage& storage = fIMAPMailbox.GetStorage();
|
||||||
storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge));
|
storage.DeleteMessage(fIMAPMailbox.MessageNumberToUID(expunge));
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ typedef std::vector<BString> StringList;
|
|||||||
namespace IMAP {
|
namespace IMAP {
|
||||||
|
|
||||||
|
|
||||||
class HandlerListener;
|
|
||||||
|
|
||||||
|
|
||||||
struct MessageEntry {
|
struct MessageEntry {
|
||||||
MessageEntry()
|
MessageEntry()
|
||||||
:
|
:
|
||||||
@@ -32,6 +29,7 @@ struct MessageEntry {
|
|||||||
|
|
||||||
uint32 uid;
|
uint32 uid;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
uint32 size;
|
||||||
};
|
};
|
||||||
typedef std::vector<MessageEntry> MessageEntryList;
|
typedef std::vector<MessageEntry> MessageEntryList;
|
||||||
|
|
||||||
@@ -49,14 +47,7 @@ public:
|
|||||||
Handler();
|
Handler();
|
||||||
virtual ~Handler();
|
virtual ~Handler();
|
||||||
|
|
||||||
void SetListener(HandlerListener& listener);
|
|
||||||
HandlerListener& Listener() { return *fListener; }
|
|
||||||
|
|
||||||
virtual bool HandleUntagged(Response& response) = 0;
|
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 {
|
class RawCommand : public Command {
|
||||||
public:
|
public:
|
||||||
RawCommand(const BString& command);
|
RawCommand(const BString& command);
|
||||||
@@ -112,8 +93,8 @@ public:
|
|||||||
SelectCommand();
|
SelectCommand();
|
||||||
SelectCommand(const char* mailboxName);
|
SelectCommand(const char* mailboxName);
|
||||||
|
|
||||||
BString CommandString();
|
virtual BString CommandString();
|
||||||
bool HandleUntagged(Response& response);
|
virtual bool HandleUntagged(Response& response);
|
||||||
|
|
||||||
void SetTo(const char* mailboxName)
|
void SetTo(const char* mailboxName)
|
||||||
{ fMailboxName = mailboxName; }
|
{ fMailboxName = mailboxName; }
|
||||||
@@ -154,88 +135,58 @@ private:
|
|||||||
uint32 fTo;
|
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
|
#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 {
|
class AppendCommand : public IMAPMailboxCommand {
|
||||||
public:
|
public:
|
||||||
AppendCommand(IMAPMailbox& mailbox,
|
AppendCommand(IMAPMailbox& mailbox,
|
||||||
|
|||||||
@@ -236,6 +236,8 @@ Protocol::SendCommand(int32 id, const char* command)
|
|||||||
else
|
else
|
||||||
length = snprintf(buffer, sizeof(buffer), "%s\r\n", command);
|
length = snprintf(buffer, sizeof(buffer), "%s\r\n", command);
|
||||||
|
|
||||||
|
TRACE("C: %s", buffer);
|
||||||
|
|
||||||
ssize_t bytesWritten = fSocket->Write(buffer, length);
|
ssize_t bytesWritten = fSocket->Write(buffer, length);
|
||||||
if (bytesWritten < 0)
|
if (bytesWritten < 0)
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
|
|||||||
@@ -412,9 +412,11 @@ Response::ParseLiteral(ArgumentList& arguments, BDataIO& stream)
|
|||||||
Consume(stream, '\r');
|
Consume(stream, '\r');
|
||||||
Consume(stream, '\n');
|
Consume(stream, '\n');
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
if (fLiteralHandler != NULL)
|
if (fLiteralHandler != NULL)
|
||||||
fLiteralHandler->HandleLiteral(stream, size);
|
handled = fLiteralHandler->HandleLiteral(*this, stream, size);
|
||||||
else {
|
|
||||||
|
if (!handled) {
|
||||||
// The default implementation just adds the data as a string
|
// The default implementation just adds the data as a string
|
||||||
TRACE("Trying to read literal with %" B_PRIuSIZE " bytes.\n", size);
|
TRACE("Trying to read literal with %" B_PRIuSIZE " bytes.\n", size);
|
||||||
BString string;
|
BString string;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace IMAP {
|
|||||||
|
|
||||||
|
|
||||||
class Argument;
|
class Argument;
|
||||||
|
class Response;
|
||||||
|
|
||||||
|
|
||||||
class ArgumentList : public BObjectList<Argument> {
|
class ArgumentList : public BObjectList<Argument> {
|
||||||
@@ -112,8 +113,8 @@ public:
|
|||||||
LiteralHandler();
|
LiteralHandler();
|
||||||
virtual ~LiteralHandler();
|
virtual ~LiteralHandler();
|
||||||
|
|
||||||
virtual void HandleLiteral(BDataIO& stream,
|
virtual bool HandleLiteral(Response& response,
|
||||||
size_t length) = 0;
|
BDataIO& stream, size_t length) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//#include "IMAPStorage.h"
|
|
||||||
#include "Protocol.h"
|
#include "Protocol.h"
|
||||||
#include "Response.h"
|
#include "Response.h"
|
||||||
|
|
||||||
@@ -26,8 +25,7 @@ static void do_help(int argc, char** argv);
|
|||||||
extern const char* __progname;
|
extern const char* __progname;
|
||||||
static const char* kProgramName = __progname;
|
static const char* kProgramName = __progname;
|
||||||
|
|
||||||
//static IMAPStorage sStorage;
|
static IMAP::Protocol sProtocol;
|
||||||
static IMAP::Protocol sMailbox;//(/*sStorage*/);
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -55,7 +53,7 @@ do_select(int argc, char** argv)
|
|||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
folder = argv[1];
|
folder = argv[1];
|
||||||
|
|
||||||
status_t status = sMailbox.SelectMailbox(folder);
|
status_t status = sProtocol.SelectMailbox(folder);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
error("select", status);
|
error("select", status);
|
||||||
}
|
}
|
||||||
@@ -66,7 +64,7 @@ do_folders(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
IMAP::FolderList folders;
|
IMAP::FolderList folders;
|
||||||
|
|
||||||
status_t status = sMailbox.GetFolders(folders);
|
status_t status = sProtocol.GetFolders(folders);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
error("folders", status);
|
error("folders", status);
|
||||||
return;
|
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
|
static void
|
||||||
do_flags(int argc, char** argv)
|
do_flags(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@@ -96,14 +128,26 @@ do_flags(int argc, char** argv)
|
|||||||
|
|
||||||
IMAP::MessageEntryList entries;
|
IMAP::MessageEntryList entries;
|
||||||
IMAP::FetchMessageEntriesCommand command(entries, from, to);
|
IMAP::FetchMessageEntriesCommand command(entries, from, to);
|
||||||
status_t status = sMailbox.ProcessCommand(command);
|
status_t status = sProtocol.ProcessCommand(command);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
error("flags", status);
|
error("flags", status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < entries.size(); i++)
|
for (size_t i = 0; i < entries.size(); i++) {
|
||||||
printf(" %lu %lx\n", entries[i].uid, entries[i].flags);
|
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;
|
const char* fCommand;
|
||||||
};
|
};
|
||||||
RawCommand rawCommand(command);
|
RawCommand rawCommand(command);
|
||||||
status_t status = sMailbox.ProcessCommand(rawCommand);
|
status_t status = sProtocol.ProcessCommand(rawCommand);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
error("raw", status);
|
error("raw", status);
|
||||||
}
|
}
|
||||||
@@ -158,6 +202,9 @@ static cmd_entry sBuiltinCommands[] = {
|
|||||||
{"folders", do_folders, "List of existing folders"},
|
{"folders", do_folders, "List of existing folders"},
|
||||||
{"flags", do_flags,
|
{"flags", do_flags,
|
||||||
"List of all mail UIDs in the mailbox with their 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"},
|
{"raw", do_raw, "Issue a raw command to the server"},
|
||||||
{"help", do_help, "prints this help text"},
|
{"help", do_help, "prints this help text"},
|
||||||
{"quit", NULL, "exits the application"},
|
{"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,
|
printf("Connecting to \"%s\" as %s%s, port %u\n", server, user,
|
||||||
useSSL ? " with SSL" : "", address.Port());
|
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) {
|
if (status != B_OK) {
|
||||||
error("connect", status);
|
error("connect", status);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user