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, bytes::complete::tag,
character::complete::space0, character::complete::space0,
combinator::opt, combinator::opt,
multi::fold_many0, multi::{many0, many1, fold_many0, separated_list1},
multi::{many0, many1},
sequence::tuple, sequence::tuple,
}; };
use crate::whitespace::{fws, perm_crlf}; use crate::whitespace::{fws, perm_crlf};
use crate::words::vchar_seq; 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::model::{PermissiveHeaderSection, HeaderDate, MailboxRef, AddressRef};
use crate::mailbox::mailbox; use crate::mailbox::mailbox;
use crate::address::{mailbox_list, address_list, address_list_cfws}; 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; section.references = id_list;
} }
// 3.6.5. Informational Fields
HeaderField::Subject(title) => { HeaderField::Subject(title) => {
// | subject | 0 | 1 | |
section.subject = Some(title); 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) => { HeaderField::Optional(name, body) => {
section.optional.insert(name, body); section.optional.insert(name, body);
} }
@ -122,7 +136,7 @@ enum HeaderField<'a> {
// 3.6.5. Informational Fields // 3.6.5. Informational Fields
Subject(String), Subject(String),
Comments(String), Comments(String),
Keywords(Vec<&'a str>), Keywords(Vec<String>),
// 3.6.6. Resent Fields // 3.6.6. Resent Fields
ResentDate, ResentDate,
@ -204,11 +218,25 @@ fn header_field(input: &str) -> IResult<&str, HeaderField> {
(input, HeaderField::References(body)) (input, HeaderField::References(body))
}, },
// Rest // 3.6.5. Informational Fields
"Subject" => { "Subject" => {
let (input, body) = unstructured(input)?; let (input, body) = unstructured(input)?;
(input, HeaderField::Subject(body)) (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)?; let (input, body) = unstructured(input)?;
(input, HeaderField::Optional(field_name, body)) (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 msg_id: Option<MessageId<'a>>,
pub in_reply_to: Vec<MessageId<'a>>, pub in_reply_to: Vec<MessageId<'a>>,
pub references: 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 // Rest
pub subject: Option<String>,
pub optional: HashMap<&'a str, String>, pub optional: HashMap<&'a str, String>,
} }

View file

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