diff options
Diffstat (limited to '')
27 files changed, 463 insertions, 49 deletions
diff --git a/src/vmime/net/imap/IMAPCommand.cpp b/src/vmime/net/imap/IMAPCommand.cpp index 19c3b723..b1840d8d 100644 --- a/src/vmime/net/imap/IMAPCommand.cpp +++ b/src/vmime/net/imap/IMAPCommand.cpp @@ -56,7 +56,7 @@ shared_ptr <IMAPCommand> IMAPCommand::LOGIN(const string& username, const string std::ostringstream trace; trace.imbue(std::locale::classic()); - trace << "LOGIN <username> <password>"; + trace << "LOGIN {username} {password}"; return createCommand(cmd.str(), trace.str()); } diff --git a/src/vmime/net/imap/IMAPCommand.hpp b/src/vmime/net/imap/IMAPCommand.hpp index c0a0d9b1..6003c227 100644 --- a/src/vmime/net/imap/IMAPCommand.hpp +++ b/src/vmime/net/imap/IMAPCommand.hpp @@ -98,7 +98,7 @@ public: /** Returns the full text of the command, suitable for outputing * to the tracer. * - * @return trace text (eg. "LOGIN myusername ***") + * @return trace text (eg. "LOGIN {username} {password}") */ virtual const string getTraceText() const; diff --git a/src/vmime/net/imap/IMAPConnection.cpp b/src/vmime/net/imap/IMAPConnection.cpp index 57f2ff5e..28a71662 100644 --- a/src/vmime/net/imap/IMAPConnection.cpp +++ b/src/vmime/net/imap/IMAPConnection.cpp @@ -71,10 +71,16 @@ IMAPConnection::IMAPConnection(shared_ptr <IMAPStore> store, shared_ptr <securit m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(null), m_secured(false), m_firstTag(true), m_capabilitiesFetched(false), m_noModSeq(false) { + static int connectionId = 0; + m_tag = make_shared <IMAPTag>(); + if (store->getTracerFactory()) + m_tracer = store->getTracerFactory()->create(store, ++connectionId); + m_parser = make_shared <IMAPParser>(); m_parser->setTag(m_tag); + m_parser->setTracer(m_tracer); } @@ -439,6 +445,9 @@ void IMAPConnection::authenticateSASL() const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n"; sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length()); + if (m_tracer) + m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange"); + // Server capabilities may change when logged in invalidateCapabilities(); } @@ -458,6 +467,9 @@ void IMAPConnection::authenticateSASL() // Cancel SASL exchange sendRaw(utility::stringUtils::bytesFromString("*\r\n"), 3); + + if (m_tracer) + m_tracer->traceSend("*"); } catch (...) { @@ -752,6 +764,14 @@ void IMAPConnection::sendCommand(shared_ptr <IMAPCommand> cmd) m_socket->send("\r\n"); m_firstTag = false; + + if (m_tracer) + { + std::ostringstream oss; + oss << string(*m_tag) << " " << cmd->getText(); + + m_tracer->traceSend(oss.str()); + } } @@ -816,6 +836,12 @@ void IMAPConnection::setSocket(shared_ptr <socket> sok) } +shared_ptr <tracer> IMAPConnection::getTracer() +{ + return m_tracer; +} + + shared_ptr <IMAPTag> IMAPConnection::getTag() { return m_tag; diff --git a/src/vmime/net/imap/IMAPConnection.hpp b/src/vmime/net/imap/IMAPConnection.hpp index da1b9ba4..b863ce33 100644 --- a/src/vmime/net/imap/IMAPConnection.hpp +++ b/src/vmime/net/imap/IMAPConnection.hpp @@ -33,6 +33,7 @@ #include "vmime/net/socket.hpp" #include "vmime/net/timeoutHandler.hpp" +#include "vmime/net/tracer.hpp" #include "vmime/net/session.hpp" #include "vmime/net/connectionInfos.hpp" @@ -105,6 +106,8 @@ public: shared_ptr <const socket> getSocket() const; void setSocket(shared_ptr <socket> sok); + shared_ptr <tracer> getTracer(); + shared_ptr <IMAPTag> getTag(); bool isMODSEQDisabled() const; @@ -151,6 +154,8 @@ private: bool m_noModSeq; + shared_ptr <tracer> m_tracer; + void internalDisconnect(); diff --git a/src/vmime/net/imap/IMAPFolder.cpp b/src/vmime/net/imap/IMAPFolder.cpp index e602ea6e..00fee93c 100644 --- a/src/vmime/net/imap/IMAPFolder.cpp +++ b/src/vmime/net/imap/IMAPFolder.cpp @@ -1124,6 +1124,9 @@ messageSet IMAPFolder::addMessage m_connection->sendRaw(utility::stringUtils::bytesFromString("\r\n"), 2); + if (m_connection->getTracer()) + m_connection->getTracer()->traceSendBytes(current); + if (progress) progress->stop(total); diff --git a/src/vmime/net/imap/IMAPParser.hpp b/src/vmime/net/imap/IMAPParser.hpp index ba0ea195..d38ac14a 100644 --- a/src/vmime/net/imap/IMAPParser.hpp +++ b/src/vmime/net/imap/IMAPParser.hpp @@ -49,6 +49,7 @@ #include "vmime/net/timeoutHandler.hpp" #include "vmime/net/socket.hpp" +#include "vmime/net/tracer.hpp" #include "vmime/net/imap/IMAPTag.hpp" @@ -281,6 +282,15 @@ public: m_timeoutHandler = toh; } + /** Set the tracer currently used by this parser. + * + * @param tr tracer + */ + void setTracer(shared_ptr <tracer> tr) + { + m_tracer = tr; + } + /** Set whether we operate in strict mode (this may not work * with some servers which are not fully standard-compliant). * @@ -5687,6 +5697,7 @@ private: weak_ptr <IMAPTag> m_tag; weak_ptr <socket> m_socket; + shared_ptr <tracer> m_tracer; utility::progressListener* m_progress; @@ -5731,6 +5742,13 @@ public: std::cout << std::endl << "Read line:" << std::endl << line << std::endl; #endif + if (m_tracer) + { + string::size_type len = line.length(); + while (len != 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) --len; + m_tracer->traceReceive(line.substr(0, len)); + } + return (line); } @@ -5860,6 +5878,9 @@ public: m_progress->progress(len, count); } + if (m_tracer) + m_tracer->traceReceiveBytes(count); + if (m_progress) m_progress->stop(count); } diff --git a/src/vmime/net/pop3/POP3Command.cpp b/src/vmime/net/pop3/POP3Command.cpp index 3c544fc0..9dfaf17a 100644 --- a/src/vmime/net/pop3/POP3Command.cpp +++ b/src/vmime/net/pop3/POP3Command.cpp @@ -42,8 +42,8 @@ namespace net { namespace pop3 { -POP3Command::POP3Command(const string& text) - : m_text(text) +POP3Command::POP3Command(const string& text, const string& traceText) + : m_text(text), m_traceText(traceText) { } @@ -109,7 +109,11 @@ shared_ptr <POP3Command> POP3Command::USER(const string& username) cmd.imbue(std::locale::classic()); cmd << "USER " << username; - return createCommand(cmd.str()); + std::ostringstream trace; + trace.imbue(std::locale::classic()); + trace << "USER {username}"; + + return createCommand(cmd.str(), trace.str()); } @@ -120,7 +124,11 @@ shared_ptr <POP3Command> POP3Command::PASS(const string& password) cmd.imbue(std::locale::classic()); cmd << "PASS " << password; - return createCommand(cmd.str()); + std::ostringstream trace; + trace.imbue(std::locale::classic()); + trace << "PASS {password}"; + + return createCommand(cmd.str(), trace.str()); } @@ -215,9 +223,13 @@ shared_ptr <POP3Command> POP3Command::QUIT() // static -shared_ptr <POP3Command> POP3Command::createCommand(const string& text) +shared_ptr <POP3Command> POP3Command::createCommand + (const string& text, const string& traceText) { - return shared_ptr <POP3Command>(new POP3Command(text)); + if (traceText.empty()) + return shared_ptr <POP3Command>(new POP3Command(text, text)); + else + return shared_ptr <POP3Command>(new POP3Command(text, traceText)); } @@ -227,9 +239,18 @@ const string POP3Command::getText() const } +const string POP3Command::getTraceText() const +{ + return m_traceText; +} + + void POP3Command::send(shared_ptr <POP3Connection> conn) { conn->getSocket()->send(m_text + "\r\n"); + + if (conn->getTracer()) + conn->getTracer()->traceSend(m_traceText); } diff --git a/src/vmime/net/pop3/POP3Command.hpp b/src/vmime/net/pop3/POP3Command.hpp index e34e4e2b..45aff661 100644 --- a/src/vmime/net/pop3/POP3Command.hpp +++ b/src/vmime/net/pop3/POP3Command.hpp @@ -76,9 +76,10 @@ public: /** Creates a new POP3 command with the specified text. * * @param text command text + * @param traceText trace text (if empty, command text is used) * @return a new POP3Command object */ - static shared_ptr <POP3Command> createCommand(const string& text); + static shared_ptr <POP3Command> createCommand(const string& text, const string& traceText = ""); /** Sends this command over the specified connection. * @@ -93,14 +94,22 @@ public: */ virtual const string getText() const; + /** Returns the full text of the command, suitable for outputing + * to the tracer. + * + * @return trace text (eg. "USER myusername") + */ + virtual const string getTraceText() const; + protected: - POP3Command(const string& text); + POP3Command(const string& text, const string& traceText); POP3Command(const POP3Command&); private: string m_text; + string m_traceText; }; diff --git a/src/vmime/net/pop3/POP3Connection.cpp b/src/vmime/net/pop3/POP3Connection.cpp index 45c668f5..0fd7e7ee 100644 --- a/src/vmime/net/pop3/POP3Connection.cpp +++ b/src/vmime/net/pop3/POP3Connection.cpp @@ -67,6 +67,10 @@ POP3Connection::POP3Connection(shared_ptr <POP3Store> store, shared_ptr <securit : m_store(store), m_auth(auth), m_socket(null), m_timeoutHandler(null), m_authenticated(false), m_secured(false), m_capabilitiesFetched(false) { + static int connectionId = 0; + + if (store->getTracerFactory()) + m_tracer = store->getTracerFactory()->create(store, ++connectionId); } @@ -500,7 +504,11 @@ void POP3Connection::authenticateSASL() (challenge, challengeLen, &resp, &respLen); // Send response - m_socket->send(saslContext->encodeB64(resp, respLen) + "\r\n"); + 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) { @@ -518,6 +526,9 @@ void POP3Connection::authenticateSASL() // Cancel SASL exchange m_socket->send("*\r\n"); + + if (m_tracer) + m_tracer->traceSend("*"); } catch (...) { @@ -677,6 +688,12 @@ shared_ptr <socket> POP3Connection::getSocket() } +shared_ptr <tracer> POP3Connection::getTracer() +{ + return m_tracer; +} + + shared_ptr <timeoutHandler> POP3Connection::getTimeoutHandler() { return m_timeoutHandler; diff --git a/src/vmime/net/pop3/POP3Connection.hpp b/src/vmime/net/pop3/POP3Connection.hpp index 3622f745..f40f9562 100644 --- a/src/vmime/net/pop3/POP3Connection.hpp +++ b/src/vmime/net/pop3/POP3Connection.hpp @@ -37,6 +37,7 @@ #include "vmime/net/timeoutHandler.hpp" #include "vmime/net/session.hpp" #include "vmime/net/connectionInfos.hpp" +#include "vmime/net/tracer.hpp" #include "vmime/net/pop3/POP3Command.hpp" #include "vmime/net/pop3/POP3Response.hpp" @@ -80,6 +81,7 @@ public: virtual shared_ptr <timeoutHandler> getTimeoutHandler(); virtual shared_ptr <security::authenticator> getAuthenticator(); virtual shared_ptr <session> getSession(); + virtual shared_ptr <tracer> getTracer(); private: @@ -104,6 +106,7 @@ private: shared_ptr <security::authenticator> m_auth; shared_ptr <socket> m_socket; shared_ptr <timeoutHandler> m_timeoutHandler; + shared_ptr <tracer> m_tracer; bool m_authenticated; bool m_secured; diff --git a/src/vmime/net/pop3/POP3Message.cpp b/src/vmime/net/pop3/POP3Message.cpp index ff1aa88f..0b7e6d37 100644 --- a/src/vmime/net/pop3/POP3Message.cpp +++ b/src/vmime/net/pop3/POP3Message.cpp @@ -149,7 +149,7 @@ void POP3Message::extract try { POP3Response::readLargeResponse - (store->getConnection(), os, progress, m_size); + (store->getConnection(), os, progress, m_size == -1 ? 0 : m_size); } catch (exceptions::command_error& e) { diff --git a/src/vmime/net/pop3/POP3Response.cpp b/src/vmime/net/pop3/POP3Response.cpp index bdbfb23c..de3c2cf3 100644 --- a/src/vmime/net/pop3/POP3Response.cpp +++ b/src/vmime/net/pop3/POP3Response.cpp @@ -46,8 +46,8 @@ namespace net { namespace pop3 { -POP3Response::POP3Response(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh) - : m_socket(sok), m_timeoutHandler(toh) +POP3Response::POP3Response(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, shared_ptr <tracer> tracer) + : m_socket(sok), m_timeoutHandler(toh), m_tracer(tracer) { } @@ -56,7 +56,7 @@ POP3Response::POP3Response(shared_ptr <socket> sok, shared_ptr <timeoutHandler> shared_ptr <POP3Response> POP3Response::readResponse(shared_ptr <POP3Connection> conn) { shared_ptr <POP3Response> resp = shared_ptr <POP3Response> - (new POP3Response(conn->getSocket(), conn->getTimeoutHandler())); + (new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())); string buffer; resp->readResponseImpl(buffer, /* multiLine */ false); @@ -65,6 +65,9 @@ shared_ptr <POP3Response> POP3Response::readResponse(shared_ptr <POP3Connection> resp->m_code = getResponseCode(buffer); stripResponseCode(buffer, resp->m_text); + if (resp->m_tracer) + resp->m_tracer->traceReceive(buffer); + return resp; } @@ -73,7 +76,7 @@ shared_ptr <POP3Response> POP3Response::readResponse(shared_ptr <POP3Connection> shared_ptr <POP3Response> POP3Response::readMultilineResponse(shared_ptr <POP3Connection> conn) { shared_ptr <POP3Response> resp = shared_ptr <POP3Response> - (new POP3Response(conn->getSocket(), conn->getTimeoutHandler())); + (new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())); string buffer; resp->readResponseImpl(buffer, /* multiLine */ true); @@ -88,8 +91,20 @@ shared_ptr <POP3Response> POP3Response::readMultilineResponse(shared_ptr <POP3Co std::istringstream iss(nextLines); string line; + if (resp->m_tracer) + resp->m_tracer->traceReceive(firstLine); + while (std::getline(iss, line, '\n')) - resp->m_lines.push_back(utility::stringUtils::trim(line)); + { + line = utility::stringUtils::trim(line); + resp->m_lines.push_back(line); + + if (resp->m_tracer) + resp->m_tracer->traceReceive(line); + } + + if (resp->m_tracer) + resp->m_tracer->traceReceive("."); return resp; } @@ -101,15 +116,22 @@ shared_ptr <POP3Response> POP3Response::readLargeResponse utility::progressListener* progress, const size_t predictedSize) { shared_ptr <POP3Response> resp = shared_ptr <POP3Response> - (new POP3Response(conn->getSocket(), conn->getTimeoutHandler())); + (new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())); string firstLine; - resp->readResponseImpl(firstLine, os, progress, predictedSize); + const size_t length = resp->readResponseImpl(firstLine, os, progress, predictedSize); resp->m_firstLine = firstLine; resp->m_code = getResponseCode(firstLine); stripResponseCode(firstLine, resp->m_text); + if (resp->m_tracer) + { + resp->m_tracer->traceReceive(firstLine); + resp->m_tracer->traceReceiveBytes(length - firstLine.length()); + resp->m_tracer->traceReceive("."); + } + return resp; } @@ -230,7 +252,7 @@ void POP3Response::readResponseImpl(string& buffer, const bool multiLine) } -void POP3Response::readResponseImpl +size_t POP3Response::readResponseImpl (string& firstLine, utility::outputStream& os, utility::progressListener* progress, const size_t predictedSize) { @@ -327,6 +349,8 @@ void POP3Response::readResponseImpl if (progress) progress->stop(total); + + return current; } diff --git a/src/vmime/net/pop3/POP3Response.hpp b/src/vmime/net/pop3/POP3Response.hpp index 20477b5e..d85b5405 100644 --- a/src/vmime/net/pop3/POP3Response.hpp +++ b/src/vmime/net/pop3/POP3Response.hpp @@ -38,6 +38,7 @@ #include "vmime/utility/progressListener.hpp" #include "vmime/net/socket.hpp" +#include "vmime/net/tracer.hpp" namespace vmime { @@ -143,10 +144,10 @@ public: private: - POP3Response(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh); + POP3Response(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, shared_ptr <tracer> tracer); void readResponseImpl(string& buffer, const bool multiLine); - void readResponseImpl + size_t readResponseImpl (string& firstLine, utility::outputStream& os, utility::progressListener* progress, const size_t predictedSize); @@ -163,6 +164,7 @@ private: shared_ptr <socket> m_socket; shared_ptr <timeoutHandler> m_timeoutHandler; + shared_ptr <tracer> m_tracer; string m_firstLine; ResponseCode m_code; diff --git a/src/vmime/net/service.cpp b/src/vmime/net/service.cpp index 482b141c..3cf94d5e 100644 --- a/src/vmime/net/service.cpp +++ b/src/vmime/net/service.cpp @@ -136,6 +136,18 @@ shared_ptr <socketFactory> service::getSocketFactory() } +void service::setTracerFactory(shared_ptr <tracerFactory> tf) +{ + m_tracerFactory = tf; +} + + +shared_ptr <tracerFactory> service::getTracerFactory() +{ + return m_tracerFactory; +} + + void service::setTimeoutHandlerFactory(shared_ptr <timeoutHandlerFactory> thf) { m_toHandlerFactory = thf; diff --git a/src/vmime/net/service.hpp b/src/vmime/net/service.hpp index 59352dea..b00d15ac 100644 --- a/src/vmime/net/service.hpp +++ b/src/vmime/net/service.hpp @@ -40,6 +40,7 @@ #include "vmime/net/socket.hpp" #include "vmime/net/timeoutHandler.hpp" +#include "vmime/net/tracer.hpp" #if VMIME_HAVE_TLS_SUPPORT #include "vmime/security/cert/certificateVerifier.hpp" @@ -183,6 +184,11 @@ public: */ shared_ptr <timeoutHandlerFactory> getTimeoutHandlerFactory(); + + void setTracerFactory(shared_ptr <tracerFactory> tf); + + shared_ptr <tracerFactory> getTracerFactory(); + /** Set a property for this service (service prefix is added automatically). * * WARNING: this sets the property on the session object, so all service @@ -219,8 +225,8 @@ private: #endif // VMIME_HAVE_TLS_SUPPORT shared_ptr <socketFactory> m_socketFactory; - shared_ptr <timeoutHandlerFactory> m_toHandlerFactory; + shared_ptr <tracerFactory> m_tracerFactory; }; diff --git a/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp b/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp index 35ff4e0d..15e24cf1 100644 --- a/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp +++ b/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp @@ -73,6 +73,9 @@ void SMTPChunkingOutputStreamAdapter::sendChunk 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")) { @@ -143,6 +146,9 @@ void SMTPChunkingOutputStreamAdapter::flush() if (m_progress) m_progress->stop(m_totalSize); + + if (m_connection->getTracer()) + m_connection->getTracer()->traceSendBytes(m_bufferSize); } diff --git a/src/vmime/net/smtp/SMTPCommand.cpp b/src/vmime/net/smtp/SMTPCommand.cpp index 2120caf5..27c8ec1b 100644 --- a/src/vmime/net/smtp/SMTPCommand.cpp +++ b/src/vmime/net/smtp/SMTPCommand.cpp @@ -30,6 +30,7 @@ #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" @@ -40,8 +41,8 @@ namespace net { namespace smtp { -SMTPCommand::SMTPCommand(const string& text) - : m_text(text) +SMTPCommand::SMTPCommand(const string& text, const string& traceText) + : m_text(text), m_traceText(traceText) { } @@ -199,9 +200,12 @@ shared_ptr <SMTPCommand> SMTPCommand::QUIT() // static -shared_ptr <SMTPCommand> SMTPCommand::createCommand(const string& text) +shared_ptr <SMTPCommand> SMTPCommand::createCommand(const string& text, const string& traceText) { - return shared_ptr <SMTPCommand>(new SMTPCommand(text)); + if (traceText.empty()) + return shared_ptr <SMTPCommand>(new SMTPCommand(text, text)); + else + return shared_ptr <SMTPCommand>(new SMTPCommand(text, traceText)); } @@ -211,9 +215,18 @@ const string SMTPCommand::getText() const } -void SMTPCommand::writeToSocket(shared_ptr <socket> sok) +const string SMTPCommand::getTraceText() const +{ + return m_traceText; +} + + +void SMTPCommand::writeToSocket(shared_ptr <socket> sok, shared_ptr <tracer> tr) { sok->send(m_text + "\r\n"); + + if (tr) + tr->traceSend(m_traceText); } diff --git a/src/vmime/net/smtp/SMTPCommand.hpp b/src/vmime/net/smtp/SMTPCommand.hpp index a5b8cca5..7c00d156 100644 --- a/src/vmime/net/smtp/SMTPCommand.hpp +++ b/src/vmime/net/smtp/SMTPCommand.hpp @@ -46,6 +46,7 @@ namespace net { class socket; class timeoutHandler; +class tracer; namespace smtp { @@ -76,13 +77,14 @@ public: * @param text command text * @return a new SMTPCommand object */ - static shared_ptr <SMTPCommand> createCommand(const string& text); + 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(shared_ptr <socket> sok); + virtual void writeToSocket(shared_ptr <socket> sok, shared_ptr <tracer> tr); /** Returns the full text of the command, including command name * and parameters (if any). @@ -91,14 +93,22 @@ public: */ 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); + SMTPCommand(const string& text, const string& traceText); SMTPCommand(const SMTPCommand&); private: string m_text; + string m_traceText; }; diff --git a/src/vmime/net/smtp/SMTPCommandSet.cpp b/src/vmime/net/smtp/SMTPCommandSet.cpp index 3e03427c..85f58fed 100644 --- a/src/vmime/net/smtp/SMTPCommandSet.cpp +++ b/src/vmime/net/smtp/SMTPCommandSet.cpp @@ -42,7 +42,7 @@ namespace smtp { SMTPCommandSet::SMTPCommandSet(const bool pipeline) - : SMTPCommand(""), m_pipeline(pipeline), + : SMTPCommand("", ""), m_pipeline(pipeline), m_started(false), m_lastCommandSent() { } @@ -67,7 +67,7 @@ void SMTPCommandSet::addCommand(shared_ptr <SMTPCommand> cmd) } -void SMTPCommandSet::writeToSocket(shared_ptr <socket> sok) +void SMTPCommandSet::writeToSocket(shared_ptr <socket> sok, shared_ptr <tracer> tr) { if (m_pipeline) { @@ -78,7 +78,7 @@ void SMTPCommandSet::writeToSocket(shared_ptr <socket> sok) it != m_commands.end() ; ++it) { shared_ptr <SMTPCommand> cmd = *it; - cmd->writeToSocket(sok); + cmd->writeToSocket(sok, tr); } } @@ -99,7 +99,7 @@ void SMTPCommandSet::writeToSocket(shared_ptr <socket> sok) shared_ptr <SMTPCommand> cmd = m_commands.front(); m_commands.pop_front(); - cmd->writeToSocket(sok); + cmd->writeToSocket(sok, tr); m_lastCommandSent = cmd; } @@ -124,6 +124,21 @@ const string SMTPCommandSet::getText() const } +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); diff --git a/src/vmime/net/smtp/SMTPCommandSet.hpp b/src/vmime/net/smtp/SMTPCommandSet.hpp index 8e744c2b..83c7fe46 100644 --- a/src/vmime/net/smtp/SMTPCommandSet.hpp +++ b/src/vmime/net/smtp/SMTPCommandSet.hpp @@ -78,9 +78,10 @@ public: shared_ptr <SMTPCommand> getLastCommandSent() const; - void writeToSocket(shared_ptr <socket> sok); + void writeToSocket(shared_ptr <socket> sok, shared_ptr <tracer> tr); const string getText() const; + const string getTraceText() const; private: diff --git a/src/vmime/net/smtp/SMTPConnection.cpp b/src/vmime/net/smtp/SMTPConnection.cpp index 4985b563..99a8e8f5 100644 --- a/src/vmime/net/smtp/SMTPConnection.cpp +++ b/src/vmime/net/smtp/SMTPConnection.cpp @@ -68,6 +68,10 @@ SMTPConnection::SMTPConnection(shared_ptr <SMTPTransport> transport, shared_ptr : 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); } @@ -416,7 +420,11 @@ void SMTPConnection::authenticateSASL() (challenge, challengeLen, &resp, &respLen); // Send response - m_socket->send(saslContext->encodeB64(resp, respLen) + "\r\n"); + 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) { @@ -434,6 +442,9 @@ void SMTPConnection::authenticateSASL() // Cancel SASL exchange m_socket->send("*\r\n"); + + if (m_tracer) + m_tracer->traceSend("*"); } catch (...) { @@ -557,14 +568,14 @@ void SMTPConnection::internalDisconnect() void SMTPConnection::sendRequest(shared_ptr <SMTPCommand> cmd) { - cmd->writeToSocket(m_socket); + cmd->writeToSocket(m_socket, m_tracer); } shared_ptr <SMTPResponse> SMTPConnection::readResponse() { shared_ptr <SMTPResponse> resp = SMTPResponse::readResponse - (m_socket, m_timeoutHandler, m_responseState); + (m_tracer, m_socket, m_timeoutHandler, m_responseState); m_responseState = resp->getCurrentState(); @@ -608,6 +619,12 @@ shared_ptr <socket> SMTPConnection::getSocket() } +shared_ptr <tracer> SMTPConnection::getTracer() +{ + return m_tracer; +} + + shared_ptr <timeoutHandler> SMTPConnection::getTimeoutHandler() { return m_timeoutHandler; diff --git a/src/vmime/net/smtp/SMTPConnection.hpp b/src/vmime/net/smtp/SMTPConnection.hpp index cc59ef34..c7614920 100644 --- a/src/vmime/net/smtp/SMTPConnection.hpp +++ b/src/vmime/net/smtp/SMTPConnection.hpp @@ -37,6 +37,7 @@ #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" @@ -80,6 +81,7 @@ public: virtual shared_ptr <timeoutHandler> getTimeoutHandler(); virtual shared_ptr <security::authenticator> getAuthenticator(); virtual shared_ptr <session> getSession(); + virtual shared_ptr <tracer> getTracer(); void sendRequest(shared_ptr <SMTPCommand> cmd); shared_ptr <SMTPResponse> readResponse(); @@ -106,6 +108,7 @@ private: 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; diff --git a/src/vmime/net/smtp/SMTPResponse.cpp b/src/vmime/net/smtp/SMTPResponse.cpp index 3d8bf15c..75dbbf6b 100644 --- a/src/vmime/net/smtp/SMTPResponse.cpp +++ b/src/vmime/net/smtp/SMTPResponse.cpp @@ -34,6 +34,7 @@ #include "vmime/net/socket.hpp" #include "vmime/net/timeoutHandler.hpp" +#include "vmime/net/tracer.hpp" #include <cctype> @@ -43,8 +44,10 @@ namespace net { namespace smtp { -SMTPResponse::SMTPResponse(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, const state& st) - : m_socket(sok), m_timeoutHandler(toh), +SMTPResponse::SMTPResponse + (shared_ptr <tracer> tr, shared_ptr <socket> sok, + shared_ptr <timeoutHandler> toh, const state& st) + : m_socket(sok), m_timeoutHandler(toh), m_tracer(tr), m_responseBuffer(st.responseBuffer), m_responseContinues(false) { } @@ -95,9 +98,11 @@ const string SMTPResponse::getText() const // static shared_ptr <SMTPResponse> SMTPResponse::readResponse - (shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, const state& st) + (shared_ptr <tracer> tr, shared_ptr <socket> sok, + shared_ptr <timeoutHandler> toh, const state& st) { - shared_ptr <SMTPResponse> resp = shared_ptr <SMTPResponse>(new SMTPResponse(sok, toh, st)); + shared_ptr <SMTPResponse> resp = + shared_ptr <SMTPResponse>(new SMTPResponse(tr, sok, toh, st)); resp->readResponse(); @@ -142,6 +147,9 @@ const string SMTPResponse::readResponseLine() currentBuffer.erase(currentBuffer.begin(), currentBuffer.begin() + lineEnd + 1); m_responseBuffer = currentBuffer; + if (m_tracer) + m_tracer->traceReceive(line); + return line; } diff --git a/src/vmime/net/smtp/SMTPResponse.hpp b/src/vmime/net/smtp/SMTPResponse.hpp index 000448ac..4d88b6b5 100644 --- a/src/vmime/net/smtp/SMTPResponse.hpp +++ b/src/vmime/net/smtp/SMTPResponse.hpp @@ -41,6 +41,7 @@ namespace net { class socket; class timeoutHandler; +class tracer; namespace smtp { @@ -95,6 +96,7 @@ public: /** 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 @@ -102,7 +104,9 @@ public: * @throws exceptions::operation_timed_out if no data * has been received within the granted time */ - static shared_ptr <SMTPResponse> readResponse(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, const state& st); + static shared_ptr <SMTPResponse> readResponse + (shared_ptr <tracer> tr, shared_ptr <socket> sok, + shared_ptr <timeoutHandler> toh, const state& st); /** Return the SMTP response code. * @@ -150,7 +154,7 @@ public: private: - SMTPResponse(shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, const state& st); + SMTPResponse(shared_ptr <tracer> tr, shared_ptr <socket> sok, shared_ptr <timeoutHandler> toh, const state& st); SMTPResponse(const SMTPResponse&); void readResponse(); @@ -166,6 +170,7 @@ private: shared_ptr <socket> m_socket; shared_ptr <timeoutHandler> m_timeoutHandler; + shared_ptr <tracer> m_tracer; string m_responseBuffer; bool m_responseContinues; diff --git a/src/vmime/net/smtp/SMTPTransport.cpp b/src/vmime/net/smtp/SMTPTransport.cpp index 56adfa21..ed775442 100644 --- a/src/vmime/net/smtp/SMTPTransport.cpp +++ b/src/vmime/net/smtp/SMTPTransport.cpp @@ -210,7 +210,7 @@ void SMTPTransport::sendEnvelope // Read response for "RSET" command if (needReset) { - commands->writeToSocket(m_connection->getSocket()); + commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); resp = m_connection->readResponse(); @@ -227,7 +227,7 @@ void SMTPTransport::sendEnvelope } // Read response for "MAIL" command - commands->writeToSocket(m_connection->getSocket()); + commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); if ((resp = m_connection->readResponse())->getCode() != 250) { @@ -257,7 +257,7 @@ void SMTPTransport::sendEnvelope // Read responses for "RCPT TO" commands for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) { - commands->writeToSocket(m_connection->getSocket()); + commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); resp = m_connection->readResponse(); @@ -291,7 +291,7 @@ void SMTPTransport::sendEnvelope // Read response for "DATA" command if (sendDATACommand) { - commands->writeToSocket(m_connection->getSocket()); + commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer()); if ((resp = m_connection->readResponse())->getCode() != 354) { @@ -326,6 +326,12 @@ void SMTPTransport::send // 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) diff --git a/src/vmime/net/tracer.cpp b/src/vmime/net/tracer.cpp new file mode 100644 index 00000000..b3610cdd --- /dev/null +++ b/src/vmime/net/tracer.cpp @@ -0,0 +1,72 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2014 Vincent Richard <[email protected]> +// +// 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 + + +#include "tracer.hpp" + + +#include <sstream> + + +namespace vmime { +namespace net { + + +void tracer::traceReceiveBytes(const size_t count, const string& state) +{ + std::ostringstream oss; + oss << "{..."; + + if (!state.empty()) + oss << state << ": "; + + oss << count << " bytes of data...}"; + + traceReceive(oss.str()); +} + + +void tracer::traceSendBytes(const size_t count, const string& state) +{ + std::ostringstream oss; + oss << "{..."; + + if (!state.empty()) + oss << state << ": "; + + oss << count << " bytes of data...}"; + + traceSend(oss.str()); +} + + +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES diff --git a/src/vmime/net/tracer.hpp b/src/vmime/net/tracer.hpp new file mode 100644 index 00000000..e30c823c --- /dev/null +++ b/src/vmime/net/tracer.hpp @@ -0,0 +1,109 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2014 Vincent Richard <[email protected]> +// +// 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_TRACER_HPP_INCLUDED +#define VMIME_NET_TRACER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES + + +#include "vmime/base.hpp" + + +namespace vmime { +namespace net { + + +class service; + + +/** Base class for an object used to trace network communication + * between the client and the server. + */ + +class VMIME_EXPORT tracer : public object +{ +public: + + virtual ~tracer() { } + + /** Trace raw bytes which have been received. + * + * @param count number of bytes + * @param state protocol state (eg. "SASL exchange"), or empty + */ + virtual void traceReceiveBytes(const size_t count, const string& state = ""); + + /** Trace raw bytes which have been sent. + * + * @param count number of bytes + * @param state protocol state (eg. "SASL exchange"), or empty + */ + virtual void traceSendBytes(const size_t count, const string& state = ""); + + /** Trace a command line which has been sent. + * + * @param line command line + */ + virtual void traceSend(const string& line) = 0; + + /** Trace a response line which has been received. + * + * @param line response line + */ + virtual void traceReceive(const string& line) = 0; +}; + + + +/** A class to create 'tracer' objects. + */ + +class VMIME_EXPORT tracerFactory : public object +{ +public: + + virtual ~tracerFactory() { } + + /** Creates a tracer for the specified service. + * + * @param serv messaging service + * @param connectionId an identifier for the connection to distinguate between + * different connections used by a service + * @return a new tracer + */ + virtual shared_ptr <tracer> create(shared_ptr <service> serv, const int connectionId) = 0; +}; + + +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES + +#endif // VMIME_NET_TRACER_HPP_INCLUDED |