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
parent
b2cd4f4b7a
commit
fc2d9a684d
|
@ -179,7 +179,7 @@ impl MailBackend for ImapType {
|
||||||
while exists > 1 {
|
while exists > 1 {
|
||||||
let mut envelopes = vec![];
|
let mut envelopes = vec![];
|
||||||
exit_on_error!(&tx,
|
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)
|
conn.read_response(&mut response)
|
||||||
);
|
);
|
||||||
debug!(
|
debug!(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::email::parser::BytesExt;
|
||||||
use nom::{digit, is_digit, rest, IResult};
|
use nom::{digit, is_digit, rest, IResult};
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::{Hash, Hasher};
|
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!(")")))))
|
>> 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 ")
|
>> tag!(" ENVELOPE ")
|
||||||
>> env: ws!(envelope)
|
>> env: ws!(envelope)
|
||||||
|
>> tag!("BODYSTRUCTURE ")
|
||||||
|
>> bodystructure: take_until!(")\r\n")
|
||||||
>> tag!(")\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()
|
||||||
|
}
|
||||||
|
|
|
@ -588,6 +588,11 @@ impl Envelope {
|
||||||
pub fn is_seen(&self) -> bool {
|
pub fn is_seen(&self) -> bool {
|
||||||
self.flags.contains(Flag::SEEN)
|
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 {
|
pub fn has_attachments(&self) -> bool {
|
||||||
self.has_attachments
|
self.has_attachments
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ pub trait BytesExt {
|
||||||
fn ltrim(&self) -> &Self;
|
fn ltrim(&self) -> &Self;
|
||||||
fn trim(&self) -> &Self;
|
fn trim(&self) -> &Self;
|
||||||
fn find(&self, needle: &[u8]) -> Option<usize>;
|
fn find(&self, needle: &[u8]) -> Option<usize>;
|
||||||
|
fn rfind(&self, needle: &[u8]) -> Option<usize>;
|
||||||
fn replace(&self, from: &[u8], to: &[u8]) -> Vec<u8>;
|
fn replace(&self, from: &[u8], to: &[u8]) -> Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +80,12 @@ impl BytesExt for [u8] {
|
||||||
self.windows(needle.len())
|
self.windows(needle.len())
|
||||||
.position(|window| window == needle)
|
.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> {
|
fn replace(&self, from: &[u8], to: &[u8]) -> Vec<u8> {
|
||||||
let mut ret = self.to_vec();
|
let mut ret = self.to_vec();
|
||||||
if let Some(idx) = self.find(from) {
|
if let Some(idx) = self.find(from) {
|
||||||
|
|
Loading…
Reference in New Issue