1
2
3use ::header_components;
4use self::validators::{
5 from as validator_from,
6 resent_any as validator_resent_any
7};
8
9
10def_headers! {
11 test_name: validate_header_names,
12 scope: header_components,
13 Date, unchecked { "Date" }, DateTime, maxOne, None,
15 _From, unchecked { "From" }, MailboxList, maxOne, validator_from,
17 Sender, unchecked { "Sender" }, Mailbox, maxOne, None,
19 ReplyTo, unchecked { "Reply-To" }, MailboxList, maxOne, None,
21 _To, unchecked { "To" }, MailboxList, maxOne, None,
23 Cc, unchecked { "Cc" }, MailboxList, maxOne, None,
25 Bcc, unchecked { "Bcc" }, MailboxList, maxOne, None,
27 MessageId, unchecked { "Message-Id" }, MessageId, maxOne, None,
29 InReplyTo, unchecked { "In-Reply-To" }, MessageIdList, maxOne, None,
31 References, unchecked { "References" }, MessageIdList, maxOne, None,
33 Subject, unchecked { "Subject" }, Unstructured, maxOne, None,
35 Comments, unchecked { "Comments" }, Unstructured, multi, None,
37 Keywords, unchecked { "Keywords" }, PhraseList, multi, None,
39 ResentDate, unchecked { "Resent-Date" }, DateTime, multi, validator_resent_any,
41 ResentFrom, unchecked { "Resent-From" }, MailboxList, multi, validator_resent_any,
43 ResentSender, unchecked { "Resent-Sender" }, Mailbox, multi, validator_resent_any,
45 ResentTo, unchecked { "Resent-To" }, MailboxList, multi, validator_resent_any,
47 ResentCc, unchecked { "Resent-Cc" }, MailboxList, multi, validator_resent_any,
49 ResentBcc, unchecked { "Resent-Bcc" }, OptMailboxList, multi, validator_resent_any,
51 ResentMsgId, unchecked { "Resent-Msg-Id" }, MessageId, multi, validator_resent_any,
53 ReturnPath, unchecked { "Return-Path" }, Path, multi, None,
55 Received, unchecked { "Received" }, ReceivedToken, multi, None,
57
58 ContentType, unchecked { "Content-Type" }, MediaType, maxOne, None,
60
61 ContentId, unchecked { "Content-Id" }, ContentId, maxOne, None,
63
64 ContentTransferEncoding, unchecked { "Content-Transfer-Encoding" }, TransferEncoding, maxOne, None,
89
90 ContentDescription, unchecked { "Content-Description" }, Unstructured, maxOne, None,
95
96 ContentDisposition, unchecked { "Content-Disposition" }, Disposition, maxOne, None
115}
116
117mod validators {
118 use std::collections::HashMap;
119
120 use ::{ HeaderMap, HeaderKind, HeaderName, HeaderObj };
121 use ::error::HeaderValidationError;
122
123 use super::{ _From, ResentFrom, Sender, ResentSender, ResentDate };
124
125
126 pub fn from(map: &HeaderMap) -> Result<(), HeaderValidationError> {
127 let needs_sender =
134 map.get(_From)
135 .filter_map(|res| res.ok())
136 .any(|list| list.len() > 1);
137
138 if needs_sender && !map.contains(Sender) {
139 header_validation_bail!(kind: MultiMailboxFromWithoutSender);
141 }
142 Ok(())
143 }
144
145 fn validate_resent_block<'a>(
146 block: &HashMap<HeaderName, &'a HeaderObj>
147 ) -> Result<(), HeaderValidationError> {
148 if !block.contains_key(&ResentDate::name()) {
149 header_validation_bail!(kind: ResentDateFieldMissing);
151 }
152 let needs_sender =
153 block.get(&ResentFrom::name())
155 .and_then(|tobj| tobj.downcast_ref::<ResentFrom>())
157 .map(|list| list.len() > 1)
158 .unwrap_or(false);
159
160 if needs_sender && !block.contains_key(&ResentSender::name()) {
161 header_validation_bail!(kind: MultiMailboxResentFromWithoutResentSender)
163 }
164 Ok(())
165 }
166
167 pub fn resent_any(map: &HeaderMap) -> Result<(), HeaderValidationError> {
168 let resents = map
169 .iter()
170 .filter(|&(name, _)| name.as_str().starts_with("Resent-"));
171
172 let mut block = HashMap::new();
173 for (name, content) in resents {
174 if block.contains_key(&name) {
175 validate_resent_block(&block)?;
176 block = HashMap::new();
178 }
179 block.insert(name, content);
180 }
181 validate_resent_block(&block)
182 }
183}
184
185#[cfg(test)]
186mod test {
187 use ::header_components::DateTime;
188 use ::{HeaderMap, HeaderKind};
189 use ::headers::{
190 _From, ResentFrom, ResentTo, ResentDate,
191 Sender, ResentSender, Subject
192 };
193
194 test!(from_validation_normal {
195 let mut map = HeaderMap::new();
196 map.insert(_From ::auto_body( [("Mr. Peté", "pete@nixmail.example")] )?);
197 map.insert(Subject ::auto_body( "Ok" )?);
198
199 assert_ok!(map.use_contextual_validators());
200 });
201
202 test!(from_validation_multi_err {
203 let mut map = HeaderMap::new();
204 map.insert(_From::auto_body((
205 ("Mr. Peté", "nixperson@nixmail.nixdomain"),
206 "a@b.c"
207 ))?);
208 map.insert(Subject::auto_body("Ok")?);
209
210 assert_err!(map.use_contextual_validators());
211 });
212
213 test!(from_validation_multi_ok {
214 let mut map = HeaderMap::new();
215 map.insert(_From::auto_body((
216 ("Mr. Peté", "nixperson@nixmail.nixdomain"),
217 "a@b.c"
218 ))?);
219 map.insert(Sender ::auto_body( "abx@d.e" )?);
220 map.insert(Subject ::auto_body( "Ok" )?);
221
222 assert_ok!(map.use_contextual_validators());
223 });
224
225 test!(resent_no_date_err {
226 let mut map = HeaderMap::new();
227 map.insert(ResentFrom ::auto_body( ["a@b.c"] )?);
228 assert_err!(map.use_contextual_validators());
229 });
230
231 test!(resent_with_date {
232 let mut map = HeaderMap::new();
233 map.insert(ResentFrom ::auto_body( ["a@b.c"] )?);
234 map.insert(ResentDate ::auto_body( DateTime::now() )?);
235 assert_ok!(map.use_contextual_validators());
236 });
237
238 test!(resent_no_date_err_second_block {
239 let mut map = HeaderMap::new();
240 map.insert(ResentDate ::auto_body( DateTime::now() )?);
241 map.insert(ResentFrom ::auto_body( ["a@b.c"] )?);
242 map.insert(ResentTo ::auto_body( ["e@f.d"] )?);
243 map.insert(ResentFrom ::auto_body( ["ee@ee.e"] )?);
244
245 assert_err!(map.use_contextual_validators());
246 });
247
248 test!(resent_with_date_second_block {
249 let mut map = HeaderMap::new();
250 map.insert(ResentDate ::auto_body( DateTime::now() )?);
251 map.insert(ResentFrom ::auto_body( ["a@b.c"] )?);
252 map.insert(ResentTo ::auto_body( ["e@f.d"] )?);
253 map.insert(ResentFrom ::auto_body( ["ee@ee.e"] )?);
254 map.insert(ResentDate ::auto_body( DateTime::now() )?);
255
256 assert_ok!(map.use_contextual_validators());
257 });
258
259 test!(resent_multi_mailbox_from_no_sender {
260
261 let mut map = HeaderMap::new();
262 map.insert(ResentDate ::auto_body( DateTime::now() )?);
263 map.insert(ResentFrom ::auto_body( ["a@b.c","e@c.d"] )?);
264
265 assert_err!(map.use_contextual_validators());
266 });
267
268 test!(resent_multi_mailbox_from_with_sender {
269 let mut map = HeaderMap::new();
270 map.insert(ResentDate ::auto_body( DateTime::now() )?);
271 map.insert(ResentFrom ::auto_body( ["a@b.c","e@c.d"] )?);
272 map.insert(ResentSender ::auto_body( "a@b.c" )?);
273 assert_ok!(map.use_contextual_validators());
274 });
275
276}