2023-06-22 10:10:25 +00:00
|
|
|
use chrono::{FixedOffset, TimeZone};
|
2023-06-22 13:08:50 +00:00
|
|
|
use imf_codec::fragments::{misc_token, model, section, trace};
|
2023-06-22 10:10:25 +00:00
|
|
|
use imf_codec::multipass;
|
2023-06-22 13:08:50 +00:00
|
|
|
use std::collections::HashMap;
|
2023-06-22 10:10:25 +00:00
|
|
|
|
|
|
|
fn parser<'a, F>(input: &'a [u8], func: F) -> ()
|
2023-06-22 13:08:50 +00:00
|
|
|
where
|
|
|
|
F: FnOnce(§ion::Section) -> (),
|
|
|
|
{
|
2023-06-22 10:10:25 +00:00
|
|
|
let seg = multipass::segment::new(input).unwrap();
|
|
|
|
let charset = seg.charset();
|
|
|
|
let fields = charset.fields().unwrap();
|
|
|
|
let field_names = fields.names();
|
|
|
|
let field_body = field_names.body();
|
|
|
|
let section = field_body.section();
|
|
|
|
|
|
|
|
func(§ion.fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_headers() {
|
|
|
|
let fullmail: &[u8] = r#"Return-Path: <gitlab@example.com>
|
|
|
|
Delivered-To: quentin@example.com
|
|
|
|
Received: from smtp.example.com ([10.83.2.2])
|
|
|
|
by doradille with LMTP
|
|
|
|
id xyzabcd
|
|
|
|
(envelope-from <gitlab@example.com>)
|
|
|
|
for <quentin@example.com>; Tue, 13 Jun 2023 19:01:08 +0000
|
|
|
|
Date: Tue, 13 Jun 2023 10:01:10 +0200
|
|
|
|
From: Mary Smith
|
|
|
|
<mary@example.net>, "A\lan" <alan@example>
|
|
|
|
Sender: imf@example.com
|
|
|
|
Reply-To: "Mary Smith: Personal Account" <smith@home.example>
|
|
|
|
To: John Doe <jdoe@machine.example>
|
|
|
|
Cc: imf2@example.com
|
|
|
|
Bcc: (hidden)
|
|
|
|
Subject: Re: Saying Hello
|
|
|
|
Comments: A simple message
|
|
|
|
Comments: Not that complicated
|
|
|
|
comments : not valid header name but should be accepted
|
|
|
|
by the parser.
|
|
|
|
Keywords: hello, world
|
|
|
|
Héron: Raté
|
|
|
|
Raté raté
|
|
|
|
Keywords: salut, le, monde
|
|
|
|
Not a real header but should still recover
|
|
|
|
Message-ID: <3456@example.net>
|
|
|
|
In-Reply-To: <1234@local.machine.example>
|
|
|
|
References: <1234@local.machine.example>
|
|
|
|
Unknown: unknown
|
|
|
|
|
|
|
|
This is a reply to your hello.
|
2023-06-22 13:08:50 +00:00
|
|
|
"#
|
|
|
|
.as_bytes();
|
|
|
|
parser(fullmail, |parsed_section| {
|
2023-06-22 10:10:25 +00:00
|
|
|
assert_eq!(
|
|
|
|
parsed_section,
|
|
|
|
§ion::Section {
|
2023-06-22 13:08:50 +00:00
|
|
|
date: Some(
|
|
|
|
&FixedOffset::east_opt(2 * 3600)
|
|
|
|
.unwrap()
|
|
|
|
.with_ymd_and_hms(2023, 06, 13, 10, 01, 10)
|
|
|
|
.unwrap()
|
|
|
|
),
|
|
|
|
|
|
|
|
from: vec![
|
|
|
|
&model::MailboxRef {
|
|
|
|
name: Some("Mary Smith".into()),
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "mary".into(),
|
|
|
|
domain: "example.net".into(),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
&model::MailboxRef {
|
|
|
|
name: Some("Alan".into()),
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "alan".into(),
|
|
|
|
domain: "example".into(),
|
|
|
|
}
|
2023-06-22 10:10:25 +00:00
|
|
|
}
|
2023-06-22 13:08:50 +00:00
|
|
|
],
|
2023-06-22 10:10:25 +00:00
|
|
|
|
|
|
|
sender: Some(&model::MailboxRef {
|
|
|
|
name: None,
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "imf".into(),
|
|
|
|
domain: "example.com".into(),
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
|
|
|
reply_to: vec![&model::AddressRef::Single(model::MailboxRef {
|
|
|
|
name: Some("Mary Smith: Personal Account".into()),
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "smith".into(),
|
|
|
|
domain: "home.example".into(),
|
|
|
|
}
|
|
|
|
})],
|
|
|
|
|
|
|
|
to: vec![&model::AddressRef::Single(model::MailboxRef {
|
|
|
|
name: Some("John Doe".into()),
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "jdoe".into(),
|
|
|
|
domain: "machine.example".into(),
|
|
|
|
}
|
|
|
|
})],
|
|
|
|
|
|
|
|
cc: vec![&model::AddressRef::Single(model::MailboxRef {
|
|
|
|
name: None,
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "imf2".into(),
|
|
|
|
domain: "example.com".into(),
|
|
|
|
}
|
|
|
|
})],
|
|
|
|
|
|
|
|
bcc: vec![],
|
|
|
|
|
2023-06-22 13:08:50 +00:00
|
|
|
msg_id: Some(&model::MessageId {
|
|
|
|
left: "3456",
|
|
|
|
right: "example.net"
|
|
|
|
}),
|
|
|
|
in_reply_to: vec![&model::MessageId {
|
|
|
|
left: "1234",
|
|
|
|
right: "local.machine.example"
|
|
|
|
}],
|
|
|
|
references: vec![&model::MessageId {
|
|
|
|
left: "1234",
|
|
|
|
right: "local.machine.example"
|
|
|
|
}],
|
2023-06-22 10:10:25 +00:00
|
|
|
|
|
|
|
subject: Some(&misc_token::Unstructured("Re: Saying Hello".into())),
|
|
|
|
|
|
|
|
comments: vec![
|
|
|
|
&misc_token::Unstructured("A simple message".into()),
|
|
|
|
&misc_token::Unstructured("Not that complicated".into()),
|
2023-06-22 13:08:50 +00:00
|
|
|
&misc_token::Unstructured(
|
|
|
|
"not valid header name but should be accepted by the parser.".into()
|
|
|
|
),
|
2023-06-22 10:10:25 +00:00
|
|
|
],
|
|
|
|
|
|
|
|
keywords: vec![
|
2023-06-22 13:08:50 +00:00
|
|
|
&misc_token::PhraseList(vec!["hello".into(), "world".into(),]),
|
|
|
|
&misc_token::PhraseList(vec!["salut".into(), "le".into(), "monde".into(),]),
|
2023-06-22 10:10:25 +00:00
|
|
|
],
|
|
|
|
|
2023-06-22 13:08:50 +00:00
|
|
|
received: vec![&trace::ReceivedLog(
|
|
|
|
r#"from smtp.example.com ([10.83.2.2])
|
|
|
|
by doradille with LMTP
|
|
|
|
id xyzabcd
|
|
|
|
(envelope-from <gitlab@example.com>)
|
|
|
|
for <quentin@example.com>"#
|
|
|
|
)],
|
2023-06-22 10:10:25 +00:00
|
|
|
|
|
|
|
return_path: vec![&model::MailboxRef {
|
|
|
|
name: None,
|
|
|
|
addrspec: model::AddrSpec {
|
|
|
|
local_part: "gitlab".into(),
|
|
|
|
domain: "example.com".into(),
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
|
|
|
|
optional: HashMap::from([
|
2023-06-22 13:08:50 +00:00
|
|
|
(
|
|
|
|
"Delivered-To",
|
|
|
|
&misc_token::Unstructured("quentin@example.com".into())
|
|
|
|
),
|
|
|
|
("Unknown", &misc_token::Unstructured("unknown".into())),
|
2023-06-22 10:10:25 +00:00
|
|
|
]),
|
|
|
|
|
|
|
|
bad_fields: vec![],
|
|
|
|
|
|
|
|
unparsed: vec![
|
|
|
|
"Héron: Raté\n Raté raté\n",
|
|
|
|
"Not a real header but should still recover\n",
|
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
2023-06-22 13:08:50 +00:00
|
|
|
})
|
2023-06-22 10:10:25 +00:00
|
|
|
}
|