aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2014-03-15 22:33:20 +0000
committerVincent Richard <[email protected]>2014-03-15 22:33:20 +0000
commit9d73fc5382c3e7f31abb2b4b22f3ae2be8720feb (patch)
treed497965f38cad2bcd90e0df2bc199c52fd08e68e
parentRemoved unused/unimplemented function. (diff)
downloadvmime-9d73fc5382c3e7f31abb2b4b22f3ae2be8720feb.tar.gz
vmime-9d73fc5382c3e7f31abb2b4b22f3ae2be8720feb.zip
IMAP commands.
-rw-r--r--src/vmime/net/imap/IMAPCommand.cpp410
-rw-r--r--src/vmime/net/imap/IMAPCommand.hpp124
-rw-r--r--src/vmime/net/imap/IMAPConnection.cpp85
-rw-r--r--src/vmime/net/imap/IMAPConnection.hpp6
-rw-r--r--src/vmime/net/imap/IMAPFolder.cpp228
-rw-r--r--src/vmime/net/imap/IMAPMessage.cpp40
-rw-r--r--src/vmime/net/imap/IMAPStore.cpp3
-rw-r--r--src/vmime/net/imap/IMAPUtils.cpp48
-rw-r--r--src/vmime/net/imap/IMAPUtils.hpp5
-rw-r--r--src/vmime/utility/stringUtils.hpp20
-rw-r--r--tests/net/imap/IMAPCommandTest.cpp484
11 files changed, 1188 insertions, 265 deletions
diff --git a/src/vmime/net/imap/IMAPCommand.cpp b/src/vmime/net/imap/IMAPCommand.cpp
new file mode 100644
index 00000000..19c3b723
--- /dev/null
+++ b/src/vmime/net/imap/IMAPCommand.cpp
@@ -0,0 +1,410 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2014 Vincent Richard <[email protected]>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+
+#include <sstream>
+
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPCommand::IMAPCommand(const string& text, const string& traceText)
+ : m_text(text), m_traceText(traceText)
+{
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGIN(const string& username, const string& password)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LOGIN " << IMAPUtils::quoteString(username)
+ << " " << IMAPUtils::quoteString(password);
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "LOGIN <username> <password>";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName, const string& initialResponse)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LIST(const string& refName, const string& mailboxName)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LIST " << IMAPUtils::quoteString(refName)
+ << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SELECT
+ (const bool readOnly, const string& mailboxName, const std::vector <string>& params)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (readOnly)
+ cmd << "EXAMINE ";
+ else
+ cmd << "SELECT ";
+
+ cmd << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty())
+ {
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STATUS
+ (const string& mailboxName, const std::vector <string>& attribs)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "STATUS " << IMAPUtils::quoteString(mailboxName);
+
+ cmd << " (";
+
+ for (size_t i = 0, n = attribs.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << attribs[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CREATE
+ (const string& mailboxName, const std::vector <string>& params)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "CREATE " << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty())
+ {
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::DELETE(const string& mailboxName)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "DELETE " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::RENAME
+ (const string& mailboxName, const string& newMailboxName)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RENAME " << IMAPUtils::quoteString(mailboxName)
+ << " " << IMAPUtils::quoteString(newMailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::FETCH
+ (const messageSet& msgs, const std::vector <string>& params)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet())
+ cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+ else
+ cmd << "FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+
+ if (params.size() == 1)
+ {
+ cmd << " " << params[0];
+ }
+ else
+ {
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STORE
+ (const messageSet& msgs, const int mode, const std::vector <string>& flags)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet())
+ cmd << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+ else
+ cmd << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+
+ if (mode == message::FLAG_MODE_ADD)
+ cmd << " +FLAGS ";
+ else if (mode == message::FLAG_MODE_REMOVE)
+ cmd << " -FLAGS ";
+ else // if (mode == message::FLAG_MODE_SET)
+ cmd << " FLAGS ";
+
+ cmd << "(";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::APPEND
+ (const string& mailboxName, const std::vector <string>& flags,
+ vmime::datetime* date, const size_t size)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "APPEND " << IMAPUtils::quoteString(mailboxName);
+
+ if (!flags.empty())
+ {
+ cmd << " (";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i)
+ {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+ }
+
+ if (date != NULL)
+ cmd << " " << IMAPUtils::dateTime(*date);
+
+ cmd << " {" << size << "}";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::COPY
+ (const messageSet& msgs, const string& mailboxName)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet())
+ cmd << "UID COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+ else
+ cmd << "COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+
+ cmd << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SEARCH
+ (const std::vector <string>& keys, const vmime::charset* charset)
+{
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "SEARCH";
+
+ if (charset)
+ cmd << " CHARSET " << charset->getName();
+
+ for (size_t i = 0, n = keys.size() ; i < n ; ++i)
+ cmd << " " << keys[i];
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STARTTLS()
+{
+ return createCommand("STARTTLS");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CAPABILITY()
+{
+ return createCommand("CAPABILITY");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::NOOP()
+{
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::EXPUNGE()
+{
+ return createCommand("EXPUNGE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CLOSE()
+{
+ return createCommand("CLOSE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGOUT()
+{
+ return createCommand("LOGOUT");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::createCommand
+ (const string& text, const string& traceText)
+{
+ if (traceText.empty())
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, text));
+ else
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, traceText));
+}
+
+
+const string IMAPCommand::getText() const
+{
+ return m_text;
+}
+
+
+const string IMAPCommand::getTraceText() const
+{
+ return m_traceText;
+}
+
+
+void IMAPCommand::send(shared_ptr <IMAPConnection> conn)
+{
+ conn->sendCommand(dynamicCast <IMAPCommand>(shared_from_this()));
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
diff --git a/src/vmime/net/imap/IMAPCommand.hpp b/src/vmime/net/imap/IMAPCommand.hpp
new file mode 100644
index 00000000..c0a0d9b1
--- /dev/null
+++ b/src/vmime/net/imap/IMAPCommand.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2014 Vincent Richard <[email protected]>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+#include "vmime/datetime.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPConnection;
+
+
+/** An IMAP command that will be sent to the server.
+ */
+class VMIME_EXPORT IMAPCommand : public object
+{
+public:
+
+ static shared_ptr <IMAPCommand> LOGIN(const string& username, const string& password);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName, const string& initialResponse);
+ static shared_ptr <IMAPCommand> LIST(const string& refName, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SELECT(const bool readOnly, const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STATUS(const string& mailboxName, const std::vector <string>& attribs);
+ static shared_ptr <IMAPCommand> CREATE(const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> DELETE(const string& mailboxName);
+ static shared_ptr <IMAPCommand> RENAME(const string& mailboxName, const string& newMailboxName);
+ static shared_ptr <IMAPCommand> FETCH(const messageSet& msgs, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STORE(const messageSet& msgs, const int mode, const std::vector <string>& flags);
+ static shared_ptr <IMAPCommand> APPEND(const string& mailboxName, const std::vector <string>& flags, vmime::datetime* date, const size_t size);
+ static shared_ptr <IMAPCommand> COPY(const messageSet& msgs, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SEARCH(const std::vector <string>& keys, const vmime::charset* charset);
+ static shared_ptr <IMAPCommand> STARTTLS();
+ static shared_ptr <IMAPCommand> CAPABILITY();
+ static shared_ptr <IMAPCommand> NOOP();
+ static shared_ptr <IMAPCommand> EXPUNGE();
+ static shared_ptr <IMAPCommand> CLOSE();
+ static shared_ptr <IMAPCommand> LOGOUT();
+
+ /** Creates a new IMAP command with the specified text.
+ *
+ * @param text command text
+ * @param traceText trace text (if empty, command text is used)
+ * @return a new IMAPCommand object
+ */
+ static shared_ptr <IMAPCommand> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command over the specified connection.
+ *
+ * @param conn connection onto which the command will be sent
+ */
+ virtual void send(shared_ptr <IMAPConnection> conn);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any). This is the text that will be sent
+ * to the server.
+ *
+ * @return command text (eg. "LOGIN myusername mypassword")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "LOGIN myusername ***")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ IMAPCommand(const string& text, const string& traceText);
+ IMAPCommand(const IMAPCommand&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
diff --git a/src/vmime/net/imap/IMAPConnection.cpp b/src/vmime/net/imap/IMAPConnection.cpp
index 04705f6c..0bde327b 100644
--- a/src/vmime/net/imap/IMAPConnection.cpp
+++ b/src/vmime/net/imap/IMAPConnection.cpp
@@ -31,6 +31,7 @@
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
#include "vmime/exception.hpp"
#include "vmime/platform.hpp"
@@ -70,6 +71,7 @@ IMAPConnection::IMAPConnection(shared_ptr <IMAPStore> store, shared_ptr <securit
m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(null),
m_secured(false), m_firstTag(true), m_capabilitiesFetched(false), m_noModSeq(false)
{
+ m_tag = make_shared <IMAPTag>();
}
@@ -133,7 +135,6 @@ void IMAPConnection::connect()
m_socket->connect(address, port);
- m_tag = make_shared <IMAPTag>();
m_parser = make_shared <IMAPParser>(m_tag, m_socket, m_timeoutHandler);
@@ -259,8 +260,8 @@ void IMAPConnection::authenticate()
const string username = getAuthenticator()->getUsername();
const string password = getAuthenticator()->getPassword();
- send(true, "LOGIN " + IMAPUtils::quoteString(username)
- + " " + IMAPUtils::quoteString(password), true);
+ shared_ptr <IMAPConnection> conn = dynamicCast <IMAPConnection>(shared_from_this());
+ IMAPCommand::LOGIN(username, password)->send(conn);
std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
@@ -355,8 +356,7 @@ void IMAPConnection::authenticateSASL()
saslSession->init();
- std::ostringstream cmd;
- cmd << "AUTHENTICATE " << mech->getName();
+ shared_ptr <IMAPCommand> authCmd;
if (saslSession->getMechanism()->hasInitialResponse())
{
@@ -369,12 +369,16 @@ void IMAPConnection::authenticateSASL()
delete [] initialResp;
if (encodedInitialResp.empty())
- cmd << " =";
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), "=");
else
- cmd << " " << encodedInitialResp;
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), encodedInitialResp);
+ }
+ else
+ {
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName());
}
- send(true, cmd.str(), true);
+ authCmd->send(dynamicCast <IMAPConnection>(shared_from_this()));
for (bool cont = true ; cont ; )
{
@@ -428,7 +432,8 @@ void IMAPConnection::authenticateSASL()
(challenge, challengeLen, &resp, &respLen);
// Send response
- send(false, saslContext->encodeB64(resp, respLen), true);
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
// Server capabilities may change when logged in
invalidateCapabilities();
@@ -448,7 +453,7 @@ void IMAPConnection::authenticateSASL()
}
// Cancel SASL exchange
- send(false, "*", true);
+ sendRaw(utility::stringUtils::bytesFromString("*\r\n"), 3);
}
catch (...)
{
@@ -483,7 +488,7 @@ void IMAPConnection::startTLS()
{
try
{
- send(true, "STARTTLS", true);
+ IMAPCommand::STARTTLS()->send(dynamicCast <IMAPConnection>(shared_from_this()));
std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
@@ -582,7 +587,7 @@ void IMAPConnection::invalidateCapabilities()
void IMAPConnection::fetchCapabilities()
{
- send(true, "CAPABILITY", true);
+ IMAPCommand::CAPABILITY()->send(dynamicCast <IMAPConnection>(shared_from_this()));
std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
@@ -675,7 +680,7 @@ void IMAPConnection::internalDisconnect()
{
if (isConnected())
{
- send(true, "LOGOUT", true);
+ IMAPCommand::LOGOUT()->send(dynamicCast <IMAPConnection>(shared_from_this()));
m_socket->disconnect();
m_socket = null;
@@ -692,7 +697,7 @@ void IMAPConnection::internalDisconnect()
void IMAPConnection::initHierarchySeparator()
{
- send(true, "LIST \"\" \"\"", true);
+ IMAPCommand::LIST("", "")->send(dynamicCast <IMAPConnection>(shared_from_this()));
std::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
@@ -732,43 +737,17 @@ void IMAPConnection::initHierarchySeparator()
}
-void IMAPConnection::send(bool tag, const string& what, bool end)
+void IMAPConnection::sendCommand(shared_ptr <IMAPCommand> cmd)
{
- if (tag && !m_firstTag)
+ if (!m_firstTag)
++(*m_tag);
-#if VMIME_DEBUG
- std::ostringstream oss;
-
- if (tag)
- {
- oss << string(*m_tag);
- oss << " ";
- }
-
- oss << what;
-
- if (end)
- oss << "\r\n";
-
- m_socket->send(oss.str());
-#else
- if (tag)
- {
- m_socket->send(*m_tag);
- m_socket->send(" ");
- }
+ m_socket->send(*m_tag);
+ m_socket->send(" ");
+ m_socket->send(cmd->getText());
+ m_socket->send("\r\n");
- m_socket->send(what);
-
- if (end)
- {
- m_socket->send("\r\n");
- }
-#endif
-
- if (tag)
- m_firstTag = false;
+ m_firstTag = false;
}
@@ -826,6 +805,18 @@ shared_ptr <const socket> IMAPConnection::getSocket() const
}
+void IMAPConnection::setSocket(shared_ptr <socket> sok)
+{
+ m_socket = sok;
+}
+
+
+shared_ptr <IMAPTag> IMAPConnection::getTag()
+{
+ return m_tag;
+}
+
+
bool IMAPConnection::isMODSEQDisabled() const
{
return m_noModSeq;
diff --git a/src/vmime/net/imap/IMAPConnection.hpp b/src/vmime/net/imap/IMAPConnection.hpp
index a3156f25..da1b9ba4 100644
--- a/src/vmime/net/imap/IMAPConnection.hpp
+++ b/src/vmime/net/imap/IMAPConnection.hpp
@@ -48,6 +48,7 @@ namespace imap {
class IMAPTag;
class IMAPStore;
+class IMAPCommand;
class VMIME_EXPORT IMAPConnection : public object
@@ -79,7 +80,7 @@ public:
char hierarchySeparator() const;
- void send(bool tag, const string& what, bool end);
+ void sendCommand(shared_ptr <IMAPCommand> cmd);
void sendRaw(const byte_t* buffer, const size_t count);
IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL);
@@ -102,6 +103,9 @@ public:
shared_ptr <connectionInfos> getConnectionInfos() const;
shared_ptr <const socket> getSocket() const;
+ void setSocket(shared_ptr <socket> sok);
+
+ shared_ptr <IMAPTag> getTag();
bool isMODSEQDisabled() const;
void disableMODSEQ();
diff --git a/src/vmime/net/imap/IMAPFolder.cpp b/src/vmime/net/imap/IMAPFolder.cpp
index d02e5683..e602ea6e 100644
--- a/src/vmime/net/imap/IMAPFolder.cpp
+++ b/src/vmime/net/imap/IMAPFolder.cpp
@@ -35,6 +35,7 @@
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
#include "vmime/message.hpp"
@@ -157,20 +158,16 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
// S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
// S: A142 OK [READ-WRITE] SELECT completed
- std::ostringstream oss;
-
- if (mode == MODE_READ_ONLY)
- oss << "EXAMINE ";
- else
- oss << "SELECT ";
-
- oss << IMAPUtils::quoteString(IMAPUtils::pathToString
- (connection->hierarchySeparator(), getFullPath()));
+ std::vector <string> selectParams;
if (m_connection->hasCapability("CONDSTORE"))
- oss << " (CONDSTORE)";
+ selectParams.push_back("CONDSTORE");
- connection->send(true, oss.str(), true);
+ IMAPCommand::SELECT(
+ mode == MODE_READ_ONLY,
+ IMAPUtils::pathToString(connection->hierarchySeparator(), getFullPath()),
+ selectParams
+ )->send(connection);
// Read the response
std::auto_ptr <IMAPParser::response> resp(connection->readResponse());
@@ -289,7 +286,7 @@ void IMAPFolder::close(const bool expunge)
if (m_mode == MODE_READ_ONLY)
throw exceptions::operation_not_supported();
- oldConnection->send(true, "CLOSE", true);
+ IMAPCommand::CLOSE()->send(oldConnection);
}
// Close this folder connection
@@ -345,8 +342,7 @@ void IMAPFolder::create(const folderAttributes& attribs)
if (attribs.getType() & folderAttributes::TYPE_CONTAINS_FOLDERS)
mailbox += m_connection->hierarchySeparator();
- std::ostringstream oss;
- oss << "CREATE " << IMAPUtils::quoteString(mailbox);
+ std::vector <string> createParams;
if (attribs.getSpecialUse() != folderAttributes::SPECIALUSE_NONE)
{
@@ -354,7 +350,8 @@ void IMAPFolder::create(const folderAttributes& attribs)
throw exceptions::operation_not_supported();
// C: t2 CREATE MySpecial (USE (\Drafts \Sent))
- oss << "(USE (";
+ std::ostringstream oss;
+ oss << "USE (";
switch (attribs.getSpecialUse())
{
@@ -369,10 +366,12 @@ void IMAPFolder::create(const folderAttributes& attribs)
case folderAttributes::SPECIALUSE_IMPORTANT: oss << "\\Important"; break;
}
- oss << "))";
+ oss << ")";
+
+ createParams.push_back(oss.str());
}
- m_connection->send(true, oss.str(), true);
+ IMAPCommand::CREATE(mailbox, createParams)->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -407,10 +406,7 @@ void IMAPFolder::destroy()
const string mailbox = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath());
- std::ostringstream oss;
- oss << "DELETE " << IMAPUtils::quoteString(mailbox);
-
- m_connection->send(true, oss.str(), true);
+ IMAPCommand::DELETE(mailbox)->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -464,12 +460,8 @@ int IMAPFolder::testExistAndGetType()
//
// ==> NO, does not exist
- std::ostringstream oss;
- oss << "LIST \"\" ";
- oss << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), getFullPath()));
-
- m_connection->send(true, oss.str(), true);
+ IMAPCommand::LIST("", IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), getFullPath()))->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -560,14 +552,10 @@ std::vector <shared_ptr <message> > IMAPFolder::getMessages(const messageSet& ms
// S: * nnnn3 FETCH (UID uuuu3)
// S: . OK UID FETCH completed
- // Prepare command and arguments
- std::ostringstream cmd;
- cmd.imbue(std::locale::classic());
-
- cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs) << " UID";
+ std::vector <string> params;
+ params.push_back("UID");
- // Send the request
- m_connection->send(true, cmd.str(), true);
+ IMAPCommand::FETCH(msgs, params)->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -679,28 +667,22 @@ std::vector <shared_ptr <folder> > IMAPFolder::getFolders(const bool recursive)
// S: * LIST (\NoInferiors) "/" foo/bar/zap
// S: a005 OK LIST completed
- std::ostringstream oss;
- oss << "LIST ";
+ shared_ptr <IMAPCommand> cmd;
const string pathString = IMAPUtils::pathToString
(m_connection->hierarchySeparator(), getFullPath());
if (recursive)
{
- oss << IMAPUtils::quoteString(pathString);
- oss << " *";
+ cmd = IMAPCommand::LIST(pathString, "*");
}
else
{
- if (pathString.empty()) // don't add sep for root folder
- oss << "\"\"";
- else
- oss << IMAPUtils::quoteString(pathString + m_connection->hierarchySeparator());
-
- oss << " %";
+ cmd = IMAPCommand::LIST
+ (pathString.empty() ? "" : (pathString + m_connection->hierarchySeparator()), "%");
}
- m_connection->send(true, oss.str(), true);
+ cmd->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -783,10 +765,8 @@ void IMAPFolder::fetchMessages(std::vector <shared_ptr <message> >& msg, const f
}
// Send the request
- const string command = IMAPUtils::buildFetchRequest
- (m_connection, messageSet::byNumber(list), options);
-
- m_connection->send(true, command, true);
+ IMAPUtils::buildFetchCommand
+ (m_connection, messageSet::byNumber(list), options)->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -881,10 +861,8 @@ std::vector <shared_ptr <message> > IMAPFolder::getAndFetchMessages
attribsWithUID.add(fetchAttributes::UID);
// Send the request
- const string command = IMAPUtils::buildFetchRequest
- (m_connection, msgs, attribsWithUID);
-
- m_connection->send(true, command, true);
+ IMAPUtils::buildFetchCommand
+ (m_connection, msgs, attribsWithUID)->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1016,19 +994,11 @@ void IMAPFolder::deleteMessages(const messageSet& msgs)
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- if (msgs.isUIDSet())
- command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
- else
- command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
-
- command << " +FLAGS (\\Deleted)";
-
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::STORE(
+ msgs, message::FLAG_MODE_ADD,
+ IMAPUtils::messageFlagList(message::FLAG_DELETED)
+ )->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1046,31 +1016,12 @@ void IMAPFolder::deleteMessages(const messageSet& msgs)
void IMAPFolder::setMessageFlags(const messageSet& msgs, const int flags, const int mode)
{
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- if (msgs.isUIDSet())
- command << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
- else
- command << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
-
- switch (mode)
- {
- case message::FLAG_MODE_ADD: command << " +FLAGS "; break;
- case message::FLAG_MODE_REMOVE: command << " -FLAGS "; break;
- default:
- case message::FLAG_MODE_SET: command << " FLAGS "; break;
- }
-
- const string flagList = IMAPUtils::messageFlagList(flags);
+ const std::vector <string> flagList = IMAPUtils::messageFlagList(flags);
if (!flagList.empty())
{
- command << flagList;
-
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::STORE(msgs, mode, flagList)->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1116,31 +1067,11 @@ messageSet IMAPFolder::addMessage
else if (m_mode == MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- command << "APPEND " << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), getFullPath())) << ' ';
-
- const string flagList = IMAPUtils::messageFlagList(flags);
-
- if (flags != -1 && !flagList.empty())
- {
- command << flagList;
- command << ' ';
- }
-
- if (date != NULL)
- {
- command << IMAPUtils::dateTime(*date);
- command << ' ';
- }
-
- command << '{' << size << '}';
-
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::APPEND(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::messageFlagList(flags), date, size
+ )->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1191,7 +1122,7 @@ messageSet IMAPFolder::addMessage
progress->progress(current, total);
}
- m_connection->send(false, "", true);
+ m_connection->sendRaw(utility::stringUtils::bytesFromString("\r\n"), 2);
if (progress)
progress->stop(total);
@@ -1230,7 +1161,7 @@ void IMAPFolder::expunge()
throw exceptions::illegal_state("Folder is read-only");
// Send the request
- m_connection->send(true, "EXPUNGE", true);
+ IMAPCommand::EXPUNGE()->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1259,18 +1190,11 @@ void IMAPFolder::rename(const folder::path& newPath)
else if (!store->isValidFolderName(newPath.getLastComponent()))
throw exceptions::invalid_folder_name();
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- command << "RENAME ";
- command << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), getFullPath())) << " ";
- command << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), newPath));
-
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::RENAME(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), newPath)
+ )->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1327,16 +1251,11 @@ messageSet IMAPFolder::copyMessages(const folder::path& dest, const messageSet&
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- command << "COPY " << IMAPUtils::messageSetToSequenceSet(set) << " ";
- command << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), dest));
-
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::COPY(
+ set,
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), dest)
+ )->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1379,24 +1298,22 @@ shared_ptr <folderStatus> IMAPFolder::getStatus()
if (!store)
throw exceptions::illegal_state("Store disconnected");
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
+ // Build the attributes list
+ std::vector <string> attribs;
- command << "STATUS ";
- command << IMAPUtils::quoteString(IMAPUtils::pathToString
- (m_connection->hierarchySeparator(), getFullPath()));
- command << " (";
-
- command << "MESSAGES" << ' ' << "UNSEEN" << ' ' << "UIDNEXT" << ' ' << "UIDVALIDITY";
+ attribs.push_back("MESSAGES");
+ attribs.push_back("UNSEEN");
+ attribs.push_back("UIDNEXT");
+ attribs.push_back("UIDVALIDITY");
if (m_connection->hasCapability("CONDSTORE"))
- command << ' ' << "HIGHESTMODSEQ";
-
- command << ")";
+ attribs.push_back("HIGHESTMODSEQ");
// Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::STATUS(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ attribs
+ )->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1443,7 +1360,7 @@ void IMAPFolder::noop()
if (!store)
throw exceptions::illegal_state("Store disconnected");
- m_connection->send(true, "NOOP", true);
+ IMAPCommand::NOOP()->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1459,15 +1376,15 @@ void IMAPFolder::noop()
std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid)
{
- std::vector<int> v;
-
- std::ostringstream command;
- command.imbue(std::locale::classic());
+ // Send the request
+ std::ostringstream uidSearchKey;
+ uidSearchKey.imbue(std::locale::classic());
+ uidSearchKey << "UID " << uid << ":*";
- command << "SEARCH UID " << uid << ":*";
+ std::vector <string> searchKeys;
+ searchKeys.push_back(uidSearchKey.str());
- // Send the request
- m_connection->send(true, command.str(), true);
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL)->send(m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
@@ -1480,6 +1397,7 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid&
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data();
+ std::vector <int> seqNumbers;
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
@@ -1505,13 +1423,13 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid&
it != mailboxData->search_nz_number_list().end();
++it)
{
- v.push_back((*it)->value());
+ seqNumbers.push_back((*it)->value());
}
}
processStatusUpdate(resp.get());
- return v;
+ return seqNumbers;
}
diff --git a/src/vmime/net/imap/IMAPMessage.cpp b/src/vmime/net/imap/IMAPMessage.cpp
index 1934d717..aa6b45ec 100644
--- a/src/vmime/net/imap/IMAPMessage.cpp
+++ b/src/vmime/net/imap/IMAPMessage.cpp
@@ -299,15 +299,7 @@ void IMAPMessage::extractImpl
}
}
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- if (m_uid.empty())
- command << "FETCH " << m_num << " BODY";
- else
- command << "UID FETCH " << m_uid << " BODY";
-
+ // Build the body descriptor for FETCH
/*
BODY[] header + body
BODY.PEEK[] header + body (peek)
@@ -316,43 +308,53 @@ void IMAPMessage::extractImpl
BODY[TEXT] body
BODY.PEEK[TEXT] body (peek)
*/
+ std::ostringstream bodyDesc;
+ bodyDesc.imbue(std::locale::classic());
+
+ bodyDesc << "BODY";
if (extractFlags & EXTRACT_PEEK)
- command << ".PEEK";
+ bodyDesc << ".PEEK";
- command << "[";
+ bodyDesc << "[";
if (section.str().empty())
{
// header + body
if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY))
- command << "";
+ bodyDesc << "";
// body only
else if (extractFlags & EXTRACT_BODY)
- command << "TEXT";
+ bodyDesc << "TEXT";
// header only
else if (extractFlags & EXTRACT_HEADER)
- command << "HEADER";
+ bodyDesc << "HEADER";
}
else
{
- command << section.str();
+ bodyDesc << section.str();
// header + body
if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY))
throw exceptions::operation_not_supported();
// header only
else if (extractFlags & EXTRACT_HEADER)
- command << ".MIME"; // "MIME" not "HEADER" for parts
+ bodyDesc << ".MIME"; // "MIME" not "HEADER" for parts
}
- command << "]";
+ bodyDesc << "]";
if (start != 0 || length != static_cast <size_t>(-1))
- command << "<" << start << "." << length << ">";
+ bodyDesc << "<" << start << "." << length << ">";
+
+ std::vector <std::string> fetchParams;
+ fetchParams.push_back(bodyDesc.str());
// Send the request
- constCast <IMAPFolder>(folder)->m_connection->send(true, command.str(), true);
+ IMAPCommand::FETCH(
+ m_uid.empty() ? messageSet::byNumber(m_num) : messageSet::byUID(m_uid),
+ fetchParams
+ )->send(constCast <IMAPFolder>(folder)->m_connection);
// Get the response
std::auto_ptr <IMAPParser::response> resp
diff --git a/src/vmime/net/imap/IMAPStore.cpp b/src/vmime/net/imap/IMAPStore.cpp
index 031ebf24..a2930c66 100644
--- a/src/vmime/net/imap/IMAPStore.cpp
+++ b/src/vmime/net/imap/IMAPStore.cpp
@@ -31,6 +31,7 @@
#include "vmime/net/imap/IMAPFolder.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
#include "vmime/exception.hpp"
#include "vmime/platform.hpp"
@@ -192,7 +193,7 @@ void IMAPStore::noop()
if (!isConnected())
throw exceptions::not_connected();
- m_connection->send(true, "NOOP", true);
+ IMAPCommand::NOOP()->send(m_connection);
std::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
diff --git a/src/vmime/net/imap/IMAPUtils.cpp b/src/vmime/net/imap/IMAPUtils.cpp
index 519e413b..0bb086ff 100644
--- a/src/vmime/net/imap/IMAPUtils.cpp
+++ b/src/vmime/net/imap/IMAPUtils.cpp
@@ -488,35 +488,21 @@ int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list* list)
}
-const string IMAPUtils::messageFlagList(const int flags)
+// static
+const std::vector <string> IMAPUtils::messageFlagList(const int flags)
{
std::vector <string> flagList;
+ if (flags == -1)
+ return flagList; // default flags
+
if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered");
if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged");
if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted");
if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen");
if (flags & message::FLAG_DRAFT) flagList.push_back("\\Draft");
- if (!flagList.empty())
- {
- std::ostringstream res;
- res.imbue(std::locale::classic());
-
- res << "(";
-
- if (flagList.size() >= 2)
- {
- std::copy(flagList.begin(), flagList.end() - 1,
- std::ostream_iterator <string>(res, " "));
- }
-
- res << *(flagList.end() - 1) << ")";
-
- return (res.str());
- }
-
- return "";
+ return flagList;
}
@@ -590,7 +576,7 @@ const string IMAPUtils::dateTime(const vmime::datetime& date)
// static
-const string IMAPUtils::buildFetchRequest
+shared_ptr <IMAPCommand> IMAPUtils::buildFetchCommand
(shared_ptr <IMAPConnection> cnt, const messageSet& msgs, const fetchAttributes& options)
{
// Example:
@@ -659,25 +645,7 @@ const string IMAPUtils::buildFetchRequest
}
}
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- if (msgs.isUIDSet())
- command << "UID FETCH " << messageSetToSequenceSet(msgs) << " (";
- else
- command << "FETCH " << messageSetToSequenceSet(msgs) << " (";
-
- for (std::vector <string>::const_iterator it = items.begin() ;
- it != items.end() ; ++it)
- {
- if (it != items.begin()) command << " ";
- command << *it;
- }
-
- command << ")";
-
- return command.str();
+ return IMAPCommand::FETCH(msgs, items);
}
diff --git a/src/vmime/net/imap/IMAPUtils.hpp b/src/vmime/net/imap/IMAPUtils.hpp
index 2a7efbb0..61b45e48 100644
--- a/src/vmime/net/imap/IMAPUtils.hpp
+++ b/src/vmime/net/imap/IMAPUtils.hpp
@@ -38,6 +38,7 @@
#include "vmime/net/message.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
#include "vmime/mailboxList.hpp"
@@ -79,7 +80,7 @@ public:
static int messageFlagsFromFlags(const IMAPParser::flag_list* list);
- static const string messageFlagList(const int flags);
+ static const std::vector <string> messageFlagList(const int flags);
/** Format a date/time to IMAP date/time format.
*
@@ -96,7 +97,7 @@ public:
* @param options fetch options
* @return fetch request
*/
- static const string buildFetchRequest
+ static shared_ptr <IMAPCommand> buildFetchCommand
(shared_ptr <IMAPConnection> cnt, const messageSet& msgs, const fetchAttributes& options);
/** Convert a parser-style address list to a mailbox list.
diff --git a/src/vmime/utility/stringUtils.hpp b/src/vmime/utility/stringUtils.hpp
index 7d9925e2..a3062af8 100644
--- a/src/vmime/utility/stringUtils.hpp
+++ b/src/vmime/utility/stringUtils.hpp
@@ -53,6 +53,26 @@ public:
return string(reinterpret_cast <const char*>(data), count);
}
+ /** Casts a string to bytes.
+ *
+ * @param str string
+ * @return pointer to the first byte of the string
+ */
+ static const byte_t* bytesFromString(const string& str)
+ {
+ return reinterpret_cast <const byte_t*>(str.data());
+ }
+
+ /** Casts a NULL-terminated string to bytes.
+ *
+ * @param str string
+ * @return pointer to the first byte of the string
+ */
+ static const byte_t* bytesFromString(const char* str)
+ {
+ return reinterpret_cast <const byte_t*>(str);
+ }
+
/** Appends bytes to a string.
*
* @param str string to which append data
diff --git a/tests/net/imap/IMAPCommandTest.cpp b/tests/net/imap/IMAPCommandTest.cpp
new file mode 100644
index 00000000..8183dfa7
--- /dev/null
+++ b/tests/net/imap/IMAPCommandTest.cpp
@@ -0,0 +1,484 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2014 Vincent Richard <[email protected]>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+
+
+using namespace vmime::net::imap;
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPCommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testLOGIN)
+ VMIME_TEST(testAUTHENTICATE)
+ VMIME_TEST(testAUTHENTICATE_InitialResponse)
+ VMIME_TEST(testLIST)
+ VMIME_TEST(testSELECT)
+ VMIME_TEST(testSTATUS)
+ VMIME_TEST(testCREATE)
+ VMIME_TEST(testDELETE)
+ VMIME_TEST(testRENAME)
+ VMIME_TEST(testFETCH)
+ VMIME_TEST(testSTORE)
+ VMIME_TEST(testAPPEND)
+ VMIME_TEST(testCOPY)
+ VMIME_TEST(testSEARCH)
+ VMIME_TEST(testSTARTTLS)
+ VMIME_TEST(testCAPABILITY)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testEXPUNGE)
+ VMIME_TEST(testCLOSE)
+ VMIME_TEST(testLOGOUT)
+ VMIME_TEST(testSend)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testLOGIN()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGIN("username", "password");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGIN username password", cmd->getText());
+ VASSERT_EQ("Trace Text", "LOGIN <username> <password>", cmd->getTraceText());
+ }
+
+ void testAUTHENTICATE()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText());
+ }
+
+ void testAUTHENTICATE_InitialResponse()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism initial-response", cmd->getText());
+ }
+
+ void testLIST()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LIST("ref-name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST ref-name mailbox-name", cmd->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote = IMAPCommand::LIST("ref name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "LIST \"ref name\" mailbox-name", cmdQuote->getText());
+ }
+
+ void testSELECT()
+ {
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRO = IMAPCommand::SELECT
+ (/* readOnly */ true, "mailbox-name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdRO);
+ VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdROQuote = IMAPCommand::SELECT
+ (/* readOnly */ true, "mailbox name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdROQuote);
+ VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRW = IMAPCommand::SELECT
+ (/* readOnly */ false, "mailbox-name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdRW);
+ VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWParams = IMAPCommand::SELECT
+ (/* readOnly */ false, "mailbox-name", params);
+
+ VASSERT_NOT_NULL("Not null", cmdRWParams);
+ VASSERT_EQ("Text", "SELECT mailbox-name (param-1 param-2)", cmdRWParams->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWQuote = IMAPCommand::SELECT
+ (/* readOnly */ false, "mailbox name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdRWQuote);
+ VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText());
+ }
+
+ void testSTATUS()
+ {
+ std::vector <vmime::string> attribs;
+ attribs.push_back("attrib-1");
+ attribs.push_back("attrib-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::STATUS("mailbox-name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STATUS mailbox-name (attrib-1 attrib-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::STATUS("mailbox name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "STATUS \"mailbox name\" (attrib-1 attrib-2)", cmdQuote->getText());
+ }
+
+ void testCREATE()
+ {
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::CREATE("mailbox-name", params);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CREATE mailbox-name (param-1 param-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::CREATE("mailbox name", params);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "CREATE \"mailbox name\" (param-1 param-2)", cmdQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNoParam =
+ IMAPCommand::CREATE("mailbox-name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdNoParam);
+ VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText());
+ }
+
+ void testDELETE()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::DELETE("mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::DELETE("mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testRENAME()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::RENAME("mailbox-name", "new-mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RENAME mailbox-name new-mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::RENAME("mailbox name", "new mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "RENAME \"mailbox name\" \"new mailbox name\"", cmdQuote->getText());
+ }
+
+ void testFETCH()
+ {
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "FETCH 42 (param-1 param-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "FETCH 42:47 (param-1 param-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID FETCH 42 (param-1 param-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID FETCH 42:47 (param-1 param-2)", cmdUIDs->getText());
+ }
+
+ void testSTORE()
+ {
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum = IMAPCommand::STORE
+ (vmime::net::messageSet::byNumber(42), vmime::net::message::FLAG_MODE_SET, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "STORE 42 FLAGS (flag-1 flag-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums = IMAPCommand::STORE
+ (vmime::net::messageSet::byNumber(42, 47), vmime::net::message::FLAG_MODE_SET, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "STORE 42:47 FLAGS (flag-1 flag-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID = IMAPCommand::STORE
+ (vmime::net::messageSet::byUID(42), vmime::net::message::FLAG_MODE_SET, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID STORE 42 FLAGS (flag-1 flag-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs = IMAPCommand::STORE
+ (vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_SET, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID STORE 42:47 FLAGS (flag-1 flag-2)", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdAdd = IMAPCommand::STORE
+ (vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_ADD, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdAdd);
+ VASSERT_EQ("Text", "UID STORE 42:47 +FLAGS (flag-1 flag-2)", cmdAdd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRem = IMAPCommand::STORE
+ (vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_REMOVE, flags);
+
+ VASSERT_NOT_NULL("Not null", cmdRem);
+ VASSERT_EQ("Text", "UID STORE 42:47 -FLAGS (flag-1 flag-2)", cmdRem->getText());
+ }
+
+ void testAPPEND()
+ {
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::APPEND("mailbox-name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "APPEND mailbox-name (flag-1 flag-2) {1234}", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::APPEND("mailbox name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) {1234}", cmdQuote->getText());
+
+
+ vmime::datetime date(2014, 3, 15, 23, 11, 47, vmime::datetime::GMT2);
+ vmime::shared_ptr <IMAPCommand> cmdDate =
+ IMAPCommand::APPEND("mailbox name", flags, &date, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdDate);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) \"15-Mar-2014 23:11:47 +0200\" {1234}", cmdDate->getText());
+ }
+
+ void testCOPY()
+ {
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "COPY 42 mailbox-name", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "COPY 42:47 mailbox-name", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID COPY 42 mailbox-name", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID COPY 42:47 mailbox-name", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "COPY 42:47 \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testSEARCH()
+ {
+ std::vector <vmime::string> searchKeys;
+ searchKeys.push_back("search-key-1");
+ searchKeys.push_back("search-key-2");
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "SEARCH search-key-1 search-key-2", cmd->getText());
+
+
+ vmime::charset cset("test-charset");
+
+ vmime::shared_ptr <IMAPCommand> cmdCset =
+ IMAPCommand::SEARCH(searchKeys, &cset);
+
+ VASSERT_NOT_NULL("Not null", cmdCset);
+ VASSERT_EQ("Text", "SEARCH CHARSET test-charset search-key-1 search-key-2", cmdCset->getText());
+ }
+
+ void testSTARTTLS()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::STARTTLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STARTTLS", cmd->getText());
+ }
+
+ void testCAPABILITY()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CAPABILITY();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CAPABILITY", cmd->getText());
+ }
+
+ void testNOOP()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testEXPUNGE()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::EXPUNGE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "EXPUNGE", cmd->getText());
+ }
+
+ void testCLOSE()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CLOSE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CLOSE", cmd->getText());
+ }
+
+ void testLOGOUT()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGOUT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGOUT", cmd->getText());
+ }
+
+ void testSend()
+ {
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <vmime::net::session> sess =
+ vmime::make_shared <vmime::net::session>();
+
+ vmime::shared_ptr <vmime::security::authenticator> auth =
+ vmime::make_shared <vmime::security::defaultAuthenticator>();
+
+ vmime::shared_ptr <IMAPStore> store =
+ vmime::make_shared <IMAPStore>(sess, auth, /* secured */ false);
+
+ vmime::shared_ptr <IMAPConnection> conn =
+ vmime::make_shared <IMAPConnection>(store, auth);
+
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ conn->setSocket(sok);
+
+ cmd->send(conn);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", vmime::string(*conn->getTag()) + " MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END