refactor(imap): make select_folder() accept non-optional folder

If no folder should be selected,
`maybe_close_folder()` can be called directly.
This commit is contained in:
link2xt
2024-06-04 12:27:56 +00:00
parent 0ca1318118
commit 90c30879b1
4 changed files with 36 additions and 42 deletions

View File

@@ -184,7 +184,7 @@ impl Session {
bail!("Attempt to fetch UID 0"); bail!("Attempt to fetch UID 0");
} }
self.select_folder(context, Some(folder)).await?; self.select_folder(context, folder).await?;
// we are connected, and the folder is selected // we are connected, and the folder is selected
info!(context, "Downloading message {}/{} fully...", folder, uid); info!(context, "Downloading message {}/{} fully...", folder, uid);

View File

@@ -838,7 +838,7 @@ impl Session {
// Collect pairs of UID and Message-ID. // Collect pairs of UID and Message-ID.
let mut msgs = BTreeMap::new(); let mut msgs = BTreeMap::new();
self.select_folder(context, Some(folder)).await?; self.select_folder(context, folder).await?;
let mut list = self let mut list = self
.uid_fetch("1:*", RFC724MID_UID) .uid_fetch("1:*", RFC724MID_UID)
@@ -1039,7 +1039,7 @@ impl Session {
// MOVE/DELETE operations. This does not result in multiple SELECT commands // MOVE/DELETE operations. This does not result in multiple SELECT commands
// being sent because `select_folder()` does nothing if the folder is already // being sent because `select_folder()` does nothing if the folder is already
// selected. // selected.
self.select_folder(context, Some(folder)).await?; self.select_folder(context, folder).await?;
// Empty target folder name means messages should be deleted. // Empty target folder name means messages should be deleted.
if target.is_empty() { if target.is_empty() {
@@ -1087,7 +1087,7 @@ impl Session {
.await?; .await?;
for (folder, rowid_set, uid_set) in UidGrouper::from(rows) { for (folder, rowid_set, uid_set) in UidGrouper::from(rows) {
self.select_folder(context, Some(&folder)) self.select_folder(context, &folder)
.await .await
.context("failed to select folder")?; .context("failed to select folder")?;
@@ -1131,7 +1131,7 @@ impl Session {
return Ok(()); return Ok(());
} }
self.select_folder(context, Some(folder)) self.select_folder(context, folder)
.await .await
.context("failed to select folder")?; .context("failed to select folder")?;
@@ -1563,7 +1563,7 @@ impl Session {
) -> Result<Option<&'a str>> { ) -> Result<Option<&'a str>> {
// Close currently selected folder if needed. // Close currently selected folder if needed.
// We are going to select folders using low-level EXAMINE operations below. // We are going to select folders using low-level EXAMINE operations below.
self.select_folder(context, None).await?; self.maybe_close_folder(context).await?;
for folder in folders { for folder in folders {
info!(context, "Looking for MVBOX-folder \"{}\"...", &folder); info!(context, "Looking for MVBOX-folder \"{}\"...", &folder);

View File

@@ -29,7 +29,7 @@ impl Session {
) -> Result<Self> { ) -> Result<Self> {
use futures::future::FutureExt; use futures::future::FutureExt;
self.select_folder(context, Some(folder)).await?; self.select_folder(context, folder).await?;
if self.server_sent_unsolicited_exists(context)? { if self.server_sent_unsolicited_exists(context)? {
return Ok(self); return Ok(self);

View File

@@ -55,15 +55,13 @@ impl ImapSession {
pub(crate) async fn select_folder( pub(crate) async fn select_folder(
&mut self, &mut self,
context: &Context, context: &Context,
folder: Option<&str>, folder: &str,
) -> Result<NewlySelected> { ) -> Result<NewlySelected> {
// if there is a new folder and the new folder is equal to the selected one, there's nothing to do. // 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 there is _no_ new folder, we continue as we might want to expunge below.
if let Some(folder) = folder { if let Some(selected_folder) = &self.selected_folder {
if let Some(selected_folder) = &self.selected_folder { if folder == selected_folder {
if folder == selected_folder { return Ok(NewlySelected::No);
return Ok(NewlySelected::No);
}
} }
} }
@@ -71,34 +69,30 @@ impl ImapSession {
self.maybe_close_folder(context).await?; self.maybe_close_folder(context).await?;
// select new folder // select new folder
if let Some(folder) = folder { let res = if self.can_condstore() {
let res = if self.can_condstore() { self.select_condstore(folder).await
self.select_condstore(folder).await
} else {
self.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) => {
self.selected_folder = Some(folder.to_string());
self.selected_mailbox = Some(mailbox);
Ok(NewlySelected::Yes)
}
Err(async_imap::error::Error::ConnectionLost) => Err(Error::ConnectionLost),
Err(async_imap::error::Error::Validate(_)) => {
Err(Error::BadFolderName(folder.to_string()))
}
Err(async_imap::error::Error::No(response)) => {
Err(Error::NoFolder(folder.to_string(), response))
}
Err(err) => Err(Error::Other(err.to_string())),
}
} else { } else {
Ok(NewlySelected::No) self.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) => {
self.selected_folder = Some(folder.to_string());
self.selected_mailbox = Some(mailbox);
Ok(NewlySelected::Yes)
}
Err(async_imap::error::Error::ConnectionLost) => Err(Error::ConnectionLost),
Err(async_imap::error::Error::Validate(_)) => {
Err(Error::BadFolderName(folder.to_string()))
}
Err(async_imap::error::Error::No(response)) => {
Err(Error::NoFolder(folder.to_string(), response))
}
Err(err) => Err(Error::Other(err.to_string())),
} }
} }
@@ -108,7 +102,7 @@ impl ImapSession {
context: &Context, context: &Context,
folder: &str, folder: &str,
) -> anyhow::Result<NewlySelected> { ) -> anyhow::Result<NewlySelected> {
match self.select_folder(context, Some(folder)).await { match self.select_folder(context, folder).await {
Ok(newly_selected) => Ok(newly_selected), Ok(newly_selected) => Ok(newly_selected),
Err(err) => match err { Err(err) => match err {
Error::NoFolder(..) => { Error::NoFolder(..) => {
@@ -118,7 +112,7 @@ impl ImapSession {
info!(context, "Couldn't select folder, then create() failed: {err:#}."); info!(context, "Couldn't select folder, then create() failed: {err:#}.");
// Need to recheck, could have been created in parallel. // Need to recheck, could have been created in parallel.
} }
let select_res = self.select_folder(context, Some(folder)).await.with_context(|| format!("failed to select newely created folder {folder}")); let select_res = self.select_folder(context, folder).await.with_context(|| format!("failed to select newely created folder {folder}"));
if select_res.is_err() { if select_res.is_err() {
create_res?; create_res?;
} }