From 6121f77853b1b9d75acc65b7d4d293326dec271f Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Wed, 22 Jul 2020 11:12:59 +0300 Subject: [PATCH] imap: support LIST-STATUS --- melib/src/backends/imap.rs | 37 ++++++++++++++++++++-- melib/src/backends/imap/protocol_parser.rs | 6 +++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index 1434e34c..3a099fb2 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -60,6 +60,7 @@ pub static SUPPORTED_CAPABILITIES: &[&str] = &[ "IDLE", "LOGIN", "LOGINDISABLED", + "LIST-STATUS", "ENABLE", "IMAP4REV1", "SPECIAL-USE", @@ -914,10 +915,26 @@ impl ImapType { let mut mailboxes: HashMap = Default::default(); let mut res = String::with_capacity(8 * 1024); let mut conn = connection.lock().await; - conn.send_command(b"LIST \"\" \"*\"").await?; - let _ = conn - .read_response(&mut res, RequiredResponses::LIST_REQUIRED) + 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(b"LIST \"\" \"*\" RETURN (STATUS (MESSAGES UNSEEN))") + .await?; + conn.read_response( + &mut res, + RequiredResponses::LIST_REQUIRED | RequiredResponses::STATUS, + ) .await?; + } else { + conn.send_command(b"LIST \"\" \"*\"").await?; + conn.read_response(&mut res, RequiredResponses::LIST_REQUIRED) + .await?; + } debug!("out: {}", &res); let mut lines = res.split_rn(); /* Remove "M__ OK .." line */ @@ -951,6 +968,20 @@ impl ImapType { } else { mailboxes.insert(mailbox.hash, mailbox); } + } else if let Ok(status) = + protocol_parser::status_response(l.as_bytes()).map(|(_, v)| v) + { + if let Some(mailbox_hash) = status.mailbox { + if mailboxes.contains_key(&mailbox_hash) { + let entry = mailboxes.entry(mailbox_hash).or_default(); + if let Some(total) = status.messages { + entry.exists.lock().unwrap().set_not_yet_seen(total); + } + if let Some(total) = status.unseen { + entry.unseen.lock().unwrap().set_not_yet_seen(total); + } + } + } } else { debug!("parse error for {:?}", l); } diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index fe95d54c..91558c03 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -1459,6 +1459,7 @@ pub fn bodystructure_has_attachments(input: &[u8]) -> bool { #[derive(Debug, Default, Clone)] pub struct StatusResponse { + pub mailbox: Option, pub messages: Option, pub recent: Option, pub uidnext: Option, @@ -1468,9 +1469,11 @@ pub struct StatusResponse { // status = "STATUS" SP mailbox SP "(" status-att *(SP status-att) ")" // status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" / "UNSEEN" +//* STATUS INBOX (MESSAGES 1057 UNSEEN 0) pub fn status_response(input: &[u8]) -> IResult<&[u8], StatusResponse> { let (input, _) = tag("* STATUS ")(input)?; - let (input, _) = take_until(" (")(input)?; + let (input, mailbox) = take_until(" (")(input)?; + let mailbox = mailbox_token(mailbox).map(|(_, m)| get_path_hash!(m)).ok(); let (input, _) = tag(" (")(input)?; let (input, result) = permutation(( opt(preceded( @@ -1508,6 +1511,7 @@ pub fn status_response(input: &[u8]) -> IResult<&[u8], StatusResponse> { Ok(( input, StatusResponse { + mailbox, messages: result.0, recent: result.1, uidnext: result.2,