melib: change BackendOp::set_flag() signature

jmap
Manos Pitsidianakis 2019-11-15 20:28:03 +02:00
parent ede512200b
commit 7463248da8
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
9 changed files with 56 additions and 42 deletions

View File

@ -250,7 +250,7 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
fn fetch_headers(&mut self) -> Result<&[u8]>; fn fetch_headers(&mut self) -> Result<&[u8]>;
fn fetch_body(&mut self) -> Result<&[u8]>; fn fetch_body(&mut self) -> Result<&[u8]>;
fn fetch_flags(&self) -> Flag; fn fetch_flags(&self) -> Flag;
fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag) -> Result<()>; fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag, value: bool) -> Result<()>;
} }
/// Wrapper for BackendOps that are to be set read-only. /// Wrapper for BackendOps that are to be set read-only.
@ -284,7 +284,7 @@ impl BackendOp for ReadOnlyOp {
fn fetch_flags(&self) -> Flag { fn fetch_flags(&self) -> Flag {
self.op.fetch_flags() self.op.fetch_flags()
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {
Err(MeliError::new("read-only set.")) Err(MeliError::new("read-only set."))
} }
} }

View File

@ -230,6 +230,9 @@ impl BackendOp for ImapOp {
} else { } else {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("EXAMINE \"{}\"", &self.folder_path,).as_bytes())
.unwrap();
conn.read_response(&mut response).unwrap();
conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes()) conn.send_command(format!("UID FETCH {} FLAGS", self.uid).as_bytes())
.unwrap(); .unwrap();
conn.read_response(&mut response).unwrap(); conn.read_response(&mut response).unwrap();
@ -238,7 +241,7 @@ impl BackendOp for ImapOp {
response.len(), response.len(),
response.lines().collect::<Vec<&str>>().len() response.lines().collect::<Vec<&str>>().len()
); );
match protocol_parser::uid_fetch_response(response.as_bytes()) match protocol_parser::uid_fetch_flags_response(response.as_bytes())
.to_full_result() .to_full_result()
.map_err(MeliError::from) .map_err(MeliError::from)
{ {
@ -248,12 +251,10 @@ impl BackendOp for ImapOp {
/* TODO: Trigger cache invalidation here. */ /* TODO: Trigger cache invalidation here. */
panic!(format!("message with UID {} was not found", self.uid)); panic!(format!("message with UID {} was not found", self.uid));
} }
let (uid, flags, _) = v[0]; let (uid, flags) = v[0];
assert_eq!(uid, self.uid); assert_eq!(uid, self.uid);
if flags.is_some() { cache.flags = Some(flags);
cache.flags = flags; self.flags.set(Some(flags));
self.flags.set(flags);
}
} }
Err(e) => Err(e).unwrap(), Err(e) => Err(e).unwrap(),
} }
@ -261,7 +262,10 @@ impl BackendOp for ImapOp {
self.flags.get().unwrap() self.flags.get().unwrap()
} }
fn set_flag(&mut self, _envelope: &mut Envelope, flag: Flag) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
let mut flags = self.fetch_flags();
flags.set(f, value);
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock().unwrap(); let mut conn = self.connection.lock().unwrap();
conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?; conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?;
@ -271,33 +275,29 @@ impl BackendOp for ImapOp {
format!( format!(
"UID STORE {} FLAGS.SILENT ({})", "UID STORE {} FLAGS.SILENT ({})",
self.uid, self.uid,
flags_to_imap_list!(flag) flags_to_imap_list!(flags)
) )
.as_bytes(), .as_bytes(),
)?; )?;
conn.read_response(&mut response)?; conn.read_response(&mut response)?;
debug!(&response); debug!(&response);
match protocol_parser::uid_fetch_response(response.as_bytes()) match protocol_parser::uid_fetch_flags_response(response.as_bytes())
.to_full_result() .to_full_result()
.map_err(MeliError::from) .map_err(MeliError::from)
{ {
Ok(v) => { Ok(v) => {
if v.len() == 1 { if v.len() == 1 {
debug!("responses len is {}", v.len()); debug!("responses len is {}", v.len());
let (uid, flags, _) = v[0]; let (uid, flags) = v[0];
assert_eq!(uid, self.uid); assert_eq!(uid, self.uid);
if flags.is_some() { self.flags.set(Some(flags));
self.flags.set(flags);
}
} }
} }
Err(e) => Err(e).unwrap(), Err(e) => Err(e).unwrap(),
} }
conn.send_command(format!("EXAMINE \"{}\"", &self.folder_path,).as_bytes())?;
conn.read_response(&mut response)?;
let mut bytes_cache = self.uid_store.byte_cache.lock()?; let mut bytes_cache = self.uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(self.uid).or_default(); let cache = bytes_cache.entry(self.uid).or_default();
cache.flags = Some(flag); cache.flags = Some(flags);
Ok(()) Ok(())
} }
} }

View File

