diff --git a/src/dehtml.rs b/src/dehtml.rs index fcab163c8..5a804d1cb 100644 --- a/src/dehtml.rs +++ b/src/dehtml.rs @@ -287,7 +287,7 @@ pub fn dehtml_manually(buf: &str) -> String { #[cfg(test)] mod tests { use super::*; - use crate::simplify::simplify; + use crate::simplify::{simplify, SimplifiedText}; #[test] fn test_dehtml() { @@ -311,7 +311,7 @@ mod tests { ("\nsome text", "some text"), ]; for (input, output) in cases { - assert_eq!(simplify(dehtml(input).unwrap(), true).0, output); + assert_eq!(simplify(dehtml(input).unwrap(), true).text, output); } let none_cases = vec![" ", ""]; for input in none_cases { @@ -387,10 +387,16 @@ mod tests { let input = include_str!("../test-data/message/gmx-quote-body.eml"); let dehtml = dehtml(input).unwrap(); println!("{}", dehtml); - let (msg, forwarded, cut, top_quote, footer) = simplify(dehtml, false); - assert_eq!(msg, "Test"); - assert_eq!(forwarded, false); - assert_eq!(cut, false); + let SimplifiedText { + text, + is_forwarded, + is_cut, + top_quote, + footer, + } = simplify(dehtml, false); + assert_eq!(text, "Test"); + assert_eq!(is_forwarded, false); + assert_eq!(is_cut, false); assert_eq!(top_quote.as_deref(), Some("test")); assert_eq!(footer, None); } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 5d3c8c2b5..e17a54759 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -27,7 +27,7 @@ use crate::location; use crate::message::{self, Viewtype}; use crate::param::{Param, Params}; use crate::peerstate::Peerstate; -use crate::simplify::simplify; +use crate::simplify::{simplify, SimplifiedText}; use crate::stock_str; use crate::sync::SyncItems; @@ -927,22 +927,27 @@ impl MimeMessage { let mut dehtml_failed = false; - let (simplified_txt, is_forwarded, is_cut, top_quote, footer) = - if decoded_data.is_empty() { - ("".to_string(), false, false, None, None) - } else { - let is_html = mime_type == mime::TEXT_HTML; - let out = if is_html { - self.is_mime_modified = true; - dehtml(&decoded_data).unwrap_or_else(|| { - dehtml_failed = true; - decoded_data.clone() - }) - } else { + let SimplifiedText { + text: simplified_txt, + is_forwarded, + is_cut, + top_quote, + footer, + } = if decoded_data.is_empty() { + Default::default() + } else { + let is_html = mime_type == mime::TEXT_HTML; + let out = if is_html { + self.is_mime_modified = true; + dehtml(&decoded_data).unwrap_or_else(|| { + dehtml_failed = true; decoded_data.clone() - }; - simplify(out, self.has_chat_version()) + }) + } else { + decoded_data.clone() }; + simplify(out, self.has_chat_version()) + }; self.is_mime_modified = self.is_mime_modified || ((is_forwarded || is_cut || top_quote.is_some()) diff --git a/src/simplify.rs b/src/simplify.rs index 74d2dcfde..f3f2a555c 100644 --- a/src/simplify.rs +++ b/src/simplify.rs @@ -71,14 +71,27 @@ pub(crate) fn split_lines(buf: &str) -> Vec<&str> { buf.split('\n').collect() } +/// Simplified text and some additional information gained from the input. +#[derive(Debug, Default)] +pub(crate) struct SimplifiedText { + pub text: String, + + /// True if the message is forwarded. + pub is_forwarded: bool, + + /// True if nonstandard footer was removed. + pub is_cut: bool, + + /// Top quote, if any. + pub top_quote: Option, + + /// Footer, if any. + pub footer: Option, +} + /// Simplify message text for chat display. /// Remove quotes, signatures, trailing empty lines etc. -/// Returns `(text, is_forwarded, is_cut, quote, footer)` tuple, -/// returning the simplified text and some additional information gained from the input. -pub fn simplify( - mut input: String, - is_chat_message: bool, -) -> (String, bool, bool, Option, Option) { +pub(crate) fn simplify(mut input: String, is_chat_message: bool) -> SimplifiedText { let mut is_cut = false; input.retain(|c| c != '\r'); @@ -118,7 +131,14 @@ pub fn simplify( render_message(quote_lines, false) }); } - (text, is_forwarded, is_cut, top_quote, footer) + + SimplifiedText { + text, + is_forwarded, + is_cut, + top_quote, + footer, + } } /// Skips "forwarded message" header. @@ -273,17 +293,25 @@ mod tests { #[test] // proptest does not support [[:graphical:][:space:]] regex. fn test_simplify_plain_text_fuzzy(input in "[!-~\t \n]+") { - let (output, _is_forwarded, _, _, _) = simplify(input, true); - assert!(output.split('\n').all(|s| s != "-- ")); + let SimplifiedText { + text, + .. + } = simplify(input, true); + assert!(text.split('\n').all(|s| s != "-- ")); } } #[test] fn test_dont_remove_whole_message() { let input = "\n------\nFailed\n------\n\nUh-oh, this workflow did not succeed!\n\nlots of other text".to_string(); - let (plain, is_forwarded, is_cut, _, _) = simplify(input, false); + let SimplifiedText { + text, + is_forwarded, + is_cut, + .. + } = simplify(input, false); assert_eq!( - plain, + text, "------\nFailed\n------\n\nUh-oh, this workflow did not succeed!\n\nlots of other text" ); assert!(!is_forwarded); @@ -293,8 +321,14 @@ mod tests { #[test] fn test_chat_message() { let input = "Hi! How are you?\n\n---\n\nI am good.\n-- \nSent with my Delta Chat Messenger: https://delta.chat".to_string(); - let (plain, is_forwarded, is_cut, _, footer) = simplify(input, true); - assert_eq!(plain, "Hi! How are you?\n\n---\n\nI am good."); + let SimplifiedText { + text, + is_forwarded, + is_cut, + footer, + .. + } = simplify(input, true); + assert_eq!(text, "Hi! How are you?\n\n---\n\nI am good."); assert!(!is_forwarded); assert!(is_cut); assert_eq!( @@ -306,9 +340,14 @@ mod tests { #[test] fn test_simplify_trim() { let input = "line1\n\r\r\rline2".to_string(); - let (plain, is_forwarded, is_cut, _, _) = simplify(input, false); + let SimplifiedText { + text, + is_forwarded, + is_cut, + .. + } = simplify(input, false); - assert_eq!(plain, "line1\nline2"); + assert_eq!(text, "line1\nline2"); assert!(!is_forwarded); assert!(!is_cut); } @@ -316,9 +355,15 @@ mod tests { #[test] fn test_simplify_forwarded_message() { let input = "---------- Forwarded message ----------\r\nFrom: test@example.com\r\n\r\nForwarded message\r\n-- \r\nSignature goes here".to_string(); - let (plain, is_forwarded, is_cut, _, footer) = simplify(input, false); + let SimplifiedText { + text, + is_forwarded, + is_cut, + footer, + .. + } = simplify(input, false); - assert_eq!(plain, "Forwarded message"); + assert_eq!(text, "Forwarded message"); assert!(is_forwarded); assert!(is_cut); assert_eq!(footer.unwrap(), "Signature goes here"); @@ -363,59 +408,104 @@ mod tests { #[test] fn test_remove_message_footer() { let input = "text\n--\nno footer".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input, true); - assert_eq!(plain, "text\n--\nno footer"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input, true); + assert_eq!(text, "text\n--\nno footer"); assert_eq!(footer, None); assert!(!is_cut); let input = "text\n\n--\n\nno footer".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input, true); - assert_eq!(plain, "text\n\n--\n\nno footer"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input, true); + assert_eq!(text, "text\n\n--\n\nno footer"); assert_eq!(footer, None); assert!(!is_cut); let input = "text\n\n-- no footer\n\n".to_string(); - let (plain, _, _, _, footer) = simplify(input, true); - assert_eq!(plain, "text\n\n-- no footer"); + let SimplifiedText { text, footer, .. } = simplify(input, true); + assert_eq!(text, "text\n\n-- no footer"); assert_eq!(footer, None); let input = "text\n\n--\nno footer\n-- \nfooter".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input, true); - assert_eq!(plain, "text\n\n--\nno footer"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input, true); + assert_eq!(text, "text\n\n--\nno footer"); assert!(is_cut); assert_eq!(footer.unwrap(), "footer"); let input = "text\n\n--\ntreated as footer when unescaped".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input.clone(), true); - assert_eq!(plain, "text"); // see remove_message_footer() for some explanations + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input.clone(), true); + assert_eq!(text, "text"); // see remove_message_footer() for some explanations assert!(is_cut); assert_eq!(footer.unwrap(), "treated as footer when unescaped"); let escaped = escape_message_footer_marks(&input); - let (plain, _, is_cut, _, footer) = simplify(escaped, true); - assert_eq!(plain, "text\n\n--\ntreated as footer when unescaped"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(escaped, true); + assert_eq!(text, "text\n\n--\ntreated as footer when unescaped"); assert!(!is_cut); assert_eq!(footer, None); // Nonstandard footer sent by let input = "Message text here\n---Desde mi teléfono con SIJÚ\n\nQuote here".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input.clone(), false); - assert_eq!(plain, "Message text here [...]"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input.clone(), false); + assert_eq!(text, "Message text here [...]"); assert!(is_cut); assert_eq!(footer, None); - let (plain, _, is_cut, _, footer) = simplify(input.clone(), true); - assert_eq!(plain, input); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input.clone(), true); + assert_eq!(text, input); assert!(!is_cut); assert_eq!(footer, None); let input = "--\ntreated as footer when unescaped".to_string(); - let (plain, _, is_cut, _, footer) = simplify(input.clone(), true); - assert_eq!(plain, ""); // see remove_message_footer() for some explanations + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(input.clone(), true); + assert_eq!(text, ""); // see remove_message_footer() for some explanations assert!(is_cut); assert_eq!(footer.unwrap(), "treated as footer when unescaped"); let escaped = escape_message_footer_marks(&input); - let (plain, _, is_cut, _, footer) = simplify(escaped, true); - assert_eq!(plain, "--\ntreated as footer when unescaped"); + let SimplifiedText { + text, + is_cut, + footer, + .. + } = simplify(escaped, true); + assert_eq!(text, "--\ntreated as footer when unescaped"); assert!(!is_cut); assert_eq!(footer, None); }