diff --git a/src/imap.rs b/src/imap/mod.rs similarity index 93% rename from src/imap.rs rename to src/imap/mod.rs index 12bef048c..20badb9c2 100644 --- a/src/imap.rs +++ b/src/imap/mod.rs @@ -28,6 +28,8 @@ use crate::param::Params; use crate::stock::StockMessage; use crate::wrapmime; +pub mod select_folder; + const DC_IMAP_SEEN: usize = 0x0001; type Result = std::result::Result; @@ -460,92 +462,6 @@ impl Imap { }) } - /// select a folder, possibly update uid_validity and, if needed, - /// expunge the folder to remove delete-marked messages. - async fn select_folder>( - &self, - context: &Context, - folder: Option, - ) -> Result<()> { - if self.session.lock().await.is_none() { - let mut cfg = self.config.write().await; - cfg.selected_folder = None; - cfg.selected_folder_needs_expunge = false; - return Err(Error::NoSession); - } - - // if there is a new folder and the new folder is equal to the selected one, there's nothing to do. - // if there is _no_ new folder, we continue as we might want to expunge below. - if let Some(ref folder) = folder { - if let Some(ref selected_folder) = self.config.read().await.selected_folder { - if folder.as_ref() == selected_folder { - return Ok(()); - } - } - } - - // deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then) - let needs_expunge = { self.config.read().await.selected_folder_needs_expunge }; - if needs_expunge { - if let Some(ref folder) = self.config.read().await.selected_folder { - info!(context, "Expunge messages in \"{}\".", folder); - - // A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see - // https://tools.ietf.org/html/rfc3501#section-6.4.2 - if let Some(ref mut session) = &mut *self.session.lock().await { - match session.close().await { - Ok(_) => { - info!(context, "close/expunge succeeded"); - } - Err(err) => { - return Err(Error::CloseExpungeFailed(err)); - } - } - } else { - return Err(Error::NoSession); - } - } - self.config.write().await.selected_folder_needs_expunge = false; - } - - // select new folder - if let Some(ref folder) = folder { - if let Some(ref mut session) = &mut *self.session.lock().await { - let res = session.select(folder).await; - - // https://tools.ietf.org/html/rfc3501#section-6.3.1 - // says that if the server reports select failure we are in - // authenticated (not-select) state. - - match res { - Ok(mailbox) => { - let mut config = self.config.write().await; - config.selected_folder = Some(folder.as_ref().to_string()); - config.selected_mailbox = Some(mailbox); - Ok(()) - } - Err(async_imap::error::Error::ConnectionLost) => { - self.trigger_reconnect(); - self.config.write().await.selected_folder = None; - Err(Error::ConnectionLost) - } - Err(async_imap::error::Error::Validate(_)) => { - Err(Error::BadFolderName(folder.as_ref().to_string())) - } - Err(err) => { - self.config.write().await.selected_folder = None; - self.trigger_reconnect(); - Err(Error::Other(err.to_string())) - } - } - } else { - Err(Error::NoSession) - } - } else { - Ok(()) - } - } - fn get_config_last_seen_uid>(&self, context: &Context, folder: S) -> (u32, u32) { let key = format!("imap.mailbox.{}", folder.as_ref()); if let Some(entry) = context.sql.get_raw_config(context, &key) { diff --git a/src/imap/select_folder.rs b/src/imap/select_folder.rs new file mode 100644 index 000000000..46d13fb5e --- /dev/null +++ b/src/imap/select_folder.rs @@ -0,0 +1,90 @@ +use super::{Result, Error, Imap}; +use crate::context::Context; + +impl Imap { + /// select a folder, possibly update uid_validity and, if needed, + /// expunge the folder to remove delete-marked messages. + pub(super) async fn select_folder>( + &self, + context: &Context, + folder: Option, + ) -> Result<()> { + if self.session.lock().await.is_none() { + let mut cfg = self.config.write().await; + cfg.selected_folder = None; + cfg.selected_folder_needs_expunge = false; + return Err(Error::NoSession); + } + + // if there is a new folder and the new folder is equal to the selected one, there's nothing to do. + // if there is _no_ new folder, we continue as we might want to expunge below. + if let Some(ref folder) = folder { + if let Some(ref selected_folder) = self.config.read().await.selected_folder { + if folder.as_ref() == selected_folder { + return Ok(()); + } + } + } + + // deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then) + let needs_expunge = { self.config.read().await.selected_folder_needs_expunge }; + if needs_expunge { + if let Some(ref folder) = self.config.read().await.selected_folder { + info!(context, "Expunge messages in \"{}\".", folder); + + // A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see + // https://tools.ietf.org/html/rfc3501#section-6.4.2 + if let Some(ref mut session) = &mut *self.session.lock().await { + match session.close().await { + Ok(_) => { + info!(context, "close/expunge succeeded"); + } + Err(err) => { + return Err(Error::CloseExpungeFailed(err)); + } + } + } else { + return Err(Error::NoSession); + } + } + self.config.write().await.selected_folder_needs_expunge = false; + } + + // select new folder + if let Some(ref folder) = folder { + if let Some(ref mut session) = &mut *self.session.lock().await { + let res = session.select(folder).await; + + // https://tools.ietf.org/html/rfc3501#section-6.3.1 + // says that if the server reports select failure we are in + // authenticated (not-select) state. + + match res { + Ok(mailbox) => { + let mut config = self.config.write().await; + config.selected_folder = Some(folder.as_ref().to_string()); + config.selected_mailbox = Some(mailbox); + Ok(()) + } + Err(async_imap::error::Error::ConnectionLost) => { + self.trigger_reconnect(); + self.config.write().await.selected_folder = None; + Err(Error::ConnectionLost) + } + Err(async_imap::error::Error::Validate(_)) => { + Err(Error::BadFolderName(folder.as_ref().to_string())) + } + Err(err) => { + self.config.write().await.selected_folder = None; + self.trigger_reconnect(); + Err(Error::Other(err.to_string())) + } + } + } else { + Err(Error::NoSession) + } + } else { + Ok(()) + } + } +}