diff --git a/melib/src/backends/imap/cache/sync.rs b/melib/src/backends/imap/cache/sync.rs index b91cee088..a38385c43 100644 --- a/melib/src/backends/imap/cache/sync.rs +++ b/melib/src/backends/imap/cache/sync.rs @@ -658,12 +658,11 @@ impl ImapConnection { pub async fn init_mailbox(&mut self, mailbox_hash: MailboxHash) -> Result { let mut response = Vec::with_capacity(8 * 1024); - let (mailbox_path, mailbox_exists, unseen, permissions) = { + let (mailbox_path, mailbox_exists, permissions) = { let f = &self.uid_store.mailboxes.lock().await[&mailbox_hash]; ( f.imap_path().to_string(), f.exists.clone(), - f.unseen.clone(), f.permissions.clone(), ) }; @@ -705,11 +704,6 @@ impl ImapConnection { mailbox_exists_lck.clear(); mailbox_exists_lck.set_not_yet_seen(select_response.exists); } - { - let mut unseen_lck = unseen.lock().unwrap(); - unseen_lck.clear(); - unseen_lck.set_not_yet_seen(select_response.unseen); - } } if select_response.exists == 0 { return Ok(select_response); diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index bf5d4a81c..32a7a50cc 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -977,7 +977,7 @@ pub struct SelectResponse { pub exists: ImapNum, pub recent: ImapNum, pub flags: (Flag, Vec), - pub unseen: MessageSequenceNumber, + pub first_unseen: MessageSequenceNumber, pub uidvalidity: UIDVALIDITY, pub uidnext: UID, pub permanentflags: (Flag, Vec), @@ -1024,7 +1024,7 @@ pub fn select_response(input: &[u8]) -> Result { } else if l.starts_with(b"* FLAGS (") { ret.flags = flags(&l[b"* FLAGS (".len()..l.len() - b")".len()]).map(|(_, v)| v)?; } else if l.starts_with(b"* OK [UNSEEN ") { - ret.unseen = MessageSequenceNumber::from_str(&String::from_utf8_lossy( + ret.first_unseen = MessageSequenceNumber::from_str(&String::from_utf8_lossy( &l[b"* OK [UNSEEN ".len()..l.find(b"]").unwrap()], ))?; } else if l.starts_with(b"* OK [UIDVALIDITY ") { @@ -1082,7 +1082,7 @@ fn test_select_response() { Flag::REPLIED | Flag::SEEN | Flag::TRASHED | Flag::DRAFT | Flag::FLAGGED, Vec::new() ), - unseen: 16, + first_unseen: 16, uidvalidity: 1554422056, uidnext: 50, permanentflags: ( @@ -1105,7 +1105,7 @@ fn test_select_response() { Flag::REPLIED | Flag::SEEN | Flag::TRASHED | Flag::DRAFT | Flag::FLAGGED, Vec::new() ), - unseen: 12, + first_unseen: 12, uidvalidity: 3857529045, uidnext: 4392, permanentflags: (Flag::SEEN | Flag::TRASHED, vec!["*".into()]), @@ -1127,7 +1127,7 @@ fn test_select_response() { Flag::REPLIED | Flag::SEEN | Flag::TRASHED | Flag::DRAFT | Flag::FLAGGED, Vec::new() ), - unseen: 12, + first_unseen: 12, uidvalidity: 3857529045, uidnext: 4392, permanentflags: (Flag::SEEN | Flag::TRASHED, vec!["*".into()]), diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index fe7cd87c1..0ca8de92a 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -246,13 +246,66 @@ pub async fn examine_updates( } if mailbox.is_cold() { /* Mailbox hasn't been loaded yet */ - if let Ok(mut exists_lck) = mailbox.exists.lock() { - exists_lck.clear(); - exists_lck.set_not_yet_seen(select_response.exists); - } - if let Ok(mut unseen_lck) = mailbox.unseen.lock() { - unseen_lck.clear(); - unseen_lck.set_not_yet_seen(select_response.unseen); + let has_list_status: bool = conn + .uid_store + .capabilities + .lock() + .unwrap() + .iter() + .any(|cap| cap.eq_ignore_ascii_case(b"LIST-STATUS")); + if has_list_status { + conn.send_command( + format!( + "LIST \"{}\" \"\" RETURN (STATUS (MESSAGES UNSEEN))", + mailbox.imap_path() + ) + .as_bytes(), + ) + .await?; + conn.read_response( + &mut response, + RequiredResponses::LIST_REQUIRED | RequiredResponses::STATUS, + ) + .await?; + debug!( + "list return status out: {}", + String::from_utf8_lossy(&response) + ); + let mut lines = response.split_rn(); + /* Remove "M__ OK .." line */ + lines.next_back(); + for l in lines { + if let Ok(status) = protocol_parser::status_response(&l).map(|(_, v)| v) { + if Some(mailbox_hash) == status.mailbox { + if let Some(total) = status.messages { + if let Ok(mut exists_lck) = mailbox.exists.lock() { + exists_lck.clear(); + exists_lck.set_not_yet_seen(total); + } + } + if let Some(total) = status.unseen { + if let Ok(mut unseen_lck) = mailbox.unseen.lock() { + unseen_lck.clear(); + unseen_lck.set_not_yet_seen(total); + } + } + break; + } + } + } + } else { + conn.send_command(b"SEARCH UNSEEN").await?; + conn.read_response(&mut response, RequiredResponses::SEARCH) + .await?; + let unseen_count = protocol_parser::search_results(&response)?.1.len(); + if let Ok(mut exists_lck) = mailbox.exists.lock() { + exists_lck.clear(); + exists_lck.set_not_yet_seen(select_response.exists); + } + if let Ok(mut unseen_lck) = mailbox.unseen.lock() { + unseen_lck.clear(); + unseen_lck.set_not_yet_seen(unseen_count); + } } mailbox.set_warm(true); return Ok(());