melib/imap: set has_attachments based on BODYSTRUCTURE

fetch BODYSTRUCTURE along with ENVELOPE from server and set
has_attachments based on the MIME structure of the envelope.

Notes: BODYSTRUCTURE returns the MIME structure of the envelope without
the data, so if it includes a multipart/mixed it *should* have
attachments.
ENVELOPE returns basic headers of the message like Sender, Subject, Date
etc.
jmap
Manos Pitsidianakis 2019-11-18 13:00:43 +02:00
parent b2cd4f4b7a
commit fc2d9a684d
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
4 changed files with 27 additions and 2 deletions

View File

@ -179,7 +179,7 @@ impl MailBackend for ImapType {
while exists > 1 {
let mut envelopes = vec![];
exit_on_error!(&tx,
conn.send_command(format!("UID FETCH {}:{} (UID FLAGS ENVELOPE)", std::cmp::max(exists.saturating_sub(20000), 1), exists).as_bytes())
conn.send_command(format!("UID FETCH {}:{} (UID FLAGS ENVELOPE BODYSTRUCTURE)", std::cmp::max(exists.saturating_sub(20000), 1), exists).as_bytes())
conn.read_response(&mut response)
);
debug!(

View File

@ -1,4 +1,5 @@
use super::*;
use crate::email::parser::BytesExt;
use nom::{digit, is_digit, rest, IResult};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
@ -597,8 +598,20 @@ named!(
>> uid_flags: permutation!(preceded!(ws!(tag!("UID ")), map_res!(digit, |s| { usize::from_str(unsafe { std::str::from_utf8_unchecked(s) }) })), opt!(preceded!(ws!(tag!("FLAGS ")), delimited!(tag!("("), byte_flags, tag!(")")))))
>> tag!(" ENVELOPE ")
>> env: ws!(envelope)
>> tag!("BODYSTRUCTURE ")
>> bodystructure: take_until!(")\r\n")
>> tag!(")\r\n")
>> ((uid_flags.0, uid_flags.1, env))
>> ({
let mut env = env;
debug!(unsafe { std::str::from_utf8_unchecked(bodystructure) });
let has_attachments = bodystructure_has_attachments(bodystructure);
env.set_has_attachments(has_attachments);
(uid_flags.0, uid_flags.1, env)
})
)
)
);
pub fn bodystructure_has_attachments(input: &[u8]) -> bool {
input.rfind(b" \"mixed\" ").is_some() || input.rfind(b" \"MIXED\" ").is_some()
}

View File

@ -588,6 +588,11 @@ impl Envelope {
pub fn is_seen(&self) -> bool {
self.flags.contains(Flag::SEEN)
}
pub fn set_has_attachments(&mut self, new_val: bool) {
self.has_attachments = new_val;
}
pub fn has_attachments(&self) -> bool {
self.has_attachments
}

View File

@ -53,6 +53,7 @@ pub trait BytesExt {
fn ltrim(&self) -> &Self;
fn trim(&self) -> &Self;
fn find(&self, needle: &[u8]) -> Option<usize>;
fn rfind(&self, needle: &[u8]) -> Option<usize>;
fn replace(&self, from: &[u8], to: &[u8]) -> Vec<u8>;
}
@ -79,6 +80,12 @@ impl BytesExt for [u8] {
self.windows(needle.len())
.position(|window| window == needle)
}
fn rfind(&self, needle: &[u8]) -> Option<usize> {
self.windows(needle.len())
.rposition(|window| window == needle)
}
fn replace(&self, from: &[u8], to: &[u8]) -> Vec<u8> {
let mut ret = self.to_vec();
if let Some(idx) = self.find(from) {