CONDSTORE #71

Merged
quentin merged 21 commits from feat/condstore-try-2 into main 2024-01-15 07:07:07 +00:00
2 changed files with 71 additions and 20 deletions
Showing only changes of commit 22cd0764d8 - Show all commits

View file

@ -34,9 +34,9 @@ fn rfc3501_imap4rev1_base() {
.context("copy message to the archive mailbox")?; .context("copy message to the archive mailbox")?;
append_email(imap_socket, Email::Basic).context("insert email in INBOX")?; append_email(imap_socket, Email::Basic).context("insert email in INBOX")?;
noop_exists(imap_socket, 2).context("noop loop must detect a new email")?; noop_exists(imap_socket, 2).context("noop loop must detect a new email")?;
// SEARCH IS NOT TESTED YET // Missing STORE command
//search(imap_socket).expect("search should return something"); search(imap_socket).expect("search should return something");
add_flags_email(imap_socket, Selection::FirstId, Flag::Deleted) store(imap_socket, Selection::FirstId, Flag::Deleted, StoreAction::AddFlags, StoreMod::None)
.context("should add delete flag to the email")?; .context("should add delete flag to the email")?;
expunge(imap_socket).context("expunge emails")?; expunge(imap_socket).context("expunge emails")?;
rename_mailbox(imap_socket, Mailbox::Archive, Mailbox::Drafts) rename_mailbox(imap_socket, Mailbox::Archive, Mailbox::Drafts)
@ -59,7 +59,7 @@ fn rfc3691_imapext_unselect() {
login(imap_socket, Account::Alice).context("login test")?; login(imap_socket, Account::Alice).context("login test")?;
select(imap_socket, Mailbox::Inbox, SelectMod::None, None).context("select inbox")?; select(imap_socket, Mailbox::Inbox, SelectMod::None, None).context("select inbox")?;
noop_exists(imap_socket, 1).context("noop loop must detect a new email")?; noop_exists(imap_socket, 1).context("noop loop must detect a new email")?;
add_flags_email(imap_socket, Selection::FirstId, Flag::Deleted) store(imap_socket, Selection::FirstId, Flag::Deleted, StoreAction::AddFlags, StoreMod::None)
.context("add delete flags to the email")?; .context("add delete flags to the email")?;
unselect(imap_socket) unselect(imap_socket)
.context("unselect inbox while preserving email with the \\Delete flag")?; .context("unselect inbox while preserving email with the \\Delete flag")?;
@ -133,16 +133,24 @@ fn rfc7888_imapext_literal() {
fn rfc4551_imapext_condstore() { fn rfc4551_imapext_condstore() {
println!("🧪 rfc4551_imapext_condstore"); println!("🧪 rfc4551_imapext_condstore");
common::aerogramme_provider_daemon_dev(|imap_socket, lmtp_socket| { common::aerogramme_provider_daemon_dev(|imap_socket, lmtp_socket| {
lmtp_handshake(lmtp_socket).context("handshake lmtp done")?; // Setup the test
lmtp_deliver_email(lmtp_socket, Email::Basic).context("mail delivered successfully")?;
lmtp_deliver_email(lmtp_socket, Email::Multipart).context("mail delivered successfully")?;
connect(imap_socket).context("server says hello")?; connect(imap_socket).context("server says hello")?;
capability(imap_socket, Extension::Condstore).context("check server capabilities")?; capability(imap_socket, Extension::Condstore).context("check server capabilities")?;
login(imap_socket, Account::Alice).context("login test")?; login(imap_socket, Account::Alice).context("login test")?;
// Check that the condstore modifier works
select(imap_socket, Mailbox::Inbox, SelectMod::Condstore, None).context("select inbox")?; select(imap_socket, Mailbox::Inbox, SelectMod::Condstore, 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")?; noop_exists(imap_socket, 2).context("noop loop must detect a new email")?;
//store(
Ok(()) Ok(())
}) })
.expect("test fully run"); .expect("test fully run");

View file

@ -63,6 +63,7 @@ pub enum Email {
pub enum Selection { pub enum Selection {
FirstId, FirstId,
SecondId, SecondId,
All,
} }
pub enum SelectMod { pub enum SelectMod {
@ -70,6 +71,20 @@ pub enum SelectMod {
Condstore, Condstore,
} }
pub enum StoreAction {
AddFlags,
DelFlags,
SetFlags,
AddFlagsSilent,
DelFlagsSilent,
SetFlagsSilent,
}
pub enum StoreMod {
None,
UnchangedSince(u64),
}
pub fn capability(imap: &mut TcpStream, ext: Extension) -> Result<()> { pub fn capability(imap: &mut TcpStream, ext: Extension) -> Result<()> {
imap.write(&b"5 capability\r\n"[..])?; imap.write(&b"5 capability\r\n"[..])?;
@ -308,18 +323,6 @@ pub fn append_email(imap: &mut TcpStream, content: Email) -> Result<()> {
Ok(()) Ok(())
} }
pub fn add_flags_email(imap: &mut TcpStream, selection: Selection, flag: Flag) -> Result<()> {
let mut buffer: [u8; 1500] = [0; 1500];
assert!(matches!(selection, Selection::FirstId));
assert!(matches!(flag, Flag::Deleted));
imap.write(&b"50 store 1 +FLAGS (\\Deleted)\r\n"[..])?;
let _read = read_lines(imap, &mut buffer, Some(&b"50 OK"[..]))?;
Ok(())
}
#[allow(dead_code)]
/// Not yet implemented
pub fn search(imap: &mut TcpStream) -> Result<()> { pub fn search(imap: &mut TcpStream) -> Result<()> {
imap.write(&b"55 search text \"OoOoO\"\r\n"[..])?; imap.write(&b"55 search text \"OoOoO\"\r\n"[..])?;
let mut buffer: [u8; 1500] = [0; 1500]; let mut buffer: [u8; 1500] = [0; 1500];
@ -327,6 +330,46 @@ pub fn search(imap: &mut TcpStream) -> Result<()> {
Ok(()) Ok(())
} }
pub fn store(
imap: &mut TcpStream,
sel: Selection,
flag: Flag,
action: StoreAction,
modifier: StoreMod
) -> Result<String> {
let mut buffer: [u8; 6000] = [0; 6000];
let seq = match sel {
Selection::FirstId => "1",
Selection::SecondId => "2",
Selection::All => "1:*",
};
let modif = match modifier {
StoreMod::None => "".into(),
StoreMod::UnchangedSince(val) => format!(" (UNCHANGEDSINCE {})", val),
};
let flags_str = match flag {
Flag::Deleted => "(\\Deleted)",
Flag::Important => "(\\Important)",
};
let action_str = match action {
StoreAction::AddFlags => "+FLAGS",
StoreAction::DelFlags => "-FLAGS",
StoreAction::SetFlags => "FLAGS",
StoreAction::AddFlagsSilent => "+FLAGS.SILENT",
StoreAction::DelFlagsSilent => "-FLAGS.SILENT",
StoreAction::SetFlagsSilent => "FLAGS.SILENT",
};
imap.write(format!("57 STORE {}{} {} {}\r\n", seq, modif, action_str, flags_str).as_bytes())?;
let read = read_lines(imap, &mut buffer, Some(&b"57 OK"[..]))?;
let srv_msg = std::str::from_utf8(read)?;
Ok(srv_msg.to_string())
}
pub fn expunge(imap: &mut TcpStream) -> Result<()> { pub fn expunge(imap: &mut TcpStream) -> Result<()> {
imap.write(&b"60 expunge\r\n"[..])?; imap.write(&b"60 expunge\r\n"[..])?;
let mut buffer: [u8; 1500] = [0; 1500]; let mut buffer: [u8; 1500] = [0; 1500];