5078 lines
108 KiB
C++
5078 lines
108 KiB
C++
//
|
|
// VMime library (http://vmime.sourceforge.net)
|
|
// Copyright (C) 2002-2004 Vincent Richard <vincent@vincent-richard.net>
|
|
//
|
|
// 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 "vmime/base.hpp"
|
|
#include "vmime/dateTime.hpp"
|
|
#include "vmime/charset.hpp"
|
|
#include "vmime/exception.hpp"
|
|
|
|
#include "vmime/utility/smartPtr.hpp"
|
|
#include "vmime/utility/stringUtils.hpp"
|
|
|
|
#include "vmime/encoderB64.hpp"
|
|
#include "vmime/encoderQP.hpp"
|
|
|
|
#include "vmime/platformDependant.hpp"
|
|
|
|
#include "vmime/messaging/progressionListener.hpp"
|
|
#include "vmime/messaging/timeoutHandler.hpp"
|
|
#include "vmime/messaging/socket.hpp"
|
|
|
|
#include "vmime/messaging/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->getProperties()["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 = utility::stringUtils::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 = utility::stringUtils::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 = utility::stringUtils::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.setHour(std::min(std::max(nh->value(), 0u), 23u));
|
|
m_datetime.setMinute(std::min(std::max(nmi->value(), 0u), 59u));
|
|
m_datetime.setSecond(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.setZone(((zh * 60) + zm) * sign);
|
|
|
|
m_datetime.setDay(std::min(std::max(nd->value(), 1u), 31u));
|
|
m_datetime.setYear(ny->value());
|
|
|
|
const string month(utility::stringUtils::toLower(amo->value()));
|
|
int 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.setMonth(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
|