Merge upstream v0.16.23

Five conflicts, resolved:

- crates/common/src/auth/authentication.rs: upstream's get_directory_for_token
  and JwtClaims replace extract_jwt_domain; the per-domain directory code
  (DIR-1, DIR-5 to DIR-7) is kept, and the token lookup routes through it.
  The release's one new Enterprise snippet was the body of
  get_directory_for_issuer, which stays returning None: a token naming no
  address gets the server default, as DIR-2 specifies and as v0.16.22 did.
- crates/common/src/manager/application.rs: upstream's rewrite of the tests,
  with the temp directory names renamed again, and the 5(a) notice the
  name-purge change should have added.
- crates/common/src/network/mta.rs: both sides' imports.
- crates/main/Cargo.toml: the AGPL-only license kept, version 0.16.23.
- Cargo.lock: upstream's, with the fork's crates added by Cargo.
This commit is contained in:
2026-09-22 16:57:06 -07:00
82 changed files with 1527 additions and 611 deletions
+35
View File
@@ -133,6 +133,41 @@ pub async fn test(test: &TestServer) {
let samples = account.spam_training_samples().await;
assert_eq!(samples.iter().filter(|x| !x.1.is_spam).count(), 11);
assert_eq!(samples.iter().filter(|x| x.1.is_spam).count(), 10);
let support_id = test.account("[email protected]").id();
let jane = test.account("[email protected]");
let jane_id = jane.id();
let mut imap_jane = jane.imap_client().await;
let samples_for = |account_id, is_spam: bool| {
let admin = &admin;
async move {
admin
.spam_training_samples()
.await
.into_iter()
.filter(|(_, sample)| {
sample.account_id == Some(account_id) && sample.is_spam == is_spam
})
.count()
}
};
imap_jane
.append("Shared Folders/[email protected]/Drafts", SPAM[1])
.await;
assert_eq!(samples_for(support_id, true).await, 0);
imap_jane
.send_ok("SELECT \"Shared Folders/[email protected]/Drafts\"")
.await;
imap_jane.send_ok("MOVE * \"Junk Mail\"").await;
assert_eq!(samples_for(support_id, true).await, 1);
imap_jane.send_ok("SELECT \"Junk Mail\"").await;
imap_jane
.send_ok("MOVE * \"Shared Folders/[email protected]/Drafts\"")
.await;
assert_eq!(samples_for(jane_id, false).await, 1);
}
pub async fn spam_classifier_model(server: &Server) -> SpamTrainer {
+18 -4
View File
@@ -122,18 +122,32 @@ pub async fn test(test: &TestServer) {
pop3.assert_read(ResponseType::Err).await;
// TOP
pop3.send("TOP 1 4").await;
pop3.send("TOP 1 0").await;
pop3.assert_read(ResponseType::Multiline)
.await
.assert_contains("+OK 203 octets")
.assert_contains("Subject: TPS Report 0")
.assert_contains("X-Spam-Status: No")
.assert_not_contains("I'm going to need those TPS 0 reports ASAP.");
pop3.send("TOP 3 4").await;
pop3.send("TOP 1 1").await;
pop3.assert_read(ResponseType::Multiline)
.await
.assert_contains("Subject: TPS Report 0")
.assert_contains("I'm going to need those TPS 0 reports ASAP.")
.assert_not_contains("So, if you could do that, that'd be great.");
pop3.send("TOP 3 0").await;
pop3.assert_read(ResponseType::Multiline)
.await
.assert_contains("Subject: TPS Report 2")
.assert_not_contains("I'm going to need those TPS 2 reports ASAP.");
pop3.send("TOP 3 100").await;
pop3.assert_read(ResponseType::Multiline)
.await
.assert_contains("+OK 203 octets")
.assert_contains("Subject: TPS Report 2")
.assert_not_contains("I'm going to need those TPS 2 reports ASAP.");
.assert_contains("I'm going to need those TPS 2 reports ASAP.")
.assert_contains("So, if you could do that, that'd be great.");
pop3.send("TOP 4 1").await;
pop3.assert_read(ResponseType::Err).await;
// DELE + RSET + QUIT (should not delete messages)
pop3.send("DELE 1").await;