IMAP server passing tests.

This commit is contained in:
mdecimus
2023-06-30 19:59:05 +02:00
parent 29f3ca284b
commit 381cedb088
33 changed files with 233 additions and 152 deletions

View File

@@ -67,8 +67,8 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_equals("* LIST (\\NoSelect) \"/\" \"Shared Folders\"")
.assert_equals("* LIST (\\NoSelect) \"/\" \"Shared Folders/Jane Smith\"")
.assert_equals("* LIST () \"/\" \"Shared Folders/Jane Smith/Inbox\"");
.assert_equals("* LIST (\\NoSelect) \"/\" \"Shared Folders/jane.smith@example.com\"")
.assert_equals("* LIST () \"/\" \"Shared Folders/jane.smith@example.com/Inbox\"");
// Grant access to Bill and check ACLs
imap_jane.send("GETACL INBOX").await;
@@ -93,7 +93,7 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
imap_bill
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("Shared Folders/Jane Smith/Inbox");
.assert_contains("Shared Folders/jane.smith@example.com/Inbox");
// Namespace should now return the Shared Folders namespace
imap_john.send("NAMESPACE").await;
@@ -104,17 +104,17 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
// List John's right on Jane's Inbox
imap_john
.send("MYRIGHTS \"Shared Folders/Jane Smith/Inbox\"")
.send("MYRIGHTS \"Shared Folders/jane.smith@example.com/Inbox\"")
.await;
imap_john
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_equals("* MYRIGHTS \"Shared Folders/Jane Smith/Inbox\" rl");
.assert_equals("* MYRIGHTS \"Shared Folders/jane.smith@example.com/Inbox\" rl");
// John should not be able to append messages
assert_append_message(
imap_john,
"Shared Folders/Jane Smith/Inbox",
"Shared Folders/jane.smith@example.com/Inbox",
"From: john\n\ncontents",
ResponseType::No,
)
@@ -125,15 +125,15 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
imap_jane.send("SETACL INBOX jdoe@example.com +i").await;
imap_jane.assert_read(Type::Tagged, ResponseType::Ok).await;
imap_john
.send("MYRIGHTS \"Shared Folders/Jane Smith/Inbox\"")
.send("MYRIGHTS \"Shared Folders/jane.smith@example.com/Inbox\"")
.await;
imap_john
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_equals("* MYRIGHTS \"Shared Folders/Jane Smith/Inbox\" rli");
.assert_equals("* MYRIGHTS \"Shared Folders/jane.smith@example.com/Inbox\" rli");
assert_append_message(
imap_john,
"Shared Folders/Jane Smith/Inbox",
"Shared Folders/jane.smith@example.com/Inbox",
"From: john\n\ncontents",
ResponseType::Ok,
)
@@ -141,7 +141,7 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
// Only Bill should be allowed to delete messages on Jane's Inbox
for imap in [&mut imap_john, &mut imap_bill] {
imap.send("SELECT \"Shared Folders/Jane Smith/Inbox\"")
imap.send("SELECT \"Shared Folders/jane.smith@example.com/Inbox\"")
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
}
@@ -152,7 +152,7 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
imap_bill.assert_read(Type::Tagged, ResponseType::Ok).await;
imap_john.send("UID EXPUNGE").await;
imap_john.assert_read(Type::Tagged, ResponseType::Ok).await;
imap_john.assert_read(Type::Tagged, ResponseType::No).await;
imap_john.send("UID FETCH 1 (PREVIEW)").await;
imap_john
@@ -170,7 +170,7 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
.assert_count("contents", 0);
imap_bill
.send("STATUS \"Shared Folders/Jane Smith/Inbox\" (MESSAGES)")
.send("STATUS \"Shared Folders/jane.smith@example.com/Inbox\" (MESSAGES)")
.await;
imap_bill
.assert_read(Type::Tagged, ResponseType::Ok)
@@ -193,7 +193,7 @@ pub async fn test(mut imap_john: &mut ImapConnection, _imap_check: &mut ImapConn
// Copy from John's Inbox to Jane's Inbox
imap_john
.send(&format!(
"UID COPY {} \"Shared Folders/Jane Smith/Inbox\"",
"UID COPY {} \"Shared Folders/jane.smith@example.com/Inbox\"",
uid
))
.await;

View File

@@ -181,7 +181,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 2")
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 3);
// Fetch changes since SEQ 4
@@ -193,7 +193,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 2")
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 2);
// Fetch changes since SEQ 6
@@ -205,7 +205,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 2")
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 1);
// Fetch changes since SEQ 7
@@ -217,7 +217,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("VANISHED", 1)
.assert_contains("VANISHED (EARLIER) 2")
.assert_contains("VANISHED (EARLIER) 1:2") // .assert_contains("VANISHED (EARLIER) 2")
.assert_count("FETCH (", 0);
// Fetch changes since SEQ 8
@@ -238,6 +238,11 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
.await
.assert_contains("ALL 1:3 MODSEQ");
imap_check.send("NOOP").await;
imap_check
.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("3 EXISTS");
imap_check
.send(&format!("SEARCH MODSEQ {}", modseqs[4]))
.await;
@@ -252,7 +257,7 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
modseqs[5]
))
.await;
imap.assert_read(Type::Tagged, ResponseType::No)
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* 1 FETCH")
.assert_contains("UID 3)")
@@ -286,5 +291,5 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("FETCH (", 3)
.assert_contains("VANISHED (EARLIER) 2");
.assert_contains("VANISHED (EARLIER) 1:2"); // .assert_contains("VANISHED (EARLIER) 2");
}

