From 9c3f44748051ce15607af3470e5d4d29abaecc37 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Sat, 20 Jan 2024 19:23:44 +0100 Subject: [PATCH] Test LIST-STATUS --- src/imap/capability.rs | 5 ++++ tests/behavior.rs | 56 ++++++++++++++++++++++++++++++++++++--- tests/common/fragments.rs | 30 +++++++++++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/imap/capability.rs b/src/imap/capability.rs index 525b3ef..256d820 100644 --- a/src/imap/capability.rs +++ b/src/imap/capability.rs @@ -18,6 +18,10 @@ fn capability_uidplus() -> Capability<'static> { Capability::try_from("UIDPLUS").unwrap() } +fn capability_liststatus() -> Capability<'static> { + Capability::try_from("LIST-STATUS").unwrap() +} + /* fn capability_qresync() -> Capability<'static> { Capability::try_from("QRESYNC").unwrap() @@ -38,6 +42,7 @@ impl Default for ServerCapability { capability_unselect(), capability_condstore(), capability_uidplus(), + capability_liststatus(), //capability_qresync(), ])) } diff --git a/tests/behavior.rs b/tests/behavior.rs index 0447d80..7fdd553 100644 --- a/tests/behavior.rs +++ b/tests/behavior.rs @@ -6,13 +6,14 @@ use crate::common::fragments::*; fn main() { rfc3501_imap4rev1_base(); - rfc3691_imapext_unselect(); - rfc5161_imapext_enable(); rfc6851_imapext_move(); - rfc7888_imapext_literal(); rfc4551_imapext_condstore(); rfc2177_imapext_idle(); - rfc4315_imapext_uidplus(); + rfc5161_imapext_enable(); // 1 + rfc3691_imapext_unselect(); // 2 + rfc7888_imapext_literal(); // 3 + rfc4315_imapext_uidplus(); // 4 + rfc5819_imapext_liststatus(); // 5 println!("โœ… SUCCESS ๐ŸŒŸ๐Ÿš€๐Ÿฅณ๐Ÿ™๐Ÿฅน"); } @@ -307,3 +308,50 @@ fn rfc4315_imapext_uidplus() { }) .expect("test fully run"); } + +/// +/// Example +/// +/// ```text +/// 30 list "" "*" RETURN (STATUS (MESSAGES UNSEEN)) +/// * LIST (\Subscribed) "." INBOX +/// * STATUS INBOX (MESSAGES 2 UNSEEN 1) +/// 30 OK LIST completed +/// ``` +fn rfc5819_imapext_liststatus() { + println!("๐Ÿงช rfc5819_imapext_liststatus"); + common::aerogramme_provider_daemon_dev(|imap_socket, lmtp_socket| { + // Test setup, check capability, add 2 emails, read 1 + connect(imap_socket).context("server says hello")?; + capability(imap_socket, Extension::ListStatus).context("check server capabilities")?; + login(imap_socket, Account::Alice).context("login test")?; + select(imap_socket, Mailbox::Inbox, SelectMod::None).context("select inbox")?; + lmtp_handshake(lmtp_socket).context("handshake lmtp done")?; + lmtp_deliver_email(lmtp_socket, Email::Basic).context("mail delivered successfully")?; + lmtp_deliver_email(lmtp_socket, Email::Multipart).context("mail delivered successfully")?; + noop_exists(imap_socket, 2).context("noop loop must detect a new email")?; + fetch( + imap_socket, + Selection::FirstId, + FetchKind::Rfc822, + FetchMod::None, + ) + .context("read one message")?; + close(imap_socket).context("close inbox")?; + + // Test return status MESSAGES UNSEEN + let ret = list( + imap_socket, + MbxSelect::All, + ListReturn::StatusMessagesUnseen, + )?; + assert!(ret.contains("* STATUS INBOX (MESSAGES 2 UNSEEN 1)")); + + // Test that without RETURN, no status is sent + let ret = list(imap_socket, MbxSelect::All, ListReturn::None)?; + assert!(!ret.contains("* STATUS")); + + Ok(()) + }) + .expect("test fully run"); +} diff --git a/tests/common/fragments.rs b/tests/common/fragments.rs index 147c8f0..a10d4e0 100644 --- a/tests/common/fragments.rs +++ b/tests/common/fragments.rs @@ -38,6 +38,7 @@ pub enum Extension { LiteralPlus, Idle, UidPlus, + ListStatus, } pub enum Enable { @@ -107,6 +108,15 @@ pub enum StatusKind { HighestModSeq, } +pub enum MbxSelect { + All, +} + +pub enum ListReturn { + None, + StatusMessagesUnseen, +} + pub fn capability(imap: &mut TcpStream, ext: Extension) -> Result<()> { imap.write(&b"5 capability\r\n"[..])?; @@ -118,6 +128,7 @@ pub fn capability(imap: &mut TcpStream, ext: Extension) -> Result<()> { Extension::LiteralPlus => Some("LITERAL+"), Extension::Idle => Some("IDLE"), Extension::UidPlus => Some("UIDPLUS"), + Extension::ListStatus => Some("LIST-STATUS"), }; let mut buffer: [u8; 6000] = [0; 6000]; @@ -169,6 +180,25 @@ pub fn create_mailbox(imap: &mut TcpStream, mbx: Mailbox) -> Result<()> { Ok(()) } +pub fn list(imap: &mut TcpStream, select: MbxSelect, mod_return: ListReturn) -> Result { + let mut buffer: [u8; 6000] = [0; 6000]; + + let select_str = match select { + MbxSelect::All => "%", + }; + + let mod_return_str = match mod_return { + ListReturn::None => "", + ListReturn::StatusMessagesUnseen => " RETURN (STATUS (MESSAGES UNSEEN))", + }; + + imap.write(format!("19 LIST \"\" \"{}\"{}\r\n", select_str, mod_return_str).as_bytes())?; + + let read = read_lines(imap, &mut buffer, Some(&b"19 OK"[..]))?; + let srv_msg = std::str::from_utf8(read)?; + Ok(srv_msg.to_string()) +} + pub fn select(imap: &mut TcpStream, mbx: Mailbox, modifier: SelectMod) -> Result { let mut buffer: [u8; 6000] = [0; 6000];