summaryrefslogtreecommitdiffstats
path: root/melib
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-29 19:21:29 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-11-30 02:20:08 +0200
commit5f6b4745b8d266a8144202918c780f788a53816a (patch)
treec2395ed65f725ec85a2bd97352129fcf4a7f81ce /melib
parent76c1c1a213fb35d882a82694da74b55b69d31c03 (diff)
melib/imap: don't use UNSEEN select response for unseen count
UNSEEN field in SELECT/EXAMINE response is meant to be the message sequence number of the first unseen message, not the count of unseen messages.
Diffstat (limited to 'melib')
-rw-r--r--melib/src/backends/imap/cache/sync.rs8
-rw-r--r--melib/src/backends/imap/protocol_parser.rs10
-rw-r--r--melib/src/backends/imap/watch.rs67
3 files changed, 66 insertions, 19 deletions
diff --git a/melib/src/backends/imap/cache/sync.rs b/melib/src/backends/imap/cache/sync.rs
index b91cee08..a38385c4 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<SelectResponse> {
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 bf5d4a81..32a7a50c 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<String>),
- pub unseen: MessageSequenceNumber,
+ pub first_unseen: MessageSequenceNumber,
pub uidvalidity: UIDVALIDITY,
pub uidnext: UID,
pub permanentflags: (Flag, Vec<String>),
@@ -1024,7 +1024,7 @@ pub fn select_response(input: &[u8]) -> Result<SelectResponse> {
} 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 fe7cd87c..0ca8de92 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(());