aboutsummaryrefslogtreecommitdiffstats
path: root/src/messaging/IMAPParser.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/messaging/IMAPParser.hpp')
-rw-r--r--src/messaging/IMAPParser.hpp5075
1 files changed, 5075 insertions, 0 deletions
diff --git a/src/messaging/IMAPParser.hpp b/src/messaging/IMAPParser.hpp
new file mode 100644
index 00000000..2e4a56ab
--- /dev/null
+++ b/src/messaging/IMAPParser.hpp
@@ -0,0 +1,5075 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 Vincent Richard <[email protected]>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef VMIME_MESSAGING_IMAPPARSER_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPPARSER_HPP_INCLUDED
+
+
+#include "../base.hpp"
+#include "../dateTime.hpp"
+#include "../charset.hpp"
+#include "../exception.hpp"
+#include "../utility/smartPtr.hpp"
+
+#include "../encoderB64.hpp"
+#include "../encoderQP.hpp"
+
+#include "../platformDependant.hpp"
+
+#include "progressionListener.hpp"
+#include "timeoutHandler.hpp"
+#include "socket.hpp"
+
+#include "IMAPTag.hpp"
+
+#include <vector>
+#include <stdexcept>
+
+
+//#define DEBUG_RESPONSE 1
+
+
+#if DEBUG_RESPONSE
+# include <iostream>
+#endif
+
+
+namespace vmime {
+namespace messaging {
+
+
+#if DEBUG_RESPONSE
+ static string DEBUG_RESPONSE_level;
+ static std::vector <string> DEBUG_RESPONSE_components;
+
+# 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;
+#else
+# define DEBUG_ENTER_COMPONENT(x)
+# define DEBUG_FOUND(x, y)
+#endif
+
+
+class IMAPParser
+{
+public:
+
+ IMAPParser(IMAPTag* tag, socket* sok, timeoutHandler* _timeoutHandler)
+ : m_tag(tag), m_socket(sok), m_progress(NULL),
+ m_literalHandler(NULL), m_timeoutHandler(_timeoutHandler)
+ {
+ }
+
+
+ const IMAPTag* tag() const
+ {
+ return (m_tag);
+ }
+
+
+ const string lastLine() const
+ {
+ // Remove blanks and new lines at the end of the line.
+ string line(m_lastLine);
+
+ string::const_iterator it = line.end();
+ int count = 0;
+
+ while (it != line.begin())
+ {
+ const unsigned char c = *(it - 1);
+
+ if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+ break;
+
+ ++count;
+ --it;
+ }
+
+ line.resize(line.length() - count);
+
+ return (line);
+ }
+
+
+
+ //
+ // literalHandler : literal content handler
+ //
+
+ class component;
+
+ class literalHandler
+ {
+ public:
+
+ virtual ~literalHandler() { }
+
+
+ // Abstract target class
+ class target
+ {
+ protected:
+
+ target(class progressionListener* progress) : m_progress(progress) {}
+ target(const target&) {}
+
+ public:
+
+ virtual ~target() { }
+
+
+ class progressionListener* progressionListener() { return (m_progress); }
+
+ virtual void putData(const string& chunk) = 0;
+
+ private:
+
+ class progressionListener* m_progress;
+ };
+
+
+ // Target: put in a string
+ class targetString : public target
+ {
+ public:
+
+ targetString(class progressionListener* progress, vmime::string& str)
+ : target(progress), m_string(str) { }
+
+ const vmime::string& string() const { return (m_string); }
+ vmime::string& string() { return (m_string); }
+
+
+ void putData(const vmime::string& chunk)
+ {
+ m_string += chunk;
+ }
+
+ private:
+
+ vmime::string& m_string;
+ };
+
+
+ // Target: redirect to an output stream
+ class targetStream : public target
+ {
+ public:
+
+ targetStream(class progressionListener* progress, utility::outputStream& stream)
+ : target(progress), m_stream(stream) { }
+
+ const utility::outputStream& stream() const { return (m_stream); }
+ utility::outputStream& stream() { return (m_stream); }
+
+
+ void putData(const string& chunk)
+ {
+ m_stream.write(chunk.data(), chunk.length());
+ }
+
+ private:
+
+ utility::outputStream& m_stream;
+ };
+
+
+ // Called when the parser needs to know what to do with a literal
+ // . comp: the component in which we are at this moment
+ // . data: data specific to the component (may not be used)
+ //
+ // Returns :
+ // . == NULL to put the literal into the response
+ // . != NULL to redirect the literal to the specified target
+
+ virtual target* targetFor(const component& comp, const int data) = 0;
+ };
+
+
+ //
+ // Base class for a terminal or a non-terminal
+ //
+
+ class component
+ {
+ public:
+
+ component() { }
+ virtual ~component() { }
+
+ virtual void go(IMAPParser& parser, string& line, string::size_type* currentPos) = 0;
+
+
+ const string makeResponseLine(const string& comp, const string& line,
+ const string::size_type pos)
+ {
+#if DEBUG_RESPONSE
+ if (pos > line.length())
+ std::cout << "WARNING: component::makeResponseLine(): pos > line.length()" << std::endl;
+#endif
+
+ string result(line.substr(0, pos));
+ result += "[^]"; // indicates current parser position
+ result += line.substr(pos, line.length());
+ if (!comp.empty()) result += " [" + comp + "]";
+
+ return (result);
+ }
+ };
+
+
+
+ //
+ // Parse one character
+ //
+
+ template <char C>
+ class one_char : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT(string("one_char <") + C + ">: current='" + ((*currentPos < line.length() ? line[*currentPos] : '?')) + "'");
+
+ const string::size_type pos = *currentPos;
+
+ if (pos < line.length() && line[pos] == C)
+ *currentPos = pos + 1;
+ else
+ throw exceptions::invalid_response("", makeResponseLine("", line, pos));
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ class SPACE : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("SPACE");
+
+ string::size_type pos = *currentPos;
+
+ while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t'))
+ ++pos;
+
+ if (pos > *currentPos)
+ *currentPos = pos;
+ else
+ throw exceptions::invalid_response("", makeResponseLine("SPACE", line, pos));
+ }
+ };
+
+
+ //
+ // CR ::= <ASCII CR, carriage return, 0x0D>
+ // LF ::= <ASCII LF, line feed, 0x0A>
+ // CRLF ::= CR LF
+ //
+
+ class CRLF : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("CRLF");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <SPACE>(line, &pos, true);
+
+ if (pos + 1 < line.length() &&
+ line[pos] == 0x0d && line[pos + 1] == 0x0a)
+ {
+ *currentPos = pos + 2;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("CRLF", line, pos));
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ //
+ // tag ::= 1*<any ATOM_CHAR except "+"> (named "xtag")
+ //
+
+ class xtag : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("tag");
+
+ string::size_type pos = *currentPos;
+
+ bool end = false;
+
+ string tagString;
+ tagString.reserve(10);
+
+ while (!end && pos < line.length())
+ {
+ const unsigned char c = line[pos];
+
+ switch (c)
+ {
+ case '+':
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f)
+ end = true;
+ else
+ {
+ tagString += c;
+ ++pos;
+ }
+
+ break;
+ }
+ }
+
+ if (tagString == (string) *(parser.tag()))
+ {
+ *currentPos = pos;
+ }
+ else
+ {
+ // Invalid tag
+ throw exceptions::invalid_response("", makeResponseLine("tag", line, pos));
+ }
+ }
+ };
+
+
+ //
+ // digit ::= "0" / digit_nz
+ // digit_nz ::= "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
+ //
+ // number ::= 1*digit
+ // ;; Unsigned 32-bit integer
+ // ;; (0 <= n < 4,294,967,296)
+ //
+
+ class number : public component
+ {
+ public:
+
+ number(const bool nonZero = false)
+ : m_nonZero(nonZero), m_value(0)
+ {
+ }
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("number");
+
+ string::size_type pos = *currentPos;
+
+ bool valid = true;
+ unsigned int val = 0;
+
+ while (valid && pos < line.length())
+ {
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9')
+ {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ }
+ else
+ {
+ valid = false;
+ }
+ }
+
+ // Check for non-null length (and for non-zero number)
+ if (!(m_nonZero && val == 0) && pos != *currentPos)
+ {
+ m_value = val;
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("number", line, pos));
+ }
+ }
+
+ private:
+
+ const bool m_nonZero;
+ unsigned int m_value;
+
+ public:
+
+ const unsigned int value() const { return (m_value); }
+ };
+
+
+ // nz_number ::= digit_nz *digit
+ // ;; Non-zero unsigned 32-bit integer
+ // ;; (0 < n < 4,294,967,296)
+ //
+
+ class nz_number : public number
+ {
+ public:
+
+ nz_number() : number(true)
+ {
+ }
+ };
+
+
+ //
+ // text ::= 1*TEXT_CHAR
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ //
+
+ class text : public component
+ {
+ public:
+
+ text(bool allow8bits = false, const char except = 0)
+ : m_allow8bits(allow8bits), m_except(except)
+ {
+ }
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("text");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+
+ if (m_allow8bits)
+ {
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (c == 0x00 || c == 0x0d || c == 0x0a || c == except)
+ {
+ end = true;
+ }
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+ else
+ {
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (c < 0x01 || c > 0x7f || c == 0x0d || c == 0x0a || c == except)
+ {
+ end = true;
+ }
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0)
+ {
+ m_value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, m_value.begin());
+
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("text", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+ const bool m_allow8bits;
+ const char m_except;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ class text8 : public text
+ {
+ public:
+
+ text8() : text(true)
+ {
+ }
+ };
+
+
+ template <char C>
+ class text_except : public text
+ {
+ public:
+
+ text_except() : text(false, C)
+ {
+ }
+ };
+
+
+ template <char C>
+ class text8_except : public text
+ {
+ public:
+
+ text8_except() : text(true, C)
+ {
+ }
+ };
+
+
+ //
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ class QUOTED_CHAR : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("quoted_char");
+
+ string::size_type pos = *currentPos;
+
+ const unsigned char c = (pos < line.length() ? line[pos] : 0);
+
+ if (c >= 0x01 && c <= 0x7f && // 0x01 - 0x7f
+ c != '"' && c != '\\' && // quoted_specials
+ c != '\r' && c != '\n') // CR and LF
+ {
+ m_value = c;
+ *currentPos = pos + 1;
+ }
+ else if (c == '\\' && pos + 1 < line.length() &&
+ (line[pos + 1] == '"' || line[pos + 1] == '\\'))
+ {
+ m_value = line[pos + 1];
+ *currentPos = pos + 2;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("QUOTED_CHAR", line, pos));
+ }
+ }
+
+ private:
+
+ char m_value;
+
+ public:
+
+ const char value() const { return (m_value); }
+ };
+
+
+ //
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ class quoted_text : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("quoted_text");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+ bool valid = false;
+
+ m_value.reserve(line.length() - pos);
+
+ for (bool end = false, quoted = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (quoted)
+ {
+ if (c == '"' || c == '\\')
+ m_value += c;
+ else
+ {
+ m_value += '\\';
+ m_value += c;
+ }
+
+ quoted = false;
+
+ ++pos;
+ ++len;
+ }
+ else
+ {
+ if (c == '\\')
+ {
+ quoted = true;
+
+ ++pos;
+ ++len;
+ }
+ else if (c == '"')
+ {
+ valid = true;
+ end = true;
+ }
+ else if (c >= 0x01 && c <= 0x7f && // CHAR
+ c != 0x0a && c != 0x0d) // CR and LF
+ {
+ m_value += c;
+
+ ++pos;
+ ++len;
+ }
+ else
+ {
+ valid = false;
+ end = true;
+ }
+ }
+ }
+
+ if (valid)
+ {
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("quoted_text", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // nil ::= "NIL"
+ //
+
+ class NIL : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("NIL");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "nil");
+
+ *currentPos = pos;
+ }
+ };
+
+
+ //
+ // string ::= quoted / literal ----> named 'xstring'
+ //
+ // nil ::= "NIL"
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // literal ::= "{" number "}" CRLF *CHAR8
+ // ;; Number represents the number of CHAR8 octets
+ // CHAR8 ::= <any 8-bit octet except NUL, 0x01 - 0xff>
+ //
+
+ class xstring : public component
+ {
+ public:
+
+ xstring(const bool canBeNIL = false, component* comp = NULL, const int data = 0)
+ : m_canBeNIL(canBeNIL), m_component(comp), m_data(data)
+ {
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("string");
+
+ string::size_type pos = *currentPos;
+
+ if (m_canBeNIL &&
+ parser.checkWithArg <special_atom>(line, &pos, "nil", true))
+ {
+ // NIL
+ }
+ else
+ {
+ pos = *currentPos;
+
+ // quoted ::= <"> *QUOTED_CHAR <">
+ if (parser.check <one_char <'"'> >(line, &pos, true))
+ {
+ utility::auto_ptr <quoted_text> text(parser.get <quoted_text>(line, &pos));
+ parser.check <one_char <'"'> >(line, &pos);
+
+ if (parser.m_literalHandler != NULL)
+ {
+ literalHandler::target* target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL)
+ {
+ m_value = "[literal-handler]";
+
+ const string::size_type length = text->value().length();
+ progressionListener* progress = target->progressionListener();
+
+ if (progress)
+ {
+ progress->start(length);
+ }
+
+ target->putData(text->value());
+
+ if (progress)
+ {
+ progress->progress(length, length);
+ progress->stop(length);
+ }
+
+ delete (target);
+ }
+ else
+ {
+ m_value = text->value();
+ }
+ }
+ else
+ {
+ m_value = text->value();
+ }
+
+ DEBUG_FOUND("string[quoted]", "<length=" << m_value.length() << ", value='" << m_value << "'>");
+ }
+ // literal ::= "{" number "}" CRLF *CHAR8
+ else
+ {
+ parser.check <one_char <'{'> >(line, &pos);
+
+ number* num = parser.get <number>(line, &pos);
+
+ const string::size_type length = num->value();
+ delete (num);
+
+ parser.check <one_char <'}'> >(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+
+ if (parser.m_literalHandler != NULL)
+ {
+ literalHandler::target* target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL)
+ {
+ m_value = "[literal-handler]";
+
+ parser.m_progress = target->progressionListener();
+ parser.readLiteral(*target, length);
+ parser.m_progress = NULL;
+
+ delete (target);
+ }
+ else
+ {
+ literalHandler::targetString target(NULL, m_value);
+ parser.readLiteral(target, length);
+ }
+ }
+ else
+ {
+ literalHandler::targetString target(NULL, m_value);
+ parser.readLiteral(target, length);
+ }
+
+ line += parser.readLine();
+
+ DEBUG_FOUND("string[literal]", "<length=" << length << ", value='" << m_value << "'>");
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ bool m_canBeNIL;
+ string m_value;
+
+ component* m_component;
+ const int m_data;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // nstring ::= string / nil
+ //
+
+ class nstring : public xstring
+ {
+ public:
+
+ nstring(component* comp = NULL, const int data = 0)
+ : xstring(true, comp, data)
+ {
+ }
+ };
+
+
+ //
+ // astring ::= atom / string
+ //
+
+ class astring : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("astring");
+
+ string::size_type pos = *currentPos;
+
+ xstring* str = NULL;
+
+ if ((str = parser.get <xstring>(line, &pos, true)))
+ {
+ m_value = str->value();
+ delete (str);
+ }
+ else
+ {
+ atom* at = parser.get <atom>(line, &pos);
+ m_value = at->value();
+ delete (at);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // atom ::= 1*ATOM_CHAR
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ class atom : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("atom");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ switch (c)
+ {
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ case '[':
+ case ']': // for "special_atom"
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f)
+ end = true;
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0)
+ {
+ m_value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, m_value.begin());
+
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("atom", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // special atom (eg. "CAPABILITY", "FLAGS", "STATUS"...)
+ //
+ // " Except as noted otherwise, all alphabetic characters are case-
+ // insensitive. The use of upper or lower case characters to define
+ // token strings is for editorial clarity only. Implementations MUST
+ // accept these strings in a case-insensitive fashion. "
+ //
+
+ class special_atom : public atom
+ {
+ public:
+
+ special_atom(const char* str)
+ : m_string(str) // 'string' must be in lower-case
+ {
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT(string("special_atom(") + m_string + ")");
+
+ string::size_type pos = *currentPos;
+
+ atom::go(parser, line, &pos);
+
+ const char* cmp = value().c_str();
+ const char* with = m_string;
+
+ bool ok = true;
+
+ while (ok && *cmp && *with)
+ {
+ ok = (std::tolower(*cmp, std::locale()) == *with);
+
+ ++cmp;
+ ++with;
+ }
+
+ if (!ok || *cmp || *with)
+ {
+ throw exceptions::invalid_response("", makeResponseLine(string("special_atom <") + m_string + ">", line, pos));
+ }
+ else
+ {
+ *currentPos = pos;
+ }
+ }
+
+ private:
+
+ const char* m_string;
+ };
+
+
+ //
+ // text_mime2 ::= "=?" <charset> "?" <encoding> "?" <encoded-text> "?="
+ // ;; Syntax defined in [MIME-HDRS]
+ //
+
+ class text_mime2 : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("text_mime2");
+
+ string::size_type pos = *currentPos;
+
+ atom* theCharset = NULL, *theEncoding = NULL;
+ text* theText = NULL;
+
+ try
+ {
+ parser.check <one_char <'='> >(line, &pos);
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theCharset = parser.get <atom>(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theEncoding = parser.get <atom>(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theText = parser.get <text8_except <'?'> >(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+ parser.check <one_char <'='> >(line, &pos);
+ }
+ catch (std::exception& e)
+ {
+ delete (theCharset);
+ delete (theEncoding);
+ delete (theText);
+
+ throw;
+ }
+
+ m_charset = theCharset->value();
+ delete (theCharset);
+
+ // Decode text
+ encoder* theEncoder = NULL;
+
+ if (theEncoding->value()[0] == 'q' || theEncoding->value()[0] == 'Q')
+ {
+ // Quoted-printable
+ theEncoder = new encoderQP;
+ theEncoder->properties()["rfc2047"] = true;
+ }
+ else if (theEncoding->value()[0] == 'b' || theEncoding->value()[0] == 'B')
+ {
+ // Base64
+ theEncoder = new encoderB64;
+ }
+
+ if (theEncoder)
+ {
+ utility::inputStreamStringAdapter in(theText->value());
+ utility::outputStreamStringAdapter out(m_value);
+
+ theEncoder->decode(in, out);
+ delete (theEncoder);
+ }
+ // No decoder available
+ else
+ {
+ m_value = theText->value();
+ }
+
+ delete (theEncoding);
+ delete (theText);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ vmime::charset m_charset;
+ string m_value;
+
+ public:
+
+ const vmime::charset& charset() const { return (m_charset); }
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // flag ::= "\Answered" / "\Flagged" / "\Deleted" /
+ // "\Seen" / "\Draft" / flag_keyword / flag_extension
+ //
+ // flag_extension ::= "\" atom
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept flag_extension flags. Server
+ // ;; implementations MUST NOT generate
+ // ;; flag_extension flags except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+ // flag_keyword ::= atom
+ //
+
+ class flag : public component
+ {
+ public:
+
+ flag()
+ : m_flag_keyword(NULL)
+ {
+ }
+
+ ~flag()
+ {
+ delete (m_flag_keyword);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("flag_keyword");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'\\'> >(line, &pos, true))
+ {
+ if (parser.check <one_char <'*'> >(line, &pos, true))
+ {
+ m_type = STAR;
+ }
+ else
+ {
+ atom* at = parser.get <atom>(line, &pos);
+ const string name = toLower(at->value());
+ delete (at);
+
+ if (name == "answered")
+ m_type = ANSWERED;
+ else if (name == "flagged")
+ m_type = FLAGGED;
+ else if (name == "deleted")
+ m_type = DELETED;
+ else if (name == "seen")
+ m_type = SEEN;
+ else if (name == "draft")
+ m_type = DRAFT;
+ else
+ {
+ m_type = UNKNOWN;
+ m_name = name;
+ }
+ }
+ }
+ else
+ {
+ m_flag_keyword = parser.get <atom>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+ ANSWERED,
+ FLAGGED,
+ DELETED,
+ SEEN,
+ DRAFT,
+ STAR // * = custom flags allowed
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ IMAPParser::atom* m_flag_keyword;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+
+ const IMAPParser::atom* flag_keyword() const { return (m_flag_keyword); }
+ };
+
+
+ //
+ // flag_list ::= "(" #flag ")"
+ //
+
+ class flag_list : public component
+ {
+ public:
+
+ ~flag_list()
+ {
+ for (std::vector <flag*>::iterator it = m_flags.begin() ;
+ it != m_flags.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("flag_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_flags.push_back(parser.get <flag>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <flag*> m_flags;
+
+ public:
+
+ const std::vector <flag*>& flags() const { return (m_flags); }
+ };
+
+
+ //
+ // mailbox ::= "INBOX" / astring
+ // ;; INBOX is case-insensitive. All case variants of
+ // ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
+ // ;; not as an astring. Refer to section 5.1 for
+ // ;; further semantic details of mailbox names.
+ //
+
+ class mailbox : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "inbox", true))
+ {
+ m_type = INBOX;
+ m_name = "INBOX";
+ }
+ else
+ {
+ m_type = OTHER;
+
+ astring* astr = parser.get <astring>(line, &pos);
+ m_name = astr->value();
+ delete (astr);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ INBOX,
+ OTHER
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+ };
+
+
+ //
+ // mailbox_flag := "\Marked" / "\Noinferiors" /
+ // "\Noselect" / "\Unmarked" / flag_extension
+ //
+
+ class mailbox_flag : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_flag");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'\\'> >(line, &pos);
+
+ atom* at = parser.get <atom>(line, &pos);
+ const string name = toLower(at->value());
+ delete (at);
+
+ if (name == "marked")
+ m_type = MARKED;
+ else if (name == "noinferiors")
+ m_type = NOINFERIORS;
+ else if (name == "noselect")
+ m_type = NOSELECT;
+ else if (name == "unmarked")
+ m_type = UNMARKED;
+ else
+ {
+ m_type = UNKNOWN;
+ m_name = name;
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+ MARKED,
+ NOINFERIORS,
+ NOSELECT,
+ UNMARKED
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+ };
+
+
+ //
+ // mailbox_flag_list ::= "(" #(mailbox_flag) ")"
+ //
+
+ class mailbox_flag_list : public component
+ {
+ public:
+
+ ~mailbox_flag_list()
+ {
+ for (std::vector <mailbox_flag*>::iterator it = m_flags.begin() ;
+ it != m_flags.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_flag_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_flags.push_back(parser.get <mailbox_flag>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <mailbox_flag*> m_flags;
+
+ public:
+
+ const std::vector <mailbox_flag*>& flags() const { return (m_flags); }
+ };
+
+
+ //
+ // mailbox_list ::= mailbox_flag_list SPACE
+ // (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
+ //
+
+ class mailbox_list : public component
+ {
+ public:
+
+ mailbox_list()
+ : m_mailbox_flag_list(NULL),
+ m_mailbox(NULL), m_quoted_char('\0')
+ {
+ }
+
+ ~mailbox_list()
+ {
+ delete (m_mailbox_flag_list);
+ delete (m_mailbox);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_list");
+
+ string::size_type pos = *currentPos;
+
+ m_mailbox_flag_list = parser.get <IMAPParser::mailbox_flag_list>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'"'> >(line, &pos);
+
+ QUOTED_CHAR* qc = parser.get <QUOTED_CHAR>(line, &pos);
+ m_quoted_char = qc->value();
+ delete (qc);
+
+ parser.check <one_char <'"'> >(line, &pos);
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox = parser.get <IMAPParser::mailbox>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::mailbox_flag_list* m_mailbox_flag_list;
+ IMAPParser::mailbox* m_mailbox;
+ char m_quoted_char;
+
+ public:
+
+ const IMAPParser::mailbox_flag_list* mailbox_flag_list() const { return (m_mailbox_flag_list); }
+ const IMAPParser::mailbox* mailbox() const { return (m_mailbox); }
+ const char quoted_char() const { return (m_quoted_char); }
+ };
+
+
+ //
+ // resp_text_code ::= "ALERT" / "PARSE" /
+ // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
+ // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ // "UIDVALIDITY" SPACE nz_number /
+ // "UNSEEN" SPACE nz_number /
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+
+ class resp_text_code : public component
+ {
+ public:
+
+ resp_text_code()
+ : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL), m_text(NULL)
+ {
+ }
+
+ ~resp_text_code()
+ {
+ delete (m_nz_number);
+ delete (m_atom);
+ delete (m_flag_list);
+ delete (m_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text_code");
+
+ string::size_type pos = *currentPos;
+
+ // "ALERT"
+ if (parser.checkWithArg <special_atom>(line, &pos, "alert", true))
+ {
+ m_type = ALERT;
+ }
+ // "PARSE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true))
+ {
+ m_type = PARSE;
+ }
+ // "PERMANENTFLAGS" SPACE flag_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true))
+ {
+ m_type = PERMANENTFLAGS;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
+ }
+ // "READ-ONLY"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true))
+ {
+ m_type = READ_ONLY;
+ }
+ // "READ-WRITE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true))
+ {
+ m_type = READ_WRITE;
+ }
+ // "TRYCREATE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true))
+ {
+ m_type = TRYCREATE;
+ }
+ // "UIDVALIDITY" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // "UNSEEN" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true))
+ {
+ m_type = UNSEEN;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ else
+ {
+ m_type = OTHER;
+
+ m_atom = parser.get <IMAPParser::atom>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_text = parser.get <text_except <']'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ ALERT,
+ PARSE,
+ PERMANENTFLAGS,
+ READ_ONLY,
+ READ_WRITE,
+ TRYCREATE,
+ UIDVALIDITY,
+ UNSEEN,
+ OTHER
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::nz_number* m_nz_number;
+ IMAPParser::atom* m_atom;
+ IMAPParser::flag_list* m_flag_list;
+ IMAPParser::text* m_text;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::nz_number* nz_number() const { return (m_nz_number); }
+ const IMAPParser::atom* atom() const { return (m_atom); }
+ const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
+ const IMAPParser::text* text() const { return (m_text); }
+ };
+
+
+ //
+ // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
+ // ;; text SHOULD NOT begin with "[" or "="
+
+ class resp_text : public component
+ {
+ public:
+
+ resp_text()
+ : m_resp_text_code(NULL)
+ {
+ }
+
+ ~resp_text()
+ {
+ delete (m_resp_text_code);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'['> >(line, &pos, true))
+ {
+ m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos);
+
+ parser.check <one_char <']'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ }
+
+ text_mime2* text1 = parser.get <text_mime2>(line, &pos, true);
+
+ if (text1 != NULL)
+ {
+ m_text = text1->value();
+ delete (text1);
+ }
+ else
+ {
+ IMAPParser::text* text2 =
+ parser.get <IMAPParser::text>(line, &pos);
+
+ m_text = text2->value();
+ delete (text2);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text_code* m_resp_text_code;
+ string m_text;
+
+ public:
+
+ const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); }
+ const string& text() const { return (m_text); }
+ };
+
+
+ //
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+
+ class continue_req : public component
+ {
+ public:
+
+ continue_req()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~continue_req()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("continue_req");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'+'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // auth_type ::= atom
+ // ;; Defined by [IMAP-AUTH]
+ //
+
+ class auth_type : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("auth_type");
+
+ atom* at = parser.get <atom>(line, currentPos);
+ m_name = toLower(at->value());
+ delete (at);
+
+ if (m_name == "kerberos_v4")
+ m_type = KERBEROS_V4;
+ else if (m_name == "gssapi")
+ m_type = GSSAPI;
+ else if (m_name == "skey")
+ m_type = SKEY;
+ else
+ m_type = UNKNOWN;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+
+ // RFC 1731 - IMAP4 Authentication Mechanisms
+ KERBEROS_V4,
+ GSSAPI,
+ SKEY
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string name() const { return (m_name); }
+ };
+
+
+ //
+ // status_att ::= "MESSAGES" / "RECENT" / "UIDNEXT" /
+ // "UIDVALIDITY" / "UNSEEN"
+ //
+
+ class status_att : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("status_att");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "messages", true))
+ {
+ m_type = MESSAGES;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true))
+ {
+ m_type = RECENT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true))
+ {
+ m_type = UIDNEXT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "unseen");
+ m_type = UNSEEN;
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ MESSAGES,
+ RECENT,
+ UIDNEXT,
+ UIDVALIDITY,
+ UNSEEN
+ };
+
+ private:
+
+ Type m_type;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ };
+
+
+ //
+ // capability ::= "AUTH=" auth_type / atom
+ // ;; New capabilities MUST begin with "X" or be
+ // ;; registered with IANA as standard or standards-track
+ //
+
+ class capability : public component
+ {
+ public:
+
+ capability()
+ : m_auth_type(NULL), m_atom(NULL)
+ {
+ }
+
+ ~capability()
+ {
+ delete (m_auth_type);
+ delete (m_atom);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("capability");
+
+ string::size_type pos = *currentPos;
+
+ class atom* at = parser.get <IMAPParser::atom>(line, &pos);
+
+ string value = at->value();
+ const char* str = value.c_str();
+
+ if ((str[0] == 'a' || str[0] == 'A') &&
+ (str[1] == 'u' || str[1] == 'U') &&
+ (str[2] == 't' || str[2] == 'T') &&
+ (str[3] == 'h' || str[3] == 'H') &&
+ (str[4] == '='))
+ {
+ string::size_type pos = 5;
+ m_auth_type = parser.get <IMAPParser::auth_type>(value, &pos);
+ delete (at);
+ }
+ else
+ {
+ m_atom = at;
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::auth_type* m_auth_type;
+ IMAPParser::atom* m_atom;
+
+ public:
+
+ const IMAPParser::auth_type* auth_type() const { return (m_auth_type); }
+ const IMAPParser::atom* atom() const { return (m_atom); }
+ };
+
+
+ //
+ // capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
+ // [SPACE 1#capability]
+ // ;; IMAP4rev1 servers which offer RFC 1730
+ // ;; compatibility MUST list "IMAP4" as the first
+ // ;; capability.
+ //
+
+ class capability_data : public component
+ {
+ public:
+
+ ~capability_data()
+ {
+ for (std::vector <capability*>::iterator it = m_capabilities.begin() ;
+ it != m_capabilities.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("capability_data");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "capability");
+ parser.check <SPACE>(line, &pos);
+
+ bool IMAP4rev1 = false;
+
+ for (bool end = false ; !end && !IMAP4rev1 ; )
+ {
+ if (parser.checkWithArg <special_atom>(line, &pos, "imap4rev1", true))
+ {
+ IMAP4rev1 = true;
+ }
+ else
+ {
+ capability* cap = parser.get <capability>(line, &pos);
+ end = (cap == NULL);
+
+ if (cap)
+ {
+ m_capabilities.push_back(cap);
+ }
+ }
+
+ parser.check <SPACE>(line, &pos);
+ }
+
+
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ for (capability* cap = NULL ;
+ (cap = parser.get <capability>(line, &pos)) != NULL ; )
+ {
+ m_capabilities.push_back(cap);
+
+ parser.check <SPACE>(line, &pos);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <capability*> m_capabilities;
+
+ public:
+
+ const std::vector <capability*>& capabilities() const { return (m_capabilities); }
+ };
+
+
+ //
+ // date_day_fixed ::= (SPACE digit) / 2digit
+ // ;; Fixed-format version of date_day
+ //
+ // date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+ //
+ // date_year ::= 4digit
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ //
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich (that is,
+ // ;; (the amount that the given time differs from
+ // ;; Universal Time). Subtracting the timezone
+ // ;; from the given time will give the UT form.
+ // ;; The Universal Time zone is "+0000".
+ //
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+
+ class date_time : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("date_time");
+
+ string::size_type pos = *currentPos;
+
+ // <"> date_day_fixed "-" date_month "-" date_year
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos, true);
+
+ utility::auto_ptr <number> nd(parser.get <number>(line, &pos));
+
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <atom> amo(parser.get <atom>(line, &pos));
+
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <number> ny(parser.get <number>(line, &pos));
+
+ parser.check <SPACE>(line, &pos, true);
+
+ // 2digit ":" 2digit ":" 2digit
+ utility::auto_ptr <number> nh(parser.get <number>(line, &pos));
+
+ parser.check <one_char <':'> >(line, &pos);
+
+ utility::auto_ptr <number> nmi(parser.get <number>(line, &pos));
+
+ parser.check <one_char <':'> >(line, &pos);
+
+ utility::auto_ptr <number> ns(parser.get <number>(line, &pos));
+
+ parser.check <SPACE>(line, &pos, true);
+
+ // ("+" / "-") 4digit
+ int sign = 1;
+
+ if (!(parser.check <one_char <'+'> >(line, &pos, true)))
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <number> nz(parser.get <number>(line, &pos));
+
+ parser.check <one_char <'"'> >(line, &pos);
+
+
+ m_datetime.hour() = std::min(std::max(nh->value(), 0u), 23u);
+ m_datetime.minute() = std::min(std::max(nmi->value(), 0u), 59u);
+ m_datetime.second() = std::min(std::max(ns->value(), 0u), 59u);
+
+ const int zone = static_cast <int>(nz->value());
+ const int zh = zone / 100; // hour offset
+ const int zm = zone % 100; // minute offset
+
+ m_datetime.zone() = ((zh * 60) + zm) * sign;
+
+ m_datetime.day() = std::min(std::max(nd->value(), 1u), 31u);
+ m_datetime.year() = ny->value();
+
+ const string month(vmime::toLower(amo->value()));
+ vmime::datetime::comp_t mon = vmime::datetime::JANUARY;
+
+ if (month.length() >= 3)
+ {
+ switch (month[0])
+ {
+ case 'j':
+ {
+ switch (month[1])
+ {
+ case 'a': mon = vmime::datetime::JANUARY; break;
+ case 'u':
+ {
+ switch (month[2])
+ {
+ case 'n': mon = vmime::datetime::JUNE; break;
+ default: mon = vmime::datetime::JULY; break;
+ }
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+ case 'f': mon = vmime::datetime::FEBRUARY; break;
+ case 'm':
+ {
+ switch (month[2])
+ {
+ case 'r': mon = vmime::datetime::MARCH; break;
+ default: mon = vmime::datetime::MAY; break;
+ }
+
+ break;
+ }
+ case 'a':
+ {
+ switch (month[1])
+ {
+ case 'p': mon = vmime::datetime::APRIL; break;
+ default: mon = vmime::datetime::AUGUST; break;
+ }
+
+ break;
+ }
+ case 's': mon = vmime::datetime::SEPTEMBER; break;
+ case 'o': mon = vmime::datetime::OCTOBER; break;
+ case 'n': mon = vmime::datetime::NOVEMBER; break;
+ case 'd': mon = vmime::datetime::DECEMBER; break;
+ }
+ }
+
+ m_datetime.month() = mon;
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ vmime::datetime m_datetime;
+ };
+
+
+ //
+ // header_fld_name ::= astring
+ //
+
+ typedef astring header_fld_name;
+
+
+ //
+ // header_list ::= "(" 1#header_fld_name ")"
+ //
+
+ class header_list : public component
+ {
+ public:
+
+ ~header_list()
+ {
+ for (std::vector <header_fld_name*>::iterator it = m_fld_names.begin() ;
+ it != m_fld_names.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("header_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_fld_names.push_back(parser.get <header_fld_name>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <header_fld_name*> m_fld_names;
+
+ public:
+
+ const std::vector <header_fld_name*>& fld_names() const { return (m_fld_names); }
+ };
+
+
+ //
+ // body_extension ::= nstring / number / "(" 1#body_extension ")"
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept body_extension fields. Server
+ // ;; implementations MUST NOT generate
+ // ;; body_extension fields except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+
+ class body_extension : public component
+ {
+ public:
+
+ body_extension()
+ : m_nstring(NULL), m_number(NULL)
+ {
+ }
+
+ ~body_extension()
+ {
+ delete (m_nstring);
+ delete (m_number);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'('> >(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_body_extensions.push_back(parser.get <body_extension>(line, &pos, true));
+ }
+ else
+ {
+ if (!(m_nstring = parser.get <IMAPParser::nstring>(line, &pos, true)))
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::nstring* m_nstring;
+ IMAPParser::number* m_number;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ IMAPParser::nstring* nstring() const { return (m_nstring); }
+ IMAPParser::number* number() const { return (m_number); }
+
+ const std::vector <body_extension*>& body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
+ // SPACE header_list / "TEXT" / "MIME"
+ //
+
+ class section_text : public component
+ {
+ public:
+
+ section_text()
+ : m_header_list(NULL)
+ {
+ }
+
+ ~section_text()
+ {
+ delete (m_header_list);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("section_text");
+
+ string::size_type pos = *currentPos;
+
+ // "HEADER.FIELDS" [".NOT"] SPACE header_list
+ const bool b1 = parser.checkWithArg <special_atom>(line, &pos, "header.fields.not", true);
+ const bool b2 = (b1 ? false : parser.checkWithArg <special_atom>(line, &pos, "header.fields", true));
+
+ if (b1 || b2)
+ {
+ m_type = b1 ? HEADER_FIELDS_NOT : HEADER_FIELDS;
+
+ parser.check <SPACE>(line, &pos);
+ m_header_list = parser.get <IMAPParser::header_list>(line, &pos);
+ }
+ // "HEADER"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "header", true))
+ {
+ m_type = HEADER;
+ }
+ // "MIME"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "mime", true))
+ {
+ m_type = MIME;
+ }
+ // "TEXT"
+ else
+ {
+ m_type = TEXT;
+
+ parser.checkWithArg <special_atom>(line, &pos, "text");
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ HEADER,
+ HEADER_FIELDS,
+ HEADER_FIELDS_NOT,
+ MIME,
+ TEXT
+ };
+
+ private:
+
+ Type m_type;
+ IMAPParser::header_list* m_header_list;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const IMAPParser::header_list* header_list() const { return (m_header_list); }
+ };
+
+
+ //
+ // section ::= "[" [section_text / (nz_number *["." nz_number]
+ // ["." (section_text / "MIME")])] "]"
+ //
+
+ class section : public component
+ {
+ public:
+
+ section()
+ : m_section_text1(NULL), m_section_text2(NULL)
+ {
+ }
+
+ ~section()
+ {
+ delete (m_section_text1);
+ delete (m_section_text2);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("section");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'['> >(line, &pos);
+
+ if (!parser.check <one_char <']'> >(line, &pos, true))
+ {
+ if (!(m_section_text1 = parser.get <section_text>(line, &pos, true)))
+ {
+ nz_number* num = parser.get <nz_number>(line, &pos);
+ m_nz_numbers.push_back(num->value());
+ delete (num);
+
+ while (parser.check <one_char <'.'> >(line, &pos, true))
+ {
+ if ((num = parser.get <nz_number>(line, &pos, true)))
+ {
+ m_nz_numbers.push_back(num->value());
+ delete (num);
+ }
+ else
+ {
+ m_section_text2 = parser.get <section_text>(line, &pos);
+ break;
+ }
+ }
+ }
+
+ parser.check <one_char <']'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ section_text* m_section_text1;
+ section_text* m_section_text2;
+ std::vector <unsigned int> m_nz_numbers;
+
+ public:
+
+ const section_text* section_text1() const { return (m_section_text1); }
+ const section_text* section_text2() const { return (m_section_text2); }
+ const std::vector <unsigned int>& nz_numbers() const { return (m_nz_numbers); }
+ };
+
+
+ //
+ // addr_adl ::= nstring
+ // ;; Holds route from [RFC-822] route-addr if
+ // ;; non-NIL
+ //
+ // addr_host ::= nstring
+ // ;; NIL indicates [RFC-822] group syntax.
+ // ;; Otherwise, holds [RFC-822] domain name
+ //
+ // addr_mailbox ::= nstring
+ // ;; NIL indicates end of [RFC-822] group; if
+ // ;; non-NIL and addr_host is NIL, holds
+ // ;; [RFC-822] group name.
+ // ;; Otherwise, holds [RFC-822] local-part
+ //
+ // addr_name ::= nstring
+ // ;; Holds phrase from [RFC-822] mailbox if
+ // ;; non-NIL
+ //
+ // address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
+ // SPACE addr_host ")"
+ //
+
+ class address : public component
+ {
+ public:
+
+ address()
+ : m_addr_name(NULL), m_addr_adl(NULL),
+ m_addr_mailbox(NULL), m_addr_host(NULL)
+ {
+ }
+
+ ~address()
+ {
+ delete (m_addr_name);
+ delete (m_addr_adl);
+ delete (m_addr_mailbox);
+ delete (m_addr_host);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("address");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+ m_addr_name = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_adl = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_mailbox = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_host = parser.get <nstring>(line, &pos);
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ nstring* m_addr_name;
+ nstring* m_addr_adl;
+ nstring* m_addr_mailbox;
+ nstring* m_addr_host;
+
+ public:
+
+ nstring* addr_name() const { return (m_addr_name); }
+ nstring* addr_adl() const { return (m_addr_adl); }
+ nstring* addr_mailbox() const { return (m_addr_mailbox); }
+ nstring* addr_host() const { return (m_addr_host); }
+ };
+
+
+ //
+ // address_list ::= "(" 1*address ")" / nil
+ //
+
+ class address_list : public component
+ {
+ public:
+
+ ~address_list()
+ {
+ for (std::vector <address*>::iterator it = m_addresses.begin() ;
+ it != m_addresses.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("address_list");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_addresses.push_back(parser.get <address>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <address*> m_addresses;
+
+ public:
+
+ const std::vector <address*>& addresses() const { return (m_addresses); }
+ };
+
+
+ //
+ // env_bcc ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_bcc;
+
+
+ //
+ // env_cc ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_cc;
+
+
+ //
+ // env_date ::= nstring
+ //
+
+ typedef nstring env_date;
+
+
+ //
+ // env_from ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_from;
+
+
+ //
+ // env_in_reply_to ::= nstring
+ //
+
+ typedef nstring env_in_reply_to;
+
+
+ //
+ // env_message_id ::= nstring
+ //
+
+ typedef nstring env_message_id;
+
+
+ //
+ // env_reply_to ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_reply_to;
+
+
+ //
+ // env_sender ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_sender;
+
+
+ //
+ // env_subject ::= nstring
+ //
+
+ typedef nstring env_subject;
+
+
+ //
+ // env_to ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_to;
+
+
+ //
+ // envelope ::= "(" env_date SPACE env_subject SPACE env_from
+ // SPACE env_sender SPACE env_reply_to SPACE env_to
+ // SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
+ // SPACE env_message_id ")"
+ //
+
+ class envelope : public component
+ {
+ public:
+
+ envelope()
+ : m_env_date(NULL), m_env_subject(NULL),
+ m_env_from(NULL), m_env_sender(NULL), m_env_reply_to(NULL),
+ m_env_to(NULL), m_env_cc(NULL), m_env_bcc(NULL),
+ m_env_in_reply_to(NULL), m_env_message_id(NULL)
+ {
+ }
+
+ ~envelope()
+ {
+ delete (m_env_date);
+ delete (m_env_subject);
+ delete (m_env_from);
+ delete (m_env_sender);
+ delete (m_env_reply_to);
+ delete (m_env_to);
+ delete (m_env_cc);
+ delete (m_env_bcc);
+ delete (m_env_in_reply_to);
+ delete (m_env_message_id);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("envelope");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_env_date = parser.get <IMAPParser::env_date>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_subject = parser.get <IMAPParser::env_subject>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_from = parser.get <IMAPParser::env_from>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_sender = parser.get <IMAPParser::env_sender>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_reply_to = parser.get <IMAPParser::env_reply_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_to = parser.get <IMAPParser::env_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_cc = parser.get <IMAPParser::env_cc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_bcc = parser.get <IMAPParser::env_bcc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_in_reply_to = parser.get <IMAPParser::env_in_reply_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_message_id = parser.get <IMAPParser::env_message_id>(line, &pos);
+
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::env_date* m_env_date;
+ IMAPParser::env_subject* m_env_subject;
+ IMAPParser::env_from* m_env_from;
+ IMAPParser::env_sender* m_env_sender;
+ IMAPParser::env_reply_to* m_env_reply_to;
+ IMAPParser::env_to* m_env_to;
+ IMAPParser::env_cc* m_env_cc;
+ IMAPParser::env_bcc* m_env_bcc;
+ IMAPParser::env_in_reply_to* m_env_in_reply_to;
+ IMAPParser::env_message_id* m_env_message_id;
+
+ public:
+
+ const IMAPParser::env_date* env_date() const { return (m_env_date); }
+ const IMAPParser::env_subject* env_subject() const { return (m_env_subject); }
+ const IMAPParser::env_from* env_from() const { return (m_env_from); }
+ const IMAPParser::env_sender* env_sender() const { return (m_env_sender); }
+ const IMAPParser::env_reply_to* env_reply_to() const { return (m_env_reply_to); }
+ const IMAPParser::env_to* env_to() const { return (m_env_to); }
+ const IMAPParser::env_cc* env_cc() const { return (m_env_cc); }
+ const IMAPParser::env_bcc* env_bcc() const { return (m_env_bcc); }
+ const IMAPParser::env_in_reply_to* env_in_reply_to() const { return (m_env_in_reply_to); }
+ const IMAPParser::env_message_id* env_message_id() const { return (m_env_message_id); }
+ };
+
+
+ //
+ // body_fld_desc ::= nstring
+ //
+
+ typedef nstring body_fld_desc;
+
+
+ //
+ // body_fld_id ::= nstring
+ //
+
+ typedef nstring body_fld_id;
+
+
+ //
+ // body_fld_md5 ::= nstring
+ //
+
+ typedef nstring body_fld_md5;
+
+
+ //
+ // body_fld_octets ::= number
+ //
+
+ typedef number body_fld_octets;
+
+
+ //
+ // body_fld_lines ::= number
+ //
+
+ typedef number body_fld_lines;
+
+
+ //
+ // body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ // "QUOTED-PRINTABLE") <">) / string
+ //
+
+ typedef xstring body_fld_enc;
+
+
+ //
+ // body_fld_param_item ::= string SPACE string
+ //
+
+ class body_fld_param_item : public component
+ {
+ public:
+
+ body_fld_param_item()
+ : m_string1(NULL), m_string2(NULL)
+ {
+ }
+
+ ~body_fld_param_item()
+ {
+ delete (m_string1);
+ delete (m_string2);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_param_item");
+
+ string::size_type pos = *currentPos;
+
+ m_string1 = parser.get <xstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_string2 = parser.get <xstring>(line, &pos);
+
+ DEBUG_FOUND("body_fld_param_item", "<" << m_string1->value() << ", " << m_string2->value() << ">");
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ xstring* m_string1;
+ xstring* m_string2;
+
+ public:
+
+ const xstring* string1() const { return (m_string1); }
+ const xstring* string2() const { return (m_string2); }
+ };
+
+
+ //
+ // body_fld_param ::= "(" 1#(body_fld_param_item) ")" / nil
+ //
+
+ class body_fld_param : public component
+ {
+ public:
+
+ ~body_fld_param()
+ {
+ for (std::vector <body_fld_param_item*>::iterator it = m_items.begin() ;
+ it != m_items.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_param");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_items.push_back(parser.get <body_fld_param_item>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ parser.check <SPACE>(line, &pos);
+ m_items.push_back(parser.get <body_fld_param_item>(line, &pos));
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <body_fld_param_item*> m_items;
+
+ public:
+
+ const std::vector <body_fld_param_item*>& items() const { return (m_items); }
+ };
+
+
+ //
+ // body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil
+ //
+
+ class body_fld_dsp : public component
+ {
+ public:
+
+ body_fld_dsp()
+ : m_string(NULL), m_body_fld_param(NULL)
+ {
+ }
+
+ ~body_fld_dsp()
+ {
+ delete (m_string);
+ delete (m_body_fld_param);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_dsp");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+ m_string = parser.get <xstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_param = parser.get <class body_fld_param>(line, &pos);
+ parser.check <one_char <')'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ class xstring* m_string;
+ class body_fld_param* m_body_fld_param;
+
+ public:
+
+ const class xstring* str() const { return (m_string); }
+ const class body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ };
+
+
+ //
+ // body_fld_lang ::= nstring / "(" 1#string ")"
+ //
+
+ class body_fld_lang : public component
+ {
+ public:
+
+ ~body_fld_lang()
+ {
+ for (std::vector <xstring*>::iterator it = m_strings.begin() ;
+ it != m_strings.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_lang");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'('> >(line, &pos, true))
+ {
+ m_strings.push_back(parser.get <class xstring>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_strings.push_back(parser.get <class xstring>(line, &pos));
+ }
+ else
+ {
+ m_strings.push_back(parser.get <class nstring>(line, &pos));
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <xstring*> m_strings;
+
+ public:
+
+ const std::vector <xstring*>& strings() const { return (m_strings); }
+ };
+
+
+ //
+ // body_fields ::= body_fld_param SPACE body_fld_id SPACE
+ // body_fld_desc SPACE body_fld_enc SPACE
+ // body_fld_octets
+ //
+
+ class body_fields : public component
+ {
+ public:
+
+ body_fields()
+ : m_body_fld_param(NULL), m_body_fld_id(NULL),
+ m_body_fld_desc(NULL), m_body_fld_enc(NULL), m_body_fld_octets(NULL)
+ {
+ }
+
+ ~body_fields()
+ {
+ delete (m_body_fld_param);
+ delete (m_body_fld_id);
+ delete (m_body_fld_desc);
+ delete (m_body_fld_enc);
+ delete (m_body_fld_octets);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fields");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_param = parser.get <IMAPParser::body_fld_param>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_id = parser.get <IMAPParser::body_fld_id>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_desc = parser.get <IMAPParser::body_fld_desc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_enc = parser.get <IMAPParser::body_fld_enc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_octets = parser.get <IMAPParser::body_fld_octets>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_param* m_body_fld_param;
+ IMAPParser::body_fld_id* m_body_fld_id;
+ IMAPParser::body_fld_desc* m_body_fld_desc;
+ IMAPParser::body_fld_enc* m_body_fld_enc;
+ IMAPParser::body_fld_octets* m_body_fld_octets;
+
+ public:
+
+ const IMAPParser::body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ const IMAPParser::body_fld_id* body_fld_id() const { return (m_body_fld_id); }
+ const IMAPParser::body_fld_desc* body_fld_desc() const { return (m_body_fld_desc); }
+ const IMAPParser::body_fld_enc* body_fld_enc() const { return (m_body_fld_enc); }
+ const IMAPParser::body_fld_octets* body_fld_octets() const { return (m_body_fld_octets); }
+ };
+
+
+ //
+ // media_subtype ::= string
+ // ;; Defined in [MIME-IMT]
+ //
+
+ typedef xstring media_subtype;
+
+
+ //
+ // media_text ::= <"> "TEXT" <"> SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+ //
+
+ class media_text : public component
+ {
+ public:
+
+ media_text()
+ : m_media_subtype(NULL)
+ {
+ }
+
+ ~media_text()
+ {
+ delete (m_media_subtype);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_text");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.checkWithArg <special_atom>(line, &pos, "text");
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // media_message ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">
+ // ;; Defined in [MIME-IMT]
+ //
+
+ class media_message : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_message");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.checkWithArg <special_atom>(line, &pos, "message");
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ //parser.check <one_char <'"'> >(line, &pos);
+ //parser.checkWithArg <special_atom>(line, &pos, "rfc822");
+ //parser.check <one_char <'"'> >(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // media_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
+ // "MESSAGE" / "VIDEO") <">) / string)
+ // SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+
+ class media_basic : public component
+ {
+ public:
+
+ media_basic()
+ : m_media_type(NULL), m_media_subtype(NULL)
+ {
+ }
+
+ ~media_basic()
+ {
+ delete (m_media_type);
+ delete (m_media_subtype);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_basic");
+
+ string::size_type pos = *currentPos;
+
+ m_media_type = parser.get <xstring>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::xstring* m_media_type;
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::xstring* media_type() const { return (m_media_type); }
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp
+ // [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+ //
+
+ class body_ext_1part : public component
+ {
+ public:
+
+ body_ext_1part()
+ : m_body_fld_md5(NULL), m_body_fld_dsp(NULL), m_body_fld_lang(NULL)
+ {
+ }
+
+ ~body_ext_1part()
+ {
+ delete (m_body_fld_md5);
+ delete (m_body_fld_dsp);
+ delete (m_body_fld_lang);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_ext_1part");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_md5 = parser.get <IMAPParser::body_fld_md5>(line, &pos);
+
+ // [SPACE body_fld_dsp
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_dsp = parser.get <IMAPParser::body_fld_dsp>(line, &pos);
+
+ // [SPACE body_fld_lang
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_lang = parser.get <IMAPParser::body_fld_lang>(line, &pos);
+
+ // [SPACE 1#body_extension]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ body_extension* ext = NULL;
+
+ while ((ext = parser.get <body_extension>(line, &pos, true)) != NULL)
+ m_body_extensions.push_back(ext);
+ }
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_md5* m_body_fld_md5;
+ IMAPParser::body_fld_dsp* m_body_fld_dsp;
+ IMAPParser::body_fld_lang* m_body_fld_lang;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ const IMAPParser::body_fld_md5* body_fld_md5() const { return (m_body_fld_md5); }
+ const IMAPParser::body_fld_dsp* body_fld_dsp() const { return (m_body_fld_dsp); }
+ const IMAPParser::body_fld_lang* body_fld_lang() const { return (m_body_fld_lang); }
+
+ const std::vector <body_extension*> body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // body_ext_mpart ::= body_fld_param
+ // [SPACE body_fld_dsp SPACE body_fld_lang
+ // [SPACE 1#body_extension]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+
+ class body_ext_mpart : public component
+ {
+ public:
+
+ body_ext_mpart()
+ : m_body_fld_param(NULL), m_body_fld_dsp(NULL), m_body_fld_lang(NULL)
+ {
+ }
+
+ ~body_ext_mpart()
+ {
+ delete (m_body_fld_param);
+ delete (m_body_fld_dsp);
+ delete (m_body_fld_lang);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_ext_mpart");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_param = parser.get <IMAPParser::body_fld_param>(line, &pos);
+
+ // [SPACE body_fld_dsp SPACE body_fld_lang [SPACE 1#body_extension]]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_dsp = parser.get <IMAPParser::body_fld_dsp>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lang = parser.get <IMAPParser::body_fld_lang>(line, &pos);
+
+ // [SPACE 1#body_extension]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ body_extension* ext = NULL;
+
+ while ((ext = parser.get <body_extension>(line, &pos, true)) != NULL)
+ m_body_extensions.push_back(ext);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_param* m_body_fld_param;
+ IMAPParser::body_fld_dsp* m_body_fld_dsp;
+ IMAPParser::body_fld_lang* m_body_fld_lang;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ const IMAPParser::body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ const IMAPParser::body_fld_dsp* body_fld_dsp() const { return (m_body_fld_dsp); }
+ const IMAPParser::body_fld_lang* body_fld_lang() const { return (m_body_fld_lang); }
+
+ const std::vector <body_extension*> body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // body_type_basic ::= media_basic SPACE body_fields
+ // ;; MESSAGE subtype MUST NOT be "RFC822"
+ //
+
+ class body_type_basic : public component
+ {
+ public:
+
+ body_type_basic()
+ : m_media_basic(NULL), m_body_fields(NULL)
+ {
+ }
+
+ ~body_type_basic()
+ {
+ delete (m_media_basic);
+ delete (m_body_fields);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_basic");
+
+ string::size_type pos = *currentPos;
+
+ m_media_basic = parser.get <IMAPParser::media_basic>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_basic* m_media_basic;
+ IMAPParser::body_fields* m_body_fields;
+
+ public:
+
+ const IMAPParser::media_basic* media_basic() const { return (m_media_basic); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ };
+
+
+ //
+ // body_type_msg ::= media_message SPACE body_fields SPACE envelope
+ // SPACE body SPACE body_fld_lines
+ //
+
+ class xbody;
+ typedef xbody body;
+
+ class body_type_msg : public component
+ {
+ public:
+
+ body_type_msg()
+ : m_media_message(NULL), m_body_fields(NULL),
+ m_envelope(NULL), m_body(NULL), m_body_fld_lines(NULL)
+ {
+ }
+
+ ~body_type_msg()
+ {
+ delete (m_media_message);
+ delete (m_body_fields);
+ delete (m_envelope);
+ delete (m_body);
+ delete (m_body_fld_lines);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_msg");
+
+ string::size_type pos = *currentPos;
+
+ m_media_message = parser.get <IMAPParser::media_message>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_envelope = parser.get <IMAPParser::envelope>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body = parser.get <IMAPParser::xbody>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lines = parser.get <IMAPParser::body_fld_lines>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_message* m_media_message;
+ IMAPParser::body_fields* m_body_fields;
+ IMAPParser::envelope* m_envelope;
+ IMAPParser::xbody* m_body;
+ IMAPParser::body_fld_lines* m_body_fld_lines;
+
+ public:
+
+ const IMAPParser::media_message* media_message() const { return (m_media_message); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ const IMAPParser::envelope* envelope() const { return (m_envelope); }
+ const IMAPParser::xbody* body() const { return (m_body); }
+ const IMAPParser::body_fld_lines* body_fld_lines() const { return (m_body_fld_lines); }
+ };
+
+
+ //
+ // body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines
+ //
+
+ class body_type_text : public component
+ {
+ public:
+
+ body_type_text()
+ : m_media_text(NULL),
+ m_body_fields(NULL), m_body_fld_lines(NULL)
+ {
+ }
+
+ ~body_type_text()
+ {
+ delete (m_media_text);
+ delete (m_body_fields);
+ delete (m_body_fld_lines);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_text");
+
+ string::size_type pos = *currentPos;
+
+ m_media_text = parser.get <IMAPParser::media_text>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lines = parser.get <IMAPParser::body_fld_lines>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_text* m_media_text;
+ IMAPParser::body_fields* m_body_fields;
+ IMAPParser::body_fld_lines* m_body_fld_lines;
+
+ public:
+
+ const IMAPParser::media_text* media_text() const { return (m_media_text); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ const IMAPParser::body_fld_lines* body_fld_lines() const { return (m_body_fld_lines); }
+ };
+
+
+ //
+ // body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
+ // [SPACE body_ext_1part]
+ //
+
+ class body_type_1part : public component
+ {
+ public:
+
+ body_type_1part()
+ : m_body_type_basic(NULL), m_body_type_msg(NULL),
+ m_body_type_text(NULL), m_body_ext_1part(NULL)
+ {
+ }
+
+ ~body_type_1part()
+ {
+ delete (m_body_type_basic);
+ delete (m_body_type_msg);
+ delete (m_body_type_text);
+
+ delete (m_body_ext_1part);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_1part");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_body_type_text = parser.get <IMAPParser::body_type_text>(line, &pos, true)))
+ if (!(m_body_type_msg = parser.get <IMAPParser::body_type_msg>(line, &pos, true)))
+ m_body_type_basic = parser.get <IMAPParser::body_type_basic>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_body_ext_1part = parser.get <IMAPParser::body_ext_1part>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_type_basic* m_body_type_basic;
+ IMAPParser::body_type_msg* m_body_type_msg;
+ IMAPParser::body_type_text* m_body_type_text;
+
+ IMAPParser::body_ext_1part* m_body_ext_1part;
+
+ public:
+
+ const IMAPParser::body_type_basic* body_type_basic() const { return (m_body_type_basic); }
+ const IMAPParser::body_type_msg* body_type_msg() const { return (m_body_type_msg); }
+ const IMAPParser::body_type_text* body_type_text() const { return (m_body_type_text); }
+
+ const IMAPParser::body_ext_1part* body_ext_1part() const { return (m_body_ext_1part); }
+ };
+
+
+ //
+ // body_type_mpart ::= 1*body SPACE media_subtype
+ // [SPACE body_ext_mpart]
+ //
+
+ class body_type_mpart : public component
+ {
+ public:
+
+ body_type_mpart()
+ : m_media_subtype(NULL), m_body_ext_mpart(NULL)
+ {
+ }
+
+ ~body_type_mpart()
+ {
+ delete (m_media_subtype);
+ delete (m_body_ext_mpart);
+
+ for (std::vector <xbody*>::iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_mpart");
+
+ string::size_type pos = *currentPos;
+
+ m_list.push_back(parser.get <xbody>(line, &pos));
+
+ for (xbody* b ; (b = parser.get <xbody>(line, &pos, true)) ; )
+ m_list.push_back(b);
+
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_body_ext_mpart = parser.get <IMAPParser::body_ext_mpart>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+ IMAPParser::body_ext_mpart* m_body_ext_mpart;
+
+ std::vector <xbody*> m_list;
+
+ public:
+
+ const std::vector <IMAPParser::xbody*>& list() const { return (m_list); }
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ const IMAPParser::body_ext_mpart* body_ext_mpart() const { return (m_body_ext_mpart); }
+ };
+
+
+ //
+ // xbody ::= "(" body_type_1part / body_type_mpart ")"
+ //
+
+ class xbody : public component
+ {
+ public:
+
+ xbody()
+ : m_body_type_1part(NULL), m_body_type_mpart(NULL)
+ {
+ }
+
+ ~xbody()
+ {
+ delete (m_body_type_1part);
+ delete (m_body_type_mpart);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ if (!(m_body_type_1part = parser.get <IMAPParser::body_type_1part>(line, &pos, true)))
+ m_body_type_mpart = parser.get <IMAPParser::body_type_mpart>(line, &pos);
+
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_type_1part* m_body_type_1part;
+ IMAPParser::body_type_mpart* m_body_type_mpart;
+
+ public:
+
+ const IMAPParser::body_type_1part* body_type_1part() const { return (m_body_type_1part); }
+ const IMAPParser::body_type_mpart* body_type_mpart() const { return (m_body_type_mpart); }
+ };
+
+
+ //
+ // uniqueid ::= nz_number
+ // ;; Strictly ascending
+ //
+ // msg_att_item ::= "ENVELOPE" SPACE envelope /
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
+ // "INTERNALDATE" SPACE date_time /
+ // "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
+ // "RFC822.SIZE" SPACE number /
+ // "BODY" ["STRUCTURE"] SPACE body /
+ // "BODY" section ["<" number ">"] SPACE nstring /
+ // "UID" SPACE uniqueid
+ //
+
+ class msg_att_item : public component
+ {
+ public:
+
+ msg_att_item()
+ : m_date_time(NULL), m_number(NULL), m_envelope(NULL),
+ m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL)
+ {
+ }
+
+ ~msg_att_item()
+ {
+ delete (m_date_time);
+ delete (m_number);
+ delete (m_envelope);
+ delete (m_uniqueid);
+ delete (m_nstring);
+ delete (m_body);
+ delete (m_flag_list);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("msg_att_item");
+
+ string::size_type pos = *currentPos;
+
+ // "ENVELOPE" SPACE envelope
+ if (parser.checkWithArg <special_atom>(line, &pos, "envelope", true))
+ {
+ m_type = ENVELOPE;
+
+ parser.check <SPACE>(line, &pos);
+ m_envelope = parser.get <IMAPParser::envelope>(line, &pos);
+ }
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "flags", true))
+ {
+ m_type = FLAGS;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
+ }
+ // "INTERNALDATE" SPACE date_time
+ else if (parser.checkWithArg <special_atom>(line, &pos, "internaldate", true))
+ {
+ m_type = INTERNALDATE;
+
+ parser.check <SPACE>(line, &pos);
+ m_date_time = parser.get <IMAPParser::date_time>(line, &pos);
+ }
+ // "RFC822" ".HEADER" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.header", true))
+ {
+ m_type = RFC822_HEADER;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.get <IMAPParser::nstring>(line, &pos);
+ }
+ // "RFC822" ".TEXT" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.text", true))
+ {
+ m_type = RFC822_TEXT;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.getWithArgs <IMAPParser::nstring>
+ (line, &pos, this, RFC822_TEXT);
+ }
+ // "RFC822.SIZE" SPACE number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.size", true))
+ {
+ m_type = RFC822_SIZE;
+
+ parser.check <SPACE>(line, &pos);
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ }
+ // "RFC822" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822", true))
+ {
+ m_type = RFC822;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.get <IMAPParser::nstring>(line, &pos);
+ }
+ // "BODY" "STRUCTURE" SPACE body
+ else if (parser.checkWithArg <special_atom>(line, &pos, "bodystructure", true))
+ {
+ m_type = BODY_STRUCTURE;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_body = parser.get <IMAPParser::body>(line, &pos);
+ }
+ // "BODY" section ["<" number ">"] SPACE nstring
+ // "BODY" SPACE body
+ else if (parser.checkWithArg <special_atom>(line, &pos, "body", true))
+ {
+ m_section = parser.get <IMAPParser::section>(line, &pos, true);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ if (m_section != NULL)
+ {
+ m_type = BODY_SECTION;
+
+ if (parser.check <one_char <'<'> >(line, &pos, true))
+ {
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ parser.check <one_char <'>'> >(line, &pos);
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.getWithArgs <IMAPParser::nstring>
+ (line, &pos, this, BODY_SECTION);
+ }
+ // "BODY" SPACE body
+ else
+ {
+ m_type = BODY;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_body = parser.get <IMAPParser::body>(line, &pos);
+ }
+ }
+ // "UID" SPACE uniqueid
+ else
+ {
+ m_type = UID;
+
+ parser.checkWithArg <special_atom>(line, &pos, "uid");
+ parser.check <SPACE>(line, &pos);
+
+ m_uniqueid = parser.get <nz_number>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ ENVELOPE,
+ FLAGS,
+ INTERNALDATE,
+ RFC822,
+ RFC822_SIZE,
+ RFC822_HEADER,
+ RFC822_TEXT,
+ BODY,
+ BODY_SECTION,
+ BODY_STRUCTURE,
+ UID
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::date_time* m_date_time;
+ IMAPParser::number* m_number;
+ IMAPParser::envelope* m_envelope;
+ IMAPParser::nz_number* m_uniqueid;
+ IMAPParser::nstring* m_nstring;
+ IMAPParser::xbody* m_body;
+ IMAPParser::flag_list* m_flag_list;
+ IMAPParser::section* m_section;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::date_time* date_time() const { return (m_date_time); }
+ const IMAPParser::number* number() const { return (m_number); }
+ const IMAPParser::envelope* envelope() const { return (m_envelope); }
+ const IMAPParser::nz_number* unique_id() const { return (m_uniqueid); }
+ const IMAPParser::nstring* nstring() const { return (m_nstring); }
+ const IMAPParser::xbody* body() const { return (m_body); }
+ const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
+ const IMAPParser::section* section() const { return (m_section); }
+ };
+
+
+ //
+ // msg_att ::= "(" 1#(msg_att_item) ")"
+ //
+
+ class msg_att : public component
+ {
+ public:
+
+ ~msg_att()
+ {
+ for (std::vector <msg_att_item*>::iterator it = m_items.begin() ;
+ it != m_items.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("msg_att");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_items.push_back(parser.get <msg_att_item>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ parser.check <SPACE>(line, &pos);
+ m_items.push_back(parser.get <msg_att_item>(line, &pos));
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <msg_att_item*> m_items;
+
+ public:
+
+ const std::vector <msg_att_item*>& items() const { return (m_items); }
+ };
+
+
+ //
+ // message_data ::= nz_number SPACE ("EXPUNGE" /
+ // ("FETCH" SPACE msg_att))
+ //
+
+ class message_data : public component
+ {
+ public:
+
+ message_data()
+ : m_number(0), m_msg_att(NULL)
+ {
+ }
+
+ ~message_data()
+ {
+ delete (m_msg_att);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("message_data");
+
+ string::size_type pos = *currentPos;
+
+ nz_number* num = parser.get <nz_number>(line, &pos);
+ m_number = num->value();
+ delete (num);
+
+ parser.check <SPACE>(line, &pos);
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "expunge", true))
+ {
+ m_type = EXPUNGE;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "fetch");
+
+ parser.check <SPACE>(line, &pos);
+
+ m_type = FETCH;
+ m_msg_att = parser.get <IMAPParser::msg_att>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ EXPUNGE,
+ FETCH
+ };
+
+ private:
+
+ Type m_type;
+ unsigned int m_number;
+ IMAPParser::msg_att* m_msg_att;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const unsigned int number() const { return (m_number); }
+ const IMAPParser::msg_att* msg_att() const { return (m_msg_att); }
+ };
+
+
+ //
+ // resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
+ // ;; Status condition
+ //
+
+ class resp_cond_state : public component
+ {
+ public:
+
+ resp_cond_state()
+ : m_resp_text(NULL), m_status(BAD)
+ {
+ }
+
+ ~resp_cond_state()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_state");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "ok", true))
+ {
+ m_status = OK;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "no", true))
+ {
+ m_status = NO;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "bad");
+ m_status = BAD;
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ enum Status
+ {
+ OK,
+ NO,
+ BAD
+ };
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+ Status m_status;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ const Status status() const { return (m_status); }
+ };
+
+
+ //
+ // resp_cond_bye ::= "BYE" SPACE resp_text
+ //
+
+ class resp_cond_bye : public component
+ {
+ public:
+
+ resp_cond_bye()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~resp_cond_bye()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_bye");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "bye");
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // resp_cond_auth ::= ("OK" / "PREAUTH") SPACE resp_text
+ // ;; Authentication condition
+ //
+
+ class resp_cond_auth : public component
+ {
+ public:
+
+ resp_cond_auth()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~resp_cond_auth()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_auth");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "ok", true))
+ {
+ m_cond = OK;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "preauth");
+
+ m_cond = PREAUTH;
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ enum Condition
+ {
+ OK,
+ PREAUTH
+ };
+
+ private:
+
+ Condition m_cond;
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const Condition condition() const { return (m_cond); }
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // status_info ::= status_att SPACE number
+ //
+
+ class status_info : public component
+ {
+ public:
+
+ status_info()
+ : m_status_att(NULL), m_number(NULL)
+ {
+ }
+
+ ~status_info()
+ {
+ delete (m_status_att);
+ delete (m_number);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("status_info");
+
+ string::size_type pos = *currentPos;
+
+ m_status_att = parser.get <IMAPParser::status_att>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::status_att* m_status_att;
+ IMAPParser::number* m_number;
+
+ public:
+
+ const IMAPParser::status_att* status_att() const { return (m_status_att); }
+ const IMAPParser::number* number() const { return (m_number); }
+ };
+
+
+ //
+ // mailbox_data ::= "FLAGS" SPACE mailbox_flag_list /
+ // "LIST" SPACE mailbox_list /
+ // "LSUB" SPACE mailbox_list /
+ // "MAILBOX" SPACE text /
+ // "SEARCH" [SPACE 1#nz_number] /
+ // "STATUS" SPACE mailbox SPACE
+ // "(" #<status_att number ")" /
+ // number SPACE "EXISTS" /
+ // number SPACE "RECENT"
+ //
+
+ class mailbox_data : public component
+ {
+ public:
+
+ mailbox_data()
+ : m_number(NULL), m_mailbox_flag_list(NULL), m_mailbox_list(NULL),
+ m_mailbox(NULL), m_text(NULL)
+ {
+ }
+
+ ~mailbox_data()
+ {
+ delete (m_number);
+ delete (m_mailbox_flag_list);
+ delete (m_mailbox_list);
+ delete (m_mailbox);
+ delete (m_text);
+
+ for (std::vector <nz_number*>::iterator it = m_search_nz_number_list.begin() ;
+ it != m_search_nz_number_list.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_data");
+
+ string::size_type pos = *currentPos;
+
+ m_number = parser.get <IMAPParser::number>(line, &pos, true);
+
+ if (m_number)
+ {
+ parser.check <SPACE>(line, &pos);
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "exists", true))
+ {
+ m_type = EXISTS;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "recent");
+
+ m_type = RECENT;
+ }
+ }
+ else
+ {
+ // "FLAGS" SPACE mailbox_flag_list
+ if (parser.checkWithArg <special_atom>(line, &pos, "flags", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_flag_list = parser.get <IMAPParser::mailbox_flag_list>(line, &pos);
+
+ m_type = FLAGS;
+ }
+ // "LIST" SPACE mailbox_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "list", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_list = parser.get <IMAPParser::mailbox_list>(line, &pos);
+
+ m_type = LIST;
+ }
+ // "LSUB" SPACE mailbox_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "lsub", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_list = parser.get <IMAPParser::mailbox_list>(line, &pos);
+
+ m_type = LSUB;
+ }
+ // "MAILBOX" SPACE text
+ else if (parser.checkWithArg <special_atom>(line, &pos, "mailbox", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_text = parser.get <IMAPParser::text>(line, &pos);
+
+ m_type = MAILBOX;
+ }
+ // "SEARCH" [SPACE 1#nz_number]
+ else if (parser.checkWithArg <special_atom>(line, &pos, "search", true))
+ {
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_search_nz_number_list.push_back
+ (parser.get <nz_number>(line, &pos));
+
+ while (parser.check <SPACE>(line, &pos, true))
+ {
+ m_search_nz_number_list.push_back
+ (parser.get <nz_number>(line, &pos));
+ }
+ }
+
+ m_type = SEARCH;
+ }
+ // "STATUS" SPACE mailbox SPACE
+ // "(" #<status_att number)] ")"
+ //
+ // "(" [status_att SPACE number *(SPACE status_att SPACE number)] ")"
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "status");
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox = parser.get <IMAPParser::mailbox>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_status_info_list.push_back(parser.get <status_info>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_status_info_list.push_back(parser.get <status_info>(line, &pos));
+
+ m_type = STATUS;
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ FLAGS,
+ LIST,
+ LSUB,
+ MAILBOX,
+ SEARCH,
+ STATUS,
+ EXISTS,
+ RECENT
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::number* m_number;
+ IMAPParser::mailbox_flag_list* m_mailbox_flag_list;
+ IMAPParser::mailbox_list* m_mailbox_list;
+ IMAPParser::mailbox* m_mailbox;
+ IMAPParser::text* m_text;
+ std::vector <nz_number*> m_search_nz_number_list;
+ std::vector <status_info*> m_status_info_list;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::number* number() const { return (m_number); }
+ const IMAPParser::mailbox_flag_list* mailbox_flag_list() const { return (m_mailbox_flag_list); }
+ const IMAPParser::mailbox_list* mailbox_list() const { return (m_mailbox_list); }
+ const IMAPParser::mailbox* mailbox() const { return (m_mailbox); }
+ const IMAPParser::text* text() const { return (m_text); }
+ const std::vector <nz_number*>& search_nz_number_list() const { return (m_search_nz_number_list); }
+ const std::vector <status_info*>& status_info_list() const { return (m_status_info_list); }
+ };
+
+
+ //
+ // response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+ // mailbox_data / message_data / capability_data) CRLF
+ //
+
+ class response_data : public component
+ {
+ public:
+
+ response_data()
+ : m_resp_cond_state(NULL), m_resp_cond_bye(NULL),
+ m_mailbox_data(NULL), m_message_data(NULL), m_capability_data(NULL)
+ {
+ }
+
+ ~response_data()
+ {
+ delete (m_resp_cond_state);
+ delete (m_resp_cond_bye);
+ delete (m_mailbox_data);
+ delete (m_message_data);
+ delete (m_capability_data);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_data");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ if (!(m_resp_cond_state = parser.get <IMAPParser::resp_cond_state>(line, &pos, true)))
+ if (!(m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos, true)))
+ if (!(m_mailbox_data = parser.get <IMAPParser::mailbox_data>(line, &pos, true)))
+ if (!(m_message_data = parser.get <IMAPParser::message_data>(line, &pos, true)))
+ m_capability_data = parser.get <IMAPParser::capability_data>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_state* m_resp_cond_state;
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+ IMAPParser::mailbox_data* m_mailbox_data;
+ IMAPParser::message_data* m_message_data;
+ IMAPParser::capability_data* m_capability_data;
+
+ public:
+
+ const IMAPParser::resp_cond_state* resp_cond_state() const { return (m_resp_cond_state); }
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ const IMAPParser::mailbox_data* mailbox_data() const { return (m_mailbox_data); }
+ const IMAPParser::message_data* message_data() const { return (m_message_data); }
+ const IMAPParser::capability_data* capability_data() const { return (m_capability_data); }
+ };
+
+
+ class continue_req_or_response_data : public component
+ {
+ public:
+
+ continue_req_or_response_data()
+ : m_continue_req(NULL), m_response_data(NULL)
+ {
+ }
+
+ ~continue_req_or_response_data()
+ {
+ delete (m_continue_req);
+ delete (m_response_data);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("continue_req_or_response_data");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_continue_req = parser.get <IMAPParser::continue_req>(line, &pos, true)))
+ m_response_data = parser.get <IMAPParser::response_data>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::continue_req* m_continue_req;
+ IMAPParser::response_data* m_response_data;
+
+ public:
+
+ const IMAPParser::continue_req* continue_req() const { return (m_continue_req); }
+ const IMAPParser::response_data* response_data() const { return (m_response_data); }
+ };
+
+
+ //
+ // response_fatal ::= "*" SPACE resp_cond_bye CRLF
+ // ;; Server closes connection immediately
+ //
+
+ class response_fatal : public component
+ {
+ public:
+
+ response_fatal()
+ : m_resp_cond_bye(NULL)
+ {
+ }
+
+ ~response_fatal()
+ {
+ delete (m_resp_cond_bye);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_fatal");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+
+ public:
+
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ };
+
+
+ //
+ // response_tagged ::= tag SPACE resp_cond_state CRLF
+ //
+
+ class response_tagged : public component
+ {
+ public:
+
+ response_tagged()
+ : m_resp_cond_state(NULL)
+ {
+ }
+
+ ~response_tagged()
+ {
+ delete (m_resp_cond_state);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_tagged");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <IMAPParser::xtag>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_resp_cond_state = parser.get <IMAPParser::resp_cond_state>(line, &pos);
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_state* m_resp_cond_state;
+
+ public:
+
+ const IMAPParser::resp_cond_state* resp_cond_state() const { return (m_resp_cond_state); }
+ };
+
+
+ //
+ // response_done ::= response_tagged / response_fatal
+ //
+
+ class response_done : public component
+ {
+ public:
+
+ response_done()
+ : m_response_tagged(NULL), m_response_fatal(NULL)
+ {
+ }
+
+ ~response_done()
+ {
+ delete (m_response_tagged);
+ delete (m_response_fatal);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_done");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_response_tagged = parser.get <IMAPParser::response_tagged>(line, &pos, true)))
+ m_response_fatal = parser.get <IMAPParser::response_fatal>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::response_tagged* m_response_tagged;
+ IMAPParser::response_fatal* m_response_fatal;
+
+ public:
+
+ const IMAPParser::response_tagged* response_tagged() const { return (m_response_tagged); }
+ const IMAPParser::response_fatal* response_fatal() const { return (m_response_fatal); }
+ };
+
+
+ //
+ // response ::= *(continue_req / response_data) response_done
+ //
+
+ class response : public component
+ {
+ public:
+
+ response()
+ : m_response_done(NULL)
+ {
+ }
+
+ ~response()
+ {
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::iterator
+ it = m_continue_req_or_response_data.begin() ;
+ it != m_continue_req_or_response_data.end() ; ++it)
+ {
+ delete (*it);
+ }
+
+ delete (m_response_done);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response");
+
+ string::size_type pos = *currentPos;
+ string curLine = line;
+ bool partial = false; // partial response
+
+ IMAPParser::continue_req_or_response_data* resp = NULL;
+
+ while ((resp = parser.get <IMAPParser::continue_req_or_response_data>(curLine, &pos, true)) != NULL)
+ {
+ m_continue_req_or_response_data.push_back(resp);
+
+ // Partial response (continue_req)
+ if (resp->continue_req())
+ {
+ partial = true;
+ break;
+ }
+
+ // We have read a CRLF, read another line
+ curLine = parser.readLine();
+ pos = 0;
+ }
+
+ if (!partial)
+ m_response_done = parser.get <IMAPParser::response_done>(curLine, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ const bool isBad() const
+ {
+ if (!response_done()) // incomplete (partial) response
+ return (true);
+
+ if (response_done()->response_fatal())
+ return (true);
+
+ if (response_done()->response_tagged()->resp_cond_state()->
+ status() == IMAPParser::resp_cond_state::BAD)
+ {
+ return (true);
+ }
+
+ return (false);
+ }
+
+ private:
+
+ std::vector <IMAPParser::continue_req_or_response_data*> m_continue_req_or_response_data;
+ IMAPParser::response_done* m_response_done;
+
+ public:
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& continue_req_or_response_data() const { return (m_continue_req_or_response_data); }
+ const IMAPParser::response_done* response_done() const { return (m_response_done); }
+ };
+
+
+ //
+ // greeting ::= "*" SPACE (resp_cond_auth / resp_cond_bye) CRLF
+ //
+
+ class greeting : public component
+ {
+ public:
+
+ greeting()
+ : m_resp_cond_auth(NULL), m_resp_cond_bye(NULL)
+ {
+ }
+
+ ~greeting()
+ {
+ delete (m_resp_cond_auth);
+ delete (m_resp_cond_bye);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("greeting");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ if (!(m_resp_cond_auth = parser.get <IMAPParser::resp_cond_auth>(line, &pos, true)))
+ m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_auth* m_resp_cond_auth;
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+
+ public:
+
+ const IMAPParser::resp_cond_auth* resp_cond_auth() const { return (m_resp_cond_auth); }
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ };
+
+
+
+ //
+ // The main functions used to parse a response
+ //
+
+ response* readResponse(literalHandler* lh = NULL)
+ {
+ string::size_type pos = 0;
+ string line = readLine();
+
+ m_literalHandler = lh;
+ response* resp = get <response>(line, &pos);
+ m_literalHandler = NULL;
+
+ return (resp);
+ }
+
+
+ greeting* readGreeting()
+ {
+ string::size_type pos = 0;
+ string line = readLine();
+
+ return get <greeting>(line, &pos);
+ }
+
+
+ //
+ // Get a token and advance
+ //
+
+ template <class TYPE>
+ TYPE* get(string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+ component* resp = new TYPE;
+ return internalGet <TYPE>(resp, line, currentPos, noThrow);
+ }
+
+
+ template <class TYPE, class ARG1_TYPE, class ARG2_TYPE>
+ TYPE* getWithArgs(string& line, string::size_type* currentPos,
+ ARG1_TYPE arg1, ARG2_TYPE arg2, const bool noThrow = false)
+ {
+ component* resp = new TYPE(arg1, arg2);
+ return internalGet <TYPE>(resp, line, currentPos, noThrow);
+ }
+
+
+private:
+
+ template <class TYPE>
+ TYPE* internalGet(component* resp, string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+#if DEBUG_RESPONSE
+ DEBUG_RESPONSE_level += " ";
+#endif
+
+ 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
+
+ delete (resp);
+ if (!noThrow) throw;
+ return (NULL);
+ }
+
+ return static_cast <TYPE*>(resp);
+ }
+
+
+public:
+
+ //
+ // Check a token and advance
+ //
+
+ template <class TYPE>
+ const bool check(string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+ 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
+
+ if (!noThrow) throw;
+ return false;
+ }
+
+ return true;
+ }
+
+ template <class TYPE, class ARG_TYPE>
+ const bool checkWithArg(string& line, string::size_type* currentPos,
+ const ARG_TYPE arg, const bool noThrow = false)
+ {
+ 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
+
+ if (!noThrow) throw;
+ return false;
+ }
+
+ return true;
+ }
+
+
+private:
+
+ IMAPTag* m_tag;
+ socket* m_socket;
+
+ progressionListener* m_progress;
+
+ literalHandler* m_literalHandler;
+
+ timeoutHandler* m_timeoutHandler;
+
+
+ string m_buffer;
+ int m_pos;
+
+ string m_lastLine;
+
+public:
+
+ //
+ // Read one line
+ //
+
+ const string readLine()
+ {
+ string::size_type pos;
+
+ while ((pos = m_buffer.find('\n')) == string::npos)
+ {
+ read();
+ }
+
+ string line;
+ line.resize(pos + 1);
+ std::copy(m_buffer.begin(), m_buffer.begin() + pos + 1, line.begin());
+
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + pos + 1);
+
+ m_lastLine = line;
+
+#if DEBUG_RESPONSE
+ std::cout << std::endl << "Read line:" << std::endl << line << std::endl;
+#endif
+
+ return (line);
+ }
+
+
+ //
+ // Read available data from socket stream
+ //
+
+ void read()
+ {
+ string receiveBuffer;
+
+ while (receiveBuffer.empty())
+ {
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // We have received data: reset the time-out counter
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data ...
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ m_buffer += receiveBuffer;
+ }
+
+
+ void readLiteral(literalHandler::target& buffer, string::size_type count)
+ {
+ string::size_type len = 0;
+ string receiveBuffer;
+
+ if (m_progress)
+ m_progress->start(count);
+
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ if (!m_buffer.empty())
+ {
+ if (m_buffer.length() > count)
+ {
+ buffer.putData(string(m_buffer.begin(), m_buffer.begin() + count));
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + count);
+ len = count;
+ }
+ else
+ {
+ len += m_buffer.length();
+ buffer.putData(m_buffer);
+ m_buffer.clear();
+ }
+ }
+
+ while (len < count)
+ {
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // Receive data from the socket
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ if (len + receiveBuffer.length() > count)
+ {
+ const string::size_type remaining = count - len;
+
+ // Get the needed amount of data
+ buffer.putData(string(receiveBuffer.begin(), receiveBuffer.begin() + remaining));
+
+ // Put the remaining data into the internal response buffer
+ receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + remaining);
+ m_buffer += receiveBuffer;
+
+ len = count;
+ }
+ else
+ {
+ buffer.putData(receiveBuffer);
+ len += receiveBuffer.length();
+ }
+
+ // Notify progression
+ if (m_progress)
+ m_progress->progress(len, count);
+ }
+
+ if (m_progress)
+ m_progress->stop(count);
+ }
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPPARSER_HPP_INCLUDED