summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-28 15:13:02 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-28 15:59:25 +0200
commit883b3e3a4f55936379e1c06b1fa09db270143ee0 (patch)
tree721b4f5a0a9d3ecc0d91184ec97e96e6be234fbd
parent98c1ece28d86a13a84678fb9918174a66f55a637 (diff)
mail/view: show multipart/alternative files properly in attachment list
Show entire multipart/alternative alternatives in attachment list instead of only the displayed one, in order for the user to be able to switch alternatives at will.
-rw-r--r--src/components/mail/view.rs231
1 files changed, 127 insertions, 104 deletions
diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs
index ff2e8cc1..4143d95a 100644
--- a/src/components/mail/view.rs
+++ b/src/components/mail/view.rs
@@ -92,6 +92,11 @@ impl ViewMode {
#[derive(Debug)]
pub enum AttachmentDisplay {
+ Alternative {
+ inner: Attachment,
+ shown_display: usize,
+ display: Vec<AttachmentDisplay>,
+ },
InlineText {
inner: Attachment,
comment: Option<String>,
@@ -436,6 +441,17 @@ impl MailView {
for d in displays {
use AttachmentDisplay::*;
match d {
+ Alternative {
+ inner: _,
+ shown_display,
+ display,
+ } => {
+ acc.push_str(&self.attachment_displays_to_text(
+ &display[*shown_display..(*shown_display + 1)],
+ context,
+ show_comments,
+ ));
+ }
InlineText {
inner: _,
text,
@@ -554,10 +570,26 @@ impl MailView {
let mut paths = Vec::with_capacity(displays.len());
let mut cur_path = vec![];
let mut idx = 0;
- for (i, d) in displays.iter().enumerate() {
+
+ fn append_entry(
+ (idx, (depth, att_display)): (&mut usize, (usize, &AttachmentDisplay)),
+ branches: &mut SmallVec<[bool; 8]>,
+ paths: &mut Vec<Vec<usize>>,
+ cur_path: &mut Vec<usize>,
+ has_sibling: bool,
+ s: &mut String,
+ ) {
use AttachmentDisplay::*;
- cur_path.push(i);
- match d {
+ let mut default_alternative: Option<usize> = None;
+ let (att, sub_att_display_vec) = match att_display {
+ Alternative {
+ inner,
+ shown_display,
+ display,
+ } => {
+ default_alternative = Some(*shown_display);
+ (inner, display.as_slice())
+ }
InlineText {
inner,
text: _,
@@ -565,41 +597,95 @@ impl MailView {
}
| InlineOther { inner }
| Attachment { inner }
- | SignedPending {
+ | EncryptedPending { inner, handle: _ }
+ | EncryptedFailed { inner, error: _ } => (inner, &[][..]),
+ SignedPending {
inner,
- display: _,
+ display,
handle: _,
job_id: _,
}
- | SignedUnverified { inner, display: _ }
+ | SignedUnverified { inner, display }
| SignedFailed {
inner,
- display: _,
+ display,
error: _,
}
| SignedVerified {
inner,
- display: _,
+ display,
description: _,
}
- | EncryptedPending { inner, handle: _ }
- | EncryptedFailed { inner, error: _ }
| EncryptedSuccess {
inner: _,
plaintext: inner,
- plaintext_display: _,
+ plaintext_display: display,
description: _,
- } => {
- attachment_tree(
- (&mut idx, (0, inner)),
- &mut branches,
- &mut paths,
- &mut cur_path,
- i + 1 < displays.len(),
- &mut acc,
- );
+ } => (inner, display.as_slice()),
+ };
+ s.extend(format!("\n[{}]", idx).chars());
+ for &b in branches.iter() {
+ if b {
+ s.push('|');
+ } else {
+ s.push(' ');
+ }
+ s.push(' ');
+ }
+ if depth > 0 {
+ if has_sibling {
+ s.push('|');
+ } else {
+ s.push(' ');
}
+ s.push_str("\\_ ");
+ } else {
+ s.push(' ');
+ s.push(' ');
}
+
+ s.extend(att.to_string().chars());
+ paths.push(cur_path.clone());
+ match att.content_type {
+ ContentType::Multipart { .. } => {
+ let mut iter = (0..sub_att_display_vec.len()).peekable();
+ if has_sibling {
+ branches.push(true);
+ } else {
+ branches.push(false);
+ }
+ while let Some(i) = iter.next() {
+ *idx += 1;
+ cur_path.push(i);
+ append_entry(
+ (idx, (depth + 1, &sub_att_display_vec[i])),
+ branches,
+ paths,
+ cur_path,
+ iter.peek() != None,
+ s,
+ );
+ if Some(i) == default_alternative {
+ s.push_str(" (displayed by default)");
+ }
+ cur_path.pop();
+ }
+ branches.pop();
+ }
+ _ => {}
+ }
+ }
+
+ for (i, d) in displays.iter().enumerate() {
+ cur_path.push(i);
+ append_entry(
+ (&mut idx, (0, d)),
+ &mut branches,
+ &mut paths,
+ &mut cur_path,
+ i + 1 < displays.len(),
+ &mut acc,
+ );
cur_path.pop();
idx += 1;
}
@@ -692,6 +778,11 @@ impl MailView {
{
match kind {
MultipartType::Alternative => {
+ if parts.is_empty() {
+ return;
+ }
+ let mut display = vec![];
+ let mut chosen_attachment_idx = 0;
if let Some(text_attachment_pos) =
parts.iter().position(|a| a.content_type == "text/plain")
{
@@ -708,33 +799,21 @@ impl MailView {
parts.iter().position(|a| a.content_type == "text/html")
{
/* Select html alternative since text/plain is empty */
- rec(
- &parts[text_attachment_pos],
- context,
- coordinates,
- acc,
- active_jobs,
- );
- } else {
- for a in parts {
- rec(a, context, coordinates, acc, active_jobs);
- }
+ chosen_attachment_idx = text_attachment_pos;
}
} else {
/* Select text/plain alternative */
- rec(
- &parts[text_attachment_pos],
- context,
- coordinates,
- acc,
- active_jobs,
- );
- }
- } else {
- for a in parts {
- rec(a, context, coordinates, acc, active_jobs);
+ chosen_attachment_idx = text_attachment_pos;
}
}
+ for a in parts {
+ rec(a, context, coordinates, &mut display, active_jobs);
+ }
+ acc.push(AttachmentDisplay::Alternative {
+ inner: a.clone(),
+ shown_display: chosen_attachment_idx,
+ display,
+ });
}
MultipartType::Signed => {
#[cfg(not(feature = "gpgme"))]
@@ -868,7 +947,12 @@ impl MailView {
let first = path[0];
use AttachmentDisplay::*;
let root_attachment = match &display[first] {
- InlineText {
+ Alternative {
+ inner,
+ shown_display: _,
+ display: _,
+ }
+ | InlineText {
inner,
text: _,
comment: _,
@@ -2441,67 +2525,6 @@ impl Component for MailView {
}
}
-fn attachment_tree(
- (idx, (depth, att)): (&mut usize, (usize, &Attachment)),
- branches: &mut SmallVec<[bool; 8]>,
- paths: &mut Vec<Vec<usize>>,
- cur_path: &mut Vec<usize>,
- has_sibling: bool,
- s: &mut String,
-) {
- s.extend(format!("\n[{}]", idx).chars());
- for &b in branches.iter() {
- if b {
- s.push('|');
- } else {
- s.push(' ');
- }
- s.push(' ');
- }
- if depth > 0 {
- if has_sibling {
- s.push('|');
- } else {
- s.push(' ');
- }
- s.push_str("\\_ ");
- } else {
- s.push(' ');
- s.push(' ');
- }
-
- s.extend(att.to_string().chars());
- paths.push(cur_path.clone());
- match att.content_type {
- ContentType::Multipart {
- parts: ref sub_att_vec,
- ..
- } => {
- let mut iter = (0..sub_att_vec.len()).peekable();
- if has_sibling {
- branches.push(true);
- } else {
- branches.push(false);
- }
- while let Some(i) = iter.next() {
- *idx += 1;
- cur_path.push(i);
- attachment_tree(
- (idx, (depth + 1, &sub_att_vec[i])),
- branches,
- paths,
- cur_path,
- iter.peek() != None,
- s,
- );
- cur_path.pop();
- }
- branches.pop();
- }
- _ => {}
- }
-}
-
fn save_attachment(path: &std::path::Path, bytes: &[u8]) -> Result<()> {
let mut f = std::fs::File::create(path)?;
let mut permissions = f.metadata()?.permissions();