melib: add has_attachments property to Envelope

Check subattachments in has_attachments check.

Instead of getting a flattened attachment view of multipart/mixed (eg
[multipart/mixed, text/plain, text/plain]) get only the subattachments
(eg [text/plain, text/plain]). Don't count text-only multipart/mixed as attachments
embed
Manos Pitsidianakis 2019-05-26 18:44:59 +03:00
parent 03317d74ca
commit d0039740b0
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 61 additions and 12 deletions

View File

@ -326,6 +326,7 @@ pub struct Envelope {
hash: EnvelopeHash,
flags: Flag,
has_attachments: bool,
}
impl fmt::Debug for Envelope {
@ -359,6 +360,7 @@ impl Envelope {
thread: ThreadHash::null(),
hash,
has_attachments: false,
flags: Flag::default(),
}
}
@ -392,7 +394,7 @@ impl Envelope {
self.hash
}
pub fn populate_headers(&mut self, bytes: &[u8]) -> Result<()> {
let (headers, _) = match parser::mail(bytes).to_full_result() {
let (headers, body) = match parser::mail(bytes).to_full_result() {
Ok(v) => v,
Err(e) => {
debug!("error in parsing mail\n{:?}\n", e);
@ -459,6 +461,22 @@ impl Envelope {
} else {
self.set_date(value);
}
} else if name.eq_ignore_ascii_case(b"content-type") {
match parser::content_type(value).to_full_result() {
Ok((ct, cst, _))
if ct.eq_ignore_ascii_case(b"multipart")
&& cst.eq_ignore_ascii_case(b"mixed") =>
{
let mut builder = AttachmentBuilder::new(body);
builder.set_content_type(value);
let b = builder.build();
let subs = b.attachments();
self.has_attachments =
subs.iter().fold(false, |acc, sub| acc || !sub.is_text());
}
_ => {}
}
}
}
/*
@ -560,9 +578,9 @@ impl Envelope {
continue;
}
if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
builder.content_transfer_encoding(value);
builder.set_content_transfer_encoding(value);
} else if name.eq_ignore_ascii_case(b"content-type") {
builder.content_type(value);
builder.set_content_type(value);
}
}
builder.build()
@ -755,6 +773,9 @@ impl Envelope {
pub fn is_seen(&self) -> bool {
self.flags.contains(Flag::SEEN)
}
pub fn has_attachments(&self) -> bool {
self.has_attachments
}
}
impl Eq for Envelope {}

View File

@ -69,7 +69,11 @@ impl AttachmentBuilder {
raw: content.to_vec(),
}
}
pub fn content_type(&mut self, value: &[u8]) -> &Self {
pub fn content_type(&mut self) -> &ContentType {
&self.content_type
}
pub fn set_content_type(&mut self, value: &[u8]) -> &Self {
match parser::content_type(value).to_full_result() {
Ok((ct, cst, params)) => {
if ct.eq_ignore_ascii_case(b"multipart") {
@ -86,7 +90,8 @@ impl AttachmentBuilder {
(_boundary.as_ptr() as usize).wrapping_sub(value.as_ptr() as usize);
let boundary = SliceBuild::new(offset, _boundary.len());
let subattachments = Self::subattachments(&self.raw, boundary.get(&value));
assert!(!subattachments.is_empty());
// Invalid mail or wrong assumption?
// assert!(!subattachments.is_empty());
self.content_type = ContentType::Multipart {
boundary,
kind: if cst.eq_ignore_ascii_case(b"mixed") {
@ -154,7 +159,7 @@ impl AttachmentBuilder {
}
self
}
pub fn content_transfer_encoding(&mut self, value: &[u8]) -> &Self {
pub fn set_content_transfer_encoding(&mut self, value: &[u8]) -> &Self {
self.content_transfer_encoding = if value.eq_ignore_ascii_case(b"base64") {
ContentTransferEncoding::Base64
} else if value.eq_ignore_ascii_case(b"7bit") {
@ -231,9 +236,9 @@ impl AttachmentBuilder {
builder.raw = body_slice.get(a).ltrim().into();
for (name, value) in headers {
if name.eq_ignore_ascii_case(b"content-type") {
builder.content_type(value);
builder.set_content_type(value);
} else if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
builder.content_transfer_encoding(value);
builder.set_content_transfer_encoding(value);
}
}
vec.push(builder.build());
@ -371,6 +376,12 @@ impl Attachment {
pub fn content_transfer_encoding(&self) -> &ContentTransferEncoding {
&self.content_transfer_encoding
}
pub fn is_text(&self) -> bool {
match self.content_type {
ContentType::Text { .. } => true,
_ => false,
}
}
pub fn is_html(&self) -> bool {
match self.content_type {
ContentType::Text {

View File

@ -112,9 +112,10 @@ impl MailboxView {
FromString(address_list!((e.from()) as comma_sep_list)),
DateString(MailboxView::format_date(e)),
SubjectString(format!(
"{} ({}){}",
"{} ({}){}{}",
e.subject(),
len,
if e.has_attachments() { " πŸ”—" } else { "" },
if is_snoozed { " πŸ’€" } else { "" }
)),
)
@ -124,8 +125,9 @@ impl MailboxView {
FromString(address_list!((e.from()) as comma_sep_list)),
DateString(MailboxView::format_date(e)),
SubjectString(format!(
"{}{}",
"{}{}{}",
e.subject(),
if e.has_attachments() { " πŸ”—" } else { "" },
if is_snoozed { " πŸ’€" } else { "" }
)),
)
@ -343,8 +345,23 @@ impl MailboxView {
((_x, idx), (widths.2 + _x, idx)),
false,
);
if threads.is_snoozed(root_idx) {
self.content[(x - 1, idx)].set_fg(Color::Red);
match (
threads.is_snoozed(root_idx),
&context.accounts[self.cursor_pos.0]
.get_env(&i)
.has_attachments(),
) {
(true, true) => {
self.content[(x - 1, idx)].set_fg(Color::Red);
self.content[(x - 2, idx)].set_fg(Color::Byte(103));
}
(true, false) => {
self.content[(x - 1, idx)].set_fg(Color::Red);
}
(false, true) => {
self.content[(x - 1, idx)].set_fg(Color::Byte(103));
}
(false, false) => {}
}
self.order.insert(i, idx);