From a46e520902de17f1ebedbe870d8c8f3eda4203c1 Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Sun, 8 Jun 2014 18:34:01 +0200 Subject: [PATCH] Fixed issue #86: workaround for invalid response from Exchange server. --- src/vmime/net/imap/IMAPParser.hpp | 64 ++++++++++++++++++++++++++----- tests/net/imap/IMAPParserTest.cpp | 35 +++++++++++++++++ 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/src/vmime/net/imap/IMAPParser.hpp b/src/vmime/net/imap/IMAPParser.hpp index d38ac14a..c71d4f93 100644 --- a/src/vmime/net/imap/IMAPParser.hpp +++ b/src/vmime/net/imap/IMAPParser.hpp @@ -1089,7 +1089,7 @@ public: DECLARE_COMPONENT(xstring) xstring(const bool canBeNIL = false, component* comp = NULL, const int data = 0) - : m_canBeNIL(canBeNIL), m_component(comp), m_data(data) + : m_canBeNIL(canBeNIL), m_isNIL(true), m_component(comp), m_data(data) { } @@ -1101,11 +1101,14 @@ public: VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "nil")) { // NIL + m_isNIL = true; } else { pos = *currentPos; + m_isNIL = false; + // quoted ::= <"> *QUOTED_CHAR <"> if (VIMAP_PARSER_TRY_CHECK(one_char <'"'>)) { @@ -1208,6 +1211,7 @@ public: private: bool m_canBeNIL; + bool m_isNIL; string m_value; component* m_component; @@ -1215,6 +1219,8 @@ public: public: + bool isNIL() const { return m_isNIL; } + const string& value() const { return (m_value); } void setValue(const string& val) { m_value = val; } }; @@ -1228,6 +1234,11 @@ public: { public: + const string getComponentName() const + { + return "nstring"; + } + nstring(component* comp = NULL, const int data = 0) : xstring(true, comp, data) { @@ -2611,7 +2622,7 @@ public: // header_fld_name ::= astring // - typedef astring header_fld_name; + COMPONENT_ALIAS(astring, header_fld_name); // @@ -3165,35 +3176,35 @@ public: // body_fld_desc ::= nstring // - typedef nstring body_fld_desc; + COMPONENT_ALIAS(nstring, body_fld_desc); // // body_fld_id ::= nstring // - typedef nstring body_fld_id; + COMPONENT_ALIAS(nstring, body_fld_id); // // body_fld_md5 ::= nstring // - typedef nstring body_fld_md5; + COMPONENT_ALIAS(nstring, body_fld_md5); // // body_fld_octets ::= number // - typedef number body_fld_octets; + COMPONENT_ALIAS(number, body_fld_octets); // // body_fld_lines ::= number // - typedef number body_fld_lines; + COMPONENT_ALIAS(number, body_fld_lines); // @@ -3201,7 +3212,42 @@ public: // "QUOTED-PRINTABLE") <">) / string // - typedef xstring body_fld_enc; + class body_fld_enc : public nstring + { + public: + + const string getComponentName() const + { + return "body_fld_enc"; + } + + body_fld_enc() + { + } + + bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) + { + size_t pos = *currentPos; + + if (!xstring::parseImpl(parser, line, &pos)) + return false; + + // " When an IMAP4 client sends a FETCH (bodystructure) request + // to a server that is running the Exchange Server 2007 IMAP4 + // service, a corrupted response is sent as a reply " + // (see http://support.microsoft.com/kb/975918/en-us) + // + // Fail in strict mode + if (isNIL() && parser.isStrict()) + { + VIMAP_PARSER_FAIL(); + } + + *currentPos = pos; + + return true; + } + }; // @@ -3478,7 +3524,7 @@ public: // ;; Defined in [MIME-IMT] // - typedef xstring media_subtype; + COMPONENT_ALIAS(xstring, media_subtype); // diff --git a/tests/net/imap/IMAPParserTest.cpp b/tests/net/imap/IMAPParserTest.cpp index b93e4b58..d98e89a0 100644 --- a/tests/net/imap/IMAPParserTest.cpp +++ b/tests/net/imap/IMAPParserTest.cpp @@ -32,6 +32,7 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest) VMIME_TEST_LIST_BEGIN VMIME_TEST(testExtraSpaceInCapaResponse) VMIME_TEST(testContinueReqWithoutSpace) + VMIME_TEST(testNILValueInBodyFldEnc) VMIME_TEST_LIST_END @@ -107,4 +108,38 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest) VASSERT_THROW("strict mode", parser->readResponse(), vmime::exceptions::invalid_response); } + // When an IMAP4 client sends a FETCH (bodystructure) request to a server + // that is running the Exchange Server 2007 IMAP4 service, a corrupted + // response is sent as a reply + // --> http://support.microsoft.com/kb/975918/en-us + void testNILValueInBodyFldEnc() + { + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr tag = + vmime::make_shared (); + + const char* resp = "* 7970 FETCH (UID 8036 FLAGS () BODYSTRUCTURE (\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL NIL 175501 1651 NIL NIL NIL NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n"; + + socket->localSend(resp); + + vmime::shared_ptr parser = + vmime::make_shared (); + + parser->setTag(tag); + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + parser->setStrict(false); + VASSERT_NO_THROW("non-strict mode", parser->readResponse()); + + ++(*tag); + + socket->localSend(resp); + + parser->setStrict(true); + VASSERT_THROW("strict mode", parser->readResponse(), vmime::exceptions::invalid_response); + } + VMIME_TEST_SUITE_END