Skip to main content

mail_builder/headers/
text.rs

1/*
2 * Copyright Stalwart Labs Ltd. See the COPYING
3 * file at the top-level directory of this distribution.
4 *
5 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8 * option. This file may not be copied, modified, or distributed
9 * except according to those terms.
10 */
11
12use std::borrow::Cow;
13
14use super::Header;
15use crate::encoders::{
16    base64::base64_encode_mime,
17    encode::{EncodingType, get_encoding_type},
18    quoted_printable::quoted_printable_encode,
19};
20
21/// Unstructured text e-mail header.
22#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Text<'x> {
24    pub text: Cow<'x, str>,
25}
26
27impl<'x> Text<'x> {
28    /// Create a new unstructured text header
29    pub fn new(text: impl Into<Cow<'x, str>>) -> Self {
30        Self {
31            text: text.into(),
32        }
33    }
34}
35
36impl<'x, T> From<T> for Text<'x>
37where
38    T: Into<Cow<'x, str>>,
39{
40    fn from(value: T) -> Self {
41        Self::new(value)
42    }
43}
44
45impl<'x> Header for Text<'x> {
46    fn write_header(&self, mut output: impl std::io::Write, mut bytes_written: usize) -> std::io::Result<usize> {
47        match get_encoding_type(self.text.as_bytes(), true, false) {
48            EncodingType::Base64 => {
49                for (pos, chunk) in self.text.as_bytes().chunks(76 - bytes_written).enumerate() {
50                    if pos > 0 {
51                        output.write_all(b"\t")?;
52                    }
53                    output.write_all(b"=?utf-8?B?")?;
54                    base64_encode_mime(chunk, &mut output, true)?;
55                    output.write_all(b"?=\r\n")?;
56                }
57            }
58            EncodingType::QuotedPrintable(is_ascii) => {
59                for (pos, chunk) in self.text.as_bytes().chunks(76 - bytes_written).enumerate() {
60                    if pos > 0 {
61                        output.write_all(b"\t")?;
62                    }
63                    if !is_ascii {
64                        output.write_all(b"=?utf-8?Q?")?;
65                    } else {
66                        output.write_all(b"=?us-ascii?Q?")?;
67                    }
68                    quoted_printable_encode(chunk, &mut output, true, false)?;
69                    output.write_all(b"?=\r\n")?;
70                }
71            }
72            EncodingType::None => {
73                for (pos, &ch) in self.text.as_bytes().iter().enumerate() {
74                    if bytes_written >= 76 && ch.is_ascii_whitespace() && pos < self.text.len() - 1 {
75                        output.write_all(b"\r\n\t")?;
76                        bytes_written = 1;
77                    }
78                    output.write_all(&[ch])?;
79                    bytes_written += 1;
80                }
81                output.write_all(b"\r\n")?;
82            }
83        }
84        Ok(0)
85    }
86}