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.
This commit is contained in:
Manos Pitsidianakis 2020-11-29 19:21:29 +02:00
parent 76c1c1a213
commit 5f6b4745b8
No known key found for this signature in database
GPG Key ID: 73627C2F690DF710
3 changed files with 66 additions and 19 deletions

View File

@ -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);

View File

@ -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()]),

View File

@ -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(());