From 1f2c0b4fa786d44abf6059aba5f19625a30d2c9a Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Fri, 3 May 2019 23:51:21 +0300 Subject: [PATCH] melib: multipart/mixed with html messages not displayed as html --- melib/src/mailbox/email/attachments.rs | 49 ++++-- ui/src/components/mail/view.rs | 235 ++++++++++++++----------- 2 files changed, 161 insertions(+), 123 deletions(-) diff --git a/melib/src/mailbox/email/attachments.rs b/melib/src/mailbox/email/attachments.rs index 5dd7c28fc..160f346e5 100644 --- a/melib/src/mailbox/email/attachments.rs +++ b/melib/src/mailbox/email/attachments.rs @@ -299,12 +299,12 @@ impl Attachment { text.extend(decode(self, None)); } ContentType::Multipart { - kind: ref multipart_type, - subattachments: ref sub_att_vec, + ref kind, + ref subattachments, .. - } => match *multipart_type { + } => match kind { MultipartType::Alternative => { - for a in sub_att_vec { + for a in subattachments { if let ContentType::Text { kind: Text::Plain, .. } = a.content_type @@ -314,9 +314,9 @@ impl Attachment { } } } - MultipartType::Mixed | MultipartType::Digest => { - for a in sub_att_vec { - a.get_text_recursive(text); + _ => { + for a in subattachments { + a.get_text_recursive(text) } } }, @@ -369,6 +369,19 @@ impl Attachment { ContentType::Text { kind: Text::Html, .. } => true, + ContentType::Multipart { + ref subattachments, .. + } => subattachments + .iter() + .fold(true, |acc, a| match &a.content_type { + ContentType::Text { + kind: Text::Plain, .. + } => false, + ContentType::Text { + kind: Text::Html, .. + } => acc, + _ => acc, + }), _ => false, } } @@ -401,17 +414,17 @@ fn decode_rfc822(_raw: &[u8]) -> Attachment { type Filter<'a> = Box) -> () + 'a>; fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option>) -> Vec { - let mut ret = match a.content_type { + let ret = match a.content_type { ContentType::Unsupported { .. } => Vec::new(), ContentType::Text { .. } => decode_helper(a, filter), ContentType::MessageRfc822 => decode_rec(&decode_rfc822(&a.raw), None), ContentType::Multipart { - kind: ref multipart_type, - subattachments: ref sub_att_vec, + ref kind, + ref subattachments, .. - } => { - if *multipart_type == MultipartType::Alternative { - for a in sub_att_vec { + } => match kind { + MultipartType::Alternative => { + for a in subattachments { if let ContentType::Text { kind: Text::Plain, .. } = a.content_type @@ -420,18 +433,16 @@ fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option>) -> } } decode_helper(a, filter) - } else { + } + _ => { let mut vec = Vec::new(); - for a in sub_att_vec { + for a in subattachments { vec.extend(decode_rec_helper(a, filter)); } vec } - } + }, }; - if let Some(filter) = filter { - filter(a, &mut ret); - } ret } diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index 714eccf2f..8da8e0545 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -131,6 +131,7 @@ impl MailView { use std::io::Write; use std::process::{Command, Stdio}; let settings = context.accounts[self.coordinates.0].runtime_settings.conf(); + /* FIXME: duplication with view/html.rs */ if let Some(filter_invocation) = settings.html_filter() { let parts = split_command!(filter_invocation); let (cmd, args) = (parts[0], &parts[1..]); @@ -163,6 +164,33 @@ impl MailView { ) .into_bytes(); v.extend(html_filter.wait_with_output().unwrap().stdout); + } else { + if let Ok(mut html_filter) = Command::new("w3m") + .args(&["-I", "utf-8", "-T", "text/html"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + { + html_filter + .stdin + .as_mut() + .unwrap() + .write_all(&v) + .expect("Failed to write to html filter stdin"); + *v = String::from( + "Text piped through `w3m`. Press `v` to open in web browser. \n\n", + ) + .into_bytes(); + v.extend(html_filter.wait_with_output().unwrap().stdout); + } else { + context.replies.push_back(UIEvent::Notification( + Some(format!( + "Failed to find any application to use as html filter" + )), + String::new(), + )); + return; + } } } })), @@ -194,7 +222,7 @@ impl MailView { } else if lidx < 1000 { 385 + (lidx - 99) * 5 } else { - panic!("BUG: Message body with more than 100 urls, fix this"); + panic!("FIXME: Message body with more than 100 urls, fix this"); }; t.insert_str(l.start() + offset, &format!("[{}]", lidx)); } @@ -261,97 +289,97 @@ impl Component for MailView { let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); + let y: usize = { + let accounts = &mut context.accounts; + let mailbox = &mut accounts[self.coordinates.0][self.coordinates.1] + .as_ref() + .unwrap(); + if !mailbox.collection.contains_key(&self.coordinates.2) { + /* The envelope has been renamed or removed, so wait for the appropriate event to + * arrive */ + return; + } + let envelope: &Envelope = &mailbox.collection[&self.coordinates.2]; + + if self.mode == ViewMode::Raw { + clear_area(grid, area); + context.dirty_areas.push_back(area); + get_y(upper_left) - 1 + } else { + let (x, y) = write_string_to_grid( + &format!("Date: {}", envelope.date_as_str()), + grid, + Color::Byte(33), + Color::Default, + area, + true, + ); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x, y) = write_string_to_grid( + &format!("From: {}", envelope.field_from_to_string()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y + 1), bottom_right), + true, + ); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x, y) = write_string_to_grid( + &format!("To: {}", envelope.field_to_to_string()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y + 1), bottom_right), + true, + ); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x, y) = write_string_to_grid( + &format!("Subject: {}", envelope.subject()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y + 1), bottom_right), + true, + ); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x, y) = write_string_to_grid( + &format!("Message-ID: <{}>", envelope.message_id_raw()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y + 1), bottom_right), + true, + ); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + clear_area(grid, (set_y(upper_left, y + 1), set_y(bottom_right, y + 1))); + context + .dirty_areas + .push_back((upper_left, set_y(bottom_right, y + 1))); + y + 1 + } + }; + if self.dirty { - let y: usize = { - let accounts = &mut context.accounts; - let mailbox = &mut accounts[self.coordinates.0][self.coordinates.1] - .as_ref() - .unwrap(); - if !mailbox.collection.contains_key(&self.coordinates.2) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ - return; - } - let envelope: &Envelope = &mailbox.collection[&self.coordinates.2]; - - if self.mode == ViewMode::Raw { - clear_area(grid, area); - context.dirty_areas.push_back(area); - get_y(upper_left) - 1 - } else { - let (x, y) = write_string_to_grid( - &format!("Date: {}", envelope.date_as_str()), - grid, - Color::Byte(33), - Color::Default, - area, - true, - ); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x, y) = write_string_to_grid( - &format!("From: {}", envelope.field_from_to_string()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y + 1), bottom_right), - true, - ); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x, y) = write_string_to_grid( - &format!("To: {}", envelope.field_to_to_string()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y + 1), bottom_right), - true, - ); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x, y) = write_string_to_grid( - &format!("Subject: {}", envelope.subject()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y + 1), bottom_right), - true, - ); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x, y) = write_string_to_grid( - &format!("Message-ID: <{}>", envelope.message_id_raw()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y + 1), bottom_right), - true, - ); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - clear_area(grid, (set_y(upper_left, y + 1), set_y(bottom_right, y + 1))); - context - .dirty_areas - .push_back((upper_left, set_y(bottom_right, y + 1))); - y + 1 - } - }; - let body = { let mailbox_idx = self.coordinates; // coordinates are mailbox idxs let mailbox = &context.accounts[mailbox_idx.0][mailbox_idx.1] @@ -407,21 +435,20 @@ impl Component for MailView { } }; self.dirty = false; - - match self.mode { - ViewMode::Subview => { - if let Some(s) = self.subview.as_mut() { - s.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); - } - } - ViewMode::ContactSelector(ref mut s) => { - clear_area(grid, (set_y(upper_left, y + 1), bottom_right)); + } + match self.mode { + ViewMode::Subview if self.subview.is_some() => { + if let Some(s) = self.subview.as_mut() { s.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); } - _ => { - if let Some(p) = self.pager.as_mut() { - p.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); - } + } + ViewMode::ContactSelector(ref mut s) => { + clear_area(grid, (set_y(upper_left, y + 1), bottom_right)); + s.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); + } + _ => { + if let Some(p) = self.pager.as_mut() { + p.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); } } }