From 2b7b5664c1a87307d8c16c9e913e29ac4e9401a4 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 20 Jun 2023 18:12:16 +0200 Subject: [PATCH] final section parser --- src/fragments/misc_token.rs | 4 +- src/fragments/mod.rs | 1 + src/fragments/section.rs | 81 ++++++++++++++++++++++++++ src/multipass/build_header_section.rs | 0 src/multipass/field_eager.rs | 2 +- src/multipass/header_section.rs | 84 +++++++++++++++++++++++++++ src/multipass/mod.rs | 1 + 7 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 src/fragments/section.rs delete mode 100644 src/multipass/build_header_section.rs create mode 100644 src/multipass/header_section.rs diff --git a/src/fragments/misc_token.rs b/src/fragments/misc_token.rs index da49777..44ddd89 100644 --- a/src/fragments/misc_token.rs +++ b/src/fragments/misc_token.rs @@ -15,10 +15,10 @@ use crate::fragments::whitespace::{fws, is_obs_no_ws_ctl}; use crate::fragments::words::{atom, is_vchar}; use crate::error::IMFError; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Default)] pub struct Unstructured(pub String); -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Default)] pub struct PhraseList(pub Vec); impl<'a> TryFrom<&'a lazy::Unstructured<'a>> for Unstructured { diff --git a/src/fragments/mod.rs b/src/fragments/mod.rs index f4a0ac6..bef25af 100644 --- a/src/fragments/mod.rs +++ b/src/fragments/mod.rs @@ -15,6 +15,7 @@ mod trace; mod datetime; pub mod lazy; pub mod eager; +pub mod section; // Header blocks pub mod header; diff --git a/src/fragments/section.rs b/src/fragments/section.rs new file mode 100644 index 0000000..b80893f --- /dev/null +++ b/src/fragments/section.rs @@ -0,0 +1,81 @@ +use std::collections::HashMap; + +use chrono::{DateTime, FixedOffset}; +use crate::fragments::model::{ + MailboxList, MailboxRef, AddressList, + MessageId, MessageIdList, AddressRef}; +use crate::fragments::misc_token::{Unstructured, PhraseList}; +use crate::fragments::trace::ReceivedLog; +use crate::fragments::eager::Field; +use crate::fragments::lazy; + +#[derive(Debug, PartialEq, Default)] +pub struct Section<'a> { + // 3.6.1. The Origination Date Field + pub date: Option>, + + // 3.6.2. Originator Fields + pub from: Vec, + pub sender: Option, + pub reply_to: Vec, + + // 3.6.3. Destination Address Fields + pub to: Vec, + pub cc: Vec, + pub bcc: Vec, + + // 3.6.4. Identification Fields + pub msg_id: Option>, + pub in_reply_to: Vec>, + pub references: Vec>, + + // 3.6.5. Informational Fields + pub subject: Option, + pub comments: Vec, + pub keywords: Vec, + + // 3.6.6 Not implemented + // 3.6.7 Trace Fields + pub return_path: Vec, + pub received: Vec>, + + // 3.6.8. Optional Fields + pub optional: HashMap<&'a str, Unstructured>, + + // Recovery + pub bad_fields: Vec>, + pub unparsed: Vec<&'a str>, +} + +//@FIXME min and max limits are not enforced, +// it may result in missing data or silently overriden data. +impl<'a> From>> for Section<'a> { + fn from(field_list: Vec>) -> Self { + field_list.into_iter().fold( + Section::default(), + |mut section, field| { + match field { + Field::Date(v) => section.date = Some(v), + Field::From(v) => section.from.extend(v), + Field::Sender(v) => section.sender = Some(v), + Field::ReplyTo(v) => section.reply_to.extend(v), + Field::To(v) => section.to.extend(v), + Field::Cc(v) => section.cc.extend(v), + Field::Bcc(v) => section.bcc.extend(v), + Field::MessageID(v) => section.msg_id = Some(v), + Field::InReplyTo(v) => section.in_reply_to.extend(v), + Field::References(v) => section.references.extend(v), + Field::Subject(v) => section.subject = Some(v), + Field::Comments(v) => section.comments.push(v), + Field::Keywords(v) => section.keywords.push(v), + Field::ReturnPath(v) => section.return_path.push(v), + Field::Received(v) => section.received.push(v), + Field::Optional(k, v) => { section.optional.insert(k, v); }, + Field::Rescue(v) => section.unparsed.push(v), + }; + section + } + ) + } +} + diff --git a/src/multipass/build_header_section.rs b/src/multipass/build_header_section.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/multipass/field_eager.rs b/src/multipass/field_eager.rs index 5b62ea1..77d1220 100644 --- a/src/multipass/field_eager.rs +++ b/src/multipass/field_eager.rs @@ -24,7 +24,7 @@ mod tests { use chrono::{FixedOffset, TimeZone}; #[test] - fn test_field_name() { + fn test_field_body() { assert_eq!(Parsed::from(&field_lazy::Parsed { fields: vec![ lazy::Field::From(lazy::MailboxList("hello@world.com,\r\n\talice@wonderlands.com\r\n")), diff --git a/src/multipass/header_section.rs b/src/multipass/header_section.rs new file mode 100644 index 0000000..93bdafe --- /dev/null +++ b/src/multipass/header_section.rs @@ -0,0 +1,84 @@ +use crate::fragments::section::Section; +use crate::multipass::field_eager; + +#[derive(Debug, PartialEq)] +pub struct Parsed<'a> { + pub fields: Section<'a>, + pub body: &'a [u8], +} + +impl<'a> From> for Parsed<'a> { + fn from(p: field_eager::Parsed<'a>) -> Self { + Parsed { + fields: p.fields.into(), + body: p.body, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::fragments::eager; + use crate::fragments::model; + use chrono::{FixedOffset, TimeZone}; + + #[test] + fn test_section() { + assert_eq!(Parsed::from(field_eager::Parsed { + fields: vec![ + eager::Field::From(vec![ + model::MailboxRef { + name: None, + addrspec: model::AddrSpec { + local_part: "hello".into(), + domain: "world.com".into() + } + }, + model::MailboxRef { + name: None, + addrspec: model::AddrSpec { + local_part: "alice".into(), + domain: "wonderlands.com".into() + } + }, + ]), + eager::Field::Date( + FixedOffset::east_opt(0) + .unwrap() + .with_ymd_and_hms(1997, 03, 12, 7, 33, 25) + .unwrap() + ), + ], + body: b"Hello world!", + }), + Parsed { + fields: Section { + from: vec![ + model::MailboxRef { + name: None, + addrspec: model::AddrSpec { + local_part: "hello".into(), + domain: "world.com".into() + } + }, + model::MailboxRef { + name: None, + addrspec: model::AddrSpec { + local_part: "alice".into(), + domain: "wonderlands.com".into() + } + }, + ], + + date: Some(FixedOffset::east_opt(0) + .unwrap() + .with_ymd_and_hms(1997, 03, 12, 7, 33, 25) + .unwrap()), + + ..Default::default() + }, + body: b"Hello world!", + }); + } +} diff --git a/src/multipass/mod.rs b/src/multipass/mod.rs index 78acf35..1f8cce3 100644 --- a/src/multipass/mod.rs +++ b/src/multipass/mod.rs @@ -3,3 +3,4 @@ pub mod guess_charset; pub mod extract_fields; pub mod field_lazy; pub mod field_eager; +pub mod header_section;