diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 8c3951c7f..a0fd4d224 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -2712,6 +2712,22 @@ class TestOnlineAccount: # We can't decrypt the message in this chat, so the chat is empty: assert len(private_messages) == 0 + def test_delete_deltachat_folder(self, acfactory): + """Test that DeltaChat folder is recreated if user deletes it manually.""" + ac1 = acfactory.get_online_configuring_account(mvbox=True) + ac2 = acfactory.get_online_configuring_account() + acfactory.wait_configure(ac1) + + ac1.direct_imap.conn.delete_folder("DeltaChat") + assert len(ac1.direct_imap.conn.list_folders(pattern="DeltaChat")) == 0 + acfactory.wait_configure_and_start_io() + + ac2.create_chat(ac1).send_text("hello") + msg = ac1._evtracker.wait_next_incoming_message() + assert msg.text == "hello" + + assert len(ac1.direct_imap.conn.list_folders(pattern="DeltaChat")) == 1 + class TestGroupStressTests: def test_group_many_members_add_leave_remove(self, acfactory, lp): diff --git a/src/imap.rs b/src/imap.rs index 6f7e2a068..63ac42465 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -552,7 +552,7 @@ impl Imap { context: &Context, folder: &str, ) -> Result { - let newly_selected = self.select_folder(context, Some(folder)).await?; + let newly_selected = self.select_or_create_folder(context, folder).await?; let mailbox = &mut self.config.selected_mailbox.as_ref(); let mailbox = @@ -657,9 +657,7 @@ impl Imap { .unwrap_or_default(); let download_limit = context.download_limit().await?; - let new_emails = self - .select_with_uidvalidity(context, folder) - .await?; + let new_emails = self.select_with_uidvalidity(context, folder).await?; if !new_emails && !fetch_existing_msgs { info!(context, "No new emails in folder {}", folder); diff --git a/src/imap/select_folder.rs b/src/imap/select_folder.rs index 81efe1103..9885ab872 100644 --- a/src/imap/select_folder.rs +++ b/src/imap/select_folder.rs @@ -15,6 +15,9 @@ pub enum Error { #[error("IMAP Folder name invalid: {0}")] BadFolderName(String), + #[error("IMAP folder does not exist: {0}")] + NoFolder(String), + #[error("IMAP close/expunge failed")] CloseExpungeFailed(#[from] async_imap::error::Error), @@ -110,6 +113,9 @@ impl Imap { Err(async_imap::error::Error::Validate(_)) => { Err(Error::BadFolderName(folder.to_string())) } + Err(async_imap::error::Error::No(_)) => { + Err(Error::NoFolder(folder.to_string())) + } Err(err) => { self.config.selected_folder = None; self.trigger_reconnect(context).await; @@ -123,6 +129,28 @@ impl Imap { Ok(NewlySelected::No) } } + + /// Selects a folder. Tries to create it once and select again if the folder does not exist. + pub(super) async fn select_or_create_folder( + &mut self, + context: &Context, + folder: &str, + ) -> Result { + match self.select_folder(context, Some(folder)).await { + Ok(newly_selected) => Ok(newly_selected), + Err(err) => match err { + Error::NoFolder(_) => { + if let Some(ref mut session) = self.session { + session.create(folder).await?; + } else { + return Err(Error::NoSession); + } + self.select_folder(context, Some(folder)).await + } + _ => Err(err), + }, + } + } } #[derive(PartialEq, Debug, Copy, Clone, Eq)] pub(super) enum NewlySelected {