diff --git a/SConstruct b/SConstruct index 5c6a0657..888e3f95 100644 --- a/SConstruct +++ b/SConstruct @@ -260,6 +260,7 @@ libvmime_messaging_proto_sources = [ 'net/smtp/SMTPCommand.cpp', 'net/smtp/SMTPCommand.hpp', 'net/smtp/SMTPCommandSet.cpp', 'net/smtp/SMTPCommandSet.hpp', 'net/smtp/SMTPConnection.cpp', 'net/smtp/SMTPConnection.hpp', + 'net/smtp/SMTPExceptions.cpp', 'net/smtp/SMTPExceptions.hpp', 'net/smtp/SMTPResponse.cpp', 'net/smtp/SMTPResponse.hpp', 'net/smtp/SMTPServiceInfos.cpp', 'net/smtp/SMTPServiceInfos.hpp', 'net/smtp/SMTPTransport.cpp', 'net/smtp/SMTPTransport.hpp', diff --git a/src/exception.cpp b/src/exception.cpp index 92ce1a30..bf37de00 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -648,34 +648,6 @@ exception* invalid_folder_name::clone() const { return new invalid_folder_name(* const char* invalid_folder_name::name() const throw() { return "invalid_folder_name"; } -// -// message_size_exceeds_max_limits -// - -message_size_exceeds_max_limits::~message_size_exceeds_max_limits() throw() {} -message_size_exceeds_max_limits::message_size_exceeds_max_limits(const string& error, const exception& other) - : net_exception(error.empty() - ? "Transport error: message size exceeds maximum server limits (permanent error)." - : error , other) {} - -exception* message_size_exceeds_max_limits::clone() const { return new message_size_exceeds_max_limits(*this); } -const char* message_size_exceeds_max_limits::name() const throw() { return "message_size_exceeds_max_limits"; } - - -// -// message_size_exceeds_cur_limits -// - -message_size_exceeds_cur_limits::~message_size_exceeds_cur_limits() throw() {} -message_size_exceeds_cur_limits::message_size_exceeds_cur_limits(const string& error, const exception& other) - : net_exception(error.empty() - ? "Transport error: message size exceeds current server limits (temporary storage error)." - : error, other) {} - -exception* message_size_exceeds_cur_limits::clone() const { return new message_size_exceeds_cur_limits(*this); } -const char* message_size_exceeds_cur_limits::name() const throw() { return "message_size_exceeds_cur_limits"; } - - #endif // VMIME_HAVE_MESSAGING_FEATURES diff --git a/src/net/smtp/SMTPConnection.cpp b/src/net/smtp/SMTPConnection.cpp index c5ec7b51..88170243 100644 --- a/src/net/smtp/SMTPConnection.cpp +++ b/src/net/smtp/SMTPConnection.cpp @@ -29,6 +29,7 @@ #include "vmime/net/smtp/SMTPConnection.hpp" #include "vmime/net/smtp/SMTPTransport.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" #include "vmime/exception.hpp" #include "vmime/platform.hpp" @@ -473,7 +474,10 @@ void SMTPConnection::startTLS() ref resp = readResponse(); if (resp->getCode() != 220) - throw exceptions::command_error("STARTTLS", resp->getText()); + { + throw SMTPCommandError("STARTTLS", resp->getText(), + resp->getCode(), resp->getEnhancedCode()); + } ref tlsSession = tls::TLSSession::create(getTransport()->getCertificateVerifier()); diff --git a/src/net/smtp/SMTPExceptions.cpp b/src/net/smtp/SMTPExceptions.cpp new file mode 100644 index 00000000..0c3112c0 --- /dev/null +++ b/src/net/smtp/SMTPExceptions.cpp @@ -0,0 +1,151 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// 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_SMTP + + +#include "vmime/net/smtp/SMTPExceptions.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +// +// SMTPCommandError +// + +SMTPCommandError::SMTPCommandError + (const string& command, const string& response, + const string& desc, const int statusCode, + const SMTPResponse::enhancedStatusCode& extendedStatusCode, + const exception& other) + : command_error(command, response, desc, other), + m_status(statusCode), m_exStatus(extendedStatusCode) +{ +} + + +SMTPCommandError::SMTPCommandError + (const string& command, const string& response, + const int statusCode, const SMTPResponse::enhancedStatusCode& extendedStatusCode, + const exception& other) + : command_error(command, response, "", other), + m_status(statusCode), m_exStatus(extendedStatusCode) +{ +} + + +SMTPCommandError::~SMTPCommandError() throw() +{ +} + + +int SMTPCommandError::statusCode() const +{ + return m_status; +} + + +const SMTPResponse::enhancedStatusCode SMTPCommandError::extendedStatusCode() const +{ + return m_exStatus; +} + + +exception* SMTPCommandError::clone() const +{ + return new SMTPCommandError(*this); +} + + +const char* SMTPCommandError::name() const throw() +{ + return "SMTPCommandError"; +} + + +// +// SMTPMessageSizeExceedsMaxLimitsException +// + +SMTPMessageSizeExceedsMaxLimitsException::SMTPMessageSizeExceedsMaxLimitsException(const exception& other) + : net_exception("Message size exceeds maximum server limits (permanent error).", other) +{ +} + + +SMTPMessageSizeExceedsMaxLimitsException::~SMTPMessageSizeExceedsMaxLimitsException() throw() +{ +} + + +exception* SMTPMessageSizeExceedsMaxLimitsException::clone() const +{ + return new SMTPMessageSizeExceedsMaxLimitsException(*this); +} + + +const char* SMTPMessageSizeExceedsMaxLimitsException::name() const throw() +{ + return "SMTPMessageSizeExceedsMaxLimitsException"; +} + + +// +// SMTPMessageSizeExceedsCurLimitsException +// + +SMTPMessageSizeExceedsCurLimitsException::SMTPMessageSizeExceedsCurLimitsException(const exception& other) + : net_exception("Message size exceeds current server limits (temporary storage error).", other) +{ +} + + +SMTPMessageSizeExceedsCurLimitsException::~SMTPMessageSizeExceedsCurLimitsException() throw() +{ +} + + +exception* SMTPMessageSizeExceedsCurLimitsException::clone() const +{ + return new SMTPMessageSizeExceedsCurLimitsException(*this); +} + + +const char* SMTPMessageSizeExceedsCurLimitsException::name() const throw() +{ + return "SMTPMessageSizeExceedsCurLimitsException"; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/src/net/smtp/SMTPResponse.cpp b/src/net/smtp/SMTPResponse.cpp index 86a7a7bd..9367dcd4 100644 --- a/src/net/smtp/SMTPResponse.cpp +++ b/src/net/smtp/SMTPResponse.cpp @@ -318,6 +318,13 @@ SMTPResponse::enhancedStatusCode::enhancedStatusCode(const enhancedStatusCode& e } +std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code) +{ + os << code.klass << '.' << code.subject << '.' << code.detail; + return os; +} + + } // smtp } // net } // vmime diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index c3431a43..91487ed4 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -32,6 +32,7 @@ #include "vmime/net/smtp/SMTPCommand.hpp" #include "vmime/net/smtp/SMTPCommandSet.hpp" #include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" #include "vmime/exception.hpp" #include "vmime/mailboxList.hpp" @@ -152,7 +153,10 @@ void SMTPTransport::noop() ref resp = m_connection->readResponse(); if (resp->getCode() != 250) - throw exceptions::command_error("NOOP", resp->getText()); + { + throw SMTPCommandError + ("NOOP", resp->getText(), resp->getCode(), resp->getEnhancedCode()); + } } @@ -211,7 +215,10 @@ void SMTPTransport::sendEnvelope if ((resp = m_connection->readResponse())->getCode() != 250) { disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPCommandError + (commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode()); } } @@ -224,21 +231,28 @@ void SMTPTransport::sendEnvelope if (resp->getCode() == 452) { disconnect(); - throw exceptions::message_size_exceeds_cur_limits - (commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPMessageSizeExceedsCurLimitsException + (SMTPCommandError(commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode())); } // SIZE extension: message size exceeds fixed maximum message size else if (resp->getCode() == 552) { disconnect(); - throw exceptions::message_size_exceeds_max_limits - (commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPMessageSizeExceedsMaxLimitsException + (SMTPCommandError(commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode())); } // Other error else { disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPCommandError + (commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode()); } } @@ -256,21 +270,28 @@ void SMTPTransport::sendEnvelope if (resp->getCode() == 452) { disconnect(); - throw exceptions::message_size_exceeds_cur_limits - (commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPMessageSizeExceedsCurLimitsException + (SMTPCommandError(commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode())); } // SIZE extension: message size exceeds fixed maximum message size else if (resp->getCode() == 552) { disconnect(); - throw exceptions::message_size_exceeds_max_limits - (commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPMessageSizeExceedsMaxLimitsException + (SMTPCommandError(commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode())); } // Other error else { disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPCommandError + (commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode()); } } } @@ -283,7 +304,10 @@ void SMTPTransport::sendEnvelope if ((resp = m_connection->readResponse())->getCode() != 354) { disconnect(); - throw exceptions::command_error(commands->getLastCommandSent()->getText(), resp->getText()); + + throw SMTPCommandError + (commands->getLastCommandSent()->getText(), resp->getText(), + resp->getCode(), resp->getEnhancedCode()); } } } @@ -317,7 +341,9 @@ void SMTPTransport::send if ((resp = m_connection->readResponse())->getCode() != 250) { disconnect(); - throw exceptions::command_error("DATA", resp->getText()); + + throw SMTPCommandError + ("DATA", resp->getText(), resp->getCode(), resp->getEnhancedCode()); } } diff --git a/tests/net/smtp/SMTPTransportTest.cpp b/tests/net/smtp/SMTPTransportTest.cpp index 4fc899dd..13c18309 100644 --- a/tests/net/smtp/SMTPTransportTest.cpp +++ b/tests/net/smtp/SMTPTransportTest.cpp @@ -25,6 +25,7 @@ #include "vmime/net/smtp/SMTPTransport.hpp" #include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" #include "SMTPTransportTestUtils.hpp" @@ -143,7 +144,7 @@ VMIME_TEST_SUITE_BEGIN(SMTPTransportTest) vmime::ref msg = vmime::create (); VASSERT_THROW("Connection", tr->send(msg, exp, recips), - vmime::exceptions::message_size_exceeds_max_limits); + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException); } void testSize_NoChunking() @@ -170,7 +171,7 @@ VMIME_TEST_SUITE_BEGIN(SMTPTransportTest) vmime::ref msg = vmime::create (); VASSERT_THROW("Connection", tr->send(msg, exp, recips), - vmime::exceptions::message_size_exceeds_max_limits); + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException); } VMIME_TEST_SUITE_END diff --git a/vmime/exception.hpp b/vmime/exception.hpp index a70c46b6..d39ac2a2 100644 --- a/vmime/exception.hpp +++ b/vmime/exception.hpp @@ -772,36 +772,6 @@ public: }; -/** Transport error: message size exceeds maximum server limits. - */ - -class VMIME_EXPORT message_size_exceeds_max_limits : public net_exception -{ -public: - - message_size_exceeds_max_limits(const string& error = "", const exception& other = NO_EXCEPTION); - ~message_size_exceeds_max_limits() throw(); - - exception* clone() const; - const char* name() const throw(); -}; - - -/** Transport error: message size exceeds current server limits. - */ - -class VMIME_EXPORT message_size_exceeds_cur_limits : public net_exception -{ -public: - - message_size_exceeds_cur_limits(const string& error = "", const exception& other = NO_EXCEPTION); - ~message_size_exceeds_cur_limits() throw(); - - exception* clone() const; - const char* name() const throw(); -}; - - #endif // VMIME_HAVE_MESSAGING_FEATURES diff --git a/vmime/net/smtp/SMTPExceptions.hpp b/vmime/net/smtp/SMTPExceptions.hpp new file mode 100644 index 00000000..75842042 --- /dev/null +++ b/vmime/net/smtp/SMTPExceptions.hpp @@ -0,0 +1,127 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard +// +// 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_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/exception.hpp" +#include "vmime/base.hpp" + +#include "vmime/net/smtp/SMTPResponse.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +/** SMTP Command error: a SMTP command failed. + */ + +class VMIME_EXPORT SMTPCommandError : public exceptions::command_error +{ +public: + + SMTPCommandError(const string& command, const string& response, + const string& desc, const int statusCode, + const SMTPResponse::enhancedStatusCode& extendedStatusCode, + const exception& other = NO_EXCEPTION); + + SMTPCommandError(const string& command, const string& response, + const int statusCode, const SMTPResponse::enhancedStatusCode& extendedStatusCode, + const exception& other = NO_EXCEPTION); + + ~SMTPCommandError() throw(); + + /** Returns the SMTP status code for this error. + * + * @return status code (protocol-dependent) + */ + int statusCode() const; + + /** Returns the extended status code (following RFC-3463) for this + * error, if available. + * + * @return status code + */ + const SMTPResponse::enhancedStatusCode extendedStatusCode() const; + + + exception* clone() const; + const char* name() const throw(); + +private: + + int m_status; + SMTPResponse::enhancedStatusCode m_exStatus; +}; + + +/** SMTP error: message size exceeds maximum server limits. + * This is a permanent error. + */ + +class VMIME_EXPORT SMTPMessageSizeExceedsMaxLimitsException : public exceptions::net_exception +{ +public: + + SMTPMessageSizeExceedsMaxLimitsException(const exception& other = NO_EXCEPTION); + ~SMTPMessageSizeExceedsMaxLimitsException() throw(); + + exception* clone() const; + const char* name() const throw(); +}; + + +/** SMTP error: message size exceeds current server limits. + * This is a temporary error (you may retry later). + */ + +class VMIME_EXPORT SMTPMessageSizeExceedsCurLimitsException : public exceptions::net_exception +{ +public: + + SMTPMessageSizeExceedsCurLimitsException(const exception& other = NO_EXCEPTION); + ~SMTPMessageSizeExceedsCurLimitsException() throw(); + + exception* clone() const; + const char* name() const throw(); +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED + diff --git a/vmime/net/smtp/SMTPResponse.hpp b/vmime/net/smtp/SMTPResponse.hpp index 79b25ee7..e0a5e1cd 100644 --- a/vmime/net/smtp/SMTPResponse.hpp +++ b/vmime/net/smtp/SMTPResponse.hpp @@ -174,6 +174,9 @@ private: }; +VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code); + + } // smtp } // net } // vmime