Files
cow-mail/src/header/encoding.rs
T

72 lines
2.5 KiB
Rust

//! RFC 2047 encoding and folding of header values.
use std::fmt::Write;
use email_encoding::headers::writer::EmailWriter;
fn allowed_str(s: &str) -> bool {
s.bytes().all(allowed_char)
}
const fn allowed_char(c: u8) -> bool {
c >= 1 && c <= 9 || c == 11 || c == 12 || c >= 14 && c <= 127
}
fn encode(encode_buf: &mut String, writer: &mut EmailWriter) {
if encode_buf.is_empty() {
return;
}
let prefix = encode_buf.trim_end_matches(' ');
email_encoding::headers::rfc2047::encode(prefix, writer).expect("String is always writable");
// TODO: add a better API for doing this in email-encoding
let spaces = encode_buf.len() - prefix.len();
for _ in 0..spaces {
writer.space();
}
encode_buf.clear();
}
/// Encode `value` as the value of the header named `key`, ready to be written out.
///
/// Walks the value word by word. A word made entirely of allowed bytes is written as it is, with a
/// line break and indentation inserted when the line would grow too long (RFC 5322 folding).
/// Consecutive words containing anything else are collected and RFC 2047-encoded together, so a
/// value mixing plain and non-ASCII text keeps its plain parts readable.
///
/// `key` itself is not part of the result: only its length matters, for the length of the first
/// line.
///
/// # Examples
///
/// ```
/// use email_message::header::encode_header_value;
///
/// // Plain text is left alone.
/// assert_eq!(encode_header_value("Subject", "a test"), "a test");
///
/// // Only the words that need it are encoded.
/// assert_eq!(encode_header_value("Subject", "Grüße"), "=?utf-8?b?R3LDvMOfZQ==?=");
/// ```
pub fn encode_header_value(key: &str, value: &str) -> String {
let mut encoded_value = String::new();
let line_len = key.len() + ": ".len();
let mut writer = EmailWriter::new(&mut encoded_value, line_len, 0, false);
let mut encode_buf = String::new();
for next_word in value.split_inclusive(' ') {
if allowed_str(next_word) {
// This word only contains allowed characters
// the next word is allowed, but we may have accumulated some words to encode
encode(&mut encode_buf, &mut writer);
writer.folding().write_str(next_word).expect("String is always writable");
} else {
// This word contains unallowed characters
encode_buf.push_str(next_word);
}
}
encode(&mut encode_buf, &mut writer);
drop(writer);
encoded_value
}