diff --git a/CHANGELOG.md b/CHANGELOG.md index fbb223b1..3ffec4c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.16.14] - 2026-07-XX + +If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If you are upgrading from v0.15.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_16.md) for more information on how to upgrade from previous versions. + +## Added + +## Changed + +## Fixed +- IMAP: Mailbox object-quota only enforced in JMAP. +- JMAP: Read-only sharee cannot set `isSubscribed` on a shared mailbox. + ## [0.16.13] - 2026-07-12 If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If you are upgrading from v0.15.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_16.md) for more information on how to upgrade from previous versions. diff --git a/Cargo.lock b/Cargo.lock index 5e6479e4..fb34dd41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1264,7 +1264,7 @@ dependencies = [ [[package]] name = "common" -version = "0.16.13" +version = "0.16.14" dependencies = [ "aes-gcm-siv", "ahash", @@ -1460,7 +1460,7 @@ checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "coordinator" -version = "0.16.13" +version = "0.16.14" dependencies = [ "async-nats", "futures", @@ -1814,7 +1814,7 @@ checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "dav" -version = "0.16.13" +version = "0.16.14" dependencies = [ "calcard", "chrono", @@ -1837,7 +1837,7 @@ dependencies = [ [[package]] name = "dav-proto" -version = "0.16.13" +version = "0.16.14" dependencies = [ "calcard", "chrono", @@ -2043,7 +2043,7 @@ dependencies = [ [[package]] name = "directory" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "argon2", @@ -2294,7 +2294,7 @@ dependencies = [ [[package]] name = "email" -version = "0.16.13" +version = "0.16.14" dependencies = [ "aes 0.9.1", "aes-gcm", @@ -2403,7 +2403,7 @@ dependencies = [ [[package]] name = "event_macro" -version = "0.16.13" +version = "0.16.14" dependencies = [ "proc-macro2", "quote", @@ -2907,7 +2907,7 @@ dependencies = [ [[package]] name = "groupware" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "calcard", @@ -3190,7 +3190,7 @@ dependencies = [ [[package]] name = "http" -version = "0.16.13" +version = "0.16.14" dependencies = [ "async-stream", "base64 0.22.1", @@ -3290,7 +3290,7 @@ dependencies = [ [[package]] name = "http_proto" -version = "0.16.13" +version = "0.16.14" dependencies = [ "common", "compact_str", @@ -3598,7 +3598,7 @@ checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" [[package]] name = "imap" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "common", @@ -3625,7 +3625,7 @@ dependencies = [ [[package]] name = "imap_proto" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "chrono", @@ -3838,7 +3838,7 @@ dependencies = [ [[package]] name = "jmap" -version = "0.16.13" +version = "0.16.14" dependencies = [ "aes-gcm", "aes-gcm-siv", @@ -3926,7 +3926,7 @@ dependencies = [ [[package]] name = "jmap_proto" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "calcard", @@ -4432,7 +4432,7 @@ dependencies = [ [[package]] name = "managesieve" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "common", @@ -4574,7 +4574,7 @@ checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" [[package]] name = "migration" -version = "0.16.13" +version = "0.16.14" dependencies = [ "base64 0.22.1", "common", @@ -4832,7 +4832,7 @@ dependencies = [ [[package]] name = "nlp" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "bincode 1.3.3", @@ -5634,7 +5634,7 @@ dependencies = [ [[package]] name = "pop3" -version = "0.16.13" +version = "0.16.14" dependencies = [ "common", "directory", @@ -5817,7 +5817,7 @@ dependencies = [ [[package]] name = "proc_macros" -version = "0.16.13" +version = "0.16.14" dependencies = [ "proc-macro2", "quote", @@ -6459,7 +6459,7 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "registry" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "hashify", @@ -7339,7 +7339,7 @@ dependencies = [ [[package]] name = "services" -version = "0.16.13" +version = "0.16.14" dependencies = [ "aes-gcm", "aes-gcm-siv", @@ -7655,7 +7655,7 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smtp" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "base64 0.22.1", @@ -7757,7 +7757,7 @@ dependencies = [ [[package]] name = "spam-filter" -version = "0.16.13" +version = "0.16.14" dependencies = [ "common", "compact_str", @@ -7872,7 +7872,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stalwart" -version = "0.16.13" +version = "0.16.14" dependencies = [ "common", "coordinator", @@ -7880,7 +7880,7 @@ dependencies = [ "directory", "email", "groupware", - "http 0.16.13", + "http 0.16.14", "http_proto", "imap", "jemallocator", @@ -7909,7 +7909,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "store" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "arc-swap", @@ -8150,7 +8150,7 @@ dependencies = [ [[package]] name = "tests" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "async-trait", @@ -8174,7 +8174,7 @@ dependencies = [ "form_urlencoded", "futures", "groupware", - "http 0.16.13", + "http 0.16.14", "http-body-util", "http_proto", "hyper", @@ -8717,7 +8717,7 @@ dependencies = [ [[package]] name = "trc" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "base64 0.22.1", @@ -8810,7 +8810,7 @@ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "types" -version = "0.16.13" +version = "0.16.14" dependencies = [ "blake3", "compact_str", @@ -9008,7 +9008,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utils" -version = "0.16.13" +version = "0.16.14" dependencies = [ "ahash", "arcstr", diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 38f23e9b..7f0a135a 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "common" -version = "0.16.13" +version = "0.16.14" edition = "2024" build = "build.rs" diff --git a/crates/coordinator/Cargo.toml b/crates/coordinator/Cargo.toml index 1d01b77c..bfb3a665 100644 --- a/crates/coordinator/Cargo.toml +++ b/crates/coordinator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coordinator" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/dav-proto/Cargo.toml b/crates/dav-proto/Cargo.toml index 3c284363..a4521f48 100644 --- a/crates/dav-proto/Cargo.toml +++ b/crates/dav-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dav-proto" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/dav/Cargo.toml b/crates/dav/Cargo.toml index eb184023..a46dcef3 100644 --- a/crates/dav/Cargo.toml +++ b/crates/dav/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dav" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml index 879f55a8..d9493084 100644 --- a/crates/directory/Cargo.toml +++ b/crates/directory/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "directory" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/email/Cargo.toml b/crates/email/Cargo.toml index 695fcd4a..bb0f3220 100644 --- a/crates/email/Cargo.toml +++ b/crates/email/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "email" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/email/src/mailbox/manage.rs b/crates/email/src/mailbox/manage.rs index 927e8f62..3bc662a9 100644 --- a/crates/email/src/mailbox/manage.rs +++ b/crates/email/src/mailbox/manage.rs @@ -7,6 +7,7 @@ use super::*; use crate::cache::MessageCacheFetch; use common::{Server, storage::index::ObjectIndexBuilder}; +use registry::schema::enums::StorageQuota; use std::future::Future; use store::write::BatchBuilder; use trc::AddContext; @@ -129,6 +130,13 @@ impl MailboxFnc for Server { return Ok(None); } + let account = self.account(account_id).await.caused_by(trc::location!())?; + if cache.mailboxes.items.len() + create_paths.len() + > self.object_quota(account.object_quotas(), StorageQuota::MaxMailboxes) as usize + { + return Ok(None); + } + let mut next_document_id = self .store() .assign_document_ids(account_id, Collection::Mailbox, create_paths.len() as u64) diff --git a/crates/groupware/Cargo.toml b/crates/groupware/Cargo.toml index 3d758435..9062c8e2 100644 --- a/crates/groupware/Cargo.toml +++ b/crates/groupware/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "groupware" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/http-proto/Cargo.toml b/crates/http-proto/Cargo.toml index f6b3f5d4..d7bc61da 100644 --- a/crates/http-proto/Cargo.toml +++ b/crates/http-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http_proto" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index 8a091637..04093b8d 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/imap-proto/Cargo.toml b/crates/imap-proto/Cargo.toml index 08db9971..0c37c58e 100644 --- a/crates/imap-proto/Cargo.toml +++ b/crates/imap-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "imap_proto" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml index b7d2c2ec..fdc45666 100644 --- a/crates/imap/Cargo.toml +++ b/crates/imap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "imap" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/imap/src/op/create.rs b/crates/imap/src/op/create.rs index 94b4b530..1757a1ac 100644 --- a/crates/imap/src/op/create.rs +++ b/crates/imap/src/op/create.rs @@ -16,7 +16,7 @@ use imap_proto::{ protocol::{ObjectId, create::Arguments, list::Attribute}, receiver::Request, }; -use registry::schema::enums::Permission; +use registry::schema::enums::{Permission, StorageQuota}; use std::time::Instant; use store::write::BatchBuilder; use trc::AddContext; @@ -71,6 +71,35 @@ impl SessionData { .imap_ctx(&arguments.tag, trc::location!())?; debug_assert!(!params.path.is_empty()); + // Validate quota + let account = self + .server + .account(params.account_id) + .await + .imap_ctx(&arguments.tag, trc::location!())?; + let mailbox_count = self + .server + .get_cached_messages(params.account_id) + .await + .imap_ctx(&arguments.tag, trc::location!())? + .mailboxes + .items + .len(); + if mailbox_count + params.path.len() + > self + .server + .object_quota(account.object_quotas(), StorageQuota::MaxMailboxes) as usize + { + return Err(trc::ImapEvent::Error + .into_err() + .details(concat!( + "There are too many mailboxes, ", + "please delete some before adding a new one." + )) + .code(ResponseCode::OverQuota) + .id(arguments.tag.clone())); + } + // Build batch let mut parent_id = params.parent_mailbox_id.map(|id| id + 1).unwrap_or(0); let mut create_ids = Vec::with_capacity(params.path.len()); diff --git a/crates/imap/src/op/rename.rs b/crates/imap/src/op/rename.rs index 224379ff..41bc9202 100644 --- a/crates/imap/src/op/rename.rs +++ b/crates/imap/src/op/rename.rs @@ -14,7 +14,8 @@ use imap_proto::{ protocol::{ObjectId, rename::Arguments}, receiver::Request, }; -use registry::schema::enums::Permission; +use email::cache::MessageCacheFetch; +use registry::schema::enums::{Permission, StorageQuota}; use std::time::Instant; use store::{ ValueKey, @@ -134,6 +135,38 @@ impl SessionData { // Get new mailbox name from path let new_mailbox_name = params.path.pop().unwrap(); + // Validate quota + if !params.path.is_empty() { + let account = self + .server + .account(params.account_id) + .await + .imap_ctx(&arguments.tag, trc::location!())?; + let mailbox_count = self + .server + .get_cached_messages(params.account_id) + .await + .imap_ctx(&arguments.tag, trc::location!())? + .mailboxes + .items + .len(); + if mailbox_count + params.path.len() + > self + .server + .object_quota(account.object_quotas(), StorageQuota::MaxMailboxes) + as usize + { + return Err(trc::ImapEvent::Error + .into_err() + .details(concat!( + "There are too many mailboxes, ", + "please delete some before adding a new one." + )) + .code(ResponseCode::OverQuota) + .id(arguments.tag.clone())); + } + } + // Build batch let mut parent_id = params.parent_mailbox_id.map(|id| id + 1).unwrap_or(0); let mut create_ids = Vec::with_capacity(params.path.len()); diff --git a/crates/jmap-proto/Cargo.toml b/crates/jmap-proto/Cargo.toml index c68dda1a..9531cb3f 100644 --- a/crates/jmap-proto/Cargo.toml +++ b/crates/jmap-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jmap_proto" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index 327fa8ce..41b5a80c 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jmap" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index af335c49..8860e9a6 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://stalw.art" keywords = ["imap", "jmap", "smtp", "email", "mail", "webdav", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" -version = "0.16.13" +version = "0.16.14" edition = "2024" [[bin]] diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml index 26bef5cc..803dd8de 100644 --- a/crates/managesieve/Cargo.toml +++ b/crates/managesieve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "managesieve" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/migration/Cargo.toml b/crates/migration/Cargo.toml index 1bf850c7..9ce6f192 100644 --- a/crates/migration/Cargo.toml +++ b/crates/migration/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "migration" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/nlp/Cargo.toml b/crates/nlp/Cargo.toml index c4e73f7e..838d0c2f 100644 --- a/crates/nlp/Cargo.toml +++ b/crates/nlp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nlp" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml index e7f38b52..54c5cacd 100644 --- a/crates/pop3/Cargo.toml +++ b/crates/pop3/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pop3" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/registry/Cargo.toml b/crates/registry/Cargo.toml index 63990751..999d5529 100644 --- a/crates/registry/Cargo.toml +++ b/crates/registry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "registry" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/services/Cargo.toml b/crates/services/Cargo.toml index 538aac15..634e7f8b 100644 --- a/crates/services/Cargo.toml +++ b/crates/services/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "services" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 6f47dcd3..e39d78f5 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://stalw.art/smtp" keywords = ["smtp", "email", "mail", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml index 5be78901..9f36b94c 100644 --- a/crates/spam-filter/Cargo.toml +++ b/crates/spam-filter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spam-filter" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 12aa0e8a..dda76853 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "store" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index b3dd289a..2a50398a 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trc" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/trc/event-macro/Cargo.toml b/crates/trc/event-macro/Cargo.toml index bcd35e9f..d091d48d 100644 --- a/crates/trc/event-macro/Cargo.toml +++ b/crates/trc/event-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "event_macro" -version = "0.16.13" +version = "0.16.14" edition = "2024" [lib] diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index 35250413..f8e43494 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "types" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 13f74b83..3b5e1ba9 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "utils" -version = "0.16.13" +version = "0.16.14" edition = "2024" [dependencies] diff --git a/crates/utils/proc-macros/Cargo.toml b/crates/utils/proc-macros/Cargo.toml index 7de66039..ce171ba2 100644 --- a/crates/utils/proc-macros/Cargo.toml +++ b/crates/utils/proc-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proc_macros" -version = "0.16.13" +version = "0.16.14" edition = "2024" [lib] diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 1be17f3e..92a3f50b 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tests" -version = "0.16.13" +version = "0.16.14" edition = "2024" [features]