From b798ca4a95ca052f854c332b3231e9f5540c0fad Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 4 Aug 2024 11:03:18 +0300 Subject: [PATCH] imap: return cached response in {select,examine}_mailbox() Signed-off-by: Manos Pitsidianakis --- melib/src/imap/connection.rs | 74 +++++++++++++++++++++++++++--------- melib/src/imap/sync/mod.rs | 15 ++++---- melib/src/imap/untagged.rs | 7 +++- melib/src/imap/watch.rs | 6 +-- 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/melib/src/imap/connection.rs b/melib/src/imap/connection.rs index a4f23b4b..32c85b1b 100644 --- a/melib/src/imap/connection.rs +++ b/melib/src/imap/connection.rs @@ -130,19 +130,38 @@ pub struct ImapStream { pub timeout: Option, } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum MailboxSelection { None, - Select(MailboxHash), - Examine(MailboxHash), + Select { + mailbox_hash: MailboxHash, + latest_response: SelectResponse, + }, + Examine { + mailbox_hash: MailboxHash, + latest_response: SelectResponse, + }, } impl MailboxSelection { pub fn take(&mut self) -> Self { std::mem::replace(self, Self::None) } + + pub fn is(&self, needle: &MailboxHash) -> &Self { + match self { + Self::None => self, + Self::Examine { mailbox_hash, .. } | Self::Select { mailbox_hash, .. } + if mailbox_hash == needle => + { + self + } + _ => &Self::None, + } + } } +#[inline] async fn try_await(cl: impl Future> + Send) -> Result<()> { cl.await } @@ -1067,10 +1086,18 @@ impl ImapConnection { mailbox_hash: MailboxHash, ret: &mut Vec, force: bool, - ) -> Result> { - if !force && self.stream.as_ref()?.current_mailbox == MailboxSelection::Select(mailbox_hash) - { - return Ok(None); + ) -> Result { + if let ( + true, + MailboxSelection::Select { + mailbox_hash: _, + latest_response, + }, + ) = ( + !force, + self.stream.as_ref()?.current_mailbox.is(&mailbox_hash), + ) { + return Ok(latest_response.clone()); } let (imap_path, no_select, permissions) = { let m = &self.uid_store.mailboxes.lock().await[&mailbox_hash]; @@ -1137,7 +1164,10 @@ impl ImapConnection { permissions.rename_messages = !select_response.read_only; permissions.delete_messages = !select_response.read_only; } - self.stream.as_mut()?.current_mailbox = MailboxSelection::Select(mailbox_hash); + self.stream.as_mut()?.current_mailbox = MailboxSelection::Select { + mailbox_hash, + latest_response: select_response.clone(), + }; if self .uid_store .msn_index @@ -1150,7 +1180,7 @@ impl ImapConnection { self.create_uid_msn_cache(mailbox_hash, 1, &select_response) .await?; } - Ok(Some(select_response)) + Ok(select_response) } pub async fn examine_mailbox( @@ -1158,11 +1188,18 @@ impl ImapConnection { mailbox_hash: MailboxHash, ret: &mut Vec, force: bool, - ) -> Result> { - if !force - && self.stream.as_ref()?.current_mailbox == MailboxSelection::Examine(mailbox_hash) - { - return Ok(None); + ) -> Result { + if let ( + true, + MailboxSelection::Examine { + mailbox_hash: _, + latest_response, + }, + ) = ( + !force, + self.stream.as_ref()?.current_mailbox.is(&mailbox_hash), + ) { + return Ok(latest_response.clone()); } let (imap_path, no_select) = { let m = &self.uid_store.mailboxes.lock().await[&mailbox_hash]; @@ -1189,7 +1226,10 @@ impl ImapConnection { let select_response = protocol_parser::select_response(ret).chain_err_summary(|| { format!("Could not parse select response for mailbox {}", imap_path) })?; - self.stream.as_mut()?.current_mailbox = MailboxSelection::Examine(mailbox_hash); + self.stream.as_mut()?.current_mailbox = MailboxSelection::Examine { + mailbox_hash, + latest_response: select_response.clone(), + }; if !self .uid_store .msn_index @@ -1202,12 +1242,12 @@ impl ImapConnection { self.create_uid_msn_cache(mailbox_hash, 1, &select_response) .await?; } - Ok(Some(select_response)) + Ok(select_response) } pub async fn unselect(&mut self) -> Result<()> { match self.stream.as_mut()?.current_mailbox.take() { - MailboxSelection::Examine(_) | MailboxSelection::Select(_) => { + MailboxSelection::Examine { .. } | MailboxSelection::Select { .. } => { let mut response = Vec::with_capacity(8 * 1024); if self .uid_store diff --git a/melib/src/imap/sync/mod.rs b/melib/src/imap/sync/mod.rs index 09d97a07..7cd804d2 100644 --- a/melib/src/imap/sync/mod.rs +++ b/melib/src/imap/sync/mod.rs @@ -122,9 +122,9 @@ impl ImapConnection { let mut new_unseen = BTreeSet::default(); let select_response = self .select_mailbox(mailbox_hash, &mut response, true) - .await? - .unwrap(); + .await?; // 1. check UIDVALIDITY. If fail, discard cache and rebuild + log::trace!("Step 1. check UIDVALIDITY. If fail, discard cache and rebuild"); if select_response.uidvalidity != current_uidvalidity { cache_handle.clear(mailbox_hash, &select_response)?; return Ok(None); @@ -386,8 +386,7 @@ impl ImapConnection { // 1. check UIDVALIDITY. If fail, discard cache and rebuild let select_response = self .select_mailbox(mailbox_hash, &mut response, true) - .await? - .unwrap(); + .await?; if select_response.uidvalidity != cached_uidvalidity { // 1a) Check the mailbox UIDVALIDITY (see section 4.1 for more //details) with SELECT/EXAMINE/STATUS. @@ -674,11 +673,11 @@ impl ImapConnection { * only returns READ-ONLY for both cases) */ let mut select_response = self .select_mailbox(mailbox_hash, &mut response, true) - .await? - .unwrap(); - debug!( + .await?; + log::trace!( "mailbox: {} select_response: {:?}", - mailbox_path, select_response + mailbox_path, + select_response ); { { diff --git a/melib/src/imap/untagged.rs b/melib/src/imap/untagged.rs index 5fec4cc5..487482d4 100644 --- a/melib/src/imap/untagged.rs +++ b/melib/src/imap/untagged.rs @@ -58,7 +58,12 @@ impl ImapConnection { }; } let mailbox_hash = match self.stream.as_ref()?.current_mailbox { - MailboxSelection::Select(h) | MailboxSelection::Examine(h) => h, + MailboxSelection::Select { + mailbox_hash: h, .. + } + | MailboxSelection::Examine { + mailbox_hash: h, .. + } => h, MailboxSelection::None => return Ok(false), }; let mailbox = diff --git a/melib/src/imap/watch.rs b/melib/src/imap/watch.rs index 5ae4df9e..42acaacd 100644 --- a/melib/src/imap/watch.rs +++ b/melib/src/imap/watch.rs @@ -83,8 +83,7 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> { let mut response = Vec::with_capacity(8 * 1024); let select_response = conn .examine_mailbox(mailbox_hash, &mut response, true) - .await? - .unwrap(); + .await?; { let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); @@ -215,8 +214,7 @@ pub async fn examine_updates( let mut response = Vec::with_capacity(8 * 1024); let select_response = conn .examine_mailbox(mailbox_hash, &mut response, true) - .await? - .unwrap(); + .await?; { let mut uidvalidities = uid_store.uidvalidity.lock().unwrap();