Informational fields support
This commit is contained in:
parent
7334085166
commit
35ff869454
3 changed files with 69 additions and 7 deletions
|
@ -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()])))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
12
src/model.rs
12
src/model.rs
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue