Fixed parsing of IMAP astring.
This commit is contained in:
parent
7d64105dee
commit
e5186e6710
@ -1022,48 +1022,6 @@ 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"
|
||||
@ -1212,47 +1170,6 @@ public:
|
||||
|
||||
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();
|
||||
@ -1298,9 +1215,21 @@ public:
|
||||
|
||||
|
||||
//
|
||||
// astring ::= atom / string
|
||||
// astring = 1*ASTRING-CHAR / string
|
||||
//
|
||||
// ASTRING-CHAR = ATOM-CHAR / resp-specials
|
||||
//
|
||||
// ATOM-CHAR = <any CHAR except atom-specials>
|
||||
//
|
||||
// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
|
||||
// quoted-specials / resp-specials
|
||||
//
|
||||
// list-wildcards = "%" / "*"
|
||||
//
|
||||
// quoted-specials = DQUOTE / "\"
|
||||
//
|
||||
// resp-specials = "]"
|
||||
//
|
||||
|
||||
DECLARE_COMPONENT(astring)
|
||||
|
||||
bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
|
||||
@ -1311,11 +1240,43 @@ public:
|
||||
VIMAP_PARSER_TRY_GET(xstring, str);
|
||||
|
||||
if (str) {
|
||||
|
||||
value = str->value;
|
||||
|
||||
} else {
|
||||
std::unique_ptr <atom> at;
|
||||
VIMAP_PARSER_GET(atom, at);
|
||||
value = at->value;
|
||||
|
||||
value.reserve(line.length() - pos);
|
||||
|
||||
for (bool end = false ; !end && pos < line.length() ; ) {
|
||||
|
||||
const unsigned char c = line[pos];
|
||||
|
||||
if (!parser.isStrict() || (c >= 0x01 && c <= 0x7f)) { // CHAR or any byte in non-strict mode
|
||||
|
||||
if (c == '(' ||
|
||||
c == ')' ||
|
||||
c == '{' ||
|
||||
c == 0x20 || // SP
|
||||
c == 0x0a || c == 0x0d || // CR and LF
|
||||
c <= 0x1f || c == 0x7f || // CTL
|
||||
c == '%' || c == '*' || // list-wildcards
|
||||
c == '"' || c == '\\' || // quoted-specials
|
||||
(parser.isStrict() && c == ']')) { // resp-specials
|
||||
|
||||
end = true;
|
||||
|
||||
} else {
|
||||
|
||||
value += c;
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*currentPos = pos;
|
||||
|
@ -39,6 +39,7 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
|
||||
VMIME_TEST(testPipelining)
|
||||
VMIME_TEST(testStarFlagWithoutBackslash)
|
||||
VMIME_TEST(testUnquotedMailboxName)
|
||||
VMIME_TEST(testInvalidCharsInAstring)
|
||||
VMIME_TEST_LIST_END
|
||||
|
||||
|
||||
@ -427,4 +428,59 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
|
||||
}
|
||||
}
|
||||
|
||||
// Some broken IMAP servers return non-ASCII chars in astring.
|
||||
// Server returns UTF-8 instead of modified UTF-7.
|
||||
void testInvalidCharsInAstring() {
|
||||
|
||||
const char* respText =
|
||||
R"END(* STATUS Segregator/Społeczności (MESSAGES 3 UIDNEXT 4 UIDVALIDITY 1519867193 UNSEEN 0))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", resp->continue_req_or_response_data[0]->response_data->mailbox_data->mailbox);
|
||||
VASSERT_EQ("mbox name", "Segregator/Społeczności", resp->continue_req_or_response_data[0]->response_data->mailbox_data->mailbox->name);
|
||||
}
|
||||
}
|
||||
|
||||
VMIME_TEST_SUITE_END
|
||||
|
Loading…
Reference in New Issue
Block a user