Skip to content

Commit

Permalink
feat(host): CRLF in temporary EML files
Browse files Browse the repository at this point in the history
According to [1], CRLF should be used in EML files regardless of
platform. Thunderbird also commits to this standard for better
interoperability [2].

And Vim/Neovim actually set fileformat=dos by default for EML files even
under Linux/macOS, hence sending CRLF to Thunderbird directly shouldn't
be an issue either.

[1] https://datatracker.ietf.org/doc/html/rfc2822
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=503271
  • Loading branch information
Frederick888 committed Aug 2, 2022
1 parent 93297f3 commit 31da04d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/model/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::io;

use super::thunderbird::*;
use crate::writeln_crlf;

pub const MAX_BODY_LENGTH: usize = 768 * 1024;

Expand Down Expand Up @@ -51,21 +52,22 @@ impl Exchange {
where
W: io::Write,
{
writeln!(w, "From: {}", self.compose_details.from.to_header_value()?)?;
writeln_crlf!(w, "From: {}", self.compose_details.from.to_header_value()?)?;
Self::compose_recipient_list_to_eml(w, "To", &self.compose_details.to)?;
Self::compose_recipient_list_to_eml(w, "Cc", &self.compose_details.cc)?;
Self::compose_recipient_list_to_eml(w, "Bcc", &self.compose_details.bcc)?;
Self::compose_recipient_list_to_eml(w, "Reply-To", &self.compose_details.reply_to)?;
writeln!(w, "Subject: {}", self.compose_details.subject)?;
writeln!(
writeln_crlf!(w, "Subject: {}", self.compose_details.subject)?;
writeln_crlf!(
w,
"{}: {}",
HEADER_SEND_ON_EXIT, self.configuration.send_on_exit
HEADER_SEND_ON_EXIT,
self.configuration.send_on_exit
)?;
if !self.configuration.suppress_help_headers {
Self::write_help_headers(w)?;
}
writeln!(w)?;
writeln_crlf!(w)?;
write!(w, "{}", self.compose_details.get_body())?;
Ok(())
}
Expand Down Expand Up @@ -189,14 +191,14 @@ impl Exchange {
{
match list {
ComposeRecipientList::Single(recipient) => {
writeln!(w, "{}: {}", name, recipient.to_header_value()?)?;
writeln_crlf!(w, "{}: {}", name, recipient.to_header_value()?)?;
}
ComposeRecipientList::Multiple(recipients) if recipients.is_empty() => {
writeln!(w, "{}: ", name)?;
writeln_crlf!(w, "{}: ", name)?;
}
ComposeRecipientList::Multiple(recipients) => {
for recipient in recipients {
writeln!(w, "{}: {}", name, recipient.to_header_value()?)?;
writeln_crlf!(w, "{}: {}", name, recipient.to_header_value()?)?;
}
}
}
Expand All @@ -208,7 +210,7 @@ impl Exchange {
W: io::Write,
{
for line in HEADER_HELP_LINES {
writeln!(w, "{}: {}", HEADER_HELP, line)?;
writeln_crlf!(w, "{}: {}", HEADER_HELP, line)?;
}
Ok(())
}
Expand Down Expand Up @@ -254,6 +256,7 @@ mod tests {
assert!(output.contains("X-ExtEditorR-Send-On-Exit: false"));
assert!(output.ends_with(&request.compose_details.plain_text_body));
assert!(!output.contains(&request.compose_details.body));
assert_eq!(output.matches('\r').count(), output.matches('\n').count());
}

#[test]
Expand Down
26 changes: 26 additions & 0 deletions src/model/thunderbird.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,18 @@ pub struct ComposeDetails {
}

impl ComposeDetails {
#[cfg(not(target_os = "windows"))]
pub fn get_body(&self) -> String {
if self.is_plain_text {
self.plain_text_body.replace('\n', "\r\n")
} else {
self.body.replace('\n', "\r\n")
}
}

#[cfg(target_os = "windows")]
pub fn get_body(&self) -> &str {
// Thunderbird under Windows already sends CRLF
if self.is_plain_text {
&self.plain_text_body
} else {
Expand Down Expand Up @@ -327,6 +338,21 @@ mod tests {
}
}

#[test]
fn compose_details_crlf_body_test() {
let mut compose_details = get_blank_compose_details();
compose_details.plain_text_body = if cfg!(target_os = "windows") {
"Hello,\r\nworld!".to_owned()
} else {
"Hello,\nworld!".to_owned()
};

let body = compose_details.get_body();
assert_eq!(1, body.matches("\r\n").count());
assert_eq!(1, body.matches('\r').count());
assert_eq!(1, body.matches('\n').count());
}

#[test]
fn compose_details_add_recipient_to_single_test() {
let mut compose_details = get_blank_compose_details();
Expand Down
10 changes: 10 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ use std::path::{Path, PathBuf};

use crate::model::thunderbird::Tab;

#[macro_export]
macro_rules! writeln_crlf {
($dst:expr $(,)?) => {
write!($dst, "\r\n")
};
($dst:expr, $fmt:expr, $($arg:tt)*) => {
write!($dst, concat!($fmt, "\r\n"), $($arg)*)
};
}

pub fn get_temp_filename(tab: &Tab) -> PathBuf {
let mut temp_dir = env::temp_dir();
temp_dir.push(format!("external_editor_revived_{}.eml", tab.id));
Expand Down

0 comments on commit 31da04d

Please sign in to comment.