Skip to content

Commit

Permalink
automatic: Translate end-of-lines in email emitter by DNF
Browse files Browse the repository at this point in the history
The fix in 9a5cba8 (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 9a5cba8 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
  • Loading branch information
ppisar committed Jan 14, 2025
1 parent 8ede807 commit 8044a6f
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 13 deletions.
22 changes: 16 additions & 6 deletions dnf5-plugins/automatic_plugin/email_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <libdnf5/utils/format.hpp>

#include <chrono>
#include <string>

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();
Expand All @@ -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;
}

Expand Down
5 changes: 3 additions & 2 deletions dnf5-plugins/automatic_plugin/email_message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#define DNF5_PLUGINS_AUTOMATIC_PLUGIN_EMAIL_MESSAGE_HPP

#include <string>
#include <sstream>
#include <vector>

namespace dnf5 {
Expand All @@ -38,7 +39,7 @@ class EmailMessage {
/// Set the To header value
void set_to(const std::vector<std::string> & 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();
Expand All @@ -47,7 +48,7 @@ class EmailMessage {
std::string subject;
std::string from;
std::vector<std::string> to;
std::string body;
std::vector<std::string> body;
};

} // namespace dnf5
Expand Down
4 changes: 1 addition & 3 deletions dnf5-plugins/automatic_plugin/emitters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions dnf5-plugins/automatic_plugin/emitters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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.
Expand Down

0 comments on commit 8044a6f

Please sign in to comment.