From 8694278369a312a1c4e605adedb7ed631c02c95a Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 2 Jan 2020 00:07:19 +0200 Subject: [PATCH] ui: add auto_choose_multipart_alternative Choose text/html by default if text/plain is empty in multipart/alternative attachments This happens in some newsletters I've come upon --- melib/src/conf.rs | 29 ++++++++++++++-------------- melib/src/email/attachment_types.rs | 8 ++++++++ ui/src/components/mail/view.rs | 30 +++++++++++++++++++++++++++++ ui/src/conf.rs | 6 +++++- ui/src/conf/notifications.rs | 3 +-- ui/src/conf/pager.rs | 8 ++++++++ 6 files changed, 67 insertions(+), 17 deletions(-) diff --git a/melib/src/conf.rs b/melib/src/conf.rs index 1b7fed64..985e38eb 100644 --- a/melib/src/conf.rs +++ b/melib/src/conf.rs @@ -78,9 +78,9 @@ pub struct FolderConf { pub alias: Option, #[serde(default = "true_val")] pub autoload: bool, - #[serde(deserialize_with = "toggleflag_de")] + #[serde(default)] pub subscribe: ToggleFlag, - #[serde(deserialize_with = "toggleflag_de")] + #[serde(default)] pub ignore: ToggleFlag, #[serde(default = "none")] pub usage: Option, @@ -158,18 +158,6 @@ impl ToggleFlag { } } -pub fn toggleflag_de<'de, D>(deserializer: D) -> std::result::Result -where - D: Deserializer<'de>, -{ - let s = ::deserialize(deserializer); - Ok(match s { - Err(_) => ToggleFlag::Unset, - Ok(true) => ToggleFlag::True, - Ok(false) => ToggleFlag::False, - }) -} - impl Serialize for ToggleFlag { fn serialize(&self, serializer: S) -> std::result::Result where @@ -182,3 +170,16 @@ impl Serialize for ToggleFlag { } } } + +impl<'de> Deserialize<'de> for ToggleFlag { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let s = ::deserialize(deserializer); + Ok(match s? { + true => ToggleFlag::True, + false => ToggleFlag::False, + }) + } +} diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs index ac05affb..2a6e74d9 100644 --- a/melib/src/email/attachment_types.rs +++ b/melib/src/email/attachment_types.rs @@ -249,6 +249,14 @@ impl ContentType { _ => None, } } + + pub fn parts(&self) -> Option<&Vec> { + if let ContentType::Multipart { ref parts, .. } = self { + Some(parts) + } else { + None + } + } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index a6328eae..7fcf78b4 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -21,6 +21,7 @@ use super::*; use melib::list_management; +use melib::parser::BytesExt; use std::convert::TryFrom; use std::process::{Command, Stdio}; @@ -605,6 +606,35 @@ impl Component for MailView { self.subview = Some(Box::new(HtmlView::new(&body, context))); self.mode = ViewMode::Subview; } + ViewMode::Normal + if context + .settings + .pager + .auto_choose_multipart_alternative + .is_true() + && match body.content_type { + ContentType::Multipart { + kind: MultipartType::Alternative, + ref parts, + .. + } => parts.iter().all(|p| { + p.is_html() || (p.is_text() && p.body().trim().is_empty()) + }), + _ => false, + } => + { + self.subview = Some(Box::new(HtmlView::new( + &body + .content_type + .parts() + .unwrap() + .into_iter() + .find(|a| a.is_html()) + .unwrap_or(&body), + context, + ))); + self.mode = ViewMode::Subview; + } ViewMode::Subview | ViewMode::ContactSelector(_) => {} ViewMode::Raw => { let text = { diff --git a/ui/src/conf.rs b/ui/src/conf.rs index ab15904b..550ab3d8 100644 --- a/ui/src/conf.rs +++ b/ui/src/conf.rs @@ -46,7 +46,7 @@ use self::terminal::TerminalSettings; use crate::pager::PagerSettings; use crate::plugins::Plugin; use melib::backends::SpecialUsageMailbox; -use melib::conf::{toggleflag_de, AccountSettings, FolderConf, ToggleFlag}; +use melib::conf::{AccountSettings, FolderConf, ToggleFlag}; use melib::error::*; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -454,6 +454,10 @@ mod default_vals { pub(in crate::conf) fn internal_value_false() -> super::ToggleFlag { super::ToggleFlag::InternalVal(false) } + + pub(in crate::conf) fn internal_value_true() -> super::ToggleFlag { + super::ToggleFlag::InternalVal(true) + } } mod deserializers { diff --git a/ui/src/conf/notifications.rs b/ui/src/conf/notifications.rs index beeac081..028d4fa9 100644 --- a/ui/src/conf/notifications.rs +++ b/ui/src/conf/notifications.rs @@ -20,7 +20,6 @@ */ use super::default_vals::internal_value_false; -use super::toggleflag_de; fn none() -> Option { None @@ -38,7 +37,7 @@ pub struct NotificationsSettings { /// Default: None #[serde(default = "none")] pub xbiff_file_path: Option, - #[serde(deserialize_with = "toggleflag_de", default = "internal_value_false")] + #[serde(default = "internal_value_false")] pub play_sound: super::ToggleFlag, #[serde(default = "none")] pub sound_file: Option, diff --git a/ui/src/conf/pager.rs b/ui/src/conf/pager.rs index 39dde1c6..40c11d12 100644 --- a/ui/src/conf/pager.rs +++ b/ui/src/conf/pager.rs @@ -21,6 +21,8 @@ use super::default_vals::*; use super::deserializers::*; +use melib::ToggleFlag; + /// Settings for the pager function. #[derive(Debug, Deserialize, Clone, Default, Serialize)] pub struct PagerSettings { @@ -68,6 +70,12 @@ pub struct PagerSettings { /// Default: 80 #[serde(default = "eighty_val")] pub minimum_width: usize, + + /// Choose `text/html` alternative if `text/plain` is empty in `multipart/alternative` + /// attachments. + /// Default: true + #[serde(default = "internal_value_true")] + pub auto_choose_multipart_alternative: ToggleFlag, } fn eighty_val() -> usize {