View File

@@ -26,6 +26,14 @@ use imap_proto::ResponseType;
use super::{AssertResult, ImapConnection, Type};
pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
// Check status
imap.send("LIST \"\" % RETURN (STATUS (UIDNEXT MESSAGES UNSEEN SIZE))")
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("\"INBOX\" (UIDNEXT 11 MESSAGES 10 UNSEEN 10 SIZE 12193)")
.assert_contains("\"All Mail\" (UIDNEXT 11 MESSAGES 10 UNSEEN 10 SIZE 12193)");
// Select INBOX
imap.send("SELECT INBOX").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;

View File

@@ -41,7 +41,7 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("FLAGS (flag_009)")
.assert_contains("FLAGS (Flag_009)")
.assert_contains("RFC822.SIZE 1457")
.assert_contains("UID 10")
.assert_contains("INTERNALDATE")
@@ -104,7 +104,7 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
imap.send("UID FETCH 10 (FLAGS)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("FLAGS (flag_009)");
.assert_contains("FLAGS (Flag_009)");
// Switch to SELECT mode
imap.send("SELECT INBOX").await;
@@ -123,7 +123,7 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
imap.send("UID FETCH 10 (FLAGS)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("FLAGS (flag_009)");
.assert_contains("FLAGS (Flag_009)");
// Fetching a body section should set the \Seen flag
imap.send("UID FETCH 10 (BODY[1.TEXT])").await;

View File

@@ -70,12 +70,17 @@ pub async fn test(mut imap: &mut ImapConnection, mut imap_check: &mut ImapConnec
imap.send("CREATE \"All Mail/Untitled\"").await;
imap.assert_read(Type::Tagged, ResponseType::No).await;
// Special use folders that already exist should not be allowed
imap.send("CREATE \"Second trash\" (USE (\\Trash))").await;
imap.assert_read(Type::Tagged, ResponseType::No).await;
// Enable IMAP4rev2
imap.send("ENABLE IMAP4rev2").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Create missing parent folders
imap.send("CREATE \"/Vegetable/Broccoli\"").await;
imap.send("CREATE \"/Vegetable/Broccoli\" (USE (\\Important))")
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("[MAILBOXID (");
@@ -100,7 +105,7 @@ pub async fn test(mut imap: &mut ImapConnection, mut imap_check: &mut ImapConnec
("Fruit/Apple", ["HasChildren", ""]),
("Fruit/Apple/Green", ["HasNoChildren", ""]),
("Vegetable", ["HasChildren", ""]),
("Vegetable/Broccoli", ["HasNoChildren", ""]),
("Vegetable/Broccoli", ["HasNoChildren", "\\Important"]),
("Tofu", ["HasNoChildren", ""]),
],
true,

View File

@@ -24,10 +24,13 @@
use std::time::Duration;
use imap_proto::ResponseType;
use mail_send::smtp::tls::build_tls_connector;
use rustls::ServerName;
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader, Lines, ReadHalf, WriteHalf},
net::TcpStream,
};
use tokio_rustls::client::TlsStream;
use super::AssertResult;
@@ -153,14 +156,21 @@ pub async fn test() {
}
pub struct SieveConnection {
reader: Lines<BufReader<ReadHalf<TcpStream>>>,
writer: WriteHalf<TcpStream>,
reader: Lines<BufReader<ReadHalf<TlsStream<TcpStream>>>>,
writer: WriteHalf<TlsStream<TcpStream>>,
}
impl SieveConnection {
pub async fn connect() -> Self {
let (reader, writer) =
tokio::io::split(TcpStream::connect("127.0.0.1:4190").await.unwrap());
let (reader, writer) = tokio::io::split(
build_tls_connector(true)
.connect(
ServerName::try_from("imap.example.org").unwrap(),
TcpStream::connect("127.0.0.1:4190").await.unwrap(),
)
.await
.unwrap(),
);
SieveConnection {
reader: BufReader::new(reader).lines(),
writer,

View File

@@ -71,12 +71,13 @@ max-connections = 81920
bind = ["127.0.0.1:9992"]
protocol = "imap"
max-connections = 81920
tls.implict = true
tls.implicit = true
[server.listener.sieve]
bind = ["127.0.0.1:4190"]
protocol = "managesieve"
max-connections = 81920
tls.implicit = true
[server.socket]
reuse-addr = true
@@ -305,6 +306,13 @@ async fn init_imap_tests(delete_if_exists: bool) -> IMAPTest {
#[tokio::test]
pub async fn imap_tests() {
/*tracing::subscriber::set_global_default(
tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::TRACE)
.finish(),
)
.unwrap();*/
// Prepare settings
let delete = true;
let handle = init_imap_tests(delete).await;
@@ -569,7 +577,7 @@ impl AssertResult for Vec<String> {
for line in &self {
if let Some((_, code)) = line.split_once("[COPYUID ") {
if let Some((code, _)) = code.split_once(']') {
if let Some((_, uid)) = code.split_once(' ') {
if let Some((_, uid)) = code.rsplit_once(' ') {
return uid.to_string();
}
}

View File

@@ -134,5 +134,5 @@ pub async fn test(imap: &mut ImapConnection, imap_check: &mut ImapConnection) {
.await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("COUNT 10 ALL 6,4:5,1,3,7:8,10,2,9");
.assert_contains("COUNT 10 ALL 6,4:5,1,10,3,7:8,2,9");
}

View File

@@ -60,6 +60,18 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
.assert_count("FLAGS", 10)
.assert_count("Seen", 0);
// Check that the flags were removed
imap.send("UID FETCH 1:* (Flags)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("\\Seen", 0);
imap.send("STATUS INBOX (UIDNEXT MESSAGES UNSEEN)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("MESSAGES 10")
.assert_contains("UNSEEN 10")
.assert_contains("UIDNEXT 11");
// Store using saved searches
imap.send("SEARCH RETURN (SAVE) FROM nathaniel").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
@@ -72,6 +84,6 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) {
imap.send("UID STORE 1:* -FLAGS (\\Answered)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_count("FLAGS", 10)
.assert_count("FLAGS", 3)
.assert_count("Answered", 0);
}