mirror of
https://github.com/mailscope/kumomta.git
synced 2026-09-09 12:02:14 +00:00
mailparsing: support unstructured header field parsing
This commit is contained in:
@@ -103,6 +103,10 @@ impl<'a> Header<'a> {
|
||||
Parser::parse_msg_id_header_list(self.get_raw_value())
|
||||
}
|
||||
|
||||
pub fn as_unstructured(&self) -> Result<String> {
|
||||
Parser::parse_unstructured_header(self.get_raw_value())
|
||||
}
|
||||
|
||||
pub fn parse_headers<S: Into<SharedString<'a>>>(
|
||||
header_block: S,
|
||||
) -> Result<HeaderParseResult<'a>> {
|
||||
|
||||
@@ -137,4 +137,18 @@ impl<'a> HeaderMap<'a> {
|
||||
Some(header) => Ok(Some(header.as_message_id_list()?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subject(&self) -> Result<Option<String>> {
|
||||
match self.get_first("Subject") {
|
||||
None => Ok(None),
|
||||
Some(header) => Ok(Some(header.as_unstructured()?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn comments(&self) -> Result<Option<String>> {
|
||||
match self.get_first("Comments") {
|
||||
None => Ok(None),
|
||||
Some(header) => Ok(Some(header.as_unstructured()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ unstructured = {
|
||||
// ((fws? ~ vchar)* ~ wsp*) |
|
||||
obs_unstruct
|
||||
}
|
||||
obs_unstruct = { (( "\r"* ~ "\n"* ~ (obs_utext ~ "\r"* ~ "\n"*)+) | fws)+ }
|
||||
obs_utext = { "\u{00}" | obs_no_ws_ctl | vchar }
|
||||
obs_unstruct = { (( "\r"* ~ "\n"* ~ ((encoded_word | obs_utext)~ "\r"* ~ "\n"*)+) | fws)+ }
|
||||
obs_utext = @{ "\u{00}" | obs_no_ws_ctl | vchar }
|
||||
|
||||
obs_no_ws_ctl = { '\u{01}'..'\u{08}' | '\u{0b}'..'\u{0c}' | '\u{0d}'..'\u{1f}' | "\u{7f}" }
|
||||
obs_ctext = { obs_no_ws_ctl }
|
||||
@@ -114,3 +114,4 @@ parse_mailbox = _{ SOI ~ mailbox ~ EOI }
|
||||
parse_address_list = _{ SOI ~ address_list ~ EOI }
|
||||
parse_msg_id = _{ SOI ~ msg_id ~ EOI }
|
||||
parse_msg_id_list = _{ SOI ~ msg_id_list ~ EOI }
|
||||
parse_unstructured = _{ SOI ~ unstructured ~ EOI }
|
||||
|
||||
@@ -143,6 +143,52 @@ impl Parser {
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn parse_unstructured_header(text: &str) -> Result<String> {
|
||||
let mut pairs = Self::parse(Rule::parse_unstructured, text)
|
||||
.map_err(|err| MailParsingError::HeaderParse(format!("{err:#}")))?
|
||||
.next()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
Self::parse_unstructured(pairs.next().unwrap().into_inner())
|
||||
}
|
||||
|
||||
fn parse_unstructured(pairs: Pairs<Rule>) -> Result<String> {
|
||||
let mut result = String::new();
|
||||
let mut fws = false;
|
||||
|
||||
for p in pairs {
|
||||
match p.as_rule() {
|
||||
Rule::encoded_word => {
|
||||
result += &Self::parse_encoded_word(p)?;
|
||||
// Implicit fws at end of encoded word
|
||||
fws = true;
|
||||
}
|
||||
Rule::fws | Rule::cfws => {
|
||||
if !result.is_empty() && !fws {
|
||||
result.push(' ');
|
||||
}
|
||||
fws = true;
|
||||
}
|
||||
Rule::obs_utext => {
|
||||
result += p.as_str();
|
||||
fws = false;
|
||||
}
|
||||
rule => {
|
||||
return Err(MailParsingError::HeaderParse(format!(
|
||||
"Unexpected {rule:?} {p:#?} in parse_unstructured"
|
||||
)))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if fws {
|
||||
result.pop();
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn parse_address(pairs: Pairs<Rule>) -> Result<Address> {
|
||||
for p in pairs {
|
||||
match p.as_rule() {
|
||||
@@ -690,7 +736,7 @@ Some(
|
||||
"From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>\n",
|
||||
"To: =?ISO-8859-1*en-us?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>\n",
|
||||
"CC: =?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>\n",
|
||||
"Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n",
|
||||
"Subject: Hello =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n",
|
||||
" =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=\n",
|
||||
"\n\n"
|
||||
);
|
||||
@@ -762,6 +808,18 @@ Some(
|
||||
],
|
||||
),
|
||||
)
|
||||
"#
|
||||
);
|
||||
let list = match msg.headers().subject() {
|
||||
Err(err) => panic!("Doh.\n{err:#}"),
|
||||
Ok(list) => list,
|
||||
};
|
||||
k9::snapshot!(
|
||||
list,
|
||||
r#"
|
||||
Some(
|
||||
"Hello If you can read this you understand the example",
|
||||
)
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user