diff options
author | vincent-richard <[email protected]> | 2021-02-05 17:28:20 +0000 |
---|---|---|
committer | vincent-richard <[email protected]> | 2021-02-05 17:28:20 +0000 |
commit | 47c6f35f5afe9d6c05cc4a9fab4a0b8c5222b3b8 (patch) | |
tree | f51ea86f43e3163b8187fd385647f1443981d6b9 | |
parent | Merge pull request #249 from mpietruschka/master (diff) | |
download | vmime-47c6f35f5afe9d6c05cc4a9fab4a0b8c5222b3b8.tar.gz vmime-47c6f35f5afe9d6c05cc4a9fab4a0b8c5222b3b8.zip |
#250 Fixed unquoted mailbox name
-rw-r--r-- | src/vmime/net/imap/IMAPParser.hpp | 91 | ||||
-rw-r--r-- | tests/net/imap/IMAPParserTest.cpp | 56 |
2 files changed, 144 insertions, 3 deletions
diff --git a/src/vmime/net/imap/IMAPParser.hpp b/src/vmime/net/imap/IMAPParser.hpp index 281fcb67..409362da 100644 --- a/src/vmime/net/imap/IMAPParser.hpp +++ b/src/vmime/net/imap/IMAPParser.hpp @@ -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(); } } diff --git a/tests/net/imap/IMAPParserTest.cpp b/tests/net/imap/IMAPParserTest.cpp index 60ce16d7..387e4c66 100644 --- a/tests/net/imap/IMAPParserTest.cpp +++ b/tests/net/imap/IMAPParserTest.cpp @@ -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 |