#250 Fixed unquoted mailbox name

This commit is contained in:
vincent-richard 2021-02-05 18:28:20 +01:00
parent ea9775c4f1
commit 47c6f35f5a
2 changed files with 144 additions and 3 deletions

View File

@ -1022,6 +1022,48 @@ public:
string value;
};
//
// unquoted_text_nonstrict: this is an alternate version of quoted_text,
// for use in non-strict mode. We stop at the first space character.
//
DECLARE_COMPONENT(unquoted_text_nonstrict)
bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
size_t pos = *currentPos;
size_t len = 0;
value.reserve(line.length() - pos);
for (bool end = false ; !end && pos < line.length() ; ) {
const unsigned char c = line[pos];
if (c >= 0x01 && c <= 0x7f && // CHAR
c != 0x0a && c != 0x0d && // CR and LF
c != 0x20 && // SPACE
c != 0x09) { // TAB
value += c;
++pos;
++len;
} else {
end = true;
}
}
*currentPos = pos;
return true;
}
string value;
};
//
// nil ::= "NIL"
@ -1129,9 +1171,7 @@ public:
DEBUG_FOUND("string[quoted]", "<length=" << value.length() << ", value='" << value << "'>");
// literal ::= "{" number "}" CRLF *CHAR8
} else {
VIMAP_PARSER_CHECK(one_char <'{'>);
} else if (VIMAP_PARSER_TRY_CHECK(one_char <'{'>)) {
shared_ptr <number> num;
VIMAP_PARSER_GET(number, num);
@ -1171,6 +1211,51 @@ public:
line += parser.readLine();
DEBUG_FOUND("string[literal]", "<length=" << length << ", value='" << value << "'>");
// In non-strict mode, accept unquoted strings, but stop at next SPACE
} else if (!parser.isStrict()) {
shared_ptr <unquoted_text_nonstrict> text;
VIMAP_PARSER_GET(unquoted_text_nonstrict, text);
if (parser.m_literalHandler != NULL) {
shared_ptr <literalHandler::target> target =
parser.m_literalHandler->targetFor(*m_component, m_data);
if (target != NULL) {
value = "[literal-handler]";
const size_t length = text->value.length();
utility::progressListener* progress = target->progressListener();
if (progress) {
progress->start(length);
}
target->putData(text->value);
if (progress) {
progress->progress(length, length);
progress->stop(length);
}
} else {
value = text->value;
}
} else {
value = text->value;
}
DEBUG_FOUND("string[non-strict]", "<length=" << value.length() << ", value='" << value << "'>");
} else {
VIMAP_PARSER_FAIL();
}
}

View File

@ -38,6 +38,7 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
VMIME_TEST(testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL)
VMIME_TEST(testPipelining)
VMIME_TEST(testStarFlagWithoutBackslash)
VMIME_TEST(testUnquotedMailboxName)
VMIME_TEST_LIST_END
@ -371,4 +372,59 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
}
}
// Some broken IMAP servers return unquoted strings for mailbox names
void testUnquotedMailboxName() {
const char* respText =
R"END(* LIST (\HasNoChildren \UnMarked) "/" [Gmail]/Starred)END"
"\r\n"
R"END(a001 OK Completed.)END"
"\r\n";
// Strict mode
{
auto socket = vmime::make_shared <testSocket>();
auto toh = vmime::make_shared <testTimeoutHandler>();
auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
socket->localSend(respText);
auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
parser->setSocket(socket);
parser->setTimeoutHandler(toh);
parser->setStrict(true);
VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
}
// Non-strict mode
{
auto socket = vmime::make_shared <testSocket>();
auto toh = vmime::make_shared <testTimeoutHandler>();
auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
socket->localSend(respText);
auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
parser->setSocket(socket);
parser->setTimeoutHandler(toh);
parser->setStrict(false);
std::unique_ptr <vmime::net::imap::IMAPParser::response> resp;
VASSERT_NO_THROW("non-strict mode", resp.reset(parser->readResponse(*tag)));
VASSERT_EQ("resp size", 1, resp->continue_req_or_response_data.size());
VASSERT("resp data", resp->continue_req_or_response_data[0]->response_data);
VASSERT("mbox data", resp->continue_req_or_response_data[0]->response_data->mailbox_data);
VASSERT("mbox list", resp->continue_req_or_response_data[0]->response_data->mailbox_data->mailbox_list);
VASSERT("mbox", resp->continue_req_or_response_data[0]->response_data->mailbox_data->mailbox_list->mailbox);
VASSERT_EQ("mbox name", "[Gmail]/Starred", resp->continue_req_or_response_data[0]->response_data->mailbox_data->mailbox_list->mailbox->name);
}
}
VMIME_TEST_SUITE_END