IMAP: add support for CAPABILITY in LOGIN tagged OK response.
Per RFC 3501, a server MAY include a CAPABILITY response code in the tagged OK response to a successful LOGIN in order to send capabilities automatically. The capabilities in the untagged response could be truncated to a shorter list of capabilities meaningful to the login process. For instance, the IMAP4rev1 server of mailo.com, a french mail provider, returns this on LOGIN command: C: A0000001 LOGIN "[email protected]" "XXXXXXXXX" S: * OK [CAPABILITY IMAP4rev1 ID LITERAL+ AUTH=LOGIN AUTH=PLAIN STARTTLS] IMAP4rev1 MAILO Ready CAPABILITY: IMAP4rev1, ID, LITERAL+, AUTH=LOGIN, AUTH=PLAIN, STARTTLS S: A0000001 OK [CAPABILITY IMAP4rev1 ID LITERAL+ ENABLE IDLE QUOTA NAMESPACE SORT UIDPLUS UNSELECT UTF8=ACCEPT] Welcome [email protected] CAPABILITY: IMAP4rev1, ID, LITERAL+, AUTH=LOGIN, AUTH=PLAIN, STARTTLS, ENABLE, IDLE, QUOTA, NAMESPACE, SORT, UIDPLUS, UNSELECT, UTF8=ACCEPT capabilities: IMAP4rev1, ID, LITERAL+, AUTH=LOGIN, AUTH=PLAIN, STARTTLS, ENABLE, IDLE, QUOTA, NAMESPACE, SORT, UIDPLUS, UNSELECT, UTF8=ACCEPT As the explicit CAPABILITY command is not sent if capabilities were retrieved from LOGIN response, before this change, the complete capabilities were not retrieved. This change merge capabilities from both untagged response and tagged OK response of LOGIN command. Also, improve server responses traces, following the RFC S: prefix. Change-Id: Id0fc18f0913ab03d2d3f5f90b296fbb7fb89446f Reviewed-on: https://review.haiku-os.org/c/haiku/+/10703 Reviewed-by: Jérôme Duval <[email protected]> Reviewed-by: Adrien Destugues <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
@@ -193,6 +193,31 @@ LoginCommand::HandleUntagged(Response& response)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LoginCommand::HandleTagged(Response& response)
|
||||
{
|
||||
if (!response.EqualsAt(0, "OK") || !response.IsListAt(1, '['))
|
||||
return Command::HandleTagged(response);
|
||||
|
||||
// RFC 3501 (IMAP4rev1):
|
||||
// A server MAY include a CAPABILITY response code in the tagged OK
|
||||
// response to a successful LOGIN command in order to send
|
||||
// capabilities automatically.
|
||||
ArgumentList& list = response.ListAt(1);
|
||||
if (!list.EqualsAt(0, "CAPABILITY"))
|
||||
return false;
|
||||
|
||||
// merge with previous capabilities extracted from command untagged response, if any
|
||||
while (list.CountItems() > 1) {
|
||||
StringArgument* argument = dynamic_cast<StringArgument*>(list.RemoveItemAt(1));
|
||||
if (argument != NULL && !fCapabilities.Contains(argument->ToString().String()))
|
||||
fCapabilities.AddItem(argument);
|
||||
}
|
||||
|
||||
TRACE("CAPABILITY: %s\n", fCapabilities.ToString().String());
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
|
||||
virtual BString CommandString();
|
||||
virtual bool HandleUntagged(Response& response);
|
||||
virtual status_t HandleTagged(Response& response);
|
||||
|
||||
const ArgumentList& Capabilities() const { return fCapabilities; }
|
||||
|
||||
|
||||
@@ -321,6 +321,7 @@ Protocol::HandleResponse(Command* command, bigtime_t timeout,
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
TRACE("S: ");
|
||||
status_t status = parser.NextResponse(response, timeout);
|
||||
if (status != B_OK) {
|
||||
// we might have lost the connection, clear the connection state
|
||||
@@ -339,7 +340,7 @@ Protocol::HandleResponse(Command* command, bigtime_t timeout,
|
||||
}
|
||||
}
|
||||
if (!handled)
|
||||
printf("Unhandled S: %s\n", response.ToString().String());
|
||||
TRACE(" => Unhandled\n");
|
||||
} else {
|
||||
CommandIDMap::iterator found
|
||||
= fOngoingCommands.find(response.Tag());
|
||||
@@ -350,7 +351,7 @@ Protocol::HandleResponse(Command* command, bigtime_t timeout,
|
||||
|
||||
fOngoingCommands.erase(found);
|
||||
} else
|
||||
printf("Unknown tag S: %s\n", response.ToString().String());
|
||||
TRACE(" => Unknown tag\n");
|
||||
}
|
||||
} catch (ParseException& exception) {
|
||||
printf("Error during parsing: %s\n", exception.Message());
|
||||
|
||||
@@ -701,7 +701,7 @@ Response::Read(BDataIO& stream)
|
||||
char c;
|
||||
ssize_t bytesRead = stream.Read(&c, 1);
|
||||
if (bytesRead == 1) {
|
||||
printf("%c", c);
|
||||
TRACE("%c", c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user