diff --git a/src/net/smtp/SMTPResponse.cpp b/src/net/smtp/SMTPResponse.cpp index 91923339..86a7a7bd 100644 --- a/src/net/smtp/SMTPResponse.cpp +++ b/src/net/smtp/SMTPResponse.cpp @@ -35,6 +35,8 @@ #include "vmime/net/socket.hpp" #include "vmime/net/timeoutHandler.hpp" +#include + namespace vmime { namespace net { @@ -71,6 +73,12 @@ int SMTPResponse::getCode() const } +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(); @@ -175,7 +183,7 @@ const SMTPResponse::responseLine SMTPResponse::getNextResponse() else text = ""; - return responseLine(code, text); + return responseLine(code, text, extractEnhancedCode(text)); } @@ -195,6 +203,33 @@ int SMTPResponse::extractResponseCode(const string& response) } +// static +const SMTPResponse::enhancedStatusCode SMTPResponse::extractEnhancedCode(const string& responseText) +{ + enhancedStatusCode enhCode; + + std::istringstream iss(responseText); + + 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]; @@ -225,8 +260,8 @@ const SMTPResponse::state SMTPResponse::getCurrentState() const // SMTPResponse::responseLine -SMTPResponse::responseLine::responseLine(const int code, const string& text) - : m_code(code), m_text(text) +SMTPResponse::responseLine::responseLine(const int code, const string& text, const enhancedStatusCode& enhCode) + : m_code(code), m_text(text), m_enhCode(enhCode) { } @@ -243,6 +278,18 @@ int SMTPResponse::responseLine::getCode() const } +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; @@ -255,6 +302,22 @@ const string SMTPResponse::responseLine::getText() const } + +// 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) +{ +} + + } // smtp } // net } // vmime diff --git a/tests/net/smtp/SMTPResponseTest.cpp b/tests/net/smtp/SMTPResponseTest.cpp index 85bf7b3a..5e75b6a7 100644 --- a/tests/net/smtp/SMTPResponseTest.cpp +++ b/tests/net/smtp/SMTPResponseTest.cpp @@ -35,6 +35,9 @@ VMIME_TEST_SUITE_BEGIN(SMTPResponseTest) VMIME_TEST(testMultiLineResponseDifferentCode) VMIME_TEST(testIncompleteMultiLineResponse) VMIME_TEST(testNoResponseText) + VMIME_TEST(testEnhancedStatusCode) + VMIME_TEST(testNoEnhancedStatusCode) + VMIME_TEST(testInvalidEnhancedStatusCode) VMIME_TEST_LIST_END @@ -171,6 +174,68 @@ VMIME_TEST_SUITE_BEGIN(SMTPResponseTest) VASSERT_EQ("Text", "", resp->getText()); } + void testEnhancedStatusCode() + { + vmime::ref socket = vmime::create (); + vmime::ref toh = + vmime::create (); + + socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::ref resp = + vmime::net::smtp::SMTPResponse::readResponse(socket, toh, responseState); + + VASSERT_EQ("Code", 250, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "2.1.5 OK fu13sm4720601wic.7 - gsmtp", resp->getText()); + VASSERT_EQ("Enh.class", 2, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 1, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 5, resp->getEnhancedCode().detail); + } + + void testNoEnhancedStatusCode() + { + vmime::ref socket = vmime::create (); + vmime::ref toh = + vmime::create (); + + socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::ref resp = + vmime::net::smtp::SMTPResponse::readResponse(socket, toh, responseState); + + VASSERT_EQ("Code", 354, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "Go ahead fu13sm4720601wic.7 - gsmtp", resp->getText()); + VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail); + } + + void testInvalidEnhancedStatusCode() + { + vmime::ref socket = vmime::create (); + vmime::ref toh = + vmime::create (); + + socket->localSend("250 4.2 xxx\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::ref resp = + vmime::net::smtp::SMTPResponse::readResponse(socket, toh, responseState); + + VASSERT_EQ("Code", 250, resp->getCode()); + VASSERT_EQ("Lines", 1, resp->getLineCount()); + VASSERT_EQ("Text", "4.2 xxx", resp->getText()); + VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass); + VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject); + VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail); + } VMIME_TEST_SUITE_END diff --git a/vmime/net/smtp/SMTPResponse.hpp b/vmime/net/smtp/SMTPResponse.hpp index eea61801..79b25ee7 100644 --- a/vmime/net/smtp/SMTPResponse.hpp +++ b/vmime/net/smtp/SMTPResponse.hpp @@ -60,16 +60,30 @@ public: 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); + 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; @@ -77,6 +91,7 @@ public: int m_code; string m_text; + enhancedStatusCode m_enhCode; }; /** Receive and parse a new SMTP response from the @@ -97,6 +112,12 @@ public: */ 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. * @@ -140,6 +161,7 @@ private: const responseLine getNextResponse(); static int extractResponseCode(const string& response); + static const enhancedStatusCode extractEnhancedCode(const string& responseText); std::vector m_lines;