diff --git a/Sming/Components/Network/src/Network/MailMessage.cpp b/Sming/Components/Network/src/Network/MailMessage.cpp index 19e33f92cb..6fdb8666de 100644 --- a/Sming/Components/Network/src/Network/MailMessage.cpp +++ b/Sming/Components/Network/src/Network/MailMessage.cpp @@ -48,13 +48,11 @@ MailMessage& MailMessage::setBody(String&& body, MimeType mime) noexcept MailMessage& MailMessage::setBody(IDataSourceStream* stream, MimeType mime) { - if(this->stream != nullptr) { + if(this->stream) { debug_e("MailMessage::setBody: Discarding already set stream!"); - delete this->stream; - this->stream = nullptr; } - this->stream = stream; + this->stream.reset(stream); headers[HTTP_HEADER_CONTENT_TYPE] = toString(mime); return *this; diff --git a/Sming/Components/Network/src/Network/MailMessage.h b/Sming/Components/Network/src/Network/MailMessage.h index f5357ebc9e..5d6f6eb745 100644 --- a/Sming/Components/Network/src/Network/MailMessage.h +++ b/Sming/Components/Network/src/Network/MailMessage.h @@ -38,6 +38,14 @@ class MailMessage String subject; String cc; + ~MailMessage() + { + for(auto& attachment : attachments) { + delete attachment.headers; + delete attachment.stream; + } + } + /** * @brief Set a header value * @param name @@ -106,7 +114,7 @@ class MailMessage MailMessage& addAttachment(IDataSourceStream* stream, const String& mime, const String& filename = ""); private: - IDataSourceStream* stream = nullptr; + std::unique_ptr stream = nullptr; HttpHeaders headers; Vector attachments; }; diff --git a/Sming/Components/Network/src/Network/SmtpClient.cpp b/Sming/Components/Network/src/Network/SmtpClient.cpp index a604133bd1..eb42a9fe53 100644 --- a/Sming/Components/Network/src/Network/SmtpClient.cpp +++ b/Sming/Components/Network/src/Network/SmtpClient.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #define ADVANCE \ { \ @@ -288,7 +289,7 @@ void SmtpClient::sendMailHeaders(MailMessage* mail) if(!mail->headers.contains(HTTP_HEADER_CONTENT_TRANSFER_ENCODING)) { mail->headers[HTTP_HEADER_CONTENT_TRANSFER_ENCODING] = _F("quoted-printable"); - mail->stream = new QuotedPrintableOutputStream(mail->stream); + mail->stream = std::make_unique(mail->stream.release()); } if(!mail->attachments.isEmpty()) { @@ -297,13 +298,13 @@ void SmtpClient::sendMailHeaders(MailMessage* mail) text.headers = new HttpHeaders(); (*text.headers)[HTTP_HEADER_CONTENT_TYPE] = mail->headers[HTTP_HEADER_CONTENT_TYPE]; (*text.headers)[HTTP_HEADER_CONTENT_TRANSFER_ENCODING] = mail->headers[HTTP_HEADER_CONTENT_TRANSFER_ENCODING]; - text.stream = mail->stream; + text.stream = mail->stream.release(); mail->attachments.insertElementAt(text, 0); mail->headers.remove(HTTP_HEADER_CONTENT_TRANSFER_ENCODING); mail->headers[HTTP_HEADER_CONTENT_TYPE] = F("multipart/mixed; boundary=") + mStream->getBoundary(); - mail->stream = mStream; + mail->stream.reset(mStream); } for(auto hdr : mail->headers) { @@ -319,8 +320,7 @@ bool SmtpClient::sendMailBody(MailMessage* mail) } delete stream; - stream = mail->stream; // avoid intermediate buffers - mail->stream = nullptr; + stream = mail->stream.release(); // avoid intermediate buffers return false; } @@ -390,8 +390,15 @@ int SmtpClient::smtpParse(char* buffer, size_t len) RETURN_ON_ERROR(SMTP_CODE_SERVICE_READY); if(!useSsl && (options & SMTP_OPT_STARTTLS)) { - useSsl = true; - TcpConnection::internalOnConnected(ERR_OK); + if(!enableSsl(url.Host)) { + /* + * Excerpt from RFC 3207: If, + * after having issued the STARTTLS command, the client finds out that + * some failure prevents it from actually starting a TLS handshake, then + * it SHOULD abort the connection. + */ + return 0; + } } sendString(F("EHLO ") + url.Host + "\r\n"); @@ -420,8 +427,16 @@ int SmtpClient::smtpParse(char* buffer, size_t len) if(isLastLine) { state = eSMTP_Ready; if(!useSsl && (options & SMTP_OPT_STARTTLS)) { - state = eSMTP_StartTLS; - } else if(url.User && authMethods.count()) { + if(Ssl::factory != nullptr) { + state = eSMTP_StartTLS; + break; + } + + bitClear(options, SMTP_OPT_STARTTLS); + debug_w("[SMTP] SSL required, no factory. Continue plain-text communication."); + } + + if(url.User && authMethods.count()) { state = eSMTP_SendAuth; } } diff --git a/Sming/Components/Network/src/Network/TcpConnection.cpp b/Sming/Components/Network/src/Network/TcpConnection.cpp index 0aae89fc2e..5f442a7c30 100644 --- a/Sming/Components/Network/src/Network/TcpConnection.cpp +++ b/Sming/Components/Network/src/Network/TcpConnection.cpp @@ -423,6 +423,29 @@ err_t TcpConnection::internalOnConnected(err_t err) return res; } +bool TcpConnection::enableSsl(const String& hostName) +{ + if(tcp == nullptr) { + return false; + } + + if(tcp->state != ESTABLISHED) { + return false; + } + + if(!sslCreateSession()) { + return false; + } + + ssl->hostName = hostName; + + useSsl = true; + if(internalOnConnected(ERR_OK) != ERR_OK) { + useSsl = false; + } + return useSsl; +} + err_t TcpConnection::internalOnReceive(pbuf* p, err_t err) { sleep = 0; diff --git a/Sming/Components/Network/src/Network/TcpConnection.h b/Sming/Components/Network/src/Network/TcpConnection.h index 3ea5367418..e61e8715e8 100644 --- a/Sming/Components/Network/src/Network/TcpConnection.h +++ b/Sming/Components/Network/src/Network/TcpConnection.h @@ -154,6 +154,13 @@ class TcpConnection : public IpConnection return ssl; } + /** + * @brief Enables Secure Socket Layer on the current connection + * @param hostName + * @retval true on success, false otherwise + */ + bool enableSsl(const String& hostName = nullptr); + protected: void initialize(tcp_pcb* pcb); bool internalConnect(IpAddress addr, uint16_t port); diff --git a/Sming/Components/Network/src/Network/Url.cpp b/Sming/Components/Network/src/Network/Url.cpp index b23df5aaac..722ec71648 100644 --- a/Sming/Components/Network/src/Network/Url.cpp +++ b/Sming/Components/Network/src/Network/Url.cpp @@ -86,6 +86,8 @@ String Url::toString() const result += ':'; result += Password; } + + result += '@'; } result += getHostWithPort(); diff --git a/samples/SmtpClient/app/application.cpp b/samples/SmtpClient/app/application.cpp index 1b6083cc6c..411150add1 100644 --- a/samples/SmtpClient/app/application.cpp +++ b/samples/SmtpClient/app/application.cpp @@ -24,7 +24,7 @@ int onServerError(SmtpClient& client, int code, char* status) { debugf("Status: %s", status); - return 0; // return non-zero value to abort the connection + return -1; // return non-zero value to abort the connection } int onMailSent(SmtpClient& client, int code, char* status)