CONDSTORE #71
2 changed files with 71 additions and 20 deletions
|
@ -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");
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in a new issue