From 54e4235b8dff6134f9ac1a415957fbcb43fc835d Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Sun, 18 Dec 2005 21:20:43 +0000 Subject: [PATCH] Compatibility bugs in IMAP response parser. --- ChangeLog | 4 + vmime/net/imap/IMAPParser.hpp | 198 ++++++++++++++++++++++------------ 2 files changed, 135 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index b5fcddd7..0a6ad965 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ VERSION 0.8.1cvs ================ +2005-12-18 Vincent Richard + + * IMAPParser.hpp: compatibility bugs + enhanced debugging trace. + 2005-12-04 Vincent Richard * exception.{hpp|cpp}: fixed segfault in destructor when destroying diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp index f8a15f33..3b7def05 100644 --- a/vmime/net/imap/IMAPParser.hpp +++ b/vmime/net/imap/IMAPParser.hpp @@ -62,19 +62,70 @@ namespace imap { #if DEBUG_RESPONSE - static string DEBUG_RESPONSE_level; - static std::vector DEBUG_RESPONSE_components; + static int IMAPParserDebugResponse_level = 0; + static std::vector IMAPParserDebugResponse_stack; -# define DEBUG_ENTER_COMPONENT(x) \ - DEBUG_RESPONSE_components.push_back(x); \ - std::cout << DEBUG_RESPONSE_level \ - << "(" << DEBUG_RESPONSE_level.length() << ") " \ - << (x) << std::endl; -# define DEBUG_FOUND(x, y) \ - std::cout << "FOUND: " << x << ": " << y << std::endl; + class IMAPParserDebugResponse + { + public: + + IMAPParserDebugResponse(const string& name, string& line, const string::size_type currentPos) + : m_name(name), m_line(line), m_pos(currentPos) + { + ++IMAPParserDebugResponse_level; + IMAPParserDebugResponse_stack.push_back(name); + + for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) + std::cout << " "; + + std::cout << "ENTER(" << m_name << "), pos=" << m_pos; + std::cout << std::endl; + + for (std::vector ::iterator it = IMAPParserDebugResponse_stack.begin() ; + it != IMAPParserDebugResponse_stack.end() ; ++it) + { + std::cout << "> " << *it << " "; + } + + std::cout << std::endl; + std::cout << string(m_line.begin() + (m_pos < 30 ? 0U : m_pos - 30), + m_line.begin() + std::min(m_line.length(), m_pos + 30)) << std::endl; + + for (string::size_type i = (m_pos < 30 ? m_pos : (m_pos - (m_pos - 30))) ; i != 0 ; --i) + std::cout << " "; + + std::cout << "^" << std::endl; + } + + ~IMAPParserDebugResponse() + { + for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) + std::cout << " "; + + std::cout << "LEAVE(" << m_name << "), result="; + std::cout << (std::uncaught_exception() ? "FALSE" : "TRUE") << ", pos=" << m_pos; + std::cout << std::endl; + + --IMAPParserDebugResponse_level; + IMAPParserDebugResponse_stack.pop_back(); + } + + private: + + const string& m_name; + string& m_line; + string::size_type m_pos; + }; + + + #define DEBUG_ENTER_COMPONENT(x) \ + IMAPParserDebugResponse dbg(x, line, *currentPos) + + #define DEBUG_FOUND(x, y) \ + std::cout << "FOUND: " << x << ": " << y << std::endl; #else -# define DEBUG_ENTER_COMPONENT(x) -# define DEBUG_FOUND(x, y) + #define DEBUG_ENTER_COMPONENT(x) + #define DEBUG_FOUND(x, y) #endif @@ -252,6 +303,16 @@ public: }; +#define COMPONENT_ALIAS(parent, name) \ + class name : public parent \ + { \ + void go(IMAPParser& parser, string& line, string::size_type* currentPos) \ + { \ + DEBUG_ENTER_COMPONENT(#name); \ + parent::go(parser, line, currentPos); \ + } \ + } + // // Parse one character @@ -1730,7 +1791,7 @@ public: m_resp_text_code = parser.get (line, &pos); parser.check >(line, &pos); - parser.check (line, &pos); + parser.check (line, &pos, true); } text_mime2* text1 = parser.get (line, &pos, true); @@ -2282,7 +2343,10 @@ public: (parser.get (line, &pos)); while (!parser.check >(line, &pos, true)) - m_body_extensions.push_back(parser.get (line, &pos, true)); + { + m_body_extensions.push_back(parser.get (line, &pos)); + parser.check (line, &pos, true); + } } else { @@ -2586,70 +2650,70 @@ public: // env_bcc ::= "(" 1*address ")" / nil // - typedef address_list env_bcc; + COMPONENT_ALIAS(address_list, env_bcc); // // env_cc ::= "(" 1*address ")" / nil // - typedef address_list env_cc; + COMPONENT_ALIAS(address_list, env_cc); // // env_date ::= nstring // - typedef nstring env_date; + COMPONENT_ALIAS(nstring, env_date); // // env_from ::= "(" 1*address ")" / nil // - typedef address_list env_from; + COMPONENT_ALIAS(address_list, env_from); // // env_in_reply_to ::= nstring // - typedef nstring env_in_reply_to; + COMPONENT_ALIAS(nstring, env_in_reply_to); // // env_message_id ::= nstring // - typedef nstring env_message_id; + COMPONENT_ALIAS(nstring, env_message_id); // // env_reply_to ::= "(" 1*address ")" / nil // - typedef address_list env_reply_to; + COMPONENT_ALIAS(address_list, env_reply_to); // // env_sender ::= "(" 1*address ")" / nil // - typedef address_list env_sender; + COMPONENT_ALIAS(address_list, env_sender); // // env_subject ::= nstring // - typedef nstring env_subject; + COMPONENT_ALIAS(nstring, env_subject); // // env_to ::= "(" 1*address ")" / nil // - typedef address_list env_to; + COMPONENT_ALIAS(address_list, env_to); // @@ -2867,10 +2931,8 @@ public: string::size_type pos = *currentPos; - if (!parser.check (line, &pos, true)) + if (parser.check >(line, &pos, true)) { - parser.check >(line, &pos); - m_items.push_back(parser.get (line, &pos)); while (!parser.check >(line, &pos, true)) @@ -2879,6 +2941,10 @@ public: m_items.push_back(parser.get (line, &pos)); } } + else + { + parser.check (line, &pos); + } *currentPos = pos; } @@ -2918,14 +2984,17 @@ public: string::size_type pos = *currentPos; - if (!parser.check (line, &pos, true)) + if (parser.check >(line, &pos, true)) { - parser.check >(line, &pos); m_string = parser.get (line, &pos); parser.check (line, &pos); m_body_fld_param = parser.get (line, &pos); parser.check >(line, &pos); } + else + { + parser.check (line, &pos); + } *currentPos = pos; } @@ -2970,7 +3039,10 @@ public: m_strings.push_back(parser.get (line, &pos)); while (!parser.check >(line, &pos, true)) + { + parser.check (line, &pos); m_strings.push_back(parser.get (line, &pos)); + } } else { @@ -3246,10 +3318,15 @@ public: m_body_extensions.push_back (parser.get (line, &pos)); + parser.check (line, &pos, true); + body_extension* ext = NULL; while ((ext = parser.get (line, &pos, true)) != NULL) + { m_body_extensions.push_back(ext); + parser.check (line, &pos, true); + } } } } @@ -3325,10 +3402,15 @@ public: m_body_extensions.push_back (parser.get (line, &pos)); + parser.check (line, &pos, true); + body_extension* ext = NULL; while ((ext = parser.get (line, &pos, true)) != NULL) + { m_body_extensions.push_back(ext); + parser.check (line, &pos, true); + } } } @@ -3435,10 +3517,13 @@ public: parser.check (line, &pos); m_body_fields = parser.get (line, &pos); parser.check (line, &pos); + + // BUGFIX: made SPACE optional. This is not standard, but some servers + // seem to return responses like that... m_envelope = parser.get (line, &pos); - parser.check (line, &pos); + parser.check (line, &pos, true); m_body = parser.get (line, &pos); - parser.check (line, &pos); + parser.check (line, &pos, true); m_body_fld_lines = parser.get (line, &pos); *currentPos = pos; @@ -3547,7 +3632,12 @@ public: m_body_type_basic = parser.get (line, &pos); if (parser.check (line, &pos, true)) - m_body_ext_1part = parser.get (line, &pos); + { + m_body_ext_1part = parser.get (line, &pos, true); + + if (!m_body_ext_1part) + --pos; + } *currentPos = pos; } @@ -3660,8 +3750,8 @@ public: parser.check >(line, &pos); - if (!(m_body_type_1part = parser.get (line, &pos, true))) - m_body_type_mpart = parser.get (line, &pos); + if (!(m_body_type_mpart = parser.get (line, &pos, true))) + m_body_type_1part = parser.get (line, &pos); parser.check >(line, &pos); @@ -4815,29 +4905,15 @@ private: TYPE* internalGet(component* resp, string& line, string::size_type* currentPos, const bool noThrow = false) { -#if DEBUG_RESPONSE - DEBUG_RESPONSE_level += " "; -#endif + const string::size_type oldPos = *currentPos; try { resp->go(*this, line, currentPos); - -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - - DEBUG_RESPONSE_level.erase(DEBUG_RESPONSE_level.begin() + DEBUG_RESPONSE_level.length() - 1); - DEBUG_RESPONSE_components.pop_back(); -#endif } catch (...) { -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - - DEBUG_RESPONSE_level.erase(DEBUG_RESPONSE_level.begin() + DEBUG_RESPONSE_level.length() - 1); - DEBUG_RESPONSE_components.pop_back(); -#endif + *currentPos = oldPos; delete (resp); if (!noThrow) throw; @@ -4858,22 +4934,16 @@ public: const bool check(string& line, string::size_type* currentPos, const bool noThrow = false) { + const string::size_type oldPos = *currentPos; + try { TYPE term; term.go(*this, line, currentPos); - -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - DEBUG_RESPONSE_components.pop_back(); -#endif } catch (...) { -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - DEBUG_RESPONSE_components.pop_back(); -#endif + *currentPos = oldPos; if (!noThrow) throw; return false; @@ -4886,22 +4956,16 @@ public: const bool checkWithArg(string& line, string::size_type* currentPos, const ARG_TYPE arg, const bool noThrow = false) { + const string::size_type oldPos = *currentPos; + try { TYPE term(arg); term.go(*this, line, currentPos); - -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - DEBUG_RESPONSE_components.pop_back(); -#endif } catch (...) { -#if DEBUG_RESPONSE - std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl; - DEBUG_RESPONSE_components.pop_back(); -#endif + *currentPos = oldPos; if (!noThrow) throw; return false;