From 7463248da88523d80783a5e43ef7fcf071fde3f4 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Fri, 15 Nov 2019 20:28:03 +0200 Subject: [PATCH] melib: change BackendOp::set_flag() signature --- melib/src/backends.rs | 4 +-- melib/src/backends/imap/operations.rs | 32 +++++++++++----------- melib/src/backends/imap/protocol_parser.rs | 16 ++++++++++- melib/src/backends/maildir.rs | 5 ++-- melib/src/backends/mbox.rs | 2 +- melib/src/collection.rs | 15 ++-------- melib/src/email.rs | 17 ++++++++---- ui/src/components/mail/view.rs | 5 +++- ui/src/conf/accounts.rs | 2 +- 9 files changed, 56 insertions(+), 42 deletions(-) diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 96c74672..9835a736 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -250,7 +250,7 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { fn fetch_headers(&mut self) -> Result<&[u8]>; fn fetch_body(&mut self) -> Result<&[u8]>; 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. @@ -284,7 +284,7 @@ impl BackendOp for ReadOnlyOp { fn fetch_flags(&self) -> Flag { 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.")) } } diff --git a/melib/src/backends/imap/operations.rs b/melib/src/backends/imap/operations.rs index 953d246b..fe32b243 100644 --- a/melib/src/backends/imap/operations.rs +++ b/melib/src/backends/imap/operations.rs @@ -230,6 +230,9 @@ impl BackendOp for ImapOp { } else { let mut response = String::with_capacity(8 * 1024); 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()) .unwrap(); conn.read_response(&mut response).unwrap(); @@ -238,7 +241,7 @@ impl BackendOp for ImapOp { response.len(), response.lines().collect::>().len() ); - match protocol_parser::uid_fetch_response(response.as_bytes()) + match protocol_parser::uid_fetch_flags_response(response.as_bytes()) .to_full_result() .map_err(MeliError::from) { @@ -248,12 +251,10 @@ impl BackendOp for ImapOp { /* TODO: Trigger cache invalidation here. */ 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); - if flags.is_some() { - cache.flags = flags; - self.flags.set(flags); - } + cache.flags = Some(flags); + self.flags.set(Some(flags)); } Err(e) => Err(e).unwrap(), } @@ -261,7 +262,10 @@ impl BackendOp for ImapOp { 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 conn = self.connection.lock().unwrap(); conn.send_command(format!("SELECT \"{}\"", &self.folder_path,).as_bytes())?; @@ -271,33 +275,29 @@ impl BackendOp for ImapOp { format!( "UID STORE {} FLAGS.SILENT ({})", self.uid, - flags_to_imap_list!(flag) + flags_to_imap_list!(flags) ) .as_bytes(), )?; conn.read_response(&mut 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() .map_err(MeliError::from) { Ok(v) => { if v.len() == 1 { debug!("responses len is {}", v.len()); - let (uid, flags, _) = v[0]; + let (uid, flags) = v[0]; assert_eq!(uid, self.uid); - if flags.is_some() { - self.flags.set(flags); - } + self.flags.set(Some(flags)); } } 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 cache = bytes_cache.entry(self.uid).or_default(); - cache.flags = Some(flag); + cache.flags = Some(flags); Ok(()) } } diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index 57ba4ff3..6d806aa9 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -70,7 +70,7 @@ named!( named!( my_flags, do_parse!( - flags: separated_nonempty_list!(tag!(" "), preceded!(tag!("\\"), is_not!(")"))) + flags: separated_list!(tag!(" "), preceded!(tag!("\\"), is_not!(")"))) >> ({ let mut ret = Flag::default(); for f in flags { @@ -122,6 +122,20 @@ named!( ) ); +named!( + pub uid_fetch_flags_response>, + 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 { ($flags:ident) => {{ let mut ret = String::new(); diff --git a/melib/src/backends/maildir.rs b/melib/src/backends/maildir.rs index acf3e5a8..a208efc9 100644 --- a/melib/src/backends/maildir.rs +++ b/melib/src/backends/maildir.rs @@ -132,7 +132,7 @@ impl<'a> BackendOp for MaildirOp { 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 = path.to_str().unwrap(); // Assume UTF-8 validity let idx: usize = path @@ -141,7 +141,8 @@ impl<'a> BackendOp for MaildirOp { + 3; let mut new_name: String = path[..idx].to_string(); let mut flags = self.fetch_flags(); - flags.toggle(f); + flags.set(f, value); + if !(flags & Flag::DRAFT).is_empty() { new_name.push('D'); } diff --git a/melib/src/backends/mbox.rs b/melib/src/backends/mbox.rs index 9cbe3f96..208e9ed2 100644 --- a/melib/src/backends/mbox.rs +++ b/melib/src/backends/mbox.rs @@ -250,7 +250,7 @@ impl BackendOp for MboxOp { 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(()) } } diff --git a/melib/src/collection.rs b/melib/src/collection.rs index b5e79d73..39a67261 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -159,21 +159,12 @@ impl Collection { &mut self, mut new_envelopes: FnvHashMap, folder_hash: FolderHash, - mailbox: &mut Mailbox, sent_folder: Option, ) -> Option> { self.sent_folder = sent_folder; - new_envelopes.retain(|&h, e| { - if self.message_ids.contains_key(e.message_id().raw()) { - /* 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 - } - }); + for (h, e) in new_envelopes.iter() { + self.message_ids.insert(e.message_id().raw().to_vec(), *h); + } let &mut Collection { ref mut threads, diff --git a/melib/src/email.rs b/melib/src/email.rs index b6043f8f..20f83aeb 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -556,10 +556,14 @@ impl Envelope { pub fn set_datetime(&mut self, new_val: chrono::DateTime) { self.timestamp = new_val.timestamp() as UnixTimestamp; } - pub fn set_flag(&mut self, f: Flag, mut operation: Box) -> Result<()> { - self.flags.toggle(f); - operation.set_flag(self, f)?; - Ok(()) + pub fn set_flag( + &mut self, + f: Flag, + value: bool, + mut operation: Box, + ) -> Result<()> { + self.flags.set(f, value); + operation.set_flag(self, f, value) } pub fn set_flags(&mut self, f: Flag) { self.flags = f; @@ -569,14 +573,14 @@ impl Envelope { } pub fn set_seen(&mut self, operation: Box) -> Result<()> { if !self.flags.contains(Flag::SEEN) { - self.set_flag(Flag::SEEN, operation) + self.set_flag(Flag::SEEN, true, operation) } else { Ok(()) } } pub fn set_unseen(&mut self, operation: Box) -> Result<()> { if self.flags.contains(Flag::SEEN) { - self.set_flag(Flag::SEEN, operation) + self.set_flag(Flag::SEEN, false, operation) } else { Ok(()) } @@ -595,6 +599,7 @@ impl Ord for Envelope { self.datetime().cmp(&other.datetime()) } } + impl PartialOrd for Envelope { fn partial_cmp(&self, other: &Envelope) -> Option { Some(self.cmp(other)) diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index 97b79739..45d11a1a 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -1292,7 +1292,10 @@ impl Component for MailView { 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("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')); } diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index af859536..4709b2f8 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -738,7 +738,7 @@ impl Account { m.merge(&envelopes); if let Some(updated_folders) = self.collection - .merge(envelopes, folder_hash, m, self.sent_folder) + .merge(envelopes, folder_hash, self.sent_folder) { for f in updated_folders { self.notify_fn.notify(f);