Files
inbuxa-server/tests/src/imap/uidonly.rs
T
jcoffey-dev 7dae9b29fd Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
2026-09-18 10:21:56 -07:00

145 lines
5.3 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::{AssertResult, ImapConnection, Type};
use crate::utils::server::TestServer;
use imap_proto::ResponseType;
pub async fn test(test: &TestServer) {
println!("Running UIDONLY tests...");
// UIDONLY is a one-way switch, so it runs on a connection of its own
let account = test.account("[email protected]");
let mut imap = ImapConnection::connect(b"_u ").await;
imap.assert_read(Type::Untagged, ResponseType::Ok).await;
imap.authenticate(account.name(), account.secret()).await;
// The capability is only advertised once authenticated
imap.send("CAPABILITY").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("UIDONLY");
imap.send("SELECT INBOX").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Message numbers still work before UIDONLY is enabled
imap.send("FETCH 1 (UID)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains(" FETCH (")
.assert_not_contains("UIDFETCH");
// Enable UIDONLY
imap.send("ENABLE UIDONLY").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* ENABLED UIDONLY");
// Every sequence-number command is now rejected with BAD [UIDREQUIRED]
for command in [
"FETCH 1 (UID)",
"STORE 1 +FLAGS (\\Seen)",
"SEARCH ALL",
"COPY 1 \"Deleted Items\"",
"MOVE 1 \"Deleted Items\"",
"SORT (ARRIVAL) UTF-8 ALL",
"THREAD REFERENCES UTF-8 ALL",
] {
imap.send(command).await;
imap.assert_read(Type::Tagged, ResponseType::Bad)
.await
.assert_response_code("UIDREQUIRED");
}
// The UID variants keep working and now answer with UIDFETCH
imap.send("UID FETCH 1:* (FLAGS)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains(" UIDFETCH (")
.assert_not_contains(" FETCH (");
// The UID is the first token of a UIDFETCH response
imap.send("UID FETCH 1 (FLAGS)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* 1 UIDFETCH (");
// UID STORE also answers with UIDFETCH
imap.send("UID STORE 1 +FLAGS (\\Answered)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains(" UIDFETCH (")
.assert_not_contains(" FETCH (");
imap.send("UID STORE 1 -FLAGS (\\Answered)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// Plain EXPUNGE stays legal, it carries no message numbers
imap.send("EXPUNGE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// The bare sequence set criterion is banned
imap.send("UID SEARCH 1:*").await;
imap.assert_read(Type::Tagged, ResponseType::Bad)
.await
.assert_response_code("UIDREQUIRED");
// RFC 9586 names "UID <sequence set>" and ALL as the replacements, so both
// must keep working; UIDBATCHES results are consumed through the former
imap.send("UID SEARCH UID 1:*").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("UID SEARCH ALL").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("UID FETCH 1:* (UID)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// The SEARCHRES $ variable is not a sequence set either
imap.send("UID SEARCH RETURN (SAVE) ALL").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("UID SEARCH $").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
// UIDNOTSTICKY must never be advertised alongside UIDONLY
imap.send("SELECT INBOX").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_not_contains("UIDNOTSTICKY");
// Deletions are reported with VANISHED rather than EXPUNGE
imap.send("UID STORE 1 +FLAGS (\\Deleted)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("EXPUNGE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains("* VANISHED ")
.assert_not_contains("* 1 EXPUNGE");
// The QRESYNC sequence matching parameter is rejected once UIDONLY is on
imap.send("ENABLE QRESYNC").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("SELECT INBOX (QRESYNC (1 1 1:10 (1,2,3 1,2,3)))")
.await;
imap.assert_read(Type::Tagged, ResponseType::Bad)
.await
.assert_response_code("UIDREQUIRED");
// RFC 8437 requires UNAUTHENTICATE to clear every enabled extension, so
// message numbers must work again for the next user of this connection
imap.send("UNAUTHENTICATE").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.authenticate(account.name(), account.secret()).await;
imap.send("SELECT INBOX").await;
imap.assert_read(Type::Tagged, ResponseType::Ok).await;
imap.send("FETCH 1 (UID)").await;
imap.assert_read(Type::Tagged, ResponseType::Ok)
.await
.assert_contains(" FETCH (")
.assert_not_contains("UIDFETCH");
imap.send("LOGOUT").await;
imap.assert_read(Type::Untagged, ResponseType::Bye).await;
}