From b998aec37dc592ca9f27eec81714f19928e26f32 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Wed, 19 Jul 2023 17:40:00 +0200 Subject: [PATCH] trace --- src/rfc5322/mailbox.rs | 9 +++-- src/rfc5322/mod.rs | 1 + src/rfc5322/trace.rs | 81 ++++++++++++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/rfc5322/mailbox.rs b/src/rfc5322/mailbox.rs index 6f9b383..b4f4cf6 100644 --- a/src/rfc5322/mailbox.rs +++ b/src/rfc5322/mailbox.rs @@ -63,9 +63,8 @@ pub fn mailbox(input: &[u8]) -> IResult<&[u8], MailboxRef> { /// ``` fn name_addr(input: &[u8]) -> IResult<&[u8], MailboxRef> { let (input, name) = opt(phrase)(input)?; - let (input, mut mbox) = angle_addr(input)?; - mbox.name = name; - Ok((input, mbox)) + let (input, addrspec) = angle_addr(input)?; + Ok((input, MailboxRef { name, addrspec })) } /// Enclosed addr-spec with < and > @@ -74,10 +73,10 @@ fn name_addr(input: &[u8]) -> IResult<&[u8], MailboxRef> { /// angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / /// obs-angle-addr /// ``` -pub fn angle_addr(input: &[u8]) -> IResult<&[u8], MailboxRef> { +pub fn angle_addr(input: &[u8]) -> IResult<&[u8], AddrSpec> { delimited( tuple((opt(cfws), tag(&[ascii::LT]), opt(obs_route))), - into(addr_spec), + addr_spec, pair(tag(&[ascii::GT]), opt(cfws)), )(input) } diff --git a/src/rfc5322/mod.rs b/src/rfc5322/mod.rs index c4c7311..7192509 100644 --- a/src/rfc5322/mod.rs +++ b/src/rfc5322/mod.rs @@ -1,3 +1,4 @@ pub mod mailbox; pub mod address; pub mod datetime; +pub mod trace; diff --git a/src/rfc5322/trace.rs b/src/rfc5322/trace.rs index 5dc99d0..c5adeee 100644 --- a/src/rfc5322/trace.rs +++ b/src/rfc5322/trace.rs @@ -1,17 +1,30 @@ -use crate::error::IMFError; -use crate::fragments::{datetime, lazy, mailbox, misc_token, model, whitespace}; use nom::{ branch::alt, - bytes::complete::tag, - combinator::{map, opt, recognize}, + bytes::complete::{is_a, tag}, + combinator::{map, opt, not}, multi::many0, - sequence::tuple, + sequence::{tuple, terminated}, IResult, }; +use chrono::{DateTime, FixedOffset}; + +use crate::rfc5322::{datetime, mailbox}; +use crate::text::{ascii, whitespace, misc_token }; #[derive(Debug, PartialEq)] -pub struct ReceivedLog<'a>(pub &'a str); +pub enum ReceivedLogToken<'a> { + Addr(mailbox::AddrSpec<'a>), + Domain(mailbox::Domain<'a>), + Word(misc_token::Word<'a>) +} +#[derive(Debug, PartialEq)] +pub struct ReceivedLog<'a> { + pub log: Vec>, + pub date: Option>, +} + +/* impl<'a> TryFrom<&'a lazy::ReceivedLog<'a>> for ReceivedLog<'a> { type Error = IMFError<'a>; @@ -20,47 +33,48 @@ impl<'a> TryFrom<&'a lazy::ReceivedLog<'a>> for ReceivedLog<'a> { .map_err(|e| IMFError::ReceivedLog(e)) .map(|(_, v)| ReceivedLog(v)) } -} +}*/ -pub fn received_body(input: &str) -> IResult<&str, &str> { +pub fn received_body(input: &[u8]) -> IResult<&[u8], ReceivedLog> { map( tuple(( - recognize(many0(received_tokens)), + many0(received_tokens), tag(";"), datetime::section, )), - |(tokens, _, _)| tokens, + |(tokens, _, dt)| ReceivedLog { log: tokens, date: dt } , )(input) } -pub fn return_path_body(input: &str) -> IResult<&str, Option> { +pub fn return_path_body(input: &[u8]) -> IResult<&[u8], Option> { alt((map(mailbox::angle_addr, |a| Some(a)), empty_path))(input) } -fn empty_path(input: &str) -> IResult<&str, Option> { +fn empty_path(input: &[u8]) -> IResult<&[u8], Option> { let (input, _) = tuple(( opt(whitespace::cfws), - tag("<"), + tag(&[ascii::LT]), opt(whitespace::cfws), - tag(">"), + tag(&[ascii::GT]), opt(whitespace::cfws), ))(input)?; Ok((input, None)) } -// @FIXME use obs_domain as it is a superset of domain -fn received_tokens(input: &str) -> IResult<&str, &str> { +fn received_tokens(input: &[u8]) -> IResult<&[u8], ReceivedLogToken> { alt(( - recognize(mailbox::angle_addr), - recognize(mailbox::addr_spec), - recognize(mailbox::obs_domain), - recognize(misc_token::word), + terminated(map(misc_token::word, |x| ReceivedLogToken::Word(x)), not(is_a([ascii::PERIOD, ascii::AT]))), + map(mailbox::angle_addr, |x| ReceivedLogToken::Addr(x)), + map(mailbox::addr_spec, |x| ReceivedLogToken::Addr(x)), + map(mailbox::obs_domain, |x| ReceivedLogToken::Domain(x)), ))(input) } #[cfg(test)] mod tests { use super::*; + use chrono::TimeZone; + use crate::rfc5322::trace::misc_token::Word; #[test] fn test_received_body() { @@ -68,17 +82,30 @@ mod tests { by server with LMTP id xxxxxxxxx (envelope-from ) - for ; Tue, 13 Jun 2023 19:01:08 +0000"#; + for ; Tue, 13 Jun 2023 19:01:08 +0000"#.as_bytes(); assert_eq!( received_body(hdrs), Ok(( - "", - r#"from smtp.example.com ([10.83.2.2]) - by server with LMTP - id xxxxxxxxx - (envelope-from ) - for "# + &b""[..], + ReceivedLog { + date: Some(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2023, 06, 13, 19, 1, 8).unwrap()), + log: vec![ + ReceivedLogToken::Word(Word::Atom(&b"from"[..])), + ReceivedLogToken::Domain(mailbox::Domain::Atoms(vec![&b"smtp"[..], &b"example"[..], &b"com"[..]])), + ReceivedLogToken::Word(Word::Atom(&b"by"[..])), + ReceivedLogToken::Word(Word::Atom(&b"server"[..])), + ReceivedLogToken::Word(Word::Atom(&b"with"[..])), + ReceivedLogToken::Word(Word::Atom(&b"LMTP"[..])), + ReceivedLogToken::Word(Word::Atom(&b"id"[..])), + ReceivedLogToken::Word(Word::Atom(&b"xxxxxxxxx"[..])), + ReceivedLogToken::Word(Word::Atom(&b"for"[..])), + ReceivedLogToken::Addr(mailbox::AddrSpec { + local_part: mailbox::LocalPart(vec![mailbox::LocalPartToken::Word(Word::Atom(&b"me"[..]))]), + domain: mailbox::Domain::Atoms(vec![&b"example"[..], &b"com"[..]]), + }) + ], + } )) ); }