Informational fields support

This commit is contained in:
Quentin 2023-06-13 16:22:04 +02:00
parent 7334085166
commit 35ff869454
Signed by: quentin
GPG key ID: E9602264D639FF68
3 changed files with 69 additions and 7 deletions

View file

@ -6,14 +6,13 @@ use nom::{
bytes::complete::tag,
character::complete::space0,
combinator::opt,
multi::fold_many0,
multi::{many0, many1},
multi::{many0, many1, fold_many0, separated_list1},
sequence::tuple,
};
use crate::whitespace::{fws, perm_crlf};
use crate::words::vchar_seq;
use crate::misc_token::unstructured;
use crate::misc_token::{phrase, unstructured};
use crate::model::{PermissiveHeaderSection, HeaderDate, MailboxRef, AddressRef};
use crate::mailbox::mailbox;
use crate::address::{mailbox_list, address_list, address_list_cfws};
@ -82,10 +81,25 @@ pub fn header_section(input: &str) -> IResult<&str, PermissiveHeaderSection> {
section.references = id_list;
}
// 3.6.5. Informational Fields
HeaderField::Subject(title) => {
// | subject | 0 | 1 | |
section.subject = Some(title);
}
HeaderField::Comments(coms) => {
// | comments | 0 | unlimited | |
section.comments.push(coms);
}
HeaderField::Keywords(mut kws) => {
// | keywords | 0 | unlimited | |
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);
}
@ -122,7 +136,7 @@ enum HeaderField<'a> {
// 3.6.5. Informational Fields
Subject(String),
Comments(String),
Keywords(Vec<&'a str>),
Keywords(Vec<String>),
// 3.6.6. Resent Fields
ResentDate,
@ -204,11 +218,25 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
(input, HeaderField::References(body))
},
// Rest
// 3.6.5. Informational Fields
"Subject" => {
let (input, body) = unstructured(input)?;
(input, HeaderField::Subject(body))
},
"Comments" => {
let (input, body) = unstructured(input)?;
(input, HeaderField::Comments(body))
}
"Keywords" => {
let (input, body) = separated_list1(tag(","), phrase)(input)?;
(input, HeaderField::Keywords(body))
}
// 3.6.6. Resent Fields
// 3.6.7. Trace Fields
// 3.6.8. Optional Fields
_ => {
let (input, body) = unstructured(input)?;
(input, HeaderField::Optional(field_name, body))
@ -364,6 +392,26 @@ mod tests {
])))
);
}
// 3.6.5. Informational Fields
fn test_subject() {
assert_eq!(
header_field("Subject: Aérogramme\r\n"),
Ok(("", HeaderField::Subject("Aérogramme".into())))
);
}
fn test_comments() {
assert_eq!(
header_field("Comments: 😛 easter egg!\r\n"),
Ok(("", HeaderField::Comments("😛 easter egg!".into())))
);
}
fn test_keywords() {
assert_eq!(
header_field("Keywords: fantasque, farfelu, fanfreluche\r\n"),
Ok(("", HeaderField::Keywords(vec!["fantasque".into(), "farfelu".into(), "fanfreluche".into()])))
);
}
}

View file

@ -88,9 +88,19 @@ pub struct PermissiveHeaderSection<'a> {
pub msg_id: Option<MessageId<'a>>,
pub in_reply_to: Vec<MessageId<'a>>,
pub references: Vec<MessageId<'a>>,
// 3.6.5. Informational Fields
pub subject: Option<String>,
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 subject: Option<String>,
pub optional: HashMap<&'a str, String>,
}

View file

@ -10,6 +10,10 @@ To: John Doe <jdoe@machine.example>
Cc: imf2@example.com
Bcc: (hidden)
Subject: Re: Saying Hello
Comments: A simple message
Comments: Not that complicated
Keywords: hello, world
Keywords: salut, le, monde
Message-ID: <3456@example.net>
In-Reply-To: <1234@local.machine.example>
References: <1234@local.machine.example>