melib: multipart/mixed with html messages not displayed as html

embed
Manos Pitsidianakis 2019-05-03 23:51:21 +03:00
parent 8ef470fb15
commit 1f2c0b4fa7
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 161 additions and 123 deletions

View File

@ -299,12 +299,12 @@ impl Attachment {
text.extend(decode(self, None)); text.extend(decode(self, None));
} }
ContentType::Multipart { ContentType::Multipart {
kind: ref multipart_type, ref kind,
subattachments: ref sub_att_vec, ref subattachments,
.. ..
} => match *multipart_type { } => match kind {
MultipartType::Alternative => { MultipartType::Alternative => {
for a in sub_att_vec { for a in subattachments {
if let ContentType::Text { if let ContentType::Text {
kind: Text::Plain, .. kind: Text::Plain, ..
} = a.content_type } = a.content_type
@ -314,9 +314,9 @@ impl Attachment {
} }
} }
} }
MultipartType::Mixed | MultipartType::Digest => { _ => {
for a in sub_att_vec { for a in subattachments {
a.get_text_recursive(text); a.get_text_recursive(text)
} }
} }
}, },
@ -369,6 +369,19 @@ impl Attachment {
ContentType::Text { ContentType::Text {
kind: Text::Html, .. kind: Text::Html, ..
} => true, } => 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, _ => false,
} }
} }
@ -401,17 +414,17 @@ fn decode_rfc822(_raw: &[u8]) -> Attachment {
type Filter<'a> = Box<FnMut(&'a Attachment, &mut Vec<u8>) -> () + 'a>; type Filter<'a> = Box<FnMut(&'a Attachment, &mut Vec<u8>) -> () + 'a>;
fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> { fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) -> Vec<u8> {
let mut ret = match a.content_type { let ret = match a.content_type {
ContentType::Unsupported { .. } => Vec::new(), ContentType::Unsupported { .. } => Vec::new(),
ContentType::Text { .. } => decode_helper(a, filter), ContentType::Text { .. } => decode_helper(a, filter),
ContentType::MessageRfc822 => decode_rec(&decode_rfc822(&a.raw), None), ContentType::MessageRfc822 => decode_rec(&decode_rfc822(&a.raw), None),
ContentType::Multipart { ContentType::Multipart {
kind: ref multipart_type, ref kind,
subattachments: ref sub_att_vec, ref subattachments,
.. ..
} => { } => match kind {
if *multipart_type == MultipartType::Alternative { MultipartType::Alternative => {
for a in sub_att_vec { for a in subattachments {
if let ContentType::Text { if let ContentType::Text {
kind: Text::Plain, .. kind: Text::Plain, ..
} = a.content_type } = a.content_type
@ -420,18 +433,16 @@ fn decode_rec_helper<'a>(a: &'a Attachment, filter: &mut Option<Filter<'a>>) ->
} }
} }
decode_helper(a, filter) decode_helper(a, filter)
} else { }
_ => {
let mut vec = Vec::new(); let mut vec = Vec::new();
for a in sub_att_vec { for a in subattachments {
vec.extend(decode_rec_helper(a, filter)); vec.extend(decode_rec_helper(a, filter));
} }
vec vec
} }
} },
}; };
if let Some(filter) = filter {
filter(a, &mut ret);
}
ret ret
} }

View File

@ -131,6 +131,7 @@ impl MailView {
use std::io::Write; use std::io::Write;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
let settings = context.accounts[self.coordinates.0].runtime_settings.conf(); let settings = context.accounts[self.coordinates.0].runtime_settings.conf();
/* FIXME: duplication with view/html.rs */
if let Some(filter_invocation) = settings.html_filter() { if let Some(filter_invocation) = settings.html_filter() {
let parts = split_command!(filter_invocation); let parts = split_command!(filter_invocation);
let (cmd, args) = (parts[0], &parts[1..]); let (cmd, args) = (parts[0], &parts[1..]);
@ -163,6 +164,33 @@ impl MailView {
) )
.into_bytes(); .into_bytes();
v.extend(html_filter.wait_with_output().unwrap().stdout); 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 { } else if lidx < 1000 {
385 + (lidx - 99) * 5 385 + (lidx - 99) * 5
} else { } 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)); t.insert_str(l.start() + offset, &format!("[{}]", lidx));
} }
@ -261,97 +289,97 @@ impl Component for MailView {
let upper_left = upper_left!(area); let upper_left = upper_left!(area);
let bottom_right = bottom_right!(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 { 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 body = {
let mailbox_idx = self.coordinates; // coordinates are mailbox idxs let mailbox_idx = self.coordinates; // coordinates are mailbox idxs
let mailbox = &context.accounts[mailbox_idx.0][mailbox_idx.1] let mailbox = &context.accounts[mailbox_idx.0][mailbox_idx.1]
@ -407,21 +435,20 @@ impl Component for MailView {
} }
}; };
self.dirty = false; self.dirty = false;
}
match self.mode { match self.mode {
ViewMode::Subview => { ViewMode::Subview if self.subview.is_some() => {
if let Some(s) = self.subview.as_mut() { 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));
s.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); s.draw(grid, (set_y(upper_left, y + 1), bottom_right), context);
} }
_ => { }
if let Some(p) = self.pager.as_mut() { ViewMode::ContactSelector(ref mut s) => {
p.draw(grid, (set_y(upper_left, y + 1), bottom_right), context); 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);
} }
} }
} }