mail_parser/parsers/fields/
id.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use crate::{parsers::MessageStream, HeaderValue};
8
9impl<'x> MessageStream<'x> {
10    pub fn parse_id(&mut self) -> HeaderValue<'x> {
11        let mut token_start: usize = 0;
12        let mut token_end: usize = 0;
13        let mut token_invalid_start: usize = 0; // Handle broken clients
14        let mut token_invalid_end: usize = 0; // Handle broken clients
15        let mut is_id_part = false;
16        let mut ids = Vec::new();
17
18        while let Some(&ch) = self.next() {
19            match ch {
20                b'\n' => {
21                    if !self.try_next_is_space() {
22                        return match ids.len() {
23                            1 => HeaderValue::Text(ids.pop().unwrap()),
24                            0 => {
25                                if token_invalid_start > 0 {
26                                    HeaderValue::Text(String::from_utf8_lossy(
27                                        self.bytes(token_invalid_start - 1..token_invalid_end),
28                                    ))
29                                } else {
30                                    HeaderValue::Empty
31                                }
32                            }
33                            _ => HeaderValue::TextList(ids),
34                        };
35                    } else {
36                        continue;
37                    }
38                }
39                b'<' => {
40                    is_id_part = true;
41                    continue;
42                }
43                b'>' => {
44                    is_id_part = false;
45                    if token_start > 0 {
46                        ids.push(String::from_utf8_lossy(
47                            self.bytes(token_start - 1..token_end),
48                        ));
49                        token_start = 0;
50                    } else {
51                        continue;
52                    }
53                }
54                b' ' | b'\t' | b'\r' => continue,
55                _ => {}
56            }
57            if is_id_part {
58                if token_start == 0 {
59                    token_start = self.offset();
60                }
61                token_end = self.offset();
62            } else {
63                if token_invalid_start == 0 {
64                    token_invalid_start = self.offset();
65                }
66                token_invalid_end = self.offset();
67            }
68        }
69
70        HeaderValue::Empty
71    }
72}
73#[cfg(test)]
74mod tests {
75    use std::borrow::Cow;
76
77    use crate::parsers::{fields::load_tests, MessageStream};
78
79    #[test]
80    fn parse_message_ids() {
81        for test in load_tests::<Option<Vec<Cow<'static, str>>>>("id.json") {
82            assert_eq!(
83                MessageStream::new(test.header.as_bytes())
84                    .parse_id()
85                    .into_text_list(),
86                test.expected,
87                "failed for {:?}",
88                test.header
89            );
90        }
91    }
92}