wip trace

This commit is contained in:
Quentin 2023-06-13 17:47:57 +02:00
parent 35ff869454
commit 09a6c6acdf
Signed by: quentin
GPG key ID: E9602264D639FF68
6 changed files with 160 additions and 32 deletions

View file

@ -24,7 +24,7 @@ use crate::model;
/// Header section
///
/// See: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.2
pub fn header_section(input: &str) -> IResult<&str, PermissiveHeaderSection> {
pub fn section(input: &str) -> IResult<&str, PermissiveHeaderSection> {
let (input, headers) = fold_many0(
header_field,
PermissiveHeaderSection::default,
@ -95,10 +95,6 @@ pub fn header_section(input: &str) -> IResult<&str, PermissiveHeaderSection> {
section.keywords.append(&mut kws);
}
// 3.6.6. Resent Fields
// 3.6.7. Trace Fields
// 3.6.8. Optional Fields
HeaderField::Optional(name, body) => {
section.optional.insert(name, body);
@ -138,18 +134,6 @@ enum HeaderField<'a> {
Comments(String),
Keywords(Vec<String>),
// 3.6.6. Resent Fields
ResentDate,
ResentFrom,
ResentSender,
ResentTo,
ResentCc,
ResentBcc,
ResentMessageID,
// 3.6.7. Trace Fields
Trace,
// 3.6.8. Optional Fields
Optional(&'a str, String)
}
@ -174,7 +158,10 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
// Extract field body
let (input, hfield) = match field_name {
// 3.6.1. The Origination Date Field
"Date" => datetime(input)?,
"Date" => {
let (input, body) = datetime(input)?;
Ok((input, HeaderField::Date(body)))
}
// 3.6.2. Originator Fields
"From" => {
@ -233,6 +220,28 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
}
// 3.6.6. Resent Fields
"Resent-Date" => {
let (input, body) = datetime(input)?;
Ok((input, HeaderField::ResentDate(body)))
}
"Resent-From" => {
unimplemented!();
}
"Resent-Sender" => {
unimplemented!();
}
"Resent-To" => {
unimplemented!();
}
"Resent-Cc" => {
unimplemented!();
}
"Resent-Bcc" => {
unimplemented!();
}
"Resent-Message-ID" => {
unimplemented!();
}
// 3.6.7. Trace Fields
@ -248,15 +257,14 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
return Ok((input, hfield));
}
fn datetime(input: &str) -> IResult<&str, HeaderField> {
fn datetime(input: &str) -> IResult<&str, HeaderDate> {
// @FIXME want to extract datetime our way in the future
// to better handle obsolete/bad cases instead of returning raw text.
let (input, raw_date) = unstructured(input)?;
let date = match DateTime::parse_from_rfc2822(&raw_date) {
match DateTime::parse_from_rfc2822(&raw_date) {
Ok(chronodt) => HeaderDate::Parsed(chronodt),
Err(e) => HeaderDate::Unknown(raw_date, e),
};
Ok((input, HeaderField::Date(date)))
}
}
#[cfg(test)]

16
src/header.rs Normal file
View file

@ -0,0 +1,16 @@
use nom::{
IResult,
multi::many0,
}
use crate::{common_fields, trace, whitespace};
pub fn section(input: &str) -> IResult(&str, HeaderSection) {
let (input, traces) = many0(trace::section)(input)?;
let (input, common) = common_fields::section(input)?;
let (input, _) = whitespace::perm_crlf(input)?;
Ok((input, HeaderSection { traces, common }))
}

View file

@ -1,4 +1,4 @@
pub mod headers;
// Model
pub mod model;
// Generic
@ -11,3 +11,12 @@ mod misc_token;
mod mailbox;
mod address;
mod identification;
// Header blocks
pub mod common_fields;
pub mod trace;
// Global mail
pub mod header;

View file

@ -63,6 +63,27 @@ pub struct MessageId<'a> {
pub right: &'a str,
}
#[derive(Debug, PartialEq)]
pub struct Trace {
// 3.6.7 Traces
pub received: Vec<String>,
pub return_path: Option<String>,
// 3.6.6. Resent Fields
pub resent_date: HeaderDate,
pub resent_from: Vec<MailboxRef>,
pub resent_sender: Option<MailboxRef>,
pub resent_to: Vec<AddressRef>,
pub resent_cc: Vec<AddressRef>,
pub resent_bcc: Vec<AddressRef>,
pub resent_msg_id: Option<MessageId<'a>>,
// 3.6.8. Optional Fields
pub optional: HashMap<&'a str, String>,
//pub failed: HashMap<&'a str, String>,
//pub garbage: &'a str,
}
/// Permissive Header Section
///
/// This is a structure intended for parsing/decoding,
@ -70,7 +91,7 @@ pub struct MessageId<'a> {
/// as invalid according to RFC5322 but for which we can
/// still extract some data.
#[derive(Debug, Default)]
pub struct PermissiveHeaderSection<'a> {
pub struct CommonFields<'a> {
// 3.6.1. The Origination Date Field
pub date: HeaderDate,
@ -94,14 +115,18 @@ pub struct PermissiveHeaderSection<'a> {
pub comments: Vec<String>,
pub keywords: Vec<String>,
// 3.6.6. Resent Fields
// 3.6.7. Trace Fields
// 3.6.8. Optional Fields
// Rest
pub optional: HashMap<&'a str, String>,
//pub failed: HashMap<&'a str, String>,
//pub garbage: &'a str,
}
pub struct HeaderSection<'a> {
// 3.6.7 Traces
pub traces: Vec<Trace>,
// 3.6.x
pub common: CommonFields,
}
enum InvalidEmailErr {

View file

@ -1,4 +1,4 @@
use imf_codec::headers;
use imf_codec::common_headers;
fn main() {
let header = r#"Date: Fri, 21 Nov 1997 10:01:10 -0600
@ -21,5 +21,5 @@ References: <1234@local.machine.example>
This is a reply to your hello.
"#;
println!("{:?}", headers::header_section(header));
println!("{:?}", common_headers::section(header));
}

70
src/trace.rs Normal file
View file

@ -0,0 +1,70 @@
use nom::{
IResult,
}
use crate::model;
enum RestField<'a> {
// 3.6.6. Resent Fields
ResentDate(HeaderDate),
ResentFrom(Vec<MailboxRef>),
ResentSender(MailboxRef),
ResentTo(Vec<AddressRef>),
ResentCc(Vec<AddressRef>),
ResentBcc(Vec<AddressRef>),
ResentMessageID(model::MessageId<'a>),
// 3.6.8. Optional fields
Optional(&'a str, String),
}
enum PreludeField<'a> {
// 3.6.7. Trace Fields
ReturnPath(String),
Received(Vec<String>),
}
/// Section
///
/// Rewritten section for more compatibility
///
/// ```abnf
///*(trace
/// *(optional-field /
/// resent-date /
/// resent-from /
/// resent-sender /
/// resent-to /
/// resent-cc /
/// resent-bcc /
/// resent-msg-id))
/// ```
pub fn section(input: &str) -> IResult<&str, model::Trace> {
let (input, mut prelude_trace) = prelude(input)?;
let (input, full_trace) = fold_many0(
rest_field,
prelude_trace,
|mut trace, field| {
match field {
}
}
}
/// Trace prelude
///
/// ```abnf
/// trace = [return]
/// 1*received
/// return = "Return-Path:" path CRLF
/// path = angle-addr / ([CFWS] "<" [CFWS] ">" [CFWS])
/// received = "Received:" *received-token ";" date-time CRLF
/// received-token = word / angle-addr / addr-spec / domain
/// ```
fn prelude(input: &str) -> IResult<&str, model::Trace> {
}
fn rest_field(input: &str) -> IResult<&str, RestField> {
// Ensure this is not a new prelude
}