diff options
Diffstat (limited to 'vmime-master/src/vmime/net/smtp')
19 files changed, 3782 insertions, 0 deletions
| diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp new file mode 100644 index 0000000..3b242d1 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp @@ -0,0 +1,180 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPChunkingOutputStreamAdapter.hpp" + +#include "vmime/net/smtp/SMTPConnection.hpp" +#include "vmime/net/smtp/SMTPTransport.hpp" + +#include <algorithm> + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPChunkingOutputStreamAdapter::SMTPChunkingOutputStreamAdapter( +	const shared_ptr <SMTPConnection>& conn, +	const size_t size, +	utility::progressListener* progress +) +	: m_connection(conn), +	  m_bufferSize(0), +	  m_chunkCount(0), +	  m_totalSize(size), +	  m_totalSent(0), +	  m_progress(progress) { + +	if (progress) { +		progress->start(size); +	} +} + + +void SMTPChunkingOutputStreamAdapter::sendChunk( +	const byte_t* const data, +	const size_t count, +	const bool last +) { + +	if (count == 0 && !last) { +		// Nothing to send +		return; +	} + +	// Send this chunk +	m_connection->sendRequest(SMTPCommand::BDAT(count, last)); +	m_connection->getSocket()->sendRaw(data, count); + +	++m_chunkCount; + +	if (m_progress) { + +		m_totalSent += count; +		m_totalSize = std::max(m_totalSize, m_totalSent); + +		m_progress->progress(m_totalSent, m_totalSize); +	} + +	if (m_connection->getTracer()) { +		m_connection->getTracer()->traceSendBytes(count); +	} + +	// If PIPELINING is not supported, read one response for this BDAT command +	if (!m_connection->hasExtension("PIPELINING")) { + +		shared_ptr <SMTPResponse> resp = m_connection->readResponse(); + +		if (resp->getCode() != 250) { +			m_connection->getTransport()->disconnect(); +			throw exceptions::command_error("BDAT", resp->getText()); +		} + +	// If PIPELINING is supported, read one response for each chunk (ie. number +	// of BDAT commands issued) after the last chunk has been sent +	} else if (last) { + +		bool invalidReply = false; +		shared_ptr <SMTPResponse> resp; + +		for (unsigned int i = 0 ; i < m_chunkCount ; ++i) { + +			resp = m_connection->readResponse(); + +			if (resp->getCode() != 250) { +				invalidReply = true; +			} +		} + +		if (invalidReply) { +			m_connection->getTransport()->disconnect(); +			throw exceptions::command_error("BDAT", resp->getText()); +		} +	} +} + + +void SMTPChunkingOutputStreamAdapter::writeImpl( +	const byte_t* const data, +	const size_t count +) { + +	const byte_t* curData = data; +	size_t curCount = count; + +	while (curCount != 0) { + +		// Fill the buffer +		const size_t remaining = sizeof(m_buffer) - m_bufferSize; +		const size_t bytesToCopy = std::min(remaining, curCount); + +		std::copy(curData, curData + bytesToCopy, m_buffer + m_bufferSize); + +		m_bufferSize += bytesToCopy; +		curData += bytesToCopy; +		curCount -= bytesToCopy; + +		// If the buffer is full, send this chunk +		if (m_bufferSize >= sizeof(m_buffer)) { + +			sendChunk(m_buffer, m_bufferSize, /* last */ false); +			m_bufferSize = 0; +		} +	} +} + + +void SMTPChunkingOutputStreamAdapter::flush() { + +	sendChunk(m_buffer, m_bufferSize, /* last */ true); +	m_bufferSize = 0; + +	if (m_progress) { +		m_progress->stop(m_totalSize); +	} + +	if (m_connection->getTracer()) { +		m_connection->getTracer()->traceSendBytes(m_bufferSize); +	} +} + + +size_t SMTPChunkingOutputStreamAdapter::getBlockSize() { + +	return sizeof(m_buffer); +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp new file mode 100644 index 0000000..4ef466a --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp @@ -0,0 +1,94 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/utility/outputStream.hpp" +#include "vmime/utility/progressListener.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +class SMTPConnection; + + +/** An output stream adapter used with ESMTP CHUNKING extension. +  */ +class VMIME_EXPORT SMTPChunkingOutputStreamAdapter : public utility::outputStream { + +public: + +	SMTPChunkingOutputStreamAdapter( +		const shared_ptr <SMTPConnection>& conn, +		const size_t size, +		utility::progressListener* progress +	); + +	void flush(); + +	size_t getBlockSize(); + +protected: + +	void writeImpl(const byte_t* const data, const size_t count); + +private: + +	SMTPChunkingOutputStreamAdapter(const SMTPChunkingOutputStreamAdapter&); + + +	void sendChunk(const byte_t* const data, const size_t count, const bool last); + + +	shared_ptr <SMTPConnection> m_connection; + +	byte_t m_buffer[262144];  // 256 KB +	size_t m_bufferSize; + +	unsigned int m_chunkCount; + +	size_t m_totalSize; +	size_t m_totalSent; +	utility::progressListener* m_progress; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp new file mode 100644 index 0000000..5e533d1 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp @@ -0,0 +1,258 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPCommand.hpp" + +#include "vmime/net/socket.hpp" +#include "vmime/net/tracer.hpp" + +#include "vmime/mailbox.hpp" +#include "vmime/utility/outputStreamAdapter.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPCommand::SMTPCommand(const string& text, const string& traceText) +	: m_text(text), +	  m_traceText(traceText) +{ +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::EHLO(const string& hostname) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "EHLO " << hostname; + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::HELO(const string& hostname) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "HELO " << hostname; + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "AUTH " << mechName; + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName, const std::string& initialResponse) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "AUTH " << mechName << " " << initialResponse; + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::STARTTLS() { + +	return createCommand("STARTTLS"); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8, +										   const std::string& dsnRet, const std::string& dsnEnvelopId) { + +	return MAIL(mbox, utf8, 0, dsnRet, dsnEnvelopId); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8, const size_t size, +										   const std::string& dsnRet, const std::string& dsnEnvelopId) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "MAIL FROM:<"; + +	if (utf8) { + +		cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8); + +	} else { + +		vmime::utility::outputStreamAdapter cmd2(cmd); +		mbox.getEmail().generate(cmd2); +	} + +	cmd << ">"; + +	if (!dsnRet.empty()) { +		cmd << " " << dsn::RET << "=" << dsnRet; +	} +	if (!dsnEnvelopId.empty()) { +		cmd << " " << dsn::ENVID << "=<" << dsnEnvelopId << ">"; +	} + +	if (utf8) { +		cmd << " SMTPUTF8"; +	} + +	if (size != 0) { +		cmd << " SIZE=" << size; +	} + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::RCPT(const mailbox& mbox, const bool utf8, +										   const string& dsnNotify) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "RCPT TO:<"; + +	if (utf8) { + +		cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8); + +	} else { + +		vmime::utility::outputStreamAdapter cmd2(cmd); +		mbox.getEmail().generate(cmd2); +	} + +	cmd << ">"; + +	if (!dsnNotify.empty()) { +		cmd << " " << dsn::NOTIFY << "=" << dsnNotify; +	} + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::RSET() { + +	return createCommand("RSET"); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::DATA() { + +	return createCommand("DATA"); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::BDAT(const size_t chunkSize, const bool last) { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); +	cmd << "BDAT " << chunkSize; + +	if (last) { +		cmd << " LAST"; +	} + +	return createCommand(cmd.str()); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::NOOP() { + +	return createCommand("NOOP"); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::QUIT() { + +	return createCommand("QUIT"); +} + + +// static +shared_ptr <SMTPCommand> SMTPCommand::createCommand(const string& text, const string& traceText) { + +	if (traceText.empty()) { +		return shared_ptr <SMTPCommand>(new SMTPCommand(text, text)); +	} else { +		return shared_ptr <SMTPCommand>(new SMTPCommand(text, traceText)); +	} +} + + +const string SMTPCommand::getText() const { + +	return m_text; +} + + +const string SMTPCommand::getTraceText() const { + +	return m_traceText; +} + + +void SMTPCommand::writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr) { + +	sok->send(m_text + "\r\n"); + +	if (tr) { +		tr->traceSend(m_traceText); +	} +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp new file mode 100644 index 0000000..9a32d1e --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp @@ -0,0 +1,125 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPCOMMAND_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/object.hpp" +#include "vmime/base.hpp" + + +namespace vmime { + + +class mailbox; + + +namespace net { + + +class socket; +class timeoutHandler; +class tracer; + + +namespace smtp { + + +/** A SMTP command, as sent to server. +  */ +class VMIME_EXPORT SMTPCommand : public object { + +public: + +	static shared_ptr <SMTPCommand> HELO(const string& hostname); +	static shared_ptr <SMTPCommand> EHLO(const string& hostname); +	static shared_ptr <SMTPCommand> AUTH(const string& mechName); +	static shared_ptr <SMTPCommand> AUTH(const string& mechName, const std::string& initialResponse); +	static shared_ptr <SMTPCommand> STARTTLS(); +	static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, +										 const std::string& dsnRet, const std::string& dsnEnvelopId); +	static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, const size_t size, +										 const std::string& dsnRet, const std::string& dsnEnvelopId); +	static shared_ptr <SMTPCommand> RCPT(const mailbox& mbox, const bool utf8, +										 const std::string& dsnNotify); +	static shared_ptr <SMTPCommand> RSET(); +	static shared_ptr <SMTPCommand> DATA(); +	static shared_ptr <SMTPCommand> BDAT(const size_t chunkSize, const bool last); +	static shared_ptr <SMTPCommand> NOOP(); +	static shared_ptr <SMTPCommand> QUIT(); + +	/** Creates a new SMTP command with the specified text. +	  * +	  * @param text command text +	  * @return a new SMTPCommand object +	  */ +	static shared_ptr <SMTPCommand> createCommand(const string& text, const string& traceText = ""); + +	/** Sends this command to the specified socket. +	  * +	  * @param sok socket to which the command will be written +	  * @param tr tracer +	  */ +	virtual void writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr); + +	/** Returns the full text of the command, including command name +	  * and parameters (if any). +	  * +	  * @return command text (eg. "RCPT TO:<vincent@kisli.com>") +	  */ +	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: + +	SMTPCommand(const string& text, const string& traceText); +	SMTPCommand(const SMTPCommand&); + +private: + +	string m_text; +	string m_traceText; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp new file mode 100644 index 0000000..eab7086 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp @@ -0,0 +1,160 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPCommandSet.hpp" + +#include "vmime/net/socket.hpp" + +#include "vmime/mailbox.hpp" + +#include <stdexcept> + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPCommandSet::SMTPCommandSet(const bool pipeline) +	: SMTPCommand("", ""), +	  m_pipeline(pipeline), +	  m_started(false), +	  m_lastCommandSent() { + +} + + +// static +shared_ptr <SMTPCommandSet> SMTPCommandSet::create(const bool pipeline) { + +	return shared_ptr <SMTPCommandSet>(new SMTPCommandSet(pipeline)); +} + + +void SMTPCommandSet::addCommand(const shared_ptr <SMTPCommand>& cmd) { + +	if (m_started) { +		throw std::runtime_error("Could not add command to pipeline: " +			"one or more commands have already been sent to the server."); +	} + +	m_commands.push_back(cmd); +} + + +void SMTPCommandSet::writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr) { + +	if (m_pipeline) { + +		if (!m_started) { + +			// Send all commands at once +			for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ; +			     it != m_commands.end() ; ++it) { + +				shared_ptr <SMTPCommand> cmd = *it; +				cmd->writeToSocket(sok, tr); +			} +		} + +		if (!m_commands.empty()) { + +			// Advance the pointer to last command sent +			shared_ptr <SMTPCommand> cmd = m_commands.front(); +			m_commands.pop_front(); + +			m_lastCommandSent = cmd; +		} + +	} else { + +		if (!m_commands.empty()) { + +			// Send only one command +			shared_ptr <SMTPCommand> cmd = m_commands.front(); +			m_commands.pop_front(); + +			cmd->writeToSocket(sok, tr); + +			m_lastCommandSent = cmd; +		} +	} + +	m_started = true; +} + + +const string SMTPCommandSet::getText() const { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); + +	for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ; +	     it != m_commands.end() ; ++it) { + +		cmd << (*it)->getText() << "\r\n"; +	} + +	return cmd.str(); +} + + +const string SMTPCommandSet::getTraceText() const { + +	std::ostringstream cmd; +	cmd.imbue(std::locale::classic()); + +	for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ; +	     it != m_commands.end() ; ++it) { + +		cmd << (*it)->getTraceText() << "\r\n"; +	} + +	return cmd.str(); +} + + +bool SMTPCommandSet::isFinished() const { + +	return (m_pipeline && m_started) || (m_commands.size() == 0 && m_started); +} + + +shared_ptr <SMTPCommand> SMTPCommandSet::getLastCommandSent() const { + +	return m_lastCommandSent; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp new file mode 100644 index 0000000..2fd977c --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp @@ -0,0 +1,106 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPCOMMANDSET_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include <list> + +#include "vmime/net/smtp/SMTPCommand.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +/** A set of SMTP commands, which may be sent all at once +  * to the server if pipelining is supported. +  */ +class VMIME_EXPORT SMTPCommandSet : public SMTPCommand { + +public: + +	/** Creates a new set of SMTP commands. +	  * +	  * @param pipeline set to true if the server supports pipelining +	  * @return a new SMTPCommandSet object +	  */ +	static shared_ptr <SMTPCommandSet> create(const bool pipeline); + +	/** Adds a new command to this set. +	  * If one or more comments have already been sent to the server, +	  * an exception will be thrown. +	  * +	  * @param cmd command to add +	  */ +	void addCommand(const shared_ptr <SMTPCommand>& cmd); + +	/** Tests whether all commands have been sent. +	  * +	  * @return true if all commands have been sent, +	  * or false otherwise +	  */ +	bool isFinished() const; + +	/** Returns the last command which has been sent. +	  * +	  * @return a pointer to a SMTPCommand, of NULL if no command +	  * has been sent yet +	  */ +	shared_ptr <SMTPCommand> getLastCommandSent() const; + + +	void writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr); + +	const string getText() const; +	const string getTraceText() const; + +private: + +	SMTPCommandSet(const bool pipeline); +	SMTPCommandSet(const SMTPCommandSet&); + + +	bool m_pipeline; +	bool m_started; +	std::list <shared_ptr <SMTPCommand> > m_commands; +	shared_ptr <SMTPCommand> m_lastCommandSent; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp new file mode 100644 index 0000000..07d0376 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp @@ -0,0 +1,714 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPConnection.hpp" +#include "vmime/net/smtp/SMTPTransport.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" + +#include "vmime/exception.hpp" +#include "vmime/platform.hpp" + +#include "vmime/security/digest/messageDigestFactory.hpp" + +#include "vmime/net/defaultConnectionInfos.hpp" + +#if VMIME_HAVE_SASL_SUPPORT +	#include "vmime/security/sasl/SASLContext.hpp" +#else +	#include "vmime/utility/encoder/b64Encoder.hpp" +	#include "vmime/utility/inputStreamStringAdapter.hpp" +	#include "vmime/utility/outputStreamStringAdapter.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 + + +// Helpers for service properties +#define GET_PROPERTY(type, prop) \ +	(m_transport.lock()->getInfos().getPropertyValue <type>(getSession(), \ +		dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ +	(m_transport.lock()->getInfos().hasProperty(getSession(), \ +		dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace smtp { + + + +SMTPConnection::SMTPConnection( +	const shared_ptr <SMTPTransport>& transport, +	const shared_ptr <security::authenticator>& auth +) +	: m_transport(transport), +	  m_auth(auth), +	  m_socket(null), +	  m_timeoutHandler(null), +	  m_authenticated(false), +	  m_secured(false), +	  m_extendedSMTP(false) { + +	static int connectionId = 0; + +	if (transport->getTracerFactory()) { +		m_tracer = transport->getTracerFactory()->create(transport, ++connectionId); +	} +} + + +SMTPConnection::~SMTPConnection() { + +	try { + +		if (isConnected()) { +			disconnect(); +		} else if (m_socket) { +			internalDisconnect(); +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +void SMTPConnection::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); + +	shared_ptr <SMTPTransport> transport = m_transport.lock(); + +	// Create the time-out handler +	if (transport->getTimeoutHandlerFactory()) { +		m_timeoutHandler = transport->getTimeoutHandlerFactory()->create(); +	} + +	// Create and connect the socket +	m_socket = transport->getSocketFactory()->create(m_timeoutHandler); +	m_socket->setTracer(m_tracer); + +#if VMIME_HAVE_TLS_SUPPORT +	if (transport->isSMTPS()) {  // dedicated port/SMTPS + +		shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create( +			transport->getCertificateVerifier(), +			transport->getSession()->getTLSProperties() +		); + +		shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket); + +		m_socket = tlsSocket; + +		m_secured = true; +		m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket); + +	} else +#endif // VMIME_HAVE_TLS_SUPPORT +	{ +		m_cntInfos = make_shared <defaultConnectionInfos>(address, port); +	} + +	m_socket->connect(address, port); + +	// Connection +	// +	// eg:  C: <connection to server> +	// ---  S: 220 smtp.domain.com Service ready + +	shared_ptr <SMTPResponse> resp; + +	if ((resp = readResponse())->getCode() != 220) { +		internalDisconnect(); +		throw exceptions::connection_greeting_error(resp->getText()); +	} + +	// Identification +	helo(); + +#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 (!transport->isSMTPS() && tls) {  // only if not SMTPS + +		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; +		} + +		// Must reissue a EHLO command [RFC-2487, 5.2] +		helo(); +	} +#endif // VMIME_HAVE_TLS_SUPPORT + +	// Authentication +	if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH)) { +		authenticate(); +	} else { +		m_authenticated = true; +	} +} + + +void SMTPConnection::helo() { + +	// First, try Extended SMTP (ESMTP) +	// +	// eg:  C: EHLO thismachine.ourdomain.com +	//      S: 250-smtp.theserver.com +	//      S: 250-AUTH CRAM-MD5 DIGEST-MD5 +	//      S: 250-PIPELINING +	//      S: 250 SIZE 2555555555 + +	sendRequest(SMTPCommand::EHLO(platform::getHandler()->getHostName())); + +	shared_ptr <SMTPResponse> resp; + +	if ((resp = readResponse())->getCode() != 250) { + +		// Next, try "Basic" SMTP +		// +		// eg:  C: HELO thismachine.ourdomain.com +		//      S: 250 OK + +		sendRequest(SMTPCommand::HELO(platform::getHandler()->getHostName())); + +		if ((resp = readResponse())->getCode() != 250) { +			internalDisconnect(); +			throw exceptions::connection_greeting_error(resp->getLastLine().getText()); +		} + +		m_extendedSMTP = false; +		m_extensions.clear(); + +	} else { + +		m_extendedSMTP = true; +		m_extensions.clear(); + +		// Get supported extensions from SMTP response +		// One extension per line, format is: EXT PARAM1 PARAM2... +		for (size_t i = 1, n = resp->getLineCount() ; i < n ; ++i) { + +			const string line = resp->getLineAt(i).getText(); + +			std::istringstream iss(line); +			iss.imbue(std::locale::classic()); + +			string ext; +			iss >> ext; + +			std::vector <string> params; +			string param; + +			// Special case: some servers send "AUTH=MECH [MECH MECH...]" +			if (ext.length() >= 5 && utility::stringUtils::toUpper(ext.substr(0, 5)) == "AUTH=") { + +				params.push_back(utility::stringUtils::toUpper(ext.substr(5))); +				ext = "AUTH"; +			} + +			while (iss >> param) { +				params.push_back(utility::stringUtils::toUpper(param)); +			} + +			m_extensions[ext] = params; +		} +	} +} + + +bool SMTPConnection::hasExtension( +	const std::string& extName, +	std::vector <string>* params +) const { + +	std::map <string, std::vector <string> >::const_iterator +		it = m_extensions.find(extName); + +	if (it != m_extensions.end()) { + +		if (params) { +			*params = (*it).second; +		} + +		return true; + +	} else { + +		return false; +	} +} + + +void SMTPConnection::authenticate() { + +	if (!m_extendedSMTP) { +		internalDisconnect(); +		throw exceptions::command_error("AUTH", "ESMTP not supported."); +	} + +	getAuthenticator()->setService(m_transport.lock()); + +#if VMIME_HAVE_SASL_SUPPORT +	// Try SASL authentication +	if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) { + +		try { + +			authenticateSASL(); + +			m_authenticated = true; +			return; + +		} catch (exception&) { + +			internalDisconnect(); +			throw; +		} +	} +#else  // no SASL + +	// allow AUTH PLAIN over TLS - it is a popular and simple mechanism +	if (m_secured) { + +		std::vector <string> authMechs; +		hasExtension("AUTH", &authMechs); + +		if (authMechs.empty()) { +			throw exceptions::authentication_error("No AUTH mechanism available."); +		} + +		const string plain("PLAIN"); + +		if (std::find(authMechs.begin(), authMechs.end(), plain) != authMechs.end()) { + +			const string username = getAuthenticator()->getUsername(); +			const string password = getAuthenticator()->getPassword(); +			const string authToken = username + '\0' + username + '\0' + password; + +			utility::inputStreamStringAdapter in(authToken); +			string authTokenBase64; +			utility::outputStreamStringAdapter out(authTokenBase64); + +			vmime::utility::encoder::b64Encoder encoder; +			encoder.encode(in, out); + +			sendRequest(SMTPCommand::AUTH(plain, authTokenBase64)); + +			shared_ptr <SMTPResponse> response = readResponse(); + +			const int code = response ? response->getCode() : -1; + +			if (code == 235) { +				m_authenticated = true; +				return; +			} +		} +	} + +#endif // VMIME_HAVE_SASL_SUPPORT + +	// No other authentication method is possible +	throw exceptions::authentication_error("All authentication methods failed"); +} + + + +#if VMIME_HAVE_SASL_SUPPORT + +void SMTPConnection::authenticateSASL() { + +	if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) { +		throw exceptions::authentication_error("No SASL authenticator available."); +	} + +	// Obtain SASL mechanisms supported by server from ESMTP extensions +	std::vector <string> saslMechs; +	hasExtension("AUTH", &saslMechs); + +	if (saslMechs.empty()) { +		throw exceptions::authentication_error("No SASL mechanism available."); +	} + +	std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList; + +	shared_ptr <security::sasl::SASLContext> saslContext = +		security::sasl::SASLContext::create(); + +	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 +	shared_ptr <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 = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())-> +		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) { + +		shared_ptr <security::sasl::SASLMechanism> mech = mechList[i]; + +		shared_ptr <security::sasl::SASLSession> saslSession = +			saslContext->createSession("smtp", getAuthenticator(), mech); + +		saslSession->init(); + +		if (saslSession->getMechanism()->hasInitialResponse()) { + +			byte_t* initialResp = 0; +			size_t initialRespLen = 0; + +			saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen); + +			string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen)); +			delete [] initialResp; + +			if (encodedInitialResp.empty()) { +				sendRequest(SMTPCommand::AUTH(mech->getName(), "=")); +			} else { +				sendRequest(SMTPCommand::AUTH(mech->getName(), encodedInitialResp)); +			} + +		} else { + +			sendRequest(SMTPCommand::AUTH(mech->getName())); +		} + +		for (bool cont = true ; cont ; ) { + +			shared_ptr <SMTPResponse> response = readResponse(); + +			switch (response->getCode()) { + +				case 235: { + +					m_socket = saslSession->getSecuredSocket(m_socket); +					return; +				} +				case 334: { + +					byte_t* challenge = 0; +					size_t challengeLen = 0; + +					byte_t* resp = 0; +					size_t respLen = 0; + +					try { + +						// Extract challenge +						saslContext->decodeB64(response->getText(), &challenge, &challengeLen); + +						// Prepare response +						saslSession->evaluateChallenge(challenge, challengeLen, &resp, &respLen); + +						// Send response +						const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n"; +						m_socket->sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length()); + +						if (m_tracer) { +							m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange"); +						} + +					} catch (exceptions::sasl_exception& e) { + +						if (challenge) { +							delete [] challenge; +							challenge = NULL; +						} + +						if (resp) { +							delete [] resp; +							resp = NULL; +						} + +						// Cancel SASL exchange +						m_socket->send("*\r\n"); + +						if (m_tracer) { +							m_tracer->traceSend("*"); +						} + +					} 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."); +} + +#endif // VMIME_HAVE_SASL_SUPPORT + + +#if VMIME_HAVE_TLS_SUPPORT + +void SMTPConnection::startTLS() { + +	try { + +		sendRequest(SMTPCommand::STARTTLS()); + +		shared_ptr <SMTPResponse> resp = readResponse(); + +		if (resp->getCode() != 220) { + +			throw SMTPCommandError( +				"STARTTLS", resp->getText(), resp->getCode(), resp->getEnhancedCode() +			); +		} + +		shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create( +			getTransport()->getCertificateVerifier(), +			getTransport()->getSession()->getTLSProperties() +		); + +		shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket); + +		tlsSocket->handshake(); + +		m_socket = tlsSocket; + +		m_secured = true; +		m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>( +			m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket +		); + +	} catch (exceptions::command_error&) { + +		// Non-fatal error +		throw; + +	} catch (exception&) { + +		// Fatal error +		internalDisconnect(); +		throw; +	} +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + +void SMTPConnection::disconnect() { + +	if (!isConnected()) { +		throw exceptions::not_connected(); +	} + +	internalDisconnect(); +} + + +void SMTPConnection::internalDisconnect() { + +	if (isConnected()) { + +		try { + +			sendRequest(SMTPCommand::QUIT()); + +			// Do not wait for server response. This is contrary to the RFC, but +			// some servers never send a response to a QUIT command. + +		} catch (exception&) { + +			// Not important +		} +	} + +	m_socket->disconnect(); +	m_socket = null; + +	m_timeoutHandler = null; + +	m_authenticated = false; +	m_extendedSMTP = false; + +	m_secured = false; +	m_cntInfos = null; +} + + +void SMTPConnection::sendRequest(const shared_ptr <SMTPCommand>& cmd) { + +	cmd->writeToSocket(m_socket, m_tracer); +} + + +shared_ptr <SMTPResponse> SMTPConnection::readResponse() { + +	shared_ptr <SMTPResponse> resp = SMTPResponse::readResponse( +		m_tracer, m_socket, m_timeoutHandler, m_responseState +	); + +	m_responseState = resp->getCurrentState(); + +	return resp; +} + + +bool SMTPConnection::isConnected() const { + +	return m_socket && m_socket->isConnected() && m_authenticated; +} + + +bool SMTPConnection::isSecuredConnection() const { + +	return m_secured; +} + + +shared_ptr <connectionInfos> SMTPConnection::getConnectionInfos() const { + +	return m_cntInfos; +} + + +shared_ptr <SMTPTransport> SMTPConnection::getTransport() { + +	return m_transport.lock(); +} + + +shared_ptr <session> SMTPConnection::getSession() { + +	return m_transport.lock()->getSession(); +} + + +shared_ptr <socket> SMTPConnection::getSocket() { + +	return m_socket; +} + + +shared_ptr <tracer> SMTPConnection::getTracer() { + +	return m_tracer; +} + + +shared_ptr <timeoutHandler> SMTPConnection::getTimeoutHandler() { + +	return m_timeoutHandler; +} + + +shared_ptr <security::authenticator> SMTPConnection::getAuthenticator() { + +	return m_auth; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp new file mode 100644 index 0000000..d8a2375 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp @@ -0,0 +1,136 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPCONNECTION_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/messageId.hpp" + +#include "vmime/net/socket.hpp" +#include "vmime/net/timeoutHandler.hpp" +#include "vmime/net/session.hpp" +#include "vmime/net/connectionInfos.hpp" +#include "vmime/net/tracer.hpp" + +#include "vmime/net/smtp/SMTPCommand.hpp" +#include "vmime/net/smtp/SMTPResponse.hpp" + +#include "vmime/security/authenticator.hpp" + + +namespace vmime { +namespace net { + + +class socket; +class timeoutHandler; + + +namespace smtp { + + +class SMTPTransport; + + +/** Manage connection to a SMTP server. +  */ +class VMIME_EXPORT SMTPConnection : public object { + +public: + +	SMTPConnection( +		const shared_ptr <SMTPTransport>& transport, +		const shared_ptr <security::authenticator>& auth +	); + +	~SMTPConnection(); + + +	virtual void connect(); +	virtual bool isConnected() const; +	virtual void disconnect(); + +	bool isSecuredConnection() const; +	shared_ptr <connectionInfos> getConnectionInfos() const; + +	virtual shared_ptr <SMTPTransport> getTransport(); +	virtual shared_ptr <socket> getSocket(); +	virtual shared_ptr <timeoutHandler> getTimeoutHandler(); +	virtual shared_ptr <security::authenticator> getAuthenticator(); +	virtual shared_ptr <session> getSession(); +	virtual shared_ptr <tracer> getTracer(); + +	void sendRequest(const shared_ptr <SMTPCommand>& cmd); +	shared_ptr <SMTPResponse> readResponse(); + +	bool hasExtension(const std::string& extName, std::vector <string>* params = NULL) const; + +private: + +	void internalDisconnect(); + +	void helo(); +	void authenticate(); +#if VMIME_HAVE_SASL_SUPPORT +	void authenticateSASL(); +#endif // VMIME_HAVE_SASL_SUPPORT + +#if VMIME_HAVE_TLS_SUPPORT +	void startTLS(); +#endif // VMIME_HAVE_TLS_SUPPORT + + +	weak_ptr <SMTPTransport> m_transport; + +	shared_ptr <security::authenticator> m_auth; +	shared_ptr <socket> m_socket; +	shared_ptr <timeoutHandler> m_timeoutHandler; +	shared_ptr <tracer> m_tracer; + +	SMTPResponse::state m_responseState; + +	bool m_authenticated; +	bool m_secured; + +	shared_ptr <connectionInfos> m_cntInfos; + +	bool m_extendedSMTP; +	std::map <string, std::vector <string> > m_extensions; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp new file mode 100644 index 0000000..e3b4652 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp @@ -0,0 +1,212 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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"; +} + + +// +// SMTPExtensionNotSupportedException +// + +SMTPExtensionNotSupportedException::SMTPExtensionNotSupportedException(const string &what, const exception& other) +	: net_exception(what.empty() ? "A required extension is not supported by the SMTP server." : what, other) { + +} + + +SMTPExtensionNotSupportedException::~SMTPExtensionNotSupportedException() throw() { + +} + + +exception* SMTPExtensionNotSupportedException::clone() const { + +	return new SMTPExtensionNotSupportedException(*this); +} + + +const char* SMTPExtensionNotSupportedException::name() const throw() { + +	return "SMTPExtensionNotSupportedException"; +} + + +// +// SMTPDSNExtensionNotSupportedException +// + +SMTPDSNExtensionNotSupportedException::SMTPDSNExtensionNotSupportedException(const exception& other) +	: SMTPExtensionNotSupportedException("RFC-1891 DSN extension is not supported by the SMTP server.", other) { + +} + + +SMTPDSNExtensionNotSupportedException::~SMTPDSNExtensionNotSupportedException() throw() { + +} + + +exception* SMTPDSNExtensionNotSupportedException::clone() const { +	return new SMTPDSNExtensionNotSupportedException(*this); +} + + +const char* SMTPDSNExtensionNotSupportedException::name() const throw() { + +	return "SMTPDSNExtensionNotSupportedException"; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp new file mode 100644 index 0000000..488ee2e --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp @@ -0,0 +1,159 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 error: a required extension is not supported by the server. +  */ +class VMIME_EXPORT SMTPExtensionNotSupportedException : public exceptions::net_exception { + +public: + +	SMTPExtensionNotSupportedException(const string& what, const exception& other = NO_EXCEPTION); +	~SMTPExtensionNotSupportedException() throw(); + +	exception* clone() const; +	const char* name() const throw(); +}; + + +/** SMTP error: RFC-1891 DSN extension is not supported by the server. +  */ +class VMIME_EXPORT SMTPDSNExtensionNotSupportedException : public SMTPExtensionNotSupportedException { + +public: + +	SMTPDSNExtensionNotSupportedException(const exception& other = NO_EXCEPTION); +	~SMTPDSNExtensionNotSupportedException() 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-master/src/vmime/net/smtp/SMTPResponse.cpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp new file mode 100644 index 0000000..2234705 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp @@ -0,0 +1,366 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPResponse.hpp" + +#include "vmime/platform.hpp" +#include "vmime/utility/stringUtils.hpp" + +#include "vmime/net/socket.hpp" +#include "vmime/net/timeoutHandler.hpp" +#include "vmime/net/tracer.hpp" + +#include <cctype> + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPResponse::SMTPResponse( +	const shared_ptr <tracer>& tr, +	const shared_ptr <socket>& sok, +	const shared_ptr <timeoutHandler>& toh, +	const state& st +) +	: m_socket(sok), +	  m_timeoutHandler(toh), +	  m_tracer(tr), +	  m_responseBuffer(st.responseBuffer), +	  m_responseContinues(false) { + +} + + +SMTPResponse::SMTPResponse(const SMTPResponse&) +	: vmime::object() { + +	// Not used +} + + +int SMTPResponse::getCode() const { + +	const int firstCode = m_lines[0].getCode(); + +	for (unsigned int i = 1 ; i < m_lines.size() ; ++i) { + +		// All response codes returned must be equal +		// or else this in an error... +		if (m_lines[i].getCode() != firstCode) { +			return 0; +		} +	} + +	return firstCode; +} + + +const SMTPResponse::enhancedStatusCode SMTPResponse::getEnhancedCode() const { + +	return m_lines[m_lines.size() - 1].getEnhancedCode(); +} + + +const string SMTPResponse::getText() const { + +	string text = m_lines[0].getText(); + +	for (unsigned int i = 1 ; i < m_lines.size() ; ++i) { + +		text += '\n'; +		text += m_lines[i].getText(); +	} + +	return text; +} + + +// static +shared_ptr <SMTPResponse> SMTPResponse::readResponse( +	const shared_ptr <tracer>& tr, +	const shared_ptr <socket>& sok, +	const shared_ptr <timeoutHandler>& toh, +	const state& st +) { + +	shared_ptr <SMTPResponse> resp = +		shared_ptr <SMTPResponse>(new SMTPResponse(tr, sok, toh, st)); + +	resp->readResponse(); + +	return resp; +} + + +void SMTPResponse::readResponse() { + +	responseLine line = getNextResponse(); +	m_lines.push_back(line); + +	while (m_responseContinues) { +		line = getNextResponse(); +		m_lines.push_back(line); +	} +} + + +const string SMTPResponse::readResponseLine() { + +	string currentBuffer = m_responseBuffer; + +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} + +	while (true) { + +		// Get a line from the response buffer +		const size_t lineEnd = currentBuffer.find_first_of('\n'); + +		if (lineEnd != string::npos) { + +			size_t actualLineEnd = lineEnd; + +			if (actualLineEnd != 0 && currentBuffer[actualLineEnd - 1] == '\r') {  // CRLF case +				actualLineEnd--; +			} + +			const string line(currentBuffer.begin(), currentBuffer.begin() + actualLineEnd); + +			currentBuffer.erase(currentBuffer.begin(), currentBuffer.begin() + lineEnd + 1); +			m_responseBuffer = currentBuffer; + +			if (m_tracer) { +				m_tracer->traceReceive(line); +			} + +			return line; +		} + +		// Check whether the time-out delay is elapsed +		if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { +				throw exceptions::operation_timed_out(); +			} + +			m_timeoutHandler->resetTimeOut(); +		} + +		// Receive data from the socket +		string receiveBuffer; +		m_socket->receive(receiveBuffer); + +		if (receiveBuffer.empty()) {   // buffer is empty +			m_socket->waitForRead(); +			continue; +		} + +		currentBuffer += receiveBuffer; +	} +} + + +const SMTPResponse::responseLine SMTPResponse::getNextResponse() { + +	string line = readResponseLine(); + +	const int code = extractResponseCode(line); +	string text; + +	m_responseContinues = (line.length() >= 4 && line[3] == '-'); + +	if (line.length() > 4) { +		text = utility::stringUtils::trim(line.substr(4)); +	} else { +		text = ""; +	} + +	return responseLine(code, text, extractEnhancedCode(text)); +} + + +// static +int SMTPResponse::extractResponseCode(const string& response) { + +	int code = 0; + +	if (response.length() >= 3) { + +		code = (response[0] - '0') * 100 +		     + (response[1] - '0') * 10 +		     + (response[2] - '0'); +	} + +	return code; +} + + +// static +const SMTPResponse::enhancedStatusCode SMTPResponse::extractEnhancedCode(const string& responseText) { + +	enhancedStatusCode enhCode; + +	std::istringstream iss(responseText); +	iss.imbue(std::locale::classic()); + +	if (std::isdigit(iss.peek())) { + +		iss >> enhCode.klass; + +		if (iss.get() == '.' && std::isdigit(iss.peek())) { + +			iss >> enhCode.subject; + +			if (iss.get() == '.' && std::isdigit(iss.peek())) { + +				iss >> enhCode.detail; +				return enhCode; +			} +		} +	} + +	return enhancedStatusCode();   // no enhanced code found +} + + +const SMTPResponse::responseLine SMTPResponse::getLineAt(const size_t pos) const { + +	return m_lines[pos]; +} + + +size_t SMTPResponse::getLineCount() const { + +	return m_lines.size(); +} + + +const SMTPResponse::responseLine SMTPResponse::getLastLine() const { + +	return m_lines[m_lines.size() - 1]; +} + + +const SMTPResponse::state SMTPResponse::getCurrentState() const { + +	state st; +	st.responseBuffer = m_responseBuffer; + +	return st; +} + + + +// SMTPResponse::responseLine + +SMTPResponse::responseLine::responseLine( +	const int code, +	const string& text, +	const enhancedStatusCode& enhCode +) +	: m_code(code), +	  m_text(text), +	  m_enhCode(enhCode) { + +} + + +void SMTPResponse::responseLine::setCode(const int code) { + +	m_code = code; +} + + +int SMTPResponse::responseLine::getCode() const { + +	return m_code; +} + + +void SMTPResponse::responseLine::setEnhancedCode(const enhancedStatusCode& enhCode) { + +	m_enhCode = enhCode; +} + + +const SMTPResponse::enhancedStatusCode SMTPResponse::responseLine::getEnhancedCode() const { + +	return m_enhCode; +} + + +void SMTPResponse::responseLine::setText(const string& text) { + +	m_text = text; +} + + +const string SMTPResponse::responseLine::getText() const { + +	return m_text; +} + + + +// SMTPResponse::enhancedStatusCode + + +SMTPResponse::enhancedStatusCode::enhancedStatusCode() +	: klass(0), +	  subject(0), +	  detail(0) { + +} + + +SMTPResponse::enhancedStatusCode::enhancedStatusCode(const enhancedStatusCode& enhCode) +	: klass(enhCode.klass), +	  subject(enhCode.subject), +	  detail(enhCode.detail) { + +} + + +std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code) { + +	os << code.klass << '.' << code.subject << '.' << code.detail; +	return os; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + diff --git a/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp new file mode 100644 index 0000000..2eec7f4 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp @@ -0,0 +1,200 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPRESPONSE_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/object.hpp" +#include "vmime/base.hpp" + + +namespace vmime { +namespace net { + + +class socket; +class timeoutHandler; +class tracer; + + +namespace smtp { + + +/** A SMTP response, as sent by the server. +  */ +class VMIME_EXPORT SMTPResponse : public object { + +public: + +	/** Current state of response parser. */ +	struct state { + +		string responseBuffer; +	}; + +	/** Enhanced status code (as per RFC-3463). */ +	struct enhancedStatusCode { + +		enhancedStatusCode(); +		enhancedStatusCode(const enhancedStatusCode& enhCode); + +		unsigned short klass;     /**< Success/failure. */ +		unsigned short subject;   /**< Source of anomaly. */ +		unsigned short detail;    /**< Precise error condition. */ +	}; + +	/** An element of a SMTP response. */ +	class responseLine { + +	public: + +		responseLine(const int code, const string& text, const enhancedStatusCode& enhCode); + +		void setCode(const int code); +		int getCode() const; + +		void setEnhancedCode(const enhancedStatusCode& enhCode); +		const enhancedStatusCode getEnhancedCode() const; + +		void setText(const string& text); +		const string getText() const; + +	private: + +		int m_code; +		string m_text; +		enhancedStatusCode m_enhCode; +	}; + +	/** Receive and parse a new SMTP response from the +	  * specified socket. +	  * +	  * @param tr tracer +	  * @param sok socket from which to read +	  * @param toh time-out handler +	  * @param st previous state of response parser for the specified socket +	  * @return SMTP response +	  * @throws exceptions::operation_timed_out if no data +	  * has been received within the granted time +	  */ +	static shared_ptr <SMTPResponse> readResponse( +		const shared_ptr <tracer>& tr, +		const shared_ptr <socket>& sok, +		const shared_ptr <timeoutHandler>& toh, +		const state& st +	); + +	/** Return the SMTP response code. +	  * +	  * @return response code +	  */ +	int getCode() const; + +	/** Return the SMTP enhanced status code, if available. +	  * +	  * @return enhanced status code +	  */ +	const enhancedStatusCode getEnhancedCode() const; + +	/** Return the SMTP response text. +	  * The text of each line is concatenated. +	  * +	  * @return response text +	  */ +	const string getText() const; + +	/** Return the response line at the specified position. +	  * +	  * @param pos line index +	  * @return line at the specified index +	  */ +	const responseLine getLineAt(const size_t pos) const; + +	/** Return the number of lines in the response. +	  * +	  * @return number of lines in the response +	  */ +	size_t getLineCount() const; + +	/** Return the last line in the response. +	  * +	  * @return last response line +	  */ +	const responseLine getLastLine() const; + +	/** Returns the current state of the response parser. +	  * +	  * @return current parser state +	  */ +	const state getCurrentState() const; + +private: + +	SMTPResponse( +		const shared_ptr <tracer>& tr, +		const shared_ptr <socket>& sok, +		const shared_ptr <timeoutHandler>& toh, +		const state& st +	); + +	SMTPResponse(const SMTPResponse&); + +	void readResponse(); + +	const string readResponseLine(); +	const responseLine getNextResponse(); + +	static int extractResponseCode(const string& response); +	static const enhancedStatusCode extractEnhancedCode(const string& responseText); + + +	std::vector <responseLine> m_lines; + +	shared_ptr <socket> m_socket; +	shared_ptr <timeoutHandler> m_timeoutHandler; +	shared_ptr <tracer> m_tracer; + +	string m_responseBuffer; +	bool m_responseContinues; +}; + + +VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code); + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp new file mode 100644 index 0000000..5158aa9 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp @@ -0,0 +1,82 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPSTransport.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPSTransport::SMTPSTransport( +	const shared_ptr <session>& sess, +	const shared_ptr <security::authenticator>& auth +) +	: SMTPTransport(sess, auth, true) { + +} + + +SMTPSTransport::~SMTPSTransport() { + +} + + +const string SMTPSTransport::getProtocolName() const { + +	return "smtps"; +} + + + +// Service infos + +SMTPServiceInfos SMTPSTransport::sm_infos(true); + + +const serviceInfos& SMTPSTransport::getInfosInstance() { + +	return sm_infos; +} + + +const serviceInfos& SMTPSTransport::getInfos() const { + +	return sm_infos; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp new file mode 100644 index 0000000..f19b3c5 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp @@ -0,0 +1,74 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPSSTORE_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/net/smtp/SMTPTransport.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +/** SMTPS transport service. +  */ +class VMIME_EXPORT SMTPSTransport : public SMTPTransport { + +public: + +	SMTPSTransport( +		const shared_ptr <session>& sess, +		const shared_ptr <security::authenticator>& auth +	); + +	~SMTPSTransport(); + +	const string getProtocolName() const; + +	static const serviceInfos& getInfosInstance(); +	const serviceInfos& getInfos() const; + +private: + +	static SMTPServiceInfos sm_infos; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp new file mode 100644 index 0000000..a2ee3d5 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp @@ -0,0 +1,144 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPServiceInfos.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPServiceInfos::SMTPServiceInfos(const bool smtps) +	: m_smtps(smtps) { + +} + + +const string SMTPServiceInfos::getPropertyPrefix() const { + +	if (m_smtps) { +		return "transport.smtps."; +	} else { +		return "transport.smtp."; +	} +} + + +const SMTPServiceInfos::props& SMTPServiceInfos::getProperties() const { + +	static props smtpProps = { +		// SMTP-specific options +		property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"), +#if VMIME_HAVE_SASL_SUPPORT +		property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"), +		property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"), +#endif // VMIME_HAVE_SASL_SUPPORT + +		property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"), +		property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"), + +		// Common properties +		property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), +		property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT +		property(serviceInfos::property::CONNECTION_TLS), +		property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + +		property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), +		property(serviceInfos::property::SERVER_PORT, "25"), +	}; + +	static props smtpsProps = { +		// SMTP-specific options +		property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"), +#if VMIME_HAVE_SASL_SUPPORT +		property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"), +		property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"), +#endif // VMIME_HAVE_SASL_SUPPORT + +		property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"), +		property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"), + +		// Common properties +		property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED), +		property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED), + +#if VMIME_HAVE_TLS_SUPPORT +		property(serviceInfos::property::CONNECTION_TLS), +		property(serviceInfos::property::CONNECTION_TLS_REQUIRED), +#endif // VMIME_HAVE_TLS_SUPPORT + +		property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED), +		property(serviceInfos::property::SERVER_PORT, "465"), +	}; + +	return m_smtps ? smtpsProps : smtpProps; +} + + +const std::vector <serviceInfos::property> SMTPServiceInfos::getAvailableProperties() const { + +	std::vector <property> list; +	const props& p = getProperties(); + +	// SMTP-specific options +	list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH); +#if VMIME_HAVE_SASL_SUPPORT +	list.push_back(p.PROPERTY_OPTIONS_SASL); +	list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK); +#endif // VMIME_HAVE_SASL_SUPPORT + +	// Common properties +	list.push_back(p.PROPERTY_AUTH_USERNAME); +	list.push_back(p.PROPERTY_AUTH_PASSWORD); + +#if VMIME_HAVE_TLS_SUPPORT +	if (!m_smtps) { +		list.push_back(p.PROPERTY_CONNECTION_TLS); +		list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED); +	} +#endif // VMIME_HAVE_TLS_SUPPORT + +	list.push_back(p.PROPERTY_SERVER_ADDRESS); +	list.push_back(p.PROPERTY_SERVER_PORT); + +	return list; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp new file mode 100644 index 0000000..005a0a2 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp @@ -0,0 +1,93 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPSERVICEINFOS_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/net/serviceInfos.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +/** Information about SMTP service. +  */ +class VMIME_EXPORT SMTPServiceInfos : public serviceInfos { + +public: + +	SMTPServiceInfos(const bool smtps); + +	struct props { +		// SMTP-specific options +		serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH; +#if VMIME_HAVE_SASL_SUPPORT +		serviceInfos::property PROPERTY_OPTIONS_SASL; +		serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK; +#endif // VMIME_HAVE_SASL_SUPPORT + +		serviceInfos::property PROPERTY_OPTIONS_PIPELINING; +		serviceInfos::property PROPERTY_OPTIONS_CHUNKING; + +		// Common properties +		serviceInfos::property PROPERTY_AUTH_USERNAME; +		serviceInfos::property PROPERTY_AUTH_PASSWORD; + +#if VMIME_HAVE_TLS_SUPPORT +		serviceInfos::property PROPERTY_CONNECTION_TLS; +		serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED; +#endif // VMIME_HAVE_TLS_SUPPORT + +		serviceInfos::property PROPERTY_SERVER_ADDRESS; +		serviceInfos::property PROPERTY_SERVER_PORT; +	}; + +	const props& getProperties() const; + +	const string getPropertyPrefix() const; +	const std::vector <serviceInfos::property> getAvailableProperties() const; + +private: + +	const bool m_smtps; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp new file mode 100644 index 0000000..561bd59 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp @@ -0,0 +1,502 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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/SMTPTransport.hpp" +#include "vmime/net/smtp/SMTPResponse.hpp" +#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" +#include "vmime/message.hpp" + +#include "vmime/utility/filteredStream.hpp" +#include "vmime/utility/stringUtils.hpp" +#include "vmime/utility/outputStreamSocketAdapter.hpp" +#include "vmime/utility/streamUtils.hpp" +#include "vmime/utility/outputStreamAdapter.hpp" +#include "vmime/utility/inputStreamStringAdapter.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPTransport::SMTPTransport( +	const shared_ptr <session>& sess, +	const shared_ptr <security::authenticator>& auth, +	const bool secured +) +	: transport(sess, getInfosInstance(), auth), +	  m_isSMTPS(secured), +	  m_needReset(false) { + +} + + +SMTPTransport::~SMTPTransport() { + +	try { + +		if (isConnected()) { +			disconnect(); +		} + +	} catch (...) { + +		// Don't throw in destructor +	} +} + + +const string SMTPTransport::getProtocolName() const { + +	return "smtp"; +} + + +bool SMTPTransport::isSMTPS() const { + +	return m_isSMTPS; +} + + +void SMTPTransport::connect() { + +	if (isConnected()) { +		throw exceptions::already_connected(); +	} + +	m_connection = make_shared <SMTPConnection>( +		dynamicCast <SMTPTransport>(shared_from_this()), getAuthenticator() +	); + +	m_connection->connect(); +} + + +bool SMTPTransport::isConnected() const { + +	return m_connection && m_connection->isConnected(); +} + + +bool SMTPTransport::isSecuredConnection() const { + +	if (!m_connection) { +		return false; +	} + +	return m_connection->isSecuredConnection(); +} + + +shared_ptr <connectionInfos> SMTPTransport::getConnectionInfos() const { + +	if (!m_connection) { +		return null; +	} + +	return m_connection->getConnectionInfos(); +} + + +shared_ptr <SMTPConnection> SMTPTransport::getConnection() { + +	return m_connection; +} + + +void SMTPTransport::disconnect() { + +	if (!isConnected()) { +		throw exceptions::not_connected(); +	} + +	m_connection->disconnect(); +	m_connection = null; +} + + +void SMTPTransport::noop() { + +	if (!isConnected()) { +		throw exceptions::not_connected(); +	} + +	m_connection->sendRequest(SMTPCommand::NOOP()); + +	shared_ptr <SMTPResponse> resp = m_connection->readResponse(); + +	if (resp->getCode() != 250) { +		throw SMTPCommandError("NOOP", resp->getText(), resp->getCode(), resp->getEnhancedCode()); +	} +} + + +// static +bool SMTPTransport::mailboxNeedsUTF8(const mailbox& mb) { + +	bool all7bit = +		   utility::stringUtils::is7bit(mb.getEmail().getLocalName().getBuffer()) +		&& utility::stringUtils::is7bit(mb.getEmail().getDomainName().getBuffer()); + +	for (size_t i = 0, n = mb.getName().getWordCount() ; all7bit && i != n ; ++i) { +		all7bit = utility::stringUtils::is7bit(mb.getName().getWordAt(i)->getBuffer()); +	} + +	return !all7bit; +} + + +void SMTPTransport::sendEnvelope( +	const mailbox& expeditor, +	const mailboxList& recipients, +	const mailbox& sender, +	bool sendDATACommand, +	const size_t size, +	const dsnAttributes& dsnAttrs +) { + +	// If no recipient/expeditor was found, throw an exception +	if (recipients.isEmpty()) { +		throw exceptions::no_recipient(); +	} else if (expeditor.isEmpty()) { +		throw exceptions::no_expeditor(); +	} + +	// If DSN extension is used, ensure it is supported by the server +	if (!dsnAttrs.isEmpty() && !m_connection->hasExtension("DSN")) { +		throw SMTPDSNExtensionNotSupportedException(); +	} + + +	const bool needReset = m_needReset; +	const bool hasPipelining = m_connection->hasExtension("PIPELINING") && +		getInfos().getPropertyValue <bool>(getSession(), +			dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_PIPELINING); + +	shared_ptr <SMTPResponse> resp; +	shared_ptr <SMTPCommandSet> commands = SMTPCommandSet::create(hasPipelining); + +	// Emit a "RSET" command if we previously sent a message on this connection +	if (needReset) { +		commands->addCommand(SMTPCommand::RSET()); +	} + +	// Check whether we need SMTPUTF8 +	const bool hasSMTPUTF8 = m_connection->hasExtension("SMTPUTF8"); +	bool needSMTPUTF8 = false; + +	if (!sender.isEmpty()) { +		needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(sender); +	} else { +		needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(expeditor); +	} + +	for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) { + +		const mailbox& mbox = *recipients.getMailboxAt(i); +		needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(mbox); +	} + +	// Emit the "MAIL" command +	const bool hasSize = m_connection->hasExtension("SIZE"); + +	if (!sender.isEmpty()) { + +		commands->addCommand( +			SMTPCommand::MAIL( +				sender, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0, +				dsnAttrs.getNotificationConditions(), +				dsnAttrs.getEnvelopId() +			) +		); + +	} else { + +		commands->addCommand( +			SMTPCommand::MAIL( +				expeditor, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0, +				dsnAttrs.getNotificationConditions(), +				dsnAttrs.getEnvelopId() +			) +		); +	} + +	// Now, we will need to reset next time +	m_needReset = true; + +	// Emit a "RCPT TO" command for each recipient +	for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) { + +		const mailbox& mbox = *recipients.getMailboxAt(i); +		commands->addCommand(SMTPCommand::RCPT(mbox, hasSMTPUTF8 && needSMTPUTF8, +											   dsnAttrs.getNotificationConditions())); +	} + +	// Prepare sending of message data +	if (sendDATACommand) { +		commands->addCommand(SMTPCommand::DATA()); +	} + +	// Read response for "RSET" command +	if (needReset) { + +		commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); + +		resp = m_connection->readResponse(); + +		if (resp->getCode() != 250 && +		    resp->getCode() != 200) {   // RFC-876: << In reply to a RSET and/or a NOOP command, +		                                //             some servers reply "200" >> + +			disconnect(); + +			throw SMTPCommandError( +				commands->getLastCommandSent()->getText(), resp->getText(), +				resp->getCode(), resp->getEnhancedCode() +			); +		} +	} + +	// Read response for "MAIL" command +	commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); + +	if ((resp = m_connection->readResponse())->getCode() != 250) { + +		// SIZE extension: insufficient system storage +		if (resp->getCode() == 452) { + +			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) { + +			throw SMTPMessageSizeExceedsMaxLimitsException( +				SMTPCommandError( +					commands->getLastCommandSent()->getText(), resp->getText(), +				 	resp->getCode(), resp->getEnhancedCode() +				 ) +			); + +		// Other error +		} else { + +			throw SMTPCommandError( +				commands->getLastCommandSent()->getText(), resp->getText(), +				resp->getCode(), resp->getEnhancedCode() +			); +		} +	} + +	// Read responses for "RCPT TO" commands +	for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) { + +		commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); + +		resp = m_connection->readResponse(); + +		if (resp->getCode() != 250 && +		    resp->getCode() != 251) { + +			// SIZE extension: insufficient system storage +			if (resp->getCode() == 452) { + +				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) { + +				throw SMTPMessageSizeExceedsMaxLimitsException( +					SMTPCommandError( +						commands->getLastCommandSent()->getText(), resp->getText(), +						resp->getCode(), resp->getEnhancedCode() +					) +				); + +			// Other error +			} else { + +				throw SMTPCommandError( +					commands->getLastCommandSent()->getText(), resp->getText(), +					resp->getCode(), resp->getEnhancedCode() +				); +			} +		} +	} + +	// Read response for "DATA" command +	if (sendDATACommand) { + +		commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); + +		if ((resp = m_connection->readResponse())->getCode() != 354) { + +			throw SMTPCommandError( +				commands->getLastCommandSent()->getText(), resp->getText(), +				resp->getCode(), resp->getEnhancedCode() +			); +		} +	} +} + + +void SMTPTransport::send( +	const mailbox& expeditor, +	const mailboxList& recipients, +	utility::inputStream& is, +	const size_t size, +	utility::progressListener* progress, +	const mailbox& sender, +	const dsnAttributes& dsnAttrs +) { + +	if (!isConnected()) { +		throw exceptions::not_connected(); +	} + +	// Send message envelope +	sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ true, size, +				 dsnAttrs); + +	// Send the message data +	// Stream copy with "\n." to "\n.." transformation +	utility::outputStreamSocketAdapter sos(*m_connection->getSocket()); +	utility::dotFilteredOutputStream fos(sos); + +	utility::bufferedStreamCopy(is, fos, size, progress); + +	fos.flush(); + +	// Send end-of-data delimiter +	m_connection->getSocket()->send("\r\n.\r\n"); + +	if (m_connection->getTracer()) { +		m_connection->getTracer()->traceSendBytes(size); +		m_connection->getTracer()->traceSend("."); +	} + +	shared_ptr <SMTPResponse> resp; + +	if ((resp = m_connection->readResponse())->getCode() != 250) { +		throw SMTPCommandError("DATA", resp->getText(), resp->getCode(), resp->getEnhancedCode()); +	} +} + + +void SMTPTransport::send( +	const shared_ptr <vmime::message>& msg, +	const mailbox& expeditor, +	const mailboxList& recipients, +	utility::progressListener* progress, +	const mailbox& sender, +	const dsnAttributes& dsnAttrs +) { + +	if (!isConnected()) { +		throw exceptions::not_connected(); +	} + +	// Generate the message with Internationalized Email support, +	// if this is supported by the SMTP server +	generationContext ctx(generationContext::getDefaultContext()); +	ctx.setInternationalizedEmailSupport(m_connection->hasExtension("SMTPUTF8")); + +	// If CHUNKING is not supported, generate the message to a temporary +	// buffer then use the send() method which takes an inputStream +	if (!m_connection->hasExtension("CHUNKING") || +	    !getInfos().getPropertyValue <bool>(getSession(), +			dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_CHUNKING)) { + +		std::ostringstream oss; +		utility::outputStreamAdapter ossAdapter(oss); + +		msg->generate(ctx, ossAdapter); + +		const string& str(oss.str()); + +		utility::inputStreamStringAdapter isAdapter(str); + +		send(expeditor, recipients, isAdapter, str.length(), progress, sender, dsnAttrs); +		return; +	} + +	// Send message envelope +	const size_t msgSize = msg->getGeneratedSize(ctx); + +	sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ false, msgSize, dsnAttrs); + +	// Send the message by chunks +	SMTPChunkingOutputStreamAdapter chunkStream(m_connection, msgSize, progress); + +	msg->generate(ctx, chunkStream); + +	chunkStream.flush(); +} + + + +// Service infos + +SMTPServiceInfos SMTPTransport::sm_infos(false); + + +const serviceInfos& SMTPTransport::getInfosInstance() { + +	return sm_infos; +} + + +const serviceInfos& SMTPTransport::getInfos() const { + +	return sm_infos; +} + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp new file mode 100644 index 0000000..cd7c712 --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp @@ -0,0 +1,144 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTPTRANSPORT_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + + +#include "vmime/net/transport.hpp" +#include "vmime/net/socket.hpp" +#include "vmime/net/timeoutHandler.hpp" + +#include "vmime/net/smtp/SMTPServiceInfos.hpp" +#include "vmime/net/smtp/SMTPConnection.hpp" + + +namespace vmime { +namespace net { +namespace smtp { + + +class SMTPCommand; + + +/** SMTP transport service. +  */ +class VMIME_EXPORT SMTPTransport : public transport { + +public: + +	SMTPTransport( +		const shared_ptr <session>& sess, +		const shared_ptr <security::authenticator>& auth, +		const bool secured = false +	); + +	~SMTPTransport(); + +	const string getProtocolName() const; + +	static const serviceInfos& getInfosInstance(); +	const serviceInfos& getInfos() const; + +	void connect(); +	bool isConnected() const; +	void disconnect(); + +	void noop(); + +	void send( +		const mailbox& expeditor, +		const mailboxList& recipients, +		utility::inputStream& is, +		const size_t size, +		utility::progressListener* progress = NULL, +		const mailbox& sender = mailbox(), +		const dsnAttributes& dsnAttrs = dsnAttributes() +	); + +	void send( +		const shared_ptr <vmime::message>& msg, +		const mailbox& expeditor, +		const mailboxList& recipients, +		utility::progressListener* progress = NULL, +		const mailbox& sender = mailbox(), +		const dsnAttributes& dsnAttrs = dsnAttributes() +	); + +	bool isSecuredConnection() const; +	shared_ptr <connectionInfos> getConnectionInfos() const; +	shared_ptr <SMTPConnection> getConnection(); + +	bool isSMTPS() const; + +private: + +	static bool mailboxNeedsUTF8(const mailbox& mb); + +	/** Send the MAIL and RCPT commands to the server, checking the +	  * response, and using pipelining if supported by the server. +	  * Optionally, the DATA command can also be sent. +	  * +	  * @param expeditor expeditor mailbox +	  * @param recipients list of recipient mailboxes +	  * @param sender envelope sender (if empty, expeditor will be used) +	  * @param sendDATACommand if true, the DATA command will be sent +	  * @param size message size, in bytes (or 0, if not known) +	  * @param dsnAttributes attributes for Delivery Status Notification (if needed) +	  */ +	void sendEnvelope( +		const mailbox& expeditor, +		const mailboxList& recipients, +		const mailbox& sender, +		bool sendDATACommand, +		const size_t size, +		const dsnAttributes& dsnAttrs = dsnAttributes() +	); + + +	shared_ptr <SMTPConnection> m_connection; + + +	const bool m_isSMTPS; + +	bool m_needReset; + +	// Service infos +	static SMTPServiceInfos sm_infos; +}; + + +} // smtp +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP + +#endif // VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED diff --git a/vmime-master/src/vmime/net/smtp/smtp.hpp b/vmime-master/src/vmime/net/smtp/smtp.hpp new file mode 100644 index 0000000..4c0b17d --- /dev/null +++ b/vmime-master/src/vmime/net/smtp/smtp.hpp @@ -0,0 +1,33 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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_SMTP_HPP_INCLUDED +#define VMIME_NET_SMTP_SMTP_HPP_INCLUDED + + +#include "vmime/net/smtp/SMTPTransport.hpp" +#include "vmime/net/smtp/SMTPSTransport.hpp" +#include "vmime/net/smtp/SMTPExceptions.hpp" + + +#endif // VMIME_NET_SMTP_SMTP_HPP_INCLUDED | 
