email_encoding/headers/
quoted_string.rs1use std::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 pretty_assertions::assert_eq;
136
137 use super::*;
138
139 #[test]
140 fn plain() {
141 let mut s = String::new();
142 let line_len = s.len();
143
144 {
145 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
146 encode("1234567890abcd", &mut w).unwrap();
147 }
148
149 assert_eq!(s, "1234567890abcd");
150 }
151
152 #[test]
153 fn quoted() {
154 let mut s = String::new();
155 let line_len = s.len();
156
157 {
158 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
159 encode("1234567890 abcd", &mut w).unwrap();
160 }
161
162 assert_eq!(s, "\"1234567890 abcd\"");
163 }
164
165 #[test]
166 fn quoted_long() {
167 let mut s = String::new();
168 let line_len = s.len();
169
170 {
171 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
172 encode("1234567890 abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", &mut w).unwrap();
173 }
174
175 assert_eq!(s, concat!(
176 "\"1234567890\r\n",
177 " abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd\""
178 ));
179 }
180
181 #[test]
182 fn quoted_escaped() {
183 let mut s = String::new();
184 let line_len = s.len();
185
186 {
187 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
188 encode("12345\\67890 ab\"cd", &mut w).unwrap();
189 }
190
191 assert_eq!(s, "\"12345\\\\67890 ab\\\"cd\"");
192 }
193
194 #[test]
212 fn rfc2047() {
213 let mut s = String::new();
214 let line_len = s.len();
215
216 {
217 let mut w = EmailWriter::new(&mut s, line_len, 0, false);
218 encode("12345\\67890 perché ab\"cd", &mut w).unwrap();
219 }
220
221 assert_eq!(s, "=?utf-8?b?MTIzNDVcNjc4OTAgcGVyY2jDqSBhYiJjZA==?=");
222 }
223}