aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vmime/net/imap/IMAPParser.hpp91
-rw-r--r--tests/net/imap/IMAPParserTest.cpp56
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