aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/pop3/POP3Store.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/pop3/POP3Store.cpp')
-rw-r--r--src/net/pop3/POP3Store.cpp543
1 files changed, 29 insertions, 514 deletions
diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp
index 0efeec5f..6ff404e2 100644
--- a/src/net/pop3/POP3Store.cpp
+++ b/src/net/pop3/POP3Store.cpp
@@ -33,42 +33,17 @@
#include "vmime/net/pop3/POP3Response.hpp"
#include "vmime/exception.hpp"
-#include "vmime/platform.hpp"
-#include "vmime/messageId.hpp"
-#include "vmime/security/digest/messageDigestFactory.hpp"
-
-#include "vmime/net/defaultConnectionInfos.hpp"
-
-#if VMIME_HAVE_SASL_SUPPORT
- #include "vmime/security/sasl/SASLContext.hpp"
-#endif // VMIME_HAVE_SASL_SUPPORT
-
-#if VMIME_HAVE_TLS_SUPPORT
- #include "vmime/net/tls/TLSSession.hpp"
- #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
-#endif // VMIME_HAVE_TLS_SUPPORT
#include <algorithm>
-// Helpers for service properties
-#define GET_PROPERTY(type, prop) \
- (getInfos().getPropertyValue <type>(getSession(), \
- dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop))
-#define HAS_PROPERTY(prop) \
- (getInfos().hasProperty(getSession(), \
- dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop))
-
-
namespace vmime {
namespace net {
namespace pop3 {
POP3Store::POP3Store(ref <session> sess, ref <security::authenticator> auth, const bool secured)
- : store(sess, getInfosInstance(), auth), m_socket(NULL),
- m_authentified(false), m_timeoutHandler(NULL),
- m_isPOP3S(secured), m_secured(false)
+ : store(sess, getInfosInstance(), auth), m_isPOP3S(secured)
{
}
@@ -79,8 +54,6 @@ POP3Store::~POP3Store()
{
if (isConnected())
disconnect();
- else if (m_socket)
- internalDisconnect();
}
catch (vmime::exception&)
{
@@ -136,458 +109,54 @@ void POP3Store::connect()
if (isConnected())
throw exceptions::already_connected();
- const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS);
- const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT);
-
- // Create the time-out handler
- if (getTimeoutHandlerFactory())
- m_timeoutHandler = getTimeoutHandlerFactory()->create();
-
- // Create and connect the socket
- m_socket = getSocketFactory()->create(m_timeoutHandler);
-
-#if VMIME_HAVE_TLS_SUPPORT
- if (m_isPOP3S) // dedicated port/POP3S
- {
- ref <tls::TLSSession> tlsSession =
- tls::TLSSession::create(getCertificateVerifier());
-
- ref <tls::TLSSocket> tlsSocket =
- tlsSession->getSocket(m_socket);
-
- m_socket = tlsSocket;
-
- m_secured = true;
- m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
- }
- else
-#endif // VMIME_HAVE_TLS_SUPPORT
- {
- m_cntInfos = vmime::create <defaultConnectionInfos>(address, port);
- }
-
- m_socket->connect(address, port);
+ m_connection = vmime::create <POP3Connection>
+ (thisRef().dynamicCast <POP3Store>(), getAuthenticator());
- // Connection
- //
- // eg: C: <connection to server>
- // --- S: +OK MailSite POP3 Server 5.3.4.0 Ready <[email protected]>
-
- ref <POP3Response> response = readResponse();
-
- if (!response->isSuccess())
+ try
{
- internalDisconnect();
- throw exceptions::connection_greeting_error(response->getFirstLine());
+ m_connection->connect();
}
-
-#if VMIME_HAVE_TLS_SUPPORT
- // Setup secured connection, if requested
- const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
- && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
- const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
- && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
-
- if (!m_isPOP3S && tls) // only if not POP3S
+ catch (std::exception&)
{
- try
- {
- startTLS();
- }
- // Non-fatal error
- catch (exceptions::command_error&)
- {
- if (tlsRequired)
- {
- throw;
- }
- else
- {
- // TLS is not required, so don't bother
- }
- }
- // Fatal error
- catch (...)
- {
- throw;
- }
+ m_connection = NULL;
+ throw;
}
-#endif // VMIME_HAVE_TLS_SUPPORT
-
- // Start authentication process
- authenticate(messageId(response->getText()));
}
-void POP3Store::authenticate(const messageId& randomMID)
+bool POP3Store::isPOP3S() const
{
- getAuthenticator()->setService(thisRef().dynamicCast <service>());
-
-#if VMIME_HAVE_SASL_SUPPORT
- // First, try SASL authentication
- if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
- {
- try
- {
- authenticateSASL();
-
- m_authentified = true;
- return;
- }
- catch (exceptions::authentication_error& e)
- {
- if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
- {
- // Can't fallback on APOP/normal authentication
- internalDisconnect();
- throw e;
- }
- else
- {
- // Ignore, will try APOP/normal authentication
- }
- }
- catch (exception& e)
- {
- internalDisconnect();
- throw e;
- }
- }
-#endif // VMIME_HAVE_SASL_SUPPORT
-
- // Secured authentication with APOP (if requested and if available)
- //
- // eg: C: APOP vincent <digest>
- // --- S: +OK vincent is a valid mailbox
-
- const string username = getAuthenticator()->getUsername();
- const string password = getAuthenticator()->getPassword();
-
- ref <POP3Response> response;
-
- if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))
- {
- if (randomMID.getLeft().length() != 0 &&
- randomMID.getRight().length() != 0)
- {
- // <digest> is the result of MD5 applied to "<message-id>password"
- ref <security::digest::messageDigest> md5 =
- security::digest::messageDigestFactory::getInstance()->create("md5");
-
- md5->update(randomMID.generate() + password);
- md5->finalize();
-
- sendRequest(POP3Command::APOP(username, md5->getHexDigest()));
- response = readResponse();
-
- if (response->isSuccess())
- {
- m_authentified = true;
- return;
- }
- else
- {
- // Some servers close the connection after an unsuccessful APOP
- // command, so the fallback may not always work...
- //
- // S: +OK Qpopper (version 4.0.5) at xxx starting. <30396.1126730747@xxx>
- // C: APOP plop c5e0a87d088ec71d60e32692d4c5bdf4
- // S: -ERR [AUTH] Password supplied for "plop" is incorrect.
- // S: +OK Pop server at xxx signing off.
- // [Connection closed by foreign host.]
-
- if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
- {
- // Can't fallback on basic authentication
- internalDisconnect();
- throw exceptions::authentication_error(response->getFirstLine());
- }
-
- // Ensure connection is valid (cf. note above)
- try
- {
- sendRequest(POP3Command::NOOP());
- readResponse();
- }
- catch (exceptions::socket_exception&)
- {
- internalDisconnect();
- throw exceptions::authentication_error(response->getFirstLine());
- }
- }
- }
- else
- {
- // APOP not supported
- if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
- {
- // Can't fallback on basic authentication
- internalDisconnect();
- throw exceptions::authentication_error("APOP not supported");
- }
- }
- }
-
- // Basic authentication
- //
- // eg: C: USER vincent
- // --- S: +OK vincent is a valid mailbox
- //
- // C: PASS couic
- // S: +OK vincent's maildrop has 2 messages (320 octets)
- sendRequest(POP3Command::USER(username));
- response = readResponse();
-
- if (!response->isSuccess())
- {
- internalDisconnect();
- throw exceptions::authentication_error(response->getFirstLine());
- }
-
- sendRequest(POP3Command::PASS(password));
- response = readResponse();
-
- if (!response->isSuccess())
- {
- internalDisconnect();
- throw exceptions::authentication_error(response->getFirstLine());
- }
-
- m_authentified = true;
+ return m_isPOP3S;
}
-#if VMIME_HAVE_SASL_SUPPORT
-
-void POP3Store::authenticateSASL()
+bool POP3Store::isConnected() const
{
- if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())
- throw exceptions::authentication_error("No SASL authenticator available.");
-
- std::vector <string> capa = getCapabilities();
- std::vector <string> saslMechs;
-
- for (unsigned int i = 0 ; i < capa.size() ; ++i)
- {
- const string& x = capa[i];
-
- // C: CAPA
- // S: +OK List of capabilities follows
- // S: LOGIN-DELAY 0
- // S: PIPELINING
- // S: UIDL
- // S: ...
- // S: SASL DIGEST-MD5 CRAM-MD5 <-----
- // S: EXPIRE NEVER
- // S: ...
-
- if (x.length() > 5 &&
- (x[0] == 'S' || x[0] == 's') &&
- (x[1] == 'A' || x[1] == 'a') &&
- (x[2] == 'S' || x[2] == 's') &&
- (x[3] == 'L' || x[3] == 'l') &&
- (x[4] == ' ' || x[4] == '\t'))
- {
- const string list(x.begin() + 5, x.end());
-
- std::istringstream iss(list);
- string mech;
-
- while (iss >> mech)
- saslMechs.push_back(mech);
- }
- }
-
- if (saslMechs.empty())
- throw exceptions::authentication_error("No SASL mechanism available.");
-
- std::vector <ref <security::sasl::SASLMechanism> > mechList;
-
- ref <security::sasl::SASLContext> saslContext =
- vmime::create <security::sasl::SASLContext>();
-
- for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)
- {
- try
- {
- mechList.push_back
- (saslContext->createMechanism(saslMechs[i]));
- }
- catch (exceptions::no_such_mechanism&)
- {
- // Ignore mechanism
- }
- }
-
- if (mechList.empty())
- throw exceptions::authentication_error("No SASL mechanism available.");
-
- // Try to suggest a mechanism among all those supported
- ref <security::sasl::SASLMechanism> suggestedMech =
- saslContext->suggestMechanism(mechList);
-
- if (!suggestedMech)
- throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
-
- // Allow application to choose which mechanisms to use
- mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->
- getAcceptableMechanisms(mechList, suggestedMech);
-
- if (mechList.empty())
- throw exceptions::authentication_error("No SASL mechanism available.");
-
- // Try each mechanism in the list in turn
- for (unsigned int i = 0 ; i < mechList.size() ; ++i)
- {
- ref <security::sasl::SASLMechanism> mech = mechList[i];
-
- ref <security::sasl::SASLSession> saslSession =
- saslContext->createSession("pop3", getAuthenticator(), mech);
-
- saslSession->init();
-
- sendRequest(POP3Command::AUTH(mech->getName()));
-
- for (bool cont = true ; cont ; )
- {
- ref <POP3Response> response = readResponse();
-
- switch (response->getCode())
- {
- case POP3Response::CODE_OK:
- {
- m_socket = saslSession->getSecuredSocket(m_socket);
- return;
- }
- case POP3Response::CODE_READY:
- {
- byte_t* challenge = 0;
- long challengeLen = 0;
-
- byte_t* resp = 0;
- long respLen = 0;
-
- try
- {
- // Extract challenge
- saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
-
- // Prepare response
- saslSession->evaluateChallenge
- (challenge, challengeLen, &resp, &respLen);
-
- // Send response
- m_socket->send(saslContext->encodeB64(resp, respLen) + "\r\n");
- }
- catch (exceptions::sasl_exception& e)
- {
- if (challenge)
- {
- delete [] challenge;
- challenge = NULL;
- }
-
- if (resp)
- {
- delete [] resp;
- resp = NULL;
- }
-
- // Cancel SASL exchange
- m_socket->sendRaw("*\r\n", 3);
- }
- catch (...)
- {
- if (challenge)
- delete [] challenge;
-
- if (resp)
- delete [] resp;
-
- throw;
- }
-
- if (challenge)
- delete [] challenge;
-
- if (resp)
- delete [] resp;
-
- break;
- }
- default:
-
- cont = false;
- break;
- }
- }
- }
-
- throw exceptions::authentication_error
- ("Could not authenticate using SASL: all mechanisms failed.");
+ return m_connection && m_connection->isConnected();
}
-#endif // VMIME_HAVE_SASL_SUPPORT
-
-#if VMIME_HAVE_TLS_SUPPORT
-
-void POP3Store::startTLS()
+bool POP3Store::isSecuredConnection() const
{
- try
- {
- sendRequest(POP3Command::STLS());
+ if (m_connection == NULL)
+ return false;
- ref <POP3Response> response = readResponse();
-
- if (!response->isSuccess())
- throw exceptions::command_error("STLS", response->getFirstLine());
-
- ref <tls::TLSSession> tlsSession =
- tls::TLSSession::create(getCertificateVerifier());
-
- ref <tls::TLSSocket> tlsSocket =
- tlsSession->getSocket(m_socket);
-
- tlsSocket->handshake(m_timeoutHandler);
-
- m_socket = tlsSocket;
-
- m_secured = true;
- m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>
- (m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket);
- }
- catch (exceptions::command_error&)
- {
- // Non-fatal error
- throw;
- }
- catch (exception&)
- {
- // Fatal error
- internalDisconnect();
- throw;
- }
+ return m_connection->isSecuredConnection();
}
-#endif // VMIME_HAVE_TLS_SUPPORT
-
-bool POP3Store::isConnected() const
+ref <connectionInfos> POP3Store::getConnectionInfos() const
{
- return (m_socket && m_socket->isConnected() && m_authentified);
-}
-
+ if (m_connection == NULL)
+ return NULL;
-bool POP3Store::isSecuredConnection() const
-{
- return m_secured;
+ return m_connection->getConnectionInfos();
}
-ref <connectionInfos> POP3Store::getConnectionInfos() const
+ref <POP3Connection> POP3Store::getConnection()
{
- return m_cntInfos;
+ return m_connection;
}
@@ -596,12 +165,6 @@ void POP3Store::disconnect()
if (!isConnected())
throw exceptions::not_connected();
- internalDisconnect();
-}
-
-
-void POP3Store::internalDisconnect()
-{
for (std::list <POP3Folder*>::iterator it = m_folders.begin() ;
it != m_folders.end() ; ++it)
{
@@ -610,74 +173,26 @@ void POP3Store::internalDisconnect()
m_folders.clear();
- try
- {
- sendRequest(POP3Command::QUIT());
- readResponse();
- }
- catch (exception&)
- {
- // Not important
- }
-
- m_socket->disconnect();
- m_socket = NULL;
- m_timeoutHandler = NULL;
-
- m_authentified = false;
-
- m_secured = false;
- m_cntInfos = NULL;
+ m_connection->disconnect();
+ m_connection = NULL;
}
void POP3Store::noop()
{
- sendRequest(POP3Command::NOOP());
+ if (!m_connection)
+ throw exceptions::not_connected();
+
+ POP3Command::NOOP()->send(m_connection);
- ref <POP3Response> response =
- readResponse();
+ ref <POP3Response> response = POP3Response::readResponse(m_connection);
if (!response->isSuccess())
throw exceptions::command_error("NOOP", response->getFirstLine());
}
-const std::vector <string> POP3Store::getCapabilities()
-{
- sendRequest(POP3Command::CAPA());
-
- ref <POP3Response> response =
- POP3Response::readMultilineResponse(m_socket, m_timeoutHandler);
-
- std::vector <string> res;
-
- if (response->isSuccess())
- {
- for (size_t i = 0, n = response->getLineCount() ; i < n ; ++i)
- res.push_back(response->getLineAt(i));
- }
-
- return res;
-}
-
-
-void POP3Store::sendRequest(ref <POP3Command> cmd)
-{
- cmd->writeToSocket(m_socket);
-}
-
-
-ref <POP3Response> POP3Store::readResponse()
-{
- ref <POP3Response> resp =
- readResponse();
-
- return resp;
-}
-
-
void POP3Store::registerFolder(POP3Folder* folder)
{
m_folders.push_back(folder);