Browse Source

imap: support LIST-STATUS

async
Manos Pitsidianakis 2 years ago
parent
commit
6121f77853
Signed by: epilys GPG Key ID: 73627C2F690DF710
  1. 37
      melib/src/backends/imap.rs
  2. 6
      melib/src/backends/imap/protocol_parser.rs

37
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<MailboxHash, ImapMailbox> = 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);
}

6
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<MailboxHash>,
pub messages: Option<usize>,
pub recent: Option<usize>,
pub uidnext: Option<usize>,
@ -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,

Loading…
Cancel
Save