2005-08-23 19:11:19 +00:00
|
|
|
//
|
|
|
|
// VMime library (http://www.vmime.org)
|
2006-02-05 10:22:59 +00:00
|
|
|
// Copyright (C) 2002-2006 Vincent Richard <vincent@vincent-richard.net>
|
2005-08-23 19:11:19 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2005-09-17 10:10:29 +00:00
|
|
|
// You should have received a copy of the GNU General Public License along along
|
|
|
|
// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc.,
|
|
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA..
|
2005-08-23 19:11:19 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "vmime/net/smtp/SMTPTransport.hpp"
|
2006-01-07 08:46:20 +00:00
|
|
|
#include "vmime/net/smtp/SMTPResponse.hpp"
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
#include "vmime/exception.hpp"
|
|
|
|
#include "vmime/platformDependant.hpp"
|
|
|
|
#include "vmime/encoderB64.hpp"
|
|
|
|
#include "vmime/mailboxList.hpp"
|
|
|
|
|
|
|
|
#include "vmime/utility/filteredStream.hpp"
|
2005-09-17 09:08:45 +00:00
|
|
|
#include "vmime/utility/stringUtils.hpp"
|
|
|
|
|
2006-01-29 17:36:34 +00:00
|
|
|
#include "vmime/net/defaultConnectionInfos.hpp"
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
#if VMIME_HAVE_SASL_SUPPORT
|
|
|
|
#include "vmime/security/sasl/SASLContext.hpp"
|
|
|
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-10-03 21:29:04 +00:00
|
|
|
#if VMIME_HAVE_TLS_SUPPORT
|
|
|
|
#include "vmime/net/tls/TLSSession.hpp"
|
2006-01-29 17:36:34 +00:00
|
|
|
#include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
|
2005-10-03 21:29:04 +00:00
|
|
|
#endif // VMIME_HAVE_TLS_SUPPORT
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
// Helpers for service properties
|
|
|
|
#define GET_PROPERTY(type, prop) \
|
2005-10-03 21:29:04 +00:00
|
|
|
(getInfos().getPropertyValue <type>(getSession(), \
|
|
|
|
dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().prop))
|
2005-08-23 19:11:19 +00:00
|
|
|
#define HAS_PROPERTY(prop) \
|
2005-10-03 21:29:04 +00:00
|
|
|
(getInfos().hasProperty(getSession(), \
|
|
|
|
dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().prop))
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace vmime {
|
|
|
|
namespace net {
|
|
|
|
namespace smtp {
|
|
|
|
|
|
|
|
|
2005-10-03 21:29:04 +00:00
|
|
|
SMTPTransport::SMTPTransport(ref <session> sess, ref <security::authenticator> auth, const bool secured)
|
2005-08-23 19:11:19 +00:00
|
|
|
: transport(sess, getInfosInstance(), auth), m_socket(NULL),
|
2005-10-03 21:29:04 +00:00
|
|
|
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL),
|
2006-01-29 17:36:34 +00:00
|
|
|
m_isSMTPS(secured), m_secured(false)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SMTPTransport::~SMTPTransport()
|
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (isConnected())
|
|
|
|
disconnect();
|
|
|
|
else if (m_socket)
|
|
|
|
internalDisconnect();
|
|
|
|
}
|
|
|
|
catch (vmime::exception&)
|
|
|
|
{
|
|
|
|
// Ignore
|
|
|
|
}
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string SMTPTransport::getProtocolName() const
|
|
|
|
{
|
|
|
|
return "smtp";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::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
|
2005-10-04 18:49:59 +00:00
|
|
|
if (getTimeoutHandlerFactory())
|
|
|
|
m_timeoutHandler = getTimeoutHandlerFactory()->create();
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
// Create and connect the socket
|
2005-10-04 18:34:25 +00:00
|
|
|
m_socket = getSocketFactory()->create();
|
2005-10-03 21:29:04 +00:00
|
|
|
|
|
|
|
#if VMIME_HAVE_TLS_SUPPORT
|
2006-01-29 17:36:34 +00:00
|
|
|
if (m_isSMTPS) // dedicated port/SMTPS
|
2005-10-03 21:29:04 +00:00
|
|
|
{
|
|
|
|
ref <tls::TLSSession> tlsSession =
|
|
|
|
vmime::create <tls::TLSSession>(getCertificateVerifier());
|
|
|
|
|
|
|
|
ref <tls::TLSSocket> tlsSocket =
|
|
|
|
tlsSession->getSocket(m_socket);
|
|
|
|
|
|
|
|
m_socket = tlsSocket;
|
2006-01-29 17:36:34 +00:00
|
|
|
|
|
|
|
m_secured = true;
|
|
|
|
m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
|
2005-10-03 21:29:04 +00:00
|
|
|
}
|
2006-01-29 17:36:34 +00:00
|
|
|
else
|
2006-02-09 21:03:16 +00:00
|
|
|
#endif // VMIME_HAVE_TLS_SUPPORT
|
2006-01-29 17:36:34 +00:00
|
|
|
{
|
|
|
|
m_cntInfos = vmime::create <defaultConnectionInfos>(address, port);
|
|
|
|
}
|
2005-10-03 21:29:04 +00:00
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
m_socket->connect(address, port);
|
|
|
|
|
|
|
|
// Connection
|
|
|
|
//
|
|
|
|
// eg: C: <connection to server>
|
|
|
|
// --- S: 220 smtp.domain.com Service ready
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> resp;
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 220)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::connection_greeting_error(resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Identification
|
|
|
|
// First, try Extended SMTP (ESMTP)
|
|
|
|
//
|
|
|
|
// eg: C: EHLO thismachine.ourdomain.com
|
2005-09-17 09:08:45 +00:00
|
|
|
// S: 250-smtp.theserver.com
|
|
|
|
// S: 250 AUTH CRAM-MD5 DIGEST-MD5
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
sendRequest("EHLO " + platformDependant::getHandler()->getHostName());
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 250)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
// Next, try "Basic" SMTP
|
|
|
|
//
|
|
|
|
// eg: C: HELO thismachine.ourdomain.com
|
|
|
|
// S: 250 OK
|
|
|
|
|
|
|
|
sendRequest("HELO " + platformDependant::getHandler()->getHostName());
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 250)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::connection_greeting_error(resp->getLastLine().getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_extendedSMTP = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_extendedSMTP = true;
|
2006-01-07 08:46:20 +00:00
|
|
|
m_extendedSMTPResponse = resp->getText();
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
2005-10-03 21:29:04 +00:00
|
|
|
#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);
|
|
|
|
|
2006-01-29 17:36:34 +00:00
|
|
|
if (!m_isSMTPS && tls) // only if not POP3S
|
2005-10-03 21:29:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // VMIME_HAVE_TLS_SUPPORT
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
// Authentication
|
|
|
|
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH))
|
2005-09-17 09:08:45 +00:00
|
|
|
authenticate();
|
2005-11-07 11:55:40 +00:00
|
|
|
else
|
|
|
|
m_authentified = true;
|
2005-09-17 09:08:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::authenticate()
|
|
|
|
{
|
|
|
|
if (!m_extendedSMTP)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
internalDisconnect();
|
|
|
|
throw exceptions::command_error("AUTH", "ESMTP not supported.");
|
|
|
|
}
|
|
|
|
|
|
|
|
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 normal authentication
|
|
|
|
internalDisconnect();
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Ignore, will try normal authentication
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (exception& e)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2005-09-17 09:08:45 +00:00
|
|
|
throw e;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
2005-09-17 09:08:45 +00:00
|
|
|
}
|
|
|
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
// No other authentication method is possible
|
|
|
|
throw exceptions::authentication_error("All authentication methods failed");
|
|
|
|
}
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
#if VMIME_HAVE_SASL_SUPPORT
|
|
|
|
|
|
|
|
void SMTPTransport::authenticateSASL()
|
|
|
|
{
|
|
|
|
if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())
|
|
|
|
throw exceptions::authentication_error("No SASL authenticator available.");
|
|
|
|
|
|
|
|
// Obtain SASL mechanisms supported by server from EHLO response
|
|
|
|
std::vector <string> saslMechs;
|
|
|
|
std::istringstream iss(m_extendedSMTPResponse);
|
|
|
|
|
|
|
|
while (!iss.eof())
|
|
|
|
{
|
|
|
|
string line;
|
|
|
|
std::getline(iss, line);
|
|
|
|
|
|
|
|
std::istringstream liss(line);
|
|
|
|
string word;
|
|
|
|
|
|
|
|
bool inAuth = false;
|
|
|
|
|
|
|
|
while (liss >> word)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
if (word.length() == 4 &&
|
|
|
|
(word[0] == 'A' || word[0] == 'a') ||
|
|
|
|
(word[0] == 'U' || word[0] == 'u') ||
|
|
|
|
(word[0] == 'T' || word[0] == 't') ||
|
|
|
|
(word[0] == 'H' || word[0] == 'h'))
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
inAuth = true;
|
|
|
|
}
|
|
|
|
else if (inAuth)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
saslMechs.push_back(word);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
if (saslMechs.empty())
|
|
|
|
throw exceptions::authentication_error("No SASL mechanism available.");
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
std::vector <ref <security::sasl::SASLMechanism> > mechList;
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
ref <security::sasl::SASLContext> saslContext =
|
|
|
|
vmime::create <security::sasl::SASLContext>();
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
mechList.push_back
|
|
|
|
(saslContext->createMechanism(saslMechs[i]));
|
|
|
|
}
|
|
|
|
catch (exceptions::no_such_mechanism&)
|
|
|
|
{
|
|
|
|
// Ignore mechanism
|
|
|
|
}
|
|
|
|
}
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
if (mechList.empty())
|
|
|
|
throw exceptions::authentication_error("No SASL mechanism available.");
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
// Try to suggest a mechanism among all those supported
|
|
|
|
ref <security::sasl::SASLMechanism> suggestedMech =
|
|
|
|
saslContext->suggestMechanism(mechList);
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
if (!suggestedMech)
|
|
|
|
throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
// Allow application to choose which mechanisms to use
|
|
|
|
mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->
|
|
|
|
getAcceptableMechanisms(mechList, suggestedMech);
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
if (mechList.empty())
|
|
|
|
throw exceptions::authentication_error("No SASL mechanism available.");
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
// 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("smtp", getAuthenticator(), mech);
|
|
|
|
|
|
|
|
saslSession->init();
|
|
|
|
|
|
|
|
sendRequest("AUTH " + mech->getName());
|
|
|
|
|
|
|
|
for (bool cont = true ; cont ; )
|
|
|
|
{
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> response = readResponse();
|
2005-09-17 09:08:45 +00:00
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
switch (response->getCode())
|
2005-09-17 09:08:45 +00:00
|
|
|
{
|
|
|
|
case 235:
|
|
|
|
{
|
|
|
|
m_socket = saslSession->getSecuredSocket(m_socket);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case 334:
|
|
|
|
{
|
2006-04-18 19:04:30 +00:00
|
|
|
byte_t* challenge = 0;
|
2005-09-17 09:08:45 +00:00
|
|
|
int challengeLen = 0;
|
|
|
|
|
2006-04-18 19:04:30 +00:00
|
|
|
byte_t* resp = 0;
|
2005-09-17 09:08:45 +00:00
|
|
|
int respLen = 0;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Extract challenge
|
2006-01-07 08:46:20 +00:00
|
|
|
saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
|
2005-09-17 09:08:45 +00:00
|
|
|
|
|
|
|
// Prepare response
|
|
|
|
saslSession->evaluateChallenge
|
|
|
|
(challenge, challengeLen, &resp, &respLen);
|
|
|
|
|
|
|
|
// Send response
|
|
|
|
sendRequest(saslContext->encodeB64(resp, respLen));
|
|
|
|
}
|
|
|
|
catch (exceptions::sasl_exception& e)
|
|
|
|
{
|
|
|
|
if (challenge)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
delete [] challenge;
|
|
|
|
challenge = NULL;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
2005-09-17 09:08:45 +00:00
|
|
|
|
|
|
|
if (resp)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2005-09-17 09:08:45 +00:00
|
|
|
delete [] resp;
|
|
|
|
resp = NULL;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
2005-09-17 09:08:45 +00:00
|
|
|
|
|
|
|
// Cancel SASL exchange
|
|
|
|
sendRequest("*");
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (challenge)
|
|
|
|
delete [] challenge;
|
|
|
|
|
|
|
|
if (resp)
|
|
|
|
delete [] resp;
|
|
|
|
|
|
|
|
throw;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
if (challenge)
|
|
|
|
delete [] challenge;
|
|
|
|
|
|
|
|
if (resp)
|
|
|
|
delete [] resp;
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-09-17 09:08:45 +00:00
|
|
|
default:
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
cont = false;
|
|
|
|
break;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
throw exceptions::authentication_error
|
|
|
|
("Could not authenticate using SASL: all mechanisms failed.");
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2005-10-03 21:29:04 +00:00
|
|
|
#if VMIME_HAVE_TLS_SUPPORT
|
|
|
|
|
|
|
|
void SMTPTransport::startTLS()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
sendRequest("STARTTLS");
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> resp = readResponse();
|
2005-10-03 21:29:04 +00:00
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if (resp->getCode() != 220)
|
|
|
|
throw exceptions::command_error("STARTTLS", resp->getText());
|
2005-10-03 21:29:04 +00:00
|
|
|
|
|
|
|
ref <tls::TLSSession> tlsSession =
|
|
|
|
vmime::create <tls::TLSSession>(getCertificateVerifier());
|
|
|
|
|
|
|
|
ref <tls::TLSSocket> tlsSocket =
|
|
|
|
tlsSession->getSocket(m_socket);
|
|
|
|
|
|
|
|
tlsSocket->handshake(m_timeoutHandler);
|
|
|
|
|
|
|
|
m_socket = tlsSocket;
|
2006-01-29 17:36:34 +00:00
|
|
|
|
|
|
|
m_secured = true;
|
|
|
|
m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>
|
|
|
|
(m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket);
|
2005-10-03 21:29:04 +00:00
|
|
|
}
|
|
|
|
catch (exceptions::command_error&)
|
|
|
|
{
|
|
|
|
// Non-fatal error
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
catch (exception&)
|
|
|
|
{
|
|
|
|
// Fatal error
|
|
|
|
internalDisconnect();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // VMIME_HAVE_TLS_SUPPORT
|
|
|
|
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
const bool SMTPTransport::isConnected() const
|
|
|
|
{
|
|
|
|
return (m_socket && m_socket->isConnected() && m_authentified);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-29 17:36:34 +00:00
|
|
|
const bool SMTPTransport::isSecuredConnection() const
|
|
|
|
{
|
|
|
|
return m_secured;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ref <connectionInfos> SMTPTransport::getConnectionInfos() const
|
|
|
|
{
|
|
|
|
return m_cntInfos;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
void SMTPTransport::disconnect()
|
|
|
|
{
|
|
|
|
if (!isConnected())
|
|
|
|
throw exceptions::not_connected();
|
|
|
|
|
|
|
|
internalDisconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::internalDisconnect()
|
|
|
|
{
|
2005-11-30 12:12:01 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
sendRequest("QUIT");
|
|
|
|
}
|
|
|
|
catch (exception&)
|
|
|
|
{
|
|
|
|
// Not important
|
|
|
|
}
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
m_socket->disconnect();
|
|
|
|
m_socket = NULL;
|
|
|
|
|
|
|
|
m_timeoutHandler = NULL;
|
|
|
|
|
|
|
|
m_authentified = false;
|
|
|
|
m_extendedSMTP = false;
|
2006-01-29 17:36:34 +00:00
|
|
|
|
|
|
|
m_secured = false;
|
|
|
|
m_cntInfos = NULL;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::noop()
|
|
|
|
{
|
2006-02-24 17:57:17 +00:00
|
|
|
if (!isConnected())
|
|
|
|
throw exceptions::not_connected();
|
|
|
|
|
2005-09-17 09:08:45 +00:00
|
|
|
sendRequest("NOOP");
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> resp = readResponse();
|
2005-08-23 19:11:19 +00:00
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if (resp->getCode() != 250)
|
|
|
|
throw exceptions::command_error("NOOP", resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients,
|
|
|
|
utility::inputStream& is, const utility::stream::size_type size,
|
2005-10-06 11:08:56 +00:00
|
|
|
utility::progressListener* progress)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
2006-02-24 17:57:17 +00:00
|
|
|
if (!isConnected())
|
|
|
|
throw exceptions::not_connected();
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
// If no recipient/expeditor was found, throw an exception
|
|
|
|
if (recipients.isEmpty())
|
|
|
|
throw exceptions::no_recipient();
|
|
|
|
else if (expeditor.isEmpty())
|
|
|
|
throw exceptions::no_expeditor();
|
|
|
|
|
|
|
|
// Emit the "MAIL" command
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> resp;
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">");
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 250)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::command_error("MAIL", resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit a "RCPT TO" command for each recipient
|
|
|
|
for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
|
|
|
|
{
|
|
|
|
const mailbox& mbox = *recipients.getMailboxAt(i);
|
|
|
|
|
|
|
|
sendRequest("RCPT TO: <" + mbox.getEmail() + ">");
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 250)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::command_error("RCPT TO", resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the message data
|
|
|
|
sendRequest("DATA");
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 354)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::command_error("DATA", resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stream copy with "\n." to "\n.." transformation
|
|
|
|
utility::outputStreamSocketAdapter sos(*m_socket);
|
|
|
|
utility::dotFilteredOutputStream fos(sos);
|
|
|
|
|
|
|
|
utility::bufferedStreamCopy(is, fos, size, progress);
|
|
|
|
|
2005-10-20 16:56:04 +00:00
|
|
|
fos.flush();
|
|
|
|
|
2005-08-23 19:11:19 +00:00
|
|
|
// Send end-of-data delimiter
|
|
|
|
m_socket->sendRaw("\r\n.\r\n", 5);
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
if ((resp = readResponse())->getCode() != 250)
|
2005-08-23 19:11:19 +00:00
|
|
|
{
|
|
|
|
internalDisconnect();
|
2006-01-07 08:46:20 +00:00
|
|
|
throw exceptions::command_error("DATA", resp->getText());
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SMTPTransport::sendRequest(const string& buffer, const bool end)
|
|
|
|
{
|
|
|
|
m_socket->send(buffer);
|
|
|
|
if (end) m_socket->send("\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-07 08:46:20 +00:00
|
|
|
ref <SMTPResponse> SMTPTransport::readResponse()
|
2005-09-17 09:08:45 +00:00
|
|
|
{
|
2006-01-07 08:46:20 +00:00
|
|
|
return SMTPResponse::readResponse(m_socket, m_timeoutHandler);
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Service infos
|
|
|
|
|
2005-10-03 21:29:04 +00:00
|
|
|
SMTPServiceInfos SMTPTransport::sm_infos(false);
|
2005-08-23 19:11:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
const serviceInfos& SMTPTransport::getInfosInstance()
|
|
|
|
{
|
2005-10-03 21:29:04 +00:00
|
|
|
return sm_infos;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const serviceInfos& SMTPTransport::getInfos() const
|
|
|
|
{
|
2005-10-03 21:29:04 +00:00
|
|
|
return sm_infos;
|
2005-08-23 19:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // smtp
|
|
|
|
} // net
|
|
|
|
} // vmime
|