From 33c1bf6558fbabd2663882fe9f8f424967b59078 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Wed, 26 Feb 2020 15:53:46 +0200 Subject: [PATCH] Add consume newlines flag to phrase() --- melib/src/backends/imap/protocol_parser.rs | 4 +-- melib/src/email.rs | 6 ++-- melib/src/email/attachments.rs | 2 +- melib/src/email/parser.rs | 40 +++++++++++++--------- src/components/mail/view.rs | 4 +-- src/plugins/backend.rs | 2 +- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index b585ef5f8..0457b8c6b 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -957,7 +957,7 @@ named!(pub literal<&[u8]>,length_bytes!(delimited!(tag!("{"), map_res!(digit, |s // Return a byte sequence surrounded by "s and decoded if necessary pub fn quoted(input: &[u8]) -> IResult<&[u8], Vec> { if let IResult::Done(r, o) = literal(input) { - return match crate::email::parser::phrase(o) { + return match crate::email::parser::phrase(o, false) { IResult::Done(_, out) => IResult::Done(r, out), e => e, }; @@ -969,7 +969,7 @@ pub fn quoted(input: &[u8]) -> IResult<&[u8], Vec> { let mut i = 1; while i < input.len() { if input[i] == b'\"' && (i == 0 || (input[i - 1] != b'\\')) { - return match crate::email::parser::phrase(&input[1..i]) { + return match crate::email::parser::phrase(&input[1..i], false) { IResult::Done(_, out) => IResult::Done(&input[i + 1..], out), e => e, }; diff --git a/melib/src/email.rs b/melib/src/email.rs index 81762caf3..56ad91585 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -246,7 +246,7 @@ impl Envelope { self.set_from(value); } } else if name.eq_ignore_ascii_case(b"subject") { - let parse_result = parser::phrase(value.trim()); + let parse_result = parser::phrase(value.trim(), false); if parse_result.is_done() { let value = parse_result.to_full_result().unwrap(); self.set_subject(value); @@ -267,7 +267,7 @@ impl Envelope { self.set_in_reply_to(value); in_reply_to = Some(value); } else if name.eq_ignore_ascii_case(b"date") { - let parse_result = parser::phrase(value); + let parse_result = parser::phrase(value, false); if parse_result.is_done() { let value = parse_result.to_full_result().unwrap(); self.set_date(value.as_slice()); @@ -302,7 +302,7 @@ impl Envelope { self.other_headers.insert( String::from_utf8(name.to_vec()) .unwrap_or_else(|err| String::from_utf8_lossy(&err.into_bytes()).into()), - parser::phrase(value) + parser::phrase(value, false) .to_full_result() .map(|value| { String::from_utf8(value).unwrap_or_else(|err| { diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index e8cda961c..395d83398 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -185,7 +185,7 @@ impl AttachmentBuilder { let mut name: Option = None; for (n, v) in params { if n.eq_ignore_ascii_case(b"name") { - if let Ok(v) = crate::email::parser::phrase(v.trim()) + if let Ok(v) = crate::email::parser::phrase(v.trim(), false) .to_full_result() .as_ref() .and_then(|r| Ok(String::from_utf8_lossy(r).to_string())) diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index c8cf707bb..849440cd5 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -455,7 +455,7 @@ fn display_addr(input: &[u8]) -> IResult<&[u8], Address> { } } if !flag { - let (rest, output) = match phrase(input) { + let (rest, output) = match phrase(input, false) { IResult::Done(rest, raw) => (rest, raw), _ => return IResult::Error(error_code!(ErrorKind::Custom(43))), }; @@ -480,7 +480,7 @@ fn display_addr(input: &[u8]) -> IResult<&[u8], Address> { } } if flag { - match phrase(&input[0..end + display_name.length + 3]) { + match phrase(&input[0..end + display_name.length + 3], false) { IResult::Error(e) => IResult::Error(e), IResult::Incomplete(i) => IResult::Incomplete(i), IResult::Done(_, raw) => { @@ -659,7 +659,7 @@ fn eat_comments(input: &[u8]) -> Vec { * * We should use a custom parser here*/ pub fn date(input: &[u8]) -> Result { - let mut parsed_result = phrase(&eat_comments(input)).to_full_result()?; + let mut parsed_result = phrase(&eat_comments(input), false).to_full_result()?; if let Some(pos) = parsed_result.find(b"-0000") { parsed_result[pos] = b'+'; } @@ -873,7 +873,7 @@ named!( ) ); -pub fn phrase(input: &[u8]) -> IResult<&[u8], Vec> { +pub fn phrase(input: &[u8], multiline: /* preserve newlines */ bool) -> IResult<&[u8], Vec> { if input.is_empty() { return IResult::Done(&[], Vec::with_capacity(0)); } @@ -907,16 +907,21 @@ pub fn phrase(input: &[u8]) -> IResult<&[u8], Vec> { let end = end.unwrap_or_else(|| input.len() - ptr) + ptr; let ascii_s = ptr; - let mut ascii_e; + let mut ascii_e = 0; while ptr < end && !(is_whitespace!(input[ptr])) { ptr += 1; } + if !multiline { + ascii_e = ptr; + } while ptr < input.len() && (is_whitespace!(input[ptr])) { ptr += 1; } - ascii_e = ptr; + if multiline { + ascii_e = ptr; + } if ptr >= input.len() { acc.extend( ascii_token(&input[ascii_s..ascii_e]) @@ -1056,33 +1061,33 @@ mod tests { let words = b"=?iso-8859-7?B?W215Y291cnNlcy5udHVhLmdyIC0gyvXs4fTp6t4g6uHpIMri4e306ere?= =?iso-8859-7?B?INb18+nq3l0gzd3hIMHt4erv3+358+c6IMzF0c/TIMHQz9TFy8XTzMHU?= =?iso-8859-7?B?2c0gwiDUzC4gysHNLiDFzsXUwdPH0yAyMDE3LTE4OiDTx8zFydnTxw==?="; - assert_eq!("[mycourses.ntua.gr - Κυματική και Κβαντική Φυσική] Νέα Ανακοίνωση: ΜΕΡΟΣ ΑΠΟΤΕΛΕΣΜΑΤΩΝ Β ΤΜ. ΚΑΝ. ΕΞΕΤΑΣΗΣ 2017-18: ΣΗΜΕΙΩΣΗ" , std::str::from_utf8(&phrase(words.trim()).to_full_result().unwrap()).unwrap()); + assert_eq!("[mycourses.ntua.gr - Κυματική και Κβαντική Φυσική] Νέα Ανακοίνωση: ΜΕΡΟΣ ΑΠΟΤΕΛΕΣΜΑΤΩΝ Β ΤΜ. ΚΑΝ. ΕΞΕΤΑΣΗΣ 2017-18: ΣΗΜΕΙΩΣΗ" , std::str::from_utf8(&phrase(words.trim(), false).to_full_result().unwrap()).unwrap()); let words = b"=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?= =?UTF-8?Q?=CF=84=CE=B7_=CE=B5=CE=BE=CE=B5=CF=84?= =?UTF-8?Q?=CE=B1=CF=83=CF=84=CE=B9=CE=BA=CE=AE?="; assert_eq!( "Πρόσθετη εξεταστική", - std::str::from_utf8(&phrase(words.trim()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.trim(), false).to_full_result().unwrap()).unwrap() ); let words = b"[Advcomparch] =?utf-8?b?zqPPhc68z4DOtc+BzrnPhs6/z4HOrCDPg861IGZs?=\n\t=?utf-8?b?dXNoIM67z4zOs8+JIG1pc3ByZWRpY3Rpb24gzrrOsc+Ezqwgz4TOt869?=\n\t=?utf-8?b?IM61zrrPhM6tzrvOtc+Dzrcgc3RvcmU=?="; assert_eq!( "[Advcomparch] Συμπεριφορά σε flush λόγω misprediction κατά την εκτέλεση store", - std::str::from_utf8(&phrase(words.trim()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.trim(), false).to_full_result().unwrap()).unwrap() ); let words = b"Re: [Advcomparch] =?utf-8?b?zqPPhc68z4DOtc+BzrnPhs6/z4HOrCDPg861IGZs?= =?utf-8?b?dXNoIM67z4zOs8+JIG1pc3ByZWRpY3Rpb24gzrrOsc+Ezqwgz4TOt869?= =?utf-8?b?IM61zrrPhM6tzrvOtc+Dzrcgc3RvcmU=?="; assert_eq!( "Re: [Advcomparch] Συμπεριφορά σε flush λόγω misprediction κατά την εκτέλεση store", - std::str::from_utf8(&phrase(words.trim()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.trim(), false).to_full_result().unwrap()).unwrap() ); let words = b"sdf"; assert_eq!( "sdf", - std::str::from_utf8(&phrase(words).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words, false).to_full_result().unwrap()).unwrap() ); let words = b"=?iso-8859-7?b?U2VnIGZhdWx0IPP05+0g5er03evl8+cg9O/1?= =?iso-8859-7?q?_example_ru_n_=5Fsniper?="; assert_eq!( "Seg fault στην εκτέλεση του example ru n _sniper", - std::str::from_utf8(&phrase(words).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words, false).to_full_result().unwrap()).unwrap() ); let words = b"Re: [Advcomparch] =?iso-8859-7?b?U2VnIGZhdWx0IPP05+0g5er03evl8+cg9O/1?= @@ -1090,28 +1095,31 @@ mod tests { assert_eq!( "Re: [Advcomparch] Seg fault στην εκτέλεση του example ru n _sniper", - std::str::from_utf8(&phrase(words).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words, false).to_full_result().unwrap()).unwrap() ); let words = r#"[internal] =?UTF-8?B?zp3Orc6/z4Igzp/OtM63zrPPjM+CIM6jz4XOs86zz4E=?= =?UTF-8?B?zrHPhs6uz4I=?="#; assert_eq!( "[internal] Νέος Οδηγός Συγγραφής", - std::str::from_utf8(&phrase(words.as_bytes()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.as_bytes(), false).to_full_result().unwrap()) + .unwrap() ); let words = r#"=?UTF-8?Q?Re=3a_Climate_crisis_reality_check_=e2=80=93=c2=a0EcoHust?= =?UTF-8?Q?ler?="#; assert_eq!( "Re: Climate crisis reality check –\u{a0}EcoHustler", - std::str::from_utf8(&phrase(words.as_bytes()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.as_bytes(), false).to_full_result().unwrap()) + .unwrap() ); let words = r#"Re: Climate crisis reality check =?windows-1250?B?lqBFY29IdXN0?= =?windows-1250?B?bGVy?="#; assert_eq!( "Re: Climate crisis reality check –\u{a0}EcoHustler", - std::str::from_utf8(&phrase(words.as_bytes()).to_full_result().unwrap()).unwrap() + std::str::from_utf8(&phrase(words.as_bytes(), false).to_full_result().unwrap()) + .unwrap() ); } diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs index 358f5f944..57aa21823 100644 --- a/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -689,7 +689,7 @@ impl Component for MailView { Ok(headers .into_iter() .map(|(h, v)| { - melib::email::parser::phrase(v) + melib::email::parser::phrase(v, true) .to_full_result() .map(|v| { let mut h = h.to_vec(); @@ -1078,7 +1078,7 @@ impl Component for MailView { let attachment_type = u.mime_type(); let binary = query_default_app(&attachment_type); let mut name_opt = name.as_ref().and_then(|n| { - melib::email::parser::phrase(n.as_bytes()) + melib::email::parser::phrase(n.as_bytes(), false) .to_full_result() .ok() .and_then(|n| String::from_utf8(n).ok()) diff --git a/src/plugins/backend.rs b/src/plugins/backend.rs index 0773b31fd..854d39b4d 100644 --- a/src/plugins/backend.rs +++ b/src/plugins/backend.rs @@ -138,7 +138,7 @@ impl MailBackend for PluginBackend { env.set_to(value); } let parse_result = - melib::email::parser::phrase(subject.as_bytes()); + melib::email::parser::phrase(subject.as_bytes(), false); if parse_result.is_done() { let value = parse_result.to_full_result().unwrap(); env.set_subject(value);