diff options
author | Vincent Richard <[email protected]> | 2012-11-11 20:55:44 +0000 |
---|---|---|
committer | Vincent Richard <[email protected]> | 2012-11-11 20:55:44 +0000 |
commit | 6ae75bc9714d8a5cae48b7a2dfe435fd2a56a6da (patch) | |
tree | df32e4e3cb10e82cf4e0c0897bfa8160132afd3a /src | |
parent | Compatibility with RFC-1341. (diff) | |
download | vmime-6ae75bc9714d8a5cae48b7a2dfe435fd2a56a6da.tar.gz vmime-6ae75bc9714d8a5cae48b7a2dfe435fd2a56a6da.zip |
SMTP Command Pipelining (RFC-2920).
Diffstat (limited to 'src')
-rw-r--r-- | src/net/smtp/SMTPResponse.cpp | 17 | ||||
-rw-r--r-- | src/net/smtp/SMTPTransport.cpp | 133 |
2 files changed, 122 insertions, 28 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; } |