eml_codec/imf/
identification.rs

1use nom::{
2    branch::alt,
3    bytes::complete::{tag, take_while},
4    combinator::opt,
5    multi::many1,
6    sequence::{delimited, pair, tuple},
7    IResult,
8};
9use std::fmt;
10
11use crate::imf::mailbox::is_dtext;
12use crate::text::whitespace::cfws;
13use crate::text::words::dot_atom_text;
14
15#[derive(PartialEq, Clone)]
16pub struct MessageID<'a> {
17    pub left: &'a [u8],
18    pub right: &'a [u8],
19}
20impl<'a> ToString for MessageID<'a> {
21    fn to_string(&self) -> String {
22        format!(
23            "{}@{}",
24            String::from_utf8_lossy(self.left),
25            String::from_utf8_lossy(self.right)
26        )
27    }
28}
29impl<'a> fmt::Debug for MessageID<'a> {
30    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
31        fmt.debug_tuple("MessageID")
32            .field(&format_args!("\"{}\"", self.to_string()))
33            .finish()
34    }
35}
36pub type MessageIDList<'a> = Vec<MessageID<'a>>;
37
38/// Message identifier
39///
40/// ```abnf
41///    msg-id          =   [CFWS] "<" id-left "@" id-right ">" [CFWS]
42/// ```
43pub fn msg_id(input: &[u8]) -> IResult<&[u8], MessageID> {
44    let (input, (left, _, right)) = delimited(
45        pair(opt(cfws), tag("<")),
46        tuple((id_left, tag("@"), id_right)),
47        pair(tag(">"), opt(cfws)),
48    )(input)?;
49    Ok((input, MessageID { left, right }))
50}
51
52pub fn msg_list(input: &[u8]) -> IResult<&[u8], MessageIDList> {
53    many1(msg_id)(input)
54}
55
56// @FIXME Missing obsolete
57fn id_left(input: &[u8]) -> IResult<&[u8], &[u8]> {
58    dot_atom_text(input)
59}
60
61// @FIXME Missing obsolete
62fn id_right(input: &[u8]) -> IResult<&[u8], &[u8]> {
63    alt((dot_atom_text, no_fold_litteral))(input)
64}
65
66fn no_fold_litteral(input: &[u8]) -> IResult<&[u8], &[u8]> {
67    delimited(tag("["), take_while(is_dtext), tag("]"))(input)
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_msg_id() {
76        assert_eq!(
77            msg_id(b"<5678.21-Nov-1997@example.com>"),
78            Ok((
79                &b""[..],
80                MessageID {
81                    left: &b"5678.21-Nov-1997"[..],
82                    right: &b"example.com"[..],
83                }
84            )),
85        );
86    }
87}