email_encoding/headers/
quoted_string.rs1use core::fmt::{self, Write};
4
5use super::{rfc2047, utils, writer::EmailWriter};
6
7pub fn encode(value: &str, w: &mut EmailWriter<'_>) -> fmt::Result {
61 #[derive(Debug)]
62 enum Strategy {
63 Plain,
64 Quoted,
65 QuotedEscaped,
66 Rfc2047,
67 }
68
69 let mut strategy = Strategy::Plain;
70
71 let mut bytes = value.as_bytes();
72
73 while !bytes.is_empty() {
75 let byte = bytes[0];
76
77 if !byte.is_ascii_alphanumeric() && !matches!(byte, b'-' | b'_' | b'.') {
78 strategy = Strategy::Quoted;
79 break;
80 }
81
82 bytes = &bytes[1..];
83 }
84
85 while !bytes.is_empty() {
87 let byte = bytes[0];
88
89 if !byte.is_ascii_alphanumeric() && !matches!(byte, b' ' | b'-' | b'_' | b'.') {
90 strategy = Strategy::QuotedEscaped;
91 break;
92 }
93
94 bytes = &bytes[1..];
95 }
96
97 while !bytes.is_empty() {
99 let byte = bytes[0];
100
101 if !byte.is_ascii_alphanumeric()
102 && !matches!(byte, b'\\' | b'"' | b' ' | b'-' | b'_' | b'.')
103 {
104 strategy = Strategy::Rfc2047;
105 break;
106 }
107
108 bytes = &bytes[1..];
109 }
110
111 match strategy {
112 Strategy::Plain => {
113 w.write_str(value)?;
114 }
115 Strategy::Quoted => {
116 w.write_char('"')?;
117 w.folding().write_str(value)?;
118 w.write_char('"')?;
119 }
120 Strategy::QuotedEscaped => {
121 w.write_char('"')?;
122 utils::write_escaped(value, &mut w.folding())?;
123 w.write_char('"')?;
124 }
125 Strategy::Rfc2047 => {
126 rfc2047::encode(value, w)?;
127 }
128 }
129
130 Ok(())
131}
132
133#[cfg(test)]
134mod tests {
135 use alloc::string::String;
136
137 use pretty_assertions::assert_eq;
138
139 use super::*;
140
141 #[test]
142 fn plain() {
143 let mut s = String::new();
144 let line_len = s.len();
145
146 {
147 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
148 encode("1234567890abcd", &mut w).unwrap();
149 }
150
151 assert_eq!(s, "1234567890abcd");
152 }
153
154 #[test]
155 fn quoted() {
156 let mut s = String::new();
157 let line_len = s.len();
158
159 {
160 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
161 encode("1234567890 abcd", &mut w).unwrap();
162 }
163
164 assert_eq!(s, "\"1234567890 abcd\"");
165 }
166
167 #[test]
168 fn quoted_long() {
169 let mut s = String::new();
170 let line_len = s.len();
171
172 {
173 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
174 encode("1234567890 abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", &mut w).unwrap();
175 }
176
177 assert_eq!(s, concat!(
178 "\"1234567890\r\n",
179 " abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\""
180 ));
181 }
182
183 #[test]
184 fn quoted_escaped() {
185 let mut s = String::new();
186 let line_len = s.len();
187
188 {
189 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
190 encode("12345\\67890 ab\"cd", &mut w).unwrap();
191 }
192
193 assert_eq!(s, "\"12345\\\\67890 ab\\\"cd\"");
194 }
195
196 #[test]
214 fn rfc2047() {
215 let mut s = String::new();
216 let line_len = s.len();
217
218 {
219 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
220 encode("12345\\67890 perché ab\"cd", &mut w).unwrap();
221 }
222
223 assert_eq!(s, "=?utf-8?b?MTIzNDVcNjc4OTAgcGVyY2jDqSBhYiJjZA==?=");
224 }
225}