diff --git a/melib/src/backends/imap/connection.rs b/melib/src/backends/imap/connection.rs index 0ba2e205..7379cea0 100644 --- a/melib/src/backends/imap/connection.rs +++ b/melib/src/backends/imap/connection.rs @@ -589,6 +589,14 @@ impl ImapConnection { ret.push_str(&response); return r.into(); } + ImapResponse::No(ref response_code) + if required_responses.intersects(RequiredResponses::NO_REQUIRED) => + { + debug!( + "Received expected NO response: {:?} {:?}", + response_code, response + ); + } ImapResponse::No(ref response_code) => { //FIXME return error debug!("Received NO response: {:?} {:?}", response_code, response); @@ -731,31 +739,45 @@ impl ImapConnection { pub async fn unselect(&mut self) -> Result<()> { match self.stream.as_mut()?.current_mailbox.take() { - MailboxSelection::Examine(mailbox_hash) | - MailboxSelection::Select(mailbox_hash) =>{ - let mut response = String::with_capacity(8 * 1024); - if self - .uid_store - .capabilities - .lock() - .unwrap() - .iter() - .any(|cap| cap.eq_ignore_ascii_case(b"UNSELECT")) - { - self.send_command(b"UNSELECT").await?; - self.read_response(&mut response, RequiredResponses::empty()) - .await?; - } else { - /* `RFC3691 - UNSELECT Command` states: "[..] IMAP4 provides this - * functionality (via a SELECT command with a nonexistent mailbox name or - * reselecting the same mailbox with EXAMINE command)[..] - */ - - self.select_mailbox(mailbox_hash, &mut response, true).await?; - self.examine_mailbox(mailbox_hash, &mut response, true).await?; - } - }, - MailboxSelection::None => {}, + MailboxSelection::Examine(_) | + MailboxSelection::Select(_) => { + let mut response = String::with_capacity(8 * 1024); + if self + .uid_store + .capabilities + .lock() + .unwrap() + .iter() + .any(|cap| cap.eq_ignore_ascii_case(b"UNSELECT")) + { + self.send_command(b"UNSELECT").await?; + self.read_response(&mut response, RequiredResponses::empty()) + .await?; + } else { + /* `RFC3691 - UNSELECT Command` states: "[..] IMAP4 provides this + * functionality (via a SELECT command with a nonexistent mailbox name or + * reselecting the same mailbox with EXAMINE command)[..] + */ + let mut nonexistent = "blurdybloop".to_string(); + { + let mailboxes = self.uid_store.mailboxes.lock().await; + while mailboxes.values().any(|m| m.imap_path() == &nonexistent) { + nonexistent.push('p'); + } + } + self.send_command( + format!( + "SELECT \"{}\"", + nonexistent + ) + .as_bytes(), + ) + .await?; + self.read_response(&mut response, RequiredResponses::NO_REQUIRED) + .await?; + } + } + MailboxSelection::None => {}, } Ok(()) } diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index af7fca19..444c6df0 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -53,6 +53,7 @@ bitflags! { const EXPUNGE = 0b0001_0000_0000_0000; const SEARCH = 0b0010_0000_0000_0000; const FETCH = 0b0100_0000_0000_0000; + const NO_REQUIRED = 0b1000_0000_0000_0000; const CAPABILITY_REQUIRED = Self::CAPABILITY.bits; const LOGOUT_REQUIRED = Self::BYE.bits; const SELECT_REQUIRED = Self::FLAGS.bits | Self::EXISTS.bits | Self::RECENT.bits | Self::UNSEEN.bits | Self::PERMANENTFLAGS.bits | Self::UIDNEXT.bits | Self::UIDVALIDITY.bits;