wip trace
This commit is contained in:
parent
35ff869454
commit
09a6c6acdf
6 changed files with 160 additions and 32 deletions
|
@ -24,7 +24,7 @@ use crate::model;
|
||||||
/// Header section
|
/// Header section
|
||||||
///
|
///
|
||||||
/// See: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.2
|
/// 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(
|
let (input, headers) = fold_many0(
|
||||||
header_field,
|
header_field,
|
||||||
PermissiveHeaderSection::default,
|
PermissiveHeaderSection::default,
|
||||||
|
@ -95,10 +95,6 @@ pub fn header_section(input: &str) -> IResult<&str, PermissiveHeaderSection> {
|
||||||
section.keywords.append(&mut kws);
|
section.keywords.append(&mut kws);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.6.6. Resent Fields
|
|
||||||
|
|
||||||
// 3.6.7. Trace Fields
|
|
||||||
|
|
||||||
// 3.6.8. Optional Fields
|
// 3.6.8. Optional Fields
|
||||||
HeaderField::Optional(name, body) => {
|
HeaderField::Optional(name, body) => {
|
||||||
section.optional.insert(name, body);
|
section.optional.insert(name, body);
|
||||||
|
@ -138,18 +134,6 @@ enum HeaderField<'a> {
|
||||||
Comments(String),
|
Comments(String),
|
||||||
Keywords(Vec<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
|
// 3.6.8. Optional Fields
|
||||||
Optional(&'a str, String)
|
Optional(&'a str, String)
|
||||||
}
|
}
|
||||||
|
@ -174,7 +158,10 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
|
||||||
// Extract field body
|
// Extract field body
|
||||||
let (input, hfield) = match field_name {
|
let (input, hfield) = match field_name {
|
||||||
// 3.6.1. The Origination Date Field
|
// 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
|
// 3.6.2. Originator Fields
|
||||||
"From" => {
|
"From" => {
|
||||||
|
@ -233,6 +220,28 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.6.6. Resent Fields
|
// 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
|
// 3.6.7. Trace Fields
|
||||||
|
|
||||||
|
@ -248,15 +257,14 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
|
||||||
return Ok((input, hfield));
|
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
|
// @FIXME want to extract datetime our way in the future
|
||||||
// to better handle obsolete/bad cases instead of returning raw text.
|
// to better handle obsolete/bad cases instead of returning raw text.
|
||||||
let (input, raw_date) = unstructured(input)?;
|
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),
|
Ok(chronodt) => HeaderDate::Parsed(chronodt),
|
||||||
Err(e) => HeaderDate::Unknown(raw_date, e),
|
Err(e) => HeaderDate::Unknown(raw_date, e),
|
||||||
};
|
}
|
||||||
Ok((input, HeaderField::Date(date)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
16
src/header.rs
Normal file
16
src/header.rs
Normal 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 }))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -1,4 +1,4 @@
|
||||||
pub mod headers;
|
// Model
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|
||||||
// Generic
|
// Generic
|
||||||
|
@ -11,3 +11,12 @@ mod misc_token;
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
mod address;
|
mod address;
|
||||||
mod identification;
|
mod identification;
|
||||||
|
|
||||||
|
// Header blocks
|
||||||
|
pub mod common_fields;
|
||||||
|
pub mod trace;
|
||||||
|
|
||||||
|
// Global mail
|
||||||
|
pub mod header;
|
||||||
|
|
||||||
|
|
||||||
|
|
39
src/model.rs
39
src/model.rs
|
@ -63,6 +63,27 @@ pub struct MessageId<'a> {
|
||||||
pub right: &'a str,
|
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
|
/// Permissive Header Section
|
||||||
///
|
///
|
||||||
/// This is a structure intended for parsing/decoding,
|
/// 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
|
/// as invalid according to RFC5322 but for which we can
|
||||||
/// still extract some data.
|
/// still extract some data.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PermissiveHeaderSection<'a> {
|
pub struct CommonFields<'a> {
|
||||||
// 3.6.1. The Origination Date Field
|
// 3.6.1. The Origination Date Field
|
||||||
pub date: HeaderDate,
|
pub date: HeaderDate,
|
||||||
|
|
||||||
|
@ -94,14 +115,18 @@ pub struct PermissiveHeaderSection<'a> {
|
||||||
pub comments: Vec<String>,
|
pub comments: Vec<String>,
|
||||||
pub keywords: Vec<String>,
|
pub keywords: Vec<String>,
|
||||||
|
|
||||||
// 3.6.6. Resent Fields
|
|
||||||
|
|
||||||
// 3.6.7. Trace Fields
|
|
||||||
|
|
||||||
// 3.6.8. Optional Fields
|
// 3.6.8. Optional Fields
|
||||||
|
|
||||||
// Rest
|
|
||||||
pub optional: HashMap<&'a str, String>,
|
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 {
|
enum InvalidEmailErr {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use imf_codec::headers;
|
use imf_codec::common_headers;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let header = r#"Date: Fri, 21 Nov 1997 10:01:10 -0600
|
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.
|
This is a reply to your hello.
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
println!("{:?}", headers::header_section(header));
|
println!("{:?}", common_headers::section(header));
|
||||||
}
|
}
|
||||||
|
|
70
src/trace.rs
Normal file
70
src/trace.rs
Normal 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
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue