From 8044a6f13184538a0462517cfe87f18f29349083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Tue, 14 Jan 2025 16:39:58 +0100 Subject: [PATCH] automatic: Translate end-of-lines in email emitter by DNF The fix in 9a5cba8fbb0c95f5da1410803f9ff5093895252a (automatic: Fix end-of-lines in messages sent by email emitter) utilized cURL library for translating LF ending to CR-LF in content of SMTP DATA command. It fixed the problem with curl-8.11.1, but broke end-of-lines in e-mail headers with old curl-8.9.1. I was unable to find what has changed in cURL, but the cause was that automatic plugin already separated headers by CR-LF, therefore cURL probably double-encoded them and that was again rejected by sendmail 8.18.1. This patch reverts 9a5cba8fbb0c95f5da1410803f9ff5093895252a and instead performs the end-of-line normalization fully in dnf5::EmailMessage::str() method. Now the output of the method is completely valid e-mail message. Implementation detail: I changed dnf5::Emitter::output_stream variable from const to non-cost to be able to call getline() on it. If is a problem, I will need to come with a more complicated solution because I can only obtain a new-line delimiter used in the std::stringstream object by getline(). Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2335508 --- .../automatic_plugin/email_message.cpp | 22 ++++++++++++++----- .../automatic_plugin/email_message.hpp | 5 +++-- dnf5-plugins/automatic_plugin/emitters.cpp | 4 +--- dnf5-plugins/automatic_plugin/emitters.hpp | 4 ++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/dnf5-plugins/automatic_plugin/email_message.cpp b/dnf5-plugins/automatic_plugin/email_message.cpp index 1d3a91b23..6acde15c6 100644 --- a/dnf5-plugins/automatic_plugin/email_message.cpp +++ b/dnf5-plugins/automatic_plugin/email_message.cpp @@ -23,18 +23,25 @@ along with libdnf. If not, see . #include #include +#include namespace dnf5 { // TODO(mblaha): use some library to create an email instead of this template -constexpr const char * MESSAGE_TEMPLATE = +constexpr const char * EMAIL_HEADER_TEMPLATE = "Date: {date}\r\n" "To: {to}\r\n" "From: {from}\r\n" "Subject: {subject}\r\n" "X-Mailer: dnf5-automatic\r\n" - "\r\n" - "{body}"; + "\r\n"; + +void EmailMessage::set_body(std::stringstream &body) { + this->body.clear(); + for (std::string line; std::getline(body, line); ) { + this->body.push_back(line); + } +} std::string EmailMessage::str() { const auto now = std::chrono::system_clock::now(); @@ -50,12 +57,15 @@ std::string EmailMessage::str() { std::string msg; msg = libdnf5::utils::sformat( - MESSAGE_TEMPLATE, + EMAIL_HEADER_TEMPLATE, fmt::arg("date", date), fmt::arg("to", to_str), fmt::arg("from", from), - fmt::arg("subject", subject), - fmt::arg("body", body)); + fmt::arg("subject", subject)); + for (const auto & line: body) { + msg.append(line).append("\r\n"); + } + return msg; } diff --git a/dnf5-plugins/automatic_plugin/email_message.hpp b/dnf5-plugins/automatic_plugin/email_message.hpp index 21a86ecbd..213972103 100644 --- a/dnf5-plugins/automatic_plugin/email_message.hpp +++ b/dnf5-plugins/automatic_plugin/email_message.hpp @@ -22,6 +22,7 @@ along with libdnf. If not, see . #define DNF5_PLUGINS_AUTOMATIC_PLUGIN_EMAIL_MESSAGE_HPP #include +#include #include namespace dnf5 { @@ -38,7 +39,7 @@ class EmailMessage { /// Set the To header value void set_to(const std::vector & to) { this->to = to; }; /// Set the message body - void set_body(std::string_view body) { this->body = body; }; + void set_body(std::stringstream &body); /// Return string representation of the message std::string str(); @@ -47,7 +48,7 @@ class EmailMessage { std::string subject; std::string from; std::vector to; - std::string body; + std::vector body; }; } // namespace dnf5 diff --git a/dnf5-plugins/automatic_plugin/emitters.cpp b/dnf5-plugins/automatic_plugin/emitters.cpp index f9223c7ea..3140d9774 100644 --- a/dnf5-plugins/automatic_plugin/emitters.cpp +++ b/dnf5-plugins/automatic_plugin/emitters.cpp @@ -167,7 +167,7 @@ void EmitterEmail::notify() { message.set_to(to); message.set_from(from); message.set_subject(subject); - message.set_body(output_stream.str()); + message.set_body(output_stream); { // use curl to send the message @@ -222,8 +222,6 @@ void EmitterEmail::notify() { curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); - curl_easy_setopt(curl, CURLOPT_CRLF, 1L); - res = curl_easy_perform(curl); fclose(payload_file); if (res != CURLE_OK) { diff --git a/dnf5-plugins/automatic_plugin/emitters.hpp b/dnf5-plugins/automatic_plugin/emitters.hpp index de28c6f0a..99bb5b9f4 100644 --- a/dnf5-plugins/automatic_plugin/emitters.hpp +++ b/dnf5-plugins/automatic_plugin/emitters.hpp @@ -35,7 +35,7 @@ class Emitter { Emitter( const ConfigAutomatic & config_automatic, const libdnf5::base::Transaction & transaction, - const std::stringstream & output_stream, + std::stringstream & output_stream, const bool success) : config_automatic(config_automatic), transaction(transaction), @@ -56,7 +56,7 @@ class Emitter { // resolved upgrade transaction const libdnf5::base::Transaction & transaction; // stream with captured upgrade outputs - const std::stringstream & output_stream; + std::stringstream & output_stream; const bool success; /// Return number of available upgrades.