@ -70,7 +70,7 @@ named!(
named!( named!(
my_flags<Flag>, my_flags<Flag>,
do_parse!( do_parse!(
flags: separated_nonempty_list!(tag!(" "), preceded!(tag!("\\"), is_not!(")"))) flags: separated_list!(tag!(" "), preceded!(tag!("\\"), is_not!(")")))
>> ({ >> ({
let mut ret = Flag::default(); let mut ret = Flag::default();
for f in flags { for f in flags {
@ -122,6 +122,20 @@ named!(
) )
); );
named!(
pub uid_fetch_flags_response<Vec<(usize, Flag)>>,
many0!(
do_parse!(
tag!("* ")
>> take_while!(call!(is_digit))
>> tag!(" FETCH (")
>> uid_flags: permutation!(preceded!(ws!(tag!("UID ")), map_res!(digit, |s| { usize::from_str(unsafe { std::str::from_utf8_unchecked(s) }) })), preceded!(ws!(tag!("FLAGS ")), delimited!(tag!("("), byte_flags, tag!(")"))))
>> tag!(")\r\n")
>> ((uid_flags.0, uid_flags.1))
)
)
);
macro_rules! flags_to_imap_list { macro_rules! flags_to_imap_list {
($flags:ident) => {{ ($flags:ident) => {{
let mut ret = String::new(); let mut ret = String::new();

View File

@ -132,7 +132,7 @@ impl<'a> BackendOp for MaildirOp {
flag flag
} }
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag) -> Result<()> { fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
let path = self.path(); let path = self.path();
let path = path.to_str().unwrap(); // Assume UTF-8 validity let path = path.to_str().unwrap(); // Assume UTF-8 validity
let idx: usize = path let idx: usize = path
@ -141,7 +141,8 @@ impl<'a> BackendOp for MaildirOp {
+ 3; + 3;
let mut new_name: String = path[..idx].to_string(); let mut new_name: String = path[..idx].to_string();
let mut flags = self.fetch_flags(); let mut flags = self.fetch_flags();
flags.toggle(f); flags.set(f, value);
if !(flags & Flag::DRAFT).is_empty() { if !(flags & Flag::DRAFT).is_empty() {
new_name.push('D'); new_name.push('D');
} }

View File

@ -250,7 +250,7 @@ impl BackendOp for MboxOp {
flags flags
} }
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag) -> Result<()> { fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {
Ok(()) Ok(())
} }
} }

View File

@ -159,21 +159,12 @@ impl Collection {
&mut self, &mut self,
mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>, mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>,
folder_hash: FolderHash, folder_hash: FolderHash,
mailbox: &mut Mailbox,
sent_folder: Option<FolderHash>, sent_folder: Option<FolderHash>,
) -> Option<StackVec<FolderHash>> { ) -> Option<StackVec<FolderHash>> {
self.sent_folder = sent_folder; self.sent_folder = sent_folder;
new_envelopes.retain(|&h, e| { for (h, e) in new_envelopes.iter() {
if self.message_ids.contains_key(e.message_id().raw()) { self.message_ids.insert(e.message_id().raw().to_vec(), *h);
/* skip duplicates until a better way to handle them is found. */ }
//FIXME
mailbox.remove(h);
false
} else {
self.message_ids.insert(e.message_id().raw().to_vec(), h);
true
}
});
let &mut Collection { let &mut Collection {
ref mut threads, ref mut threads,

View File

@ -556,10 +556,14 @@ impl Envelope {
pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) { pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) {
self.timestamp = new_val.timestamp() as UnixTimestamp; self.timestamp = new_val.timestamp() as UnixTimestamp;
} }
pub fn set_flag(&mut self, f: Flag, mut operation: Box<dyn BackendOp>) -> Result<()> { pub fn set_flag(
self.flags.toggle(f); &mut self,
operation.set_flag(self, f)?; f: Flag,
Ok(()) value: bool,
mut operation: Box<dyn BackendOp>,
) -> Result<()> {
self.flags.set(f, value);
operation.set_flag(self, f, value)
} }
pub fn set_flags(&mut self, f: Flag) { pub fn set_flags(&mut self, f: Flag) {
self.flags = f; self.flags = f;
@ -569,14 +573,14 @@ impl Envelope {
} }
pub fn set_seen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> { pub fn set_seen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
if !self.flags.contains(Flag::SEEN) { if !self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, operation) self.set_flag(Flag::SEEN, true, operation)
} else { } else {
Ok(()) Ok(())
} }
} }
pub fn set_unseen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> { pub fn set_unseen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
if self.flags.contains(Flag::SEEN) { if self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, operation) self.set_flag(Flag::SEEN, false, operation)
} else { } else {
Ok(()) Ok(())
} }
@ -595,6 +599,7 @@ impl Ord for Envelope {
self.datetime().cmp(&other.datetime()) self.datetime().cmp(&other.datetime())
} }
} }
impl PartialOrd for Envelope { impl PartialOrd for Envelope {
fn partial_cmp(&self, other: &Envelope) -> Option<Ordering> { fn partial_cmp(&self, other: &Envelope) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))

View File

@ -1292,7 +1292,10 @@ impl Component for MailView {
let mut our_map = FnvHashMap::with_capacity_and_hasher(4, Default::default()); let mut our_map = FnvHashMap::with_capacity_and_hasher(4, Default::default());
our_map.insert("add_addresses_to_contacts", Key::Char('c')); our_map.insert("add_addresses_to_contacts", Key::Char('c'));
our_map.insert("view_raw_source", Key::Alt('r')); our_map.insert("view_raw_source", Key::Alt('r'));
if self.mode.is_attachment() || self.mode == ViewMode::Subview || self.mode == ViewMode::Raw if self.mode.is_attachment()
|| self.mode == ViewMode::Subview
|| self.mode == ViewMode::Raw
|| self.mode == ViewMode::Url
{ {
our_map.insert("return_to_normal_view", Key::Char('r')); our_map.insert("return_to_normal_view", Key::Char('r'));
} }

View File

@ -738,7 +738,7 @@ impl Account {
m.merge(&envelopes); m.merge(&envelopes);
if let Some(updated_folders) = if let Some(updated_folders) =
self.collection self.collection
.merge(envelopes, folder_hash, m, self.sent_folder) .merge(envelopes, folder_hash, self.sent_folder)
{ {
for f in updated_folders { for f in updated_folders {
self.notify_fn.notify(f); self.notify_fn.notify(f);