aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/net/smtp/SMTPResponse.cpp17
-rw-r--r--src/net/smtp/SMTPTransport.cpp133
-rw-r--r--vmime/net/smtp/SMTPResponse.hpp17
-rw-r--r--vmime/net/smtp/SMTPTransport.hpp13
4 files changed, 147 insertions, 33 deletions
diff --git a/src/net/smtp/SMTPResponse.cpp b/src/net/smtp/SMTPResponse.cpp
index e1ac2af6..28a1ea87 100644
--- a/src/net/smtp/SMTPResponse.cpp
+++ b/src/net/smtp/SMTPResponse.cpp
@@ -41,9 +41,9 @@ namespace net {
namespace smtp {
-SMTPResponse::SMTPResponse(ref <socket> sok, ref <timeoutHandler> toh)
+SMTPResponse::SMTPResponse(ref <socket> sok, ref <timeoutHandler> toh, const state& st)
: m_socket(sok), m_timeoutHandler(toh),
- m_responseContinues(false)
+ m_responseBuffer(st.responseBuffer), m_responseContinues(false)
{
}
@@ -87,9 +87,9 @@ const string SMTPResponse::getText() const
// static
ref <SMTPResponse> SMTPResponse::readResponse
- (ref <socket> sok, ref <timeoutHandler> toh)
+ (ref <socket> sok, ref <timeoutHandler> toh, const state& st)
{
- ref <SMTPResponse> resp = vmime::create <SMTPResponse>(sok, toh);
+ ref <SMTPResponse> resp = vmime::create <SMTPResponse>(sok, toh, st);
resp->readResponse();
@@ -218,6 +218,15 @@ const SMTPResponse::responseLine SMTPResponse::getLastLine() const
}
+const SMTPResponse::state SMTPResponse::getCurrentState() const
+{
+ state st;
+ st.responseBuffer = m_responseBuffer;
+
+ return st;
+}
+
+
// SMTPResponse::responseLine
diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp
index e658ecb7..eb29e65d 100644
--- a/src/net/smtp/SMTPTransport.cpp
+++ b/src/net/smtp/SMTPTransport.cpp
@@ -68,7 +68,7 @@ namespace smtp {
SMTPTransport::SMTPTransport(ref <session> sess, ref <security::authenticator> auth, const bool secured)
: transport(sess, getInfosInstance(), auth), m_socket(NULL),
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL),
- m_isSMTPS(secured), m_secured(false)
+ m_isSMTPS(secured), m_secured(false), m_pipelineStarted(false)
{
}
@@ -571,40 +571,91 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
else if (expeditor.isEmpty())
throw exceptions::no_expeditor();
- // Emit the "MAIL" command
- ref <SMTPResponse> resp;
- sendRequest("MAIL FROM:<" + expeditor.getEmail() + ">");
+ ref <SMTPResponse> resp;
- if ((resp = readResponse())->getCode() != 250)
+ if (m_extensions.find("PIPELINING") != m_extensions.end())
{
- internalDisconnect();
- throw exceptions::command_error("MAIL", resp->getText());
- }
+ beginCommandPipeline();
- // Emit a "RCPT TO" command for each recipient
- for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
- {
- const mailbox& mbox = *recipients.getMailboxAt(i);
+ // Emit the "MAIL" command
+ sendRequest("MAIL FROM:<" + expeditor.getEmail() + ">");
+
+ // Emit a "RCPT TO" command for each recipient
+ for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
+ {
+ const mailbox& mbox = *recipients.getMailboxAt(i);
- sendRequest("RCPT TO:<" + mbox.getEmail() + ">");
+ sendRequest("RCPT TO:<" + mbox.getEmail() + ">");
+ }
+
+ // Prepare sending of message data
+ sendRequest("DATA");
+ endCommandPipeline();
+
+ // Read response for "MAIL" command
if ((resp = readResponse())->getCode() != 250)
{
internalDisconnect();
- throw exceptions::command_error("RCPT TO", resp->getText(), mbox.getEmail());
+ throw exceptions::command_error("MAIL", resp->getText());
}
- }
- // Send the message data
- sendRequest("DATA");
+ // Read responses for "RCPT TO" commands
+ for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
+ {
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+
+ if ((resp = readResponse())->getCode() != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("RCPT TO", resp->getText(), mbox.getEmail());
+ }
+ }
- if ((resp = readResponse())->getCode() != 354)
+ // Read response for "DATA" command
+ if ((resp = readResponse())->getCode() != 354)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("DATA", resp->getText());
+ }
+ }
+ else
{
- internalDisconnect();
- throw exceptions::command_error("DATA", resp->getText());
+ // Emit the "MAIL" command
+ sendRequest("MAIL FROM:<" + expeditor.getEmail() + ">");
+
+ if ((resp = readResponse())->getCode() != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("MAIL", resp->getText());
+ }
+
+ // Emit a "RCPT TO" command for each recipient
+ for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
+ {
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+
+ sendRequest("RCPT TO:<" + mbox.getEmail() + ">");
+
+ if ((resp = readResponse())->getCode() != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("RCPT TO", resp->getText(), mbox.getEmail());
+ }
+ }
+
+ // Prepare sending of message data
+ sendRequest("DATA");
+
+ if ((resp = readResponse())->getCode() != 354)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("DATA", resp->getText());
+ }
}
+ // Send the message data
// Stream copy with "\n." to "\n.." transformation
utility::outputStreamSocketAdapter sos(*m_socket);
utility::dotFilteredOutputStream fos(sos);
@@ -624,18 +675,52 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
}
+void SMTPTransport::beginCommandPipeline()
+{
+ m_pipeline.clear();
+ m_pipelineStarted = true;
+}
+
+
+void SMTPTransport::endCommandPipeline()
+{
+ if (m_pipelineStarted)
+ {
+ m_socket->send(m_pipeline.str());
+
+ m_pipeline.clear();
+ m_pipelineStarted = false;
+ }
+}
+
+
void SMTPTransport::sendRequest(const string& buffer, const bool end)
{
- if (end)
- m_socket->send(buffer + "\r\n");
+ if (m_pipelineStarted)
+ {
+ m_pipeline << buffer;
+
+ if (end)
+ m_pipeline << "\r\n";
+ }
else
- m_socket->send(buffer);
+ {
+ if (end)
+ m_socket->send(buffer + "\r\n");
+ else
+ m_socket->send(buffer);
+ }
}
ref <SMTPResponse> SMTPTransport::readResponse()
{
- return SMTPResponse::readResponse(m_socket, m_timeoutHandler);
+ ref <SMTPResponse> resp = SMTPResponse::readResponse
+ (m_socket, m_timeoutHandler, m_responseState);
+
+ m_responseState = resp->getCurrentState();
+
+ return resp;
}
diff --git a/vmime/net/smtp/SMTPResponse.hpp b/vmime/net/smtp/SMTPResponse.hpp
index 265e16fe..0a96530c 100644
--- a/vmime/net/smtp/SMTPResponse.hpp
+++ b/vmime/net/smtp/SMTPResponse.hpp
@@ -54,6 +54,12 @@ class SMTPResponse : public object
public:
+ /** Current state of response parser. */
+ struct state
+ {
+ string responseBuffer;
+ };
+
/** An element of a SMTP response. */
class responseLine
{
@@ -78,11 +84,12 @@ public:
*
* @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 ref <SMTPResponse> readResponse(ref <socket> sok, ref <timeoutHandler> toh);
+ static ref <SMTPResponse> readResponse(ref <socket> sok, ref <timeoutHandler> toh, const state& st);
/** Return the SMTP response code.
*
@@ -116,9 +123,15 @@ public:
*/
const responseLine getLastLine() const;
+ /** Returns the current state of the response parser.
+ *
+ * @return current parser state
+ */
+ const state getCurrentState() const;
+
private:
- SMTPResponse(ref <socket> sok, ref <timeoutHandler> toh);
+ SMTPResponse(ref <socket> sok, ref <timeoutHandler> toh, const state& st);
SMTPResponse(const SMTPResponse&);
void readResponse();
diff --git a/vmime/net/smtp/SMTPTransport.hpp b/vmime/net/smtp/SMTPTransport.hpp
index a8b4558b..5cec7c70 100644
--- a/vmime/net/smtp/SMTPTransport.hpp
+++ b/vmime/net/smtp/SMTPTransport.hpp
@@ -36,6 +36,7 @@
#include "vmime/net/timeoutHandler.hpp"
#include "vmime/net/smtp/SMTPServiceInfos.hpp"
+#include "vmime/net/smtp/SMTPResponse.hpp"
namespace vmime {
@@ -43,9 +44,6 @@ namespace net {
namespace smtp {
-class SMTPResponse;
-
-
/** SMTP transport service.
*/
@@ -102,6 +100,15 @@ private:
bool m_secured;
ref <connectionInfos> m_cntInfos;
+ SMTPResponse::state m_responseState;
+
+ // Pipelining
+ std::ostringstream m_pipeline;
+ bool m_pipelineStarted;
+
+ void beginCommandPipeline();
+ void endCommandPipeline();
+
// Service infos
static SMTPServiceInfos sm_infos;