From 7ec5701af8480c2ac21698998b5526181eea6934 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Sun, 11 May 2025 16:56:55 +0200 Subject: [PATCH] Zero-copy deserialization of Sieve scripts and reports + Bump multiple dependencies to their latest versions --- Cargo.lock | 957 ++++++++++-------- crates/cli/Cargo.toml | 4 +- crates/common/Cargo.toml | 14 +- crates/common/src/auth/mod.rs | 1 - crates/common/src/auth/oauth/introspect.rs | 1 - crates/common/src/auth/oauth/registration.rs | 1 - crates/common/src/auth/oauth/token.rs | 1 - crates/common/src/config/smtp/resolver.rs | 22 +- crates/common/src/scripts/functions/header.rs | 4 +- crates/common/src/scripts/mod.rs | 1 - crates/common/src/scripts/plugins/lookup.rs | 17 +- crates/dav-proto/Cargo.toml | 2 +- crates/dav-proto/src/parser/property.rs | 4 +- crates/dav-proto/src/requests/report.rs | 8 +- crates/dav/src/calendar/query.rs | 7 +- crates/dav/src/request.rs | 2 +- crates/directory/Cargo.toml | 2 +- crates/directory/src/backend/imap/lookup.rs | 1 - crates/directory/src/backend/memory/config.rs | 5 +- crates/directory/src/backend/mod.rs | 2 - crates/directory/src/backend/smtp/lookup.rs | 1 - crates/directory/src/backend/sql/lookup.rs | 4 +- crates/directory/src/core/dispatch.rs | 1 - crates/email/Cargo.toml | 7 +- crates/email/src/identity/mod.rs | 1 - crates/email/src/message/copy.rs | 6 +- crates/email/src/message/crypto.rs | 8 +- crates/email/src/message/index.rs | 122 +-- crates/email/src/message/ingest.rs | 22 +- crates/email/src/message/metadata.rs | 838 +-------------- crates/email/src/sieve/ingest.rs | 23 +- crates/http/Cargo.toml | 6 +- crates/http/src/management/report.rs | 159 +-- crates/imap-proto/Cargo.toml | 2 +- crates/imap-proto/src/parser/append.rs | 7 +- crates/imap-proto/src/protocol/acl.rs | 2 - crates/imap-proto/src/protocol/append.rs | 2 - .../imap-proto/src/protocol/authenticate.rs | 2 - crates/imap-proto/src/protocol/copy_move.rs | 2 - crates/imap-proto/src/protocol/create.rs | 2 - crates/imap-proto/src/protocol/delete.rs | 2 - crates/imap-proto/src/protocol/enable.rs | 2 - crates/imap-proto/src/protocol/fetch.rs | 2 - crates/imap-proto/src/protocol/list.rs | 3 - crates/imap-proto/src/protocol/login.rs | 2 - crates/imap-proto/src/protocol/namespace.rs | 2 - crates/imap-proto/src/protocol/quota.rs | 2 - crates/imap-proto/src/protocol/rename.rs | 2 - crates/imap-proto/src/protocol/search.rs | 1 - crates/imap-proto/src/protocol/select.rs | 2 - crates/imap-proto/src/protocol/status.rs | 2 - crates/imap-proto/src/protocol/store.rs | 2 - crates/imap-proto/src/protocol/subscribe.rs | 2 - crates/imap-proto/src/protocol/thread.rs | 2 - crates/imap/Cargo.toml | 2 +- crates/imap/src/op/fetch.rs | 10 +- crates/jmap-proto/Cargo.toml | 2 +- crates/jmap/Cargo.toml | 7 +- crates/jmap/src/email/body.rs | 30 +- crates/jmap/src/email/get.rs | 27 +- crates/jmap/src/email/headers.rs | 12 +- crates/jmap/src/email/parse.rs | 4 +- crates/jmap/src/email/snippet.rs | 9 +- crates/jmap/src/sieve/set.rs | 6 +- crates/jmap/src/submission/set.rs | 3 +- crates/jmap/src/vacation/set.rs | 11 +- crates/managesieve/Cargo.toml | 7 +- crates/managesieve/src/op/putscript.rs | 19 +- crates/nlp/Cargo.toml | 2 +- crates/pop3/Cargo.toml | 2 +- crates/services/Cargo.toml | 2 +- crates/smtp/Cargo.toml | 11 +- crates/smtp/src/inbound/ehlo.rs | 6 +- crates/smtp/src/inbound/hooks/mod.rs | 5 +- crates/smtp/src/inbound/milter/protocol.rs | 7 +- crates/smtp/src/outbound/dane/dnssec.rs | 100 +- crates/smtp/src/reporting/analysis.rs | 31 +- crates/smtp/src/reporting/dmarc.rs | 42 +- crates/smtp/src/reporting/mod.rs | 34 +- crates/smtp/src/reporting/tls.rs | 28 +- crates/spam-filter/Cargo.toml | 6 +- crates/spam-filter/src/analysis/domain.rs | 3 +- crates/spam-filter/src/analysis/from.rs | 2 +- crates/spam-filter/src/analysis/headers.rs | 2 +- crates/spam-filter/src/analysis/html.rs | 1 + crates/spam-filter/src/analysis/ip.rs | 1 + crates/spam-filter/src/analysis/messageid.rs | 3 +- crates/spam-filter/src/analysis/mime.rs | 18 +- crates/spam-filter/src/analysis/mod.rs | 4 +- crates/spam-filter/src/analysis/received.rs | 2 +- crates/spam-filter/src/analysis/recipient.rs | 2 +- crates/spam-filter/src/analysis/replyto.rs | 2 +- crates/spam-filter/src/analysis/rules.rs | 3 +- crates/spam-filter/src/analysis/subject.rs | 2 +- crates/spam-filter/src/analysis/url.rs | 1 + crates/spam-filter/src/modules/bayes.rs | 4 +- crates/spam-filter/src/modules/expression.rs | 10 +- crates/store/Cargo.toml | 7 +- crates/store/src/backend/s3/mod.rs | 2 +- crates/store/src/lib.rs | 1 + crates/store/src/write/mod.rs | 8 - crates/store/src/write/serialize.rs | 53 +- crates/trc/Cargo.toml | 5 +- crates/trc/src/event/conv.rs | 4 - crates/utils/Cargo.toml | 2 +- tests/Cargo.toml | 6 +- tests/src/imap/body_structure.rs | 5 +- tests/src/jmap/mod.rs | 4 +- tests/src/smtp/inbound/milter.rs | 2 +- tests/src/smtp/lookup/sql.rs | 1 - tests/src/smtp/mod.rs | 4 +- tests/src/smtp/outbound/dane.rs | 35 +- 112 files changed, 1109 insertions(+), 1816 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97711089..8b656d55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,17 +80,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.11" @@ -271,6 +260,22 @@ dependencies = [ "time", ] +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive 0.6.0", + "asn1-rs-impl 0.2.0", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.12", + "time", +] + [[package]] name = "asn1-rs-derive" version = "0.4.0" @@ -295,6 +300,18 @@ dependencies = [ "synstructure 0.13.2", ] +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure 0.13.2", +] + [[package]] name = "asn1-rs-impl" version = "0.1.0" @@ -639,19 +656,6 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" -[[package]] -name = "bigdecimal" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" -dependencies = [ - "autocfg", - "libm", - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "bincode" version = "1.3.3" @@ -661,6 +665,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -878,29 +902,6 @@ dependencies = [ "cipher 0.4.4", ] -[[package]] -name = "borsh" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" -dependencies = [ - "borsh-derive", - "cfg_aliases 0.2.1", -] - -[[package]] -name = "borsh-derive" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "btoi" version = "0.4.3" @@ -925,40 +926,18 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive 0.6.12", - "ptr_meta 0.1.4", - "simdutf8", -] - [[package]] name = "bytecheck" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3" dependencies = [ - "bytecheck_derive 0.8.1", - "ptr_meta 0.3.0", + "bytecheck_derive", + "ptr_meta", "rancor", "simdutf8", ] -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bytecheck_derive" version = "0.8.1" @@ -1011,13 +990,13 @@ dependencies = [ name = "calcard" version = "0.1.0" dependencies = [ - "ahash 0.8.11", + "ahash", "chrono", "chrono-tz", "hashify", "mail-builder", - "mail-parser", - "rkyv 0.8.10", + "mail-parser 0.10.2", + "rkyv", "serde", ] @@ -1243,15 +1222,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - [[package]] name = "colorchoice" version = "1.0.3" @@ -1277,10 +1247,10 @@ name = "common" version = "0.11.8" dependencies = [ "aes-gcm-siv", - "ahash 0.8.11", + "ahash", "arc-swap", "base64 0.22.1", - "bincode", + "bincode 2.0.1", "biscuit", "calcard", "chrono", @@ -1296,12 +1266,12 @@ dependencies = [ "imagesize", "imap_proto", "indexmap 2.9.0", - "infer 0.16.0", + "infer 0.19.0", "jmap_proto", "libc", "mail-auth", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "md5", "nlp", @@ -1323,7 +1293,7 @@ dependencies = [ "regex", "reqwest 0.12.15", "ring 0.17.14", - "rkyv 0.8.10", + "rkyv", "rsa", "rustls 0.23.27", "rustls-pemfile 2.2.0", @@ -1342,7 +1312,7 @@ dependencies = [ "unicode-security", "utils", "whatlang", - "x509-parser 0.16.0", + "x509-parser 0.17.0", "xxhash-rust", "zip", ] @@ -1356,7 +1326,7 @@ dependencies = [ "castaway", "cfg-if", "itoa", - "rkyv 0.8.10", + "rkyv", "rustversion", "ryu", "serde", @@ -1498,17 +1468,10 @@ dependencies = [ ] [[package]] -name = "crossbeam" -version = "0.8.4" +name = "critical-section" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" @@ -1747,7 +1710,7 @@ dependencies = [ "hyper 1.6.0", "jmap_proto", "percent-encoding", - "rkyv 0.8.10", + "rkyv", "store", "trc", "utils", @@ -1762,9 +1725,9 @@ dependencies = [ "compact_str", "hashify", "hyper 1.6.0", - "mail-parser", + "mail-parser 0.11.0", "quick-xml 0.37.5", - "rkyv 0.8.10", + "rkyv", "serde", "serde_json", "trc", @@ -1881,6 +1844,20 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs 0.7.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.4.0" @@ -1936,7 +1913,7 @@ dependencies = [ name = "directory" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "argon2", "async-trait", "base64 0.22.1", @@ -1946,7 +1923,7 @@ dependencies = [ "jmap_proto", "ldap3", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "md5", "nlp", @@ -1956,7 +1933,7 @@ dependencies = [ "pwhash", "regex", "reqwest 0.12.15", - "rkyv 0.8.10", + "rkyv", "rustls 0.23.27", "rustls-pki-types", "scrypt", @@ -2195,7 +2172,6 @@ dependencies = [ "aes", "aes-gcm", "aes-gcm-siv", - "bincode", "cbc", "common", "compact_str", @@ -2203,13 +2179,13 @@ dependencies = [ "hashify", "jmap_proto", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "nlp", "rand 0.8.5", "rasn", "rasn-cms", "rasn-pkix", - "rkyv 0.8.10", + "rkyv", "rsa", "sequoia-openpgp", "serde", @@ -2352,8 +2328,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set 0.8.0", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2525,62 +2501,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "frunk" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874b6a17738fc273ec753618bac60ddaeac48cb1d7684c3e7bd472e57a28b817" -dependencies = [ - "frunk_core", - "frunk_derives", - "frunk_proc_macros", - "serde", -] - -[[package]] -name = "frunk_core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3529a07095650187788833d585c219761114005d5976185760cf794d265b6a5c" -dependencies = [ - "serde", -] - -[[package]] -name = "frunk_derives" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99b8b3c28ae0e84b604c75f721c21dc77afb3706076af5e8216d15fd1deaae3" -dependencies = [ - "frunk_proc_macro_helpers", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "frunk_proc_macro_helpers" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a956ef36c377977e512e227dcad20f68c2786ac7a54dacece3746046fea5ce" -dependencies = [ - "frunk_core", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "frunk_proc_macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e86c2c9183662713fea27ea527aad20fb15fee635a71081ff91bf93df4dc51" -dependencies = [ - "frunk_core", - "frunk_proc_macro_helpers", - "quote", - "syn 2.0.101", -] - [[package]] name = "funty" version = "2.0.0" @@ -2700,6 +2620,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2824,7 +2757,7 @@ dependencies = [ "hashify", "jmap_proto", "percent-encoding", - "rkyv 0.8.10", + "rkyv", "store", "tokio", "trc", @@ -2883,9 +2816,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" @@ -2893,7 +2823,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash", "allocator-api2", ] @@ -2968,7 +2898,7 @@ dependencies = [ "data-encoding", "futures-channel", "futures-util", - "hickory-proto", + "hickory-proto 0.24.4", "once_cell", "radix_trie", "rand 0.8.5", @@ -3010,25 +2940,56 @@ dependencies = [ ] [[package]] -name = "hickory-resolver" -version = "0.24.4" +name = "hickory-proto" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +dependencies = [ + "async-trait", + "bitflags 2.9.0", + "bytes", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.1", + "ring 0.17.14", + "rustls 0.23.27", + "rustls-pki-types", + "thiserror 2.0.12", + "time", + "tinyvec", + "tokio", + "tokio-rustls 0.26.2", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" dependencies = [ "cfg-if", "futures-util", - "hickory-proto", + "hickory-proto 0.25.2", "ipconfig", - "lru-cache", + "moka", "once_cell", "parking_lot", - "rand 0.8.5", + "rand 0.9.1", "resolv-conf", - "rustls 0.21.12", + "rustls 0.23.27", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls 0.26.2", "tracing", ] @@ -3113,13 +3074,13 @@ dependencies = [ "jmap_proto", "mail-auth", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "mime", "pkcs8", "quick-xml 0.37.5", "rev_lines", - "rkyv 0.8.10", + "rkyv", "rsa", "serde", "serde_json", @@ -3133,7 +3094,7 @@ dependencies = [ "tokio", "trc", "utils", - "x509-parser 0.16.0", + "x509-parser 0.17.0", ] [[package]] @@ -3357,7 +3318,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.0", ] [[package]] @@ -3525,15 +3486,15 @@ dependencies = [ [[package]] name = "imagesize" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" [[package]] name = "imap" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "common", "compact_str", "directory", @@ -3541,7 +3502,7 @@ dependencies = [ "imap_proto", "indexmap 2.9.0", "jmap_proto", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "md5", "nlp", @@ -3560,12 +3521,12 @@ dependencies = [ name = "imap_proto" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "chrono", "compact_str", "hashify", "jmap_proto", - "mail-parser", + "mail-parser 0.11.0", "store", "tokio", "trc", @@ -3635,9 +3596,9 @@ checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" [[package]] name = "infer" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" dependencies = [ "cfb", ] @@ -3799,7 +3760,6 @@ dependencies = [ "aes-gcm-siv", "async-stream", "base64 0.22.1", - "bincode", "chrono", "common", "compact_str", @@ -3815,14 +3775,14 @@ dependencies = [ "lz4_flex", "mail-auth", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "nlp", "p256", "pkcs8", "rand 0.9.1", "reqwest 0.12.15", - "rkyv 0.8.10", + "rkyv", "rsa", "serde", "serde_json", @@ -3847,7 +3807,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12c697483ad894a8184d0fd61848e057f86b16642049993b3e6a80c959dbc90a" dependencies = [ - "ahash 0.8.11", + "ahash", "async-stream", "base64 0.13.1", "chrono", @@ -3867,12 +3827,12 @@ dependencies = [ name = "jmap_proto" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "compact_str", "fast-float", "hashify", - "mail-parser", - "rkyv 0.8.10", + "mail-parser 0.11.0", + "rkyv", "serde", "serde_json", "store", @@ -3901,6 +3861,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "keyed_priority_queue" version = "0.4.2" @@ -3943,7 +3912,7 @@ dependencies = [ "lalrpop-util", "petgraph", "regex", - "regex-syntax", + "regex-syntax 0.8.5", "string_cache", "term", "tiny-keccak", @@ -3957,7 +3926,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata", + "regex-automata 0.4.9", ] [[package]] @@ -4085,9 +4054,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb8270bb4060bd76c6e96f20c52d80620f1d82a3470885694e41e0f81ef6fe7" +checksum = "947e6816f7825b2b45027c2c32e7085da9934defa535de4a6a46b10a4d5257fa" dependencies = [ "cc", "pkg-config", @@ -4146,10 +4115,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] -name = "lru" -version = "0.12.5" +name = "loom" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" dependencies = [ "hashbrown 0.15.3", ] @@ -4202,19 +4184,20 @@ dependencies = [ [[package]] name = "mail-auth" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "971b381e86bc19e81d7f4b5ffa3328a15fb7e2998fec82a82f4f144e65c73f5f" +checksum = "948946ae9bf1bb98f6101dad1a6b473f140eeb633e74d48c732464796924073b" dependencies = [ - "ahash 0.8.11", + "ahash", "flate2", "hickory-resolver", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "quick-xml 0.37.5", "quick_cache", "rand 0.8.5", "ring 0.17.14", + "rkyv", "rsa", "rustls-pemfile 2.2.0", "serde", @@ -4239,6 +4222,17 @@ checksum = "187a2b93c4c8c32f552ee06c2d99915e575de2fc7e04b07891c9edfee5b8edd6" dependencies = [ "encoding_rs", "hashify", +] + +[[package]] +name = "mail-parser" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e3a04056838aad1ad3f66ef4f7b72a3f33d8c3a8f2664b9363de5383bccaf1" +dependencies = [ + "encoding_rs", + "hashify", + "rkyv", "serde", ] @@ -4288,8 +4282,7 @@ dependencies = [ name = "managesieve" version = "0.11.8" dependencies = [ - "ahash 0.8.11", - "bincode", + "ahash", "common", "compact_str", "directory", @@ -4297,10 +4290,11 @@ dependencies = [ "imap", "imap_proto", "jmap_proto", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "md5", "parking_lot", + "rkyv", "rustls 0.23.27", "rustls-pemfile 2.2.0", "sieve-rs", @@ -4317,6 +4311,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchit" version = "0.7.3" @@ -4421,11 +4424,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "loom", + "parking_lot", + "portable-atomic", + "rustc_version 0.4.1", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + [[package]] name = "munge" version = "0.4.4" @@ -4448,9 +4469,9 @@ dependencies = [ [[package]] name = "mysql-common-derive" -version = "0.31.2" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c3512cf11487168e0e9db7157801bf5273be13055a9cc95356dc9e0035e49c" +checksum = "66f62cad7623a9cb6f8f64037f0c4f69c8db8e82914334a83c9788201c2c1bfa" dependencies = [ "darling 0.20.11", "heck 0.5.0", @@ -4461,83 +4482,66 @@ dependencies = [ "quote", "syn 2.0.101", "termcolor", - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] name = "mysql_async" -version = "0.34.1" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbfe87d7e35cb72363326216cc1712b865d8d4f70abf3b2d2e6b251fb6b2f427" +checksum = "277ce2f2459b2af4cc6d0a0b7892381f80800832f57c533f03e2845f4ea331ea" dependencies = [ "bytes", - "crossbeam", + "crossbeam-queue", "flate2", "futures-core", "futures-sink", "futures-util", "keyed_priority_queue", - "lazy_static", "lru", - "mio", "mysql_common", - "once_cell", "pem", "percent-encoding", - "pin-project", - "rand 0.8.5", - "rustls 0.22.4", + "rand 0.9.1", + "rustls 0.23.27", "rustls-pemfile 2.2.0", "serde", "serde_json", "socket2", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", - "tokio-rustls 0.25.0", + "tokio-rustls 0.26.2", "tokio-util", "twox-hash", "url", - "webpki", "webpki-roots 0.26.10", ] [[package]] name = "mysql_common" -version = "0.32.4" +version = "0.35.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478b0ff3f7d67b79da2b96f56f334431aef65e15ba4b29dd74a4236e29582bdc" +checksum = "6e0ec195e788c95f36b7cf88127d538465fc2f7773e6e47af01834738eab0aee" dependencies = [ - "base64 0.21.7", - "bigdecimal", - "bindgen 0.71.1", + "base64 0.22.1", "bitflags 2.9.0", - "bitvec", "btoi", "byteorder", "bytes", - "cc", - "cmake", "crc32fast", "flate2", - "frunk", - "lazy_static", + "getrandom 0.3.2", "mysql-common-derive", "num-bigint", "num-traits", - "rand 0.8.5", "regex", - "rust_decimal", "saturating", "serde", "serde_json", "sha1", "sha2 0.10.9", - "smallvec", - "subprocess", - "thiserror 1.0.69", - "time", + "thiserror 2.0.12", "uuid", - "zstd", ] [[package]] @@ -4571,8 +4575,8 @@ dependencies = [ name = "nlp" version = "0.11.8" dependencies = [ - "ahash 0.8.11", - "bincode", + "ahash", + "bincode 1.3.3", "farmhash", "hashify", "jieba-rs", @@ -4607,6 +4611,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -4695,6 +4709,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "ocb3" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" +dependencies = [ + "aead", + "cipher 0.4.4", + "ctr", + "subtle", +] + [[package]] name = "oid-registry" version = "0.6.1" @@ -4713,11 +4739,24 @@ dependencies = [ "asn1-rs 0.6.2", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs 0.7.1", +] + [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "opaque-debug" @@ -4863,6 +4902,12 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "p256" version = "0.13.2" @@ -5121,7 +5166,7 @@ dependencies = [ "email", "imap", "jmap_proto", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "rustls 0.23.27", "store", @@ -5341,33 +5386,13 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive 0.1.4", -] - [[package]] name = "ptr_meta" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" dependencies = [ - "ptr_meta_derive 0.3.0", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "ptr_meta_derive", ] [[package]] @@ -5431,7 +5456,7 @@ version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287e56aac5a2b4fb25a6fb050961d157635924c8696305a5c937a76f29841a0f" dependencies = [ - "ahash 0.8.11", + "ahash", "equivalent", "hashbrown 0.15.3", "parking_lot", @@ -5539,7 +5564,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" dependencies = [ - "ptr_meta 0.3.0", + "ptr_meta", ] [[package]] @@ -5801,8 +5826,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -5813,31 +5847,28 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck 0.6.12", -] - [[package]] name = "rend" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" dependencies = [ - "bytecheck 0.8.1", + "bytecheck", ] [[package]] @@ -5995,54 +6026,25 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck 0.6.12", - "bytes", - "hashbrown 0.12.3", - "ptr_meta 0.1.4", - "rend 0.4.2", - "rkyv_derive 0.7.45", - "seahash", - "tinyvec", - "uuid", -] - [[package]] name = "rkyv" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" dependencies = [ - "bytecheck 0.8.1", + "bytecheck", "bytes", "hashbrown 0.15.3", "indexmap 2.9.0", "munge", - "ptr_meta 0.3.0", + "ptr_meta", "rancor", - "rend 0.5.2", - "rkyv_derive 0.8.10", + "rend", + "rkyv_derive", "tinyvec", "uuid", ] -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rkyv_derive" version = "0.8.10" @@ -6129,9 +6131,9 @@ checksum = "ad8388ea1a9e0ea807e442e8263a699e7edcb320ecbcd21b4fa8ff859acce3ba" [[package]] name = "rusqlite" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e34486da88d8e051c7c0e23c3f15fd806ea8546260aa2fec247e97242ec143" +checksum = "a22715a5d6deef63c637207afbe68d0c72c3f8d0022d7cf9714c442d6157606b" dependencies = [ "bitflags 2.9.0", "fallible-iterator 0.3.0", @@ -6154,9 +6156,9 @@ dependencies = [ [[package]] name = "rust-s3" -version = "0.35.0-alpha.2" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48e3a4e58d3bc73949db3dda917e8fb0d31d635fbe496084847b8d45049787" +checksum = "c3df3f353b1f4209dcf437d777cda90279c397ab15a0cd6fd06bd32c88591533" dependencies = [ "async-trait", "aws-creds", @@ -6199,22 +6201,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "rust_decimal" -version = "1.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv 0.7.45", - "serde", - "serde_json", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -6318,6 +6304,7 @@ version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ + "log", "once_cell", "ring 0.17.14", "rustls-pki-types", @@ -6472,6 +6459,12 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -6506,12 +6499,6 @@ version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "sec1" version = "0.7.3" @@ -6585,13 +6572,14 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "sequoia-openpgp" -version = "1.22.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e858e4e9e48ff079cede92e1b45c942a5466ce9a4e3cc0c2a7e66586a718ef59" +checksum = "015e5fc3d023418b9db98ca9a7f3e90b305872eeafe5ca45c5c32b5eb335c1e8" dependencies = [ "aes", "aes-gcm", "anyhow", + "argon2", "base64 0.22.1", "block-padding", "blowfish 0.9.1", @@ -6611,28 +6599,29 @@ dependencies = [ "ed25519", "ed25519-dalek", "getrandom 0.2.16", + "hkdf", "idea", "idna", "lalrpop", "lalrpop-util", - "lazy_static", "libc", "md-5 0.10.6", "memsec", "num-bigint-dig", - "once_cell", + "ocb3", "p256", "p384", "p521", "rand 0.8.5", "rand_core 0.6.4", "regex", - "regex-syntax", + "regex-syntax 0.8.5", "ripemd", "rsa", "sha1collisiondetection", "sha2 0.10.9", - "thiserror 1.0.69", + "sha3", + "thiserror 2.0.12", "twofish", "typenum", "x25519-dalek", @@ -6764,7 +6753,7 @@ dependencies = [ "email", "hkdf", "jmap_proto", - "mail-parser", + "mail-parser 0.11.0", "memory-stats", "p256", "reqwest 0.12.15", @@ -6844,6 +6833,25 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -6852,16 +6860,17 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "sieve-rs" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15ac54053752c25a0e545dd1953de716abcc80b12cfe0b6c2f2c1c73759d4f45" +checksum = "9ada516ead6adf4f915e69fcb123640bcf23a9b29fc4b537145487e91af7a594" dependencies = [ - "ahash 0.8.11", - "bincode", + "ahash", + "arc-swap", "fancy-regex", "hashify", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", + "rkyv", "serde", ] @@ -6921,8 +6930,7 @@ checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" name = "smtp" version = "0.11.8" dependencies = [ - "ahash 0.8.11", - "bincode", + "ahash", "blake3", "chrono", "common", @@ -6936,7 +6944,7 @@ dependencies = [ "lru-cache", "mail-auth", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "md5", "nlp", @@ -6946,7 +6954,7 @@ dependencies = [ "rayon", "regex", "reqwest 0.12.15", - "rkyv 0.8.10", + "rkyv", "rustls 0.23.27", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -6962,8 +6970,8 @@ dependencies = [ "tokio-rustls 0.26.2", "trc", "utils", - "webpki-roots 0.26.10", - "x509-parser 0.16.0", + "webpki-roots 1.0.0", + "x509-parser 0.17.0", ] [[package]] @@ -6972,7 +6980,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7d3950ab75b03c52f2f13fd52aab91c9d62698b231b67240e85c3ef5301e63e" dependencies = [ - "rkyv 0.8.10", + "rkyv", ] [[package]] @@ -7017,10 +7025,10 @@ dependencies = [ "decancer", "hyper 1.6.0", "idna", - "infer 0.16.0", + "infer 0.19.0", "mail-auth", "mail-builder", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "nlp", "psl", @@ -7076,7 +7084,7 @@ dependencies = [ "indicatif", "jmap-client", "mail-auth", - "mail-parser", + "mail-parser 0.11.0", "num_cpus", "prettytable-rs", "pwhash", @@ -7098,13 +7106,12 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" name = "store" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "arc-swap", "async-trait", "azure_core", "azure_storage", "azure_storage_blobs", - "bincode", "bitpacking", "blake3", "bytes", @@ -7131,7 +7138,7 @@ dependencies = [ "regex", "reqwest 0.12.15", "ring 0.17.14", - "rkyv 0.8.10", + "rkyv", "roaring", "rocksdb", "rusqlite", @@ -7183,16 +7190,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "subprocess" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "subtle" version = "2.6.1" @@ -7280,6 +7277,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -7310,7 +7313,7 @@ dependencies = [ name = "tests" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "async-trait", "base64 0.22.1", "biscuit", @@ -7341,7 +7344,7 @@ dependencies = [ "jmap-client", "jmap_proto", "mail-auth", - "mail-parser", + "mail-parser 0.11.0", "mail-send", "managesieve", "nlp", @@ -7351,7 +7354,7 @@ dependencies = [ "rayon", "reqwest 0.12.15", "ring 0.17.14", - "rkyv 0.8.10", + "rkyv", "rustls 0.23.27", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -7410,6 +7413,16 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.41" @@ -7753,22 +7766,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] name = "trc" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "base64 0.22.1", - "bincode", "compact_str", "event_macro", "mail-auth", - "mail-parser", + "mail-parser 0.11.0", "parking_lot", "reqwest 0.12.15", - "rkyv 0.8.10", + "rkyv", "rtrb", "serde", "serde_json", @@ -7842,14 +7884,9 @@ dependencies = [ [[package]] name = "twox-hash" -version = "1.6.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "rand 0.8.5", - "static_assertions", -] +checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908" [[package]] name = "typeid" @@ -7967,6 +8004,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.4" @@ -8013,7 +8056,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" name = "utils" version = "0.11.8" dependencies = [ - "ahash 0.8.11", + "ahash", "base64 0.22.1", "blake3", "chrono", @@ -8036,7 +8079,7 @@ dependencies = [ "regex", "reqwest 0.12.15", "ring 0.17.14", - "rkyv 0.8.10", + "rkyv", "rustls 0.23.27", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -8060,6 +8103,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -8072,6 +8121,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "void" version = "1.0.2" @@ -8234,16 +8289,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -8259,6 +8304,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "whatlang" version = "0.16.4" @@ -8317,19 +8371,53 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.0", + "windows-interface 0.59.1", "windows-link", - "windows-result", + "windows-result 0.3.2", "windows-strings 0.4.0", ] +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "windows-implement" version = "0.60.0" @@ -8341,6 +8429,17 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "windows-interface" version = "0.59.1" @@ -8364,11 +8463,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result", + "windows-result 0.3.2", "windows-strings 0.3.1", "windows-targets 0.53.0", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.2" @@ -8378,6 +8486,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-strings" version = "0.3.1" @@ -8702,6 +8820,23 @@ dependencies = [ "time", ] +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs 0.7.1", + "data-encoding", + "der-parser 10.0.0", + "lazy_static", + "nom", + "oid-registry 0.8.1", + "rusticata-macros", + "thiserror 2.0.12", + "time", +] + [[package]] name = "xml-rs" version = "0.8.26" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index df088180..33c3003b 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -12,7 +12,7 @@ resolver = "2" [dependencies] jmap-client = { version = "0.3", features = ["async"] } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "serde"] } reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]} tokio = { version = "1.23", features = ["full"] } num_cpus = "1.13.1" @@ -29,4 +29,4 @@ human-size = "0.4.2" futures = "0.3.28" pwhash = "1.0.0" rand = "0.9.0" -mail-auth = { version = "0.6" } +mail-auth = { version = "0.7" } diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 4f02282a..23df5083 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -12,10 +12,10 @@ trc = { path = "../trc" } directory = { path = "../directory" } jmap_proto = { path = "../jmap-proto" } imap_proto = { path = "../imap-proto" } -sieve-rs = { version = "0.6" } -mail-parser = { version = "0.10", features = ["full_encoding"] } +sieve-rs = { version = "0.7", features = ["rkyv", "serde"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.6" } +mail-auth = { version = "0.7" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } smtp-proto = { version = "0.1", features = ["rkyv"] } dns-update = { version = "0.1" } @@ -37,7 +37,7 @@ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls- serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" base64 = "0.22" -x509-parser = "0.16.0" +x509-parser = "0.17.0" pem = "3.0" chrono = { version = "0.4", features = ["serde"] } hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } @@ -46,7 +46,7 @@ opentelemetry_sdk = { version = "0.25" } opentelemetry-otlp = { version = "0.25", features = ["http-proto", "reqwest-client"] } opentelemetry-semantic-conventions = { version = "0.25.0" } prometheus = { version = "0.13.4", default-features = false } -imagesize = "0.13" +imagesize = "0.14" sha1 = "0.10" sha2 = "0.10.6" md5 = "0.7.0" @@ -54,8 +54,8 @@ whatlang = "0.16" idna = "1.0" decancer = "3.0.1" unicode-security = "0.1.0" -infer = "0.16" -bincode = "1.3.1" +infer = "0.19" +bincode = { version = "2.0", features = ["serde"] } hostname = "0.4.0" zip = "2.1" pwhash = "1.0.0" diff --git a/crates/common/src/auth/mod.rs b/crates/common/src/auth/mod.rs index 6db82787..ec7297f2 100644 --- a/crates/common/src/auth/mod.rs +++ b/crates/common/src/auth/mod.rs @@ -6,7 +6,6 @@ use std::{net::IpAddr, sync::Arc}; - use directory::{ Directory, Permission, Permissions, Principal, QueryBy, core::secret::verify_secret_hash, }; diff --git a/crates/common/src/auth/oauth/introspect.rs b/crates/common/src/auth/oauth/introspect.rs index ab81eb57..d31d314e 100644 --- a/crates/common/src/auth/oauth/introspect.rs +++ b/crates/common/src/auth/oauth/introspect.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use serde::{Deserialize, Serialize}; use trc::{AddContext, AuthEvent, EventType}; diff --git a/crates/common/src/auth/oauth/registration.rs b/crates/common/src/auth/oauth/registration.rs index 6a0b0adf..2408aba5 100644 --- a/crates/common/src/auth/oauth/registration.rs +++ b/crates/common/src/auth/oauth/registration.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/crates/common/src/auth/oauth/token.rs b/crates/common/src/auth/oauth/token.rs index 0f33c9e3..3fea0135 100644 --- a/crates/common/src/auth/oauth/token.rs +++ b/crates/common/src/auth/oauth/token.rs @@ -6,7 +6,6 @@ use std::time::SystemTime; - use directory::QueryBy; use mail_builder::encoders::base64::base64_encode; use mail_parser::decoders::base64::base64_decode; diff --git a/crates/common/src/config/smtp/resolver.rs b/crates/common/src/config/smtp/resolver.rs index 4524e66b..463d9ea8 100644 --- a/crates/common/src/config/smtp/resolver.rs +++ b/crates/common/src/config/smtp/resolver.rs @@ -14,8 +14,10 @@ use std::{ use mail_auth::{ MessageAuthenticator, hickory_resolver::{ - AsyncResolver, TokioAsyncResolver, - config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}, + TokioResolver, + config::{NameServerConfig, ResolverConfig, ResolverOpts}, + name_server::TokioConnectionProvider, + proto::xfer::Protocol, system_conf::read_system_conf, }, }; @@ -34,7 +36,7 @@ pub struct Resolvers { #[derive(Clone)] pub struct DnssecResolver { - pub resolver: TokioAsyncResolver, + pub resolver: TokioResolver, } #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] @@ -230,7 +232,12 @@ impl Resolvers { Resolvers { dns: MessageAuthenticator::new(resolver_config, opts).unwrap(), dnssec: DnssecResolver { - resolver: AsyncResolver::tokio(config_dnssec, opts_dnssec), + resolver: TokioResolver::builder_with_config( + config_dnssec, + TokioConnectionProvider::default(), + ) + .with_options(opts_dnssec) + .build(), }, } } @@ -355,7 +362,12 @@ impl Default for Resolvers { Self { dns: MessageAuthenticator::new(config, opts).expect("Failed to build DNS resolver"), dnssec: DnssecResolver { - resolver: AsyncResolver::tokio(config_dnssec, opts_dnssec), + resolver: TokioResolver::builder_with_config( + config_dnssec, + TokioConnectionProvider::default(), + ) + .with_options(opts_dnssec) + .build(), }, } } diff --git a/crates/common/src/scripts/functions/header.rs b/crates/common/src/scripts/functions/header.rs index e6da15a8..cfe5713d 100644 --- a/crates/common/src/scripts/functions/header.rs +++ b/crates/common/src/scripts/functions/header.rs @@ -75,7 +75,7 @@ pub fn fn_is_header_utf8_valid<'x>(ctx: &'x Context<'x>, v: Vec) -> Va for header in &p.headers { if header.name == header_name && raw - .get(header.offset_start()..header.offset_end()) + .get(header.offset_start() as usize..header.offset_end() as usize) .and_then(|raw| std::str::from_utf8(raw).ok()) .is_none() { @@ -85,7 +85,7 @@ pub fn fn_is_header_utf8_valid<'x>(ctx: &'x Context<'x>, v: Vec) -> Va } } else { is_valid = raw - .get(p.raw_header_offset()..p.raw_body_offset()) + .get(p.raw_header_offset() as usize..p.raw_body_offset() as usize) .and_then(|raw| std::str::from_utf8(raw).ok()) .is_some(); } diff --git a/crates/common/src/scripts/mod.rs b/crates/common/src/scripts/mod.rs index 60602e12..a7fed493 100644 --- a/crates/common/src/scripts/mod.rs +++ b/crates/common/src/scripts/mod.rs @@ -6,7 +6,6 @@ use std::sync::Arc; - use sieve::{Envelope, runtime::Variable}; use store::Value; use unicode_security::mixed_script::AugmentedScriptSet; diff --git a/crates/common/src/scripts/plugins/lookup.rs b/crates/common/src/scripts/plugins/lookup.rs index 7abd2d72..a8003e55 100644 --- a/crates/common/src/scripts/plugins/lookup.rs +++ b/crates/common/src/scripts/plugins/lookup.rs @@ -4,13 +4,11 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use super::PluginContext; +use crate::scripts::into_sieve_value; use sieve::{FunctionMap, runtime::Variable}; use store::{Deserialize, Value, dispatch::lookup::KeyValue}; -use crate::scripts::into_sieve_value; - -use super::PluginContext; - pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) { fnc_map.set_external_function("key_exists", plugin_id, 2); } @@ -88,7 +86,8 @@ pub async fn exec_set(ctx: PluginContext<'_>) -> trc::Result { KeyValue::new( ctx.arguments[1].to_string().into_owned().into_bytes(), if !ctx.arguments[2].is_empty() { - bincode::serialize(&ctx.arguments[2]).unwrap_or_default() + bincode::serde::encode_to_vec(&ctx.arguments[2], bincode::config::standard()) + .unwrap_or_default() } else { vec![] }, @@ -128,9 +127,11 @@ pub struct VariableWrapper(Variable); impl Deserialize for VariableWrapper { fn deserialize(bytes: &[u8]) -> trc::Result { Ok(VariableWrapper( - bincode::deserialize::(bytes).unwrap_or_else(|_| { - Variable::String(String::from_utf8_lossy(bytes).into_owned().into()) - }), + bincode::serde::decode_from_slice::(bytes, bincode::config::standard()) + .map(|v| v.0) + .unwrap_or_else(|_| { + Variable::String(String::from_utf8_lossy(bytes).into_owned().into()) + }), )) } } diff --git a/crates/dav-proto/Cargo.toml b/crates/dav-proto/Cargo.toml index f6169858..91275a14 100644 --- a/crates/dav-proto/Cargo.toml +++ b/crates/dav-proto/Cargo.toml @@ -8,7 +8,7 @@ trc = { path = "../trc" } hashify = "0.2.6" quick-xml = "0.37.2" calcard = { path = "/Users/me/code/calcard", features = ["rkyv"] } -mail-parser = "0.10.2" +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } hyper = "1.6.0" rkyv = { version = "0.8.10", features = ["little_endian"] } chrono = { version = "0.4.40", features = ["serde"], optional = true } diff --git a/crates/dav-proto/src/parser/property.rs b/crates/dav-proto/src/parser/property.rs index d00ec135..8c19b472 100644 --- a/crates/dav-proto/src/parser/property.rs +++ b/crates/dav-proto/src/parser/property.rs @@ -105,7 +105,7 @@ impl Tokenizer<'_> { }, .. } => { - if let Some(component) = components.last().copied() { + if let Some(component) = components.last().cloned() { data.properties.push(CalDavPropertyName { component: Some(component), name: None, @@ -155,7 +155,7 @@ impl Tokenizer<'_> { if let Some(name) = name { data.properties.push(CalDavPropertyName { - component: components.last().copied(), + component: components.last().cloned(), name: Some(name), no_value, }); diff --git a/crates/dav-proto/src/requests/report.rs b/crates/dav-proto/src/requests/report.rs index f09133d6..a867fb50 100644 --- a/crates/dav-proto/src/requests/report.rs +++ b/crates/dav-proto/src/requests/report.rs @@ -172,7 +172,7 @@ impl DavParser for CalendarQuery { } => { stream.expect_element_end()?; if let Some(filter) = Filter::from_parts( - components.iter().map(|(c, _)| *c).collect(), + components.iter().map(|(c, _)| c.clone()).collect(), property.clone(), parameter.clone(), FilterOp::Undefined, @@ -187,7 +187,7 @@ impl DavParser for CalendarQuery { let mut tm = TextMatch::parse(raw)?; tm.value = stream.collect_string_value()?.unwrap_or_default(); if let Some(filter) = Filter::from_parts( - components.iter().map(|(c, _)| *c).collect(), + components.iter().map(|(c, _)| c.clone()).collect(), property.clone(), parameter.clone(), FilterOp::TextMatch(tm), @@ -203,7 +203,7 @@ impl DavParser for CalendarQuery { stream.expect_element_end()?; if let Some(filter) = range.and_then(|range| { Filter::from_parts( - components.iter().map(|(c, _)| *c).collect(), + components.iter().map(|(c, _)| c.clone()).collect(), property.clone(), parameter.clone(), FilterOp::TimeRange(range), @@ -228,7 +228,7 @@ impl DavParser for CalendarQuery { .is_none_or(|c| c.len() < components.len()) { cq.filters.push(Filter::Component { - comp: components.iter().map(|(c, _)| *c).collect(), + comp: components.iter().map(|(c, _)| c.clone()).collect(), op: FilterOp::Exists, }); } diff --git a/crates/dav/src/calendar/query.rs b/crates/dav/src/calendar/query.rs index addf2464..137cb64a 100644 --- a/crates/dav/src/calendar/query.rs +++ b/crates/dav/src/calendar/query.rs @@ -618,15 +618,12 @@ fn find_components<'x>( comp: &[ICalendarComponentType], ) -> impl Iterator { // TODO: Properly expand the component type path - let comp = comp - .last() - .copied() - .unwrap_or(ICalendarComponentType::VCalendar); + let comp = comp.last().unwrap_or(&ICalendarComponentType::VCalendar); ical.components .iter() .enumerate() .filter(move |(_, entry)| { - comp == ICalendarComponentType::VCalendar || entry.component_type == comp + comp == &ICalendarComponentType::VCalendar || &entry.component_type == comp }) } diff --git a/crates/dav/src/request.rs b/crates/dav/src/request.rs index 013a3146..52935001 100644 --- a/crates/dav/src/request.rs +++ b/crates/dav/src/request.rs @@ -550,7 +550,7 @@ impl DavRequestHandler for Server { //let c = println!("------------------------------------------"); - let std_body = std::str::from_utf8(&body).unwrap_or("[binary]").to_string(); + //let std_body = std::str::from_utf8(&body).unwrap_or("[binary]").to_string(); // Parse headers let mut headers = RequestHeaders::new(request.uri().path()); diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml index 81aa38d3..34821f28 100644 --- a/crates/directory/Cargo.toml +++ b/crates/directory/Cargo.toml @@ -12,7 +12,7 @@ trc = { path = "../trc" } nlp = { path = "../nlp" } jmap_proto = { path = "../jmap-proto" } smtp-proto = { version = "0.1" } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } mail-builder = { version = "0.4" } tokio = { version = "1.23", features = ["net"] } diff --git a/crates/directory/src/backend/imap/lookup.rs b/crates/directory/src/backend/imap/lookup.rs index 1806246a..658c70aa 100644 --- a/crates/directory/src/backend/imap/lookup.rs +++ b/crates/directory/src/backend/imap/lookup.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use mail_send::Credentials; use smtp_proto::{AUTH_CRAM_MD5, AUTH_LOGIN, AUTH_OAUTHBEARER, AUTH_PLAIN, AUTH_XOAUTH2}; diff --git a/crates/directory/src/backend/memory/config.rs b/crates/directory/src/backend/memory/config.rs index a6aac415..e9a3ac9c 100644 --- a/crates/directory/src/backend/memory/config.rs +++ b/crates/directory/src/backend/memory/config.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use store::Store; use utils::config::{Config, utils::AsKey}; @@ -117,9 +116,7 @@ impl MemoryDirectory { directory.domains.insert(domain.to_lowercase()); } - principal - .emails - .push(email.to_lowercase()); + principal.emails.push(email.to_lowercase()); } // Parse mailing lists diff --git a/crates/directory/src/backend/mod.rs b/crates/directory/src/backend/mod.rs index 939a5148..2058580a 100644 --- a/crates/directory/src/backend/mod.rs +++ b/crates/directory/src/backend/mod.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - pub mod imap; pub mod internal; pub mod ldap; diff --git a/crates/directory/src/backend/smtp/lookup.rs b/crates/directory/src/backend/smtp/lookup.rs index d4fbd7b4..47be10fd 100644 --- a/crates/directory/src/backend/smtp/lookup.rs +++ b/crates/directory/src/backend/smtp/lookup.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use mail_send::{Credentials, smtp::AssertReply}; use smtp_proto::Severity; diff --git a/crates/directory/src/backend/sql/lookup.rs b/crates/directory/src/backend/sql/lookup.rs index 24ebd7bf..83c39432 100644 --- a/crates/directory/src/backend/sql/lookup.rs +++ b/crates/directory/src/backend/sql/lookup.rs @@ -296,9 +296,7 @@ impl SqlMappings { } } else if name.eq_ignore_ascii_case(&self.column_email) { if let Value::Text(text) = value { - principal - .emails - .push(text.to_lowercase()); + principal.emails.push(text.to_lowercase()); } } else if name.eq_ignore_ascii_case(&self.column_quota) { if let Value::Integer(quota) = value { diff --git a/crates/directory/src/core/dispatch.rs b/crates/directory/src/core/dispatch.rs index 5343726e..60bc81dc 100644 --- a/crates/directory/src/core/dispatch.rs +++ b/crates/directory/src/core/dispatch.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use trc::AddContext; use crate::{ diff --git a/crates/email/Cargo.toml b/crates/email/Cargo.toml index 15519ab8..0928c623 100644 --- a/crates/email/Cargo.toml +++ b/crates/email/Cargo.toml @@ -14,13 +14,12 @@ common = { path = "../common" } directory = { path = "../directory" } spam-filter = { path = "../spam-filter" } smtp-proto = { version = "0.1", features = ["rkyv"] } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -sieve-rs = { version = "0.6" } +sieve-rs = { version = "0.7", features = ["rkyv"] } tokio = { version = "1.23", features = ["net", "macros"] } serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" -bincode = "1.3.3" aes = "0.8.3" aes-gcm = "0.10.1" aes-gcm-siv = "0.11.1" @@ -30,7 +29,7 @@ rasn-cms = "0.10" rasn-pkix = "0.10" rsa = "0.9.2" rand = "0.8" -sequoia-openpgp = { version = "1.16", default-features = false, features = ["crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] } +sequoia-openpgp = { version = "2.0", default-features = false, features = ["crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] } hashify = "0.2" rkyv = { version = "0.8.10", features = ["little_endian"] } compact_str = "0.9.0" diff --git a/crates/email/src/identity/mod.rs b/crates/email/src/identity/mod.rs index 00843e89..524e5cc6 100644 --- a/crates/email/src/identity/mod.rs +++ b/crates/email/src/identity/mod.rs @@ -6,7 +6,6 @@ pub mod index; - use store::{SERIALIZE_IDENTITY_V1, SerializedVersion}; #[derive( diff --git a/crates/email/src/message/copy.rs b/crates/email/src/message/copy.rs index b80b860b..24f58cbe 100644 --- a/crates/email/src/message/copy.rs +++ b/crates/email/src/message/copy.rs @@ -16,7 +16,7 @@ use jmap_proto::{ property::Property, }, }; -use mail_parser::parsers::fields::thread::thread_name; +use mail_parser::{HeaderName, HeaderValue, parsers::fields::thread::thread_name}; use store::{ BlobClass, write::{BatchBuilder, TaskQueueClass, ValueClass}, @@ -26,9 +26,9 @@ use trc::AddContext; use crate::{cache::MessageCacheFetch, mailbox::UidMailbox}; use super::{ - index::{MAX_ID_LENGTH, MAX_SORT_FIELD_LENGTH, TrimTextValue}, + index::{MAX_ID_LENGTH, MAX_SORT_FIELD_LENGTH, TrimTextValue, VisitText}, ingest::{EmailIngest, IngestedEmail, ThreadResult}, - metadata::{HeaderName, HeaderValue, MessageData, MessageMetadata}, + metadata::{MessageData, MessageMetadata}, }; pub trait EmailCopy: Sync + Send { diff --git a/crates/email/src/message/crypto.rs b/crates/email/src/message/crypto.rs index 07cb7501..ff63b64d 100644 --- a/crates/email/src/message/crypto.rs +++ b/crates/email/src/message/crypto.rs @@ -140,10 +140,12 @@ impl EncryptMessage for Message<'_> { } else { &mut outer_message }) - .extend_from_slice(&raw_message[header.offset_field()..header.offset_end()]); + .extend_from_slice( + &raw_message[header.offset_field() as usize..header.offset_end() as usize], + ); } inner_message.extend_from_slice(b"\r\n"); - inner_message.extend_from_slice(&raw_message[root.raw_body_offset()..]); + inner_message.extend_from_slice(&raw_message[root.raw_body_offset() as usize..]); // Encrypt inner message match params.method { @@ -226,7 +228,7 @@ impl EncryptMessage for Message<'_> { .map_err(|err| { EncryptMessageError::Error(format!("Failed to create armorer: {}", err)) })?; - let message = stream::Encryptor2::for_recipients(message, keys) + let message = stream::Encryptor::for_recipients(message, keys) .symmetric_algo(match algo { ArchivedAlgorithm::Aes128 => SymmetricAlgorithm::AES128, ArchivedAlgorithm::Aes256 => SymmetricAlgorithm::AES256, diff --git a/crates/email/src/message/index.rs b/crates/email/src/message/index.rs index 0305a5df..4581202d 100644 --- a/crates/email/src/message/index.rs +++ b/crates/email/src/message/index.rs @@ -4,15 +4,19 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use std::borrow::Cow; + use super::metadata::{ - Addr, Address, ArchivedAddress, ArchivedGetHeader, ArchivedHeaderName, ArchivedHeaderValue, ArchivedMessageData, ArchivedMessageMetadata, ArchivedMessageMetadataContents, - ArchivedMessageMetadataPart, ArchivedMetadataPartType, DecodedPartContent, Group, HeaderName, - HeaderValue, MessageData, MessageMetadata, MessageMetadataPart, + ArchivedMessageMetadataPart, ArchivedMetadataPartType, DecodedPartContent, MessageData, + MessageMetadata, MessageMetadataPart, }; use common::storage::index::{IndexValue, IndexableObject, ObjectIndexBuilder}; use jmap_proto::types::{collection::SyncCollection, property::Property}; use mail_parser::{ + Addr, Address, ArchivedAddress, ArchivedHeaderName, ArchivedHeaderValue, Group, HeaderName, + HeaderValue, + core::rkyv::ArchivedGetHeader, decoders::html::html_to_text, parsers::{fields::thread::thread_name, preview::preview_text}, }; @@ -167,9 +171,7 @@ impl MessageMetadata { HeaderName::Date => { if !seen_headers[header.name.id() as usize] { if let HeaderValue::DateTime(datetime) = &header.value { - let value = (mail_parser::DateTime::from(datetime).to_timestamp() - as u64) - .serialize(); + let value = (datetime.to_timestamp() as u64).serialize(); if set { batch.index(Property::SentAt, value); } else { @@ -487,9 +489,10 @@ impl IndexMessage for BatchBuilder { .first() .or_else(|| message.html_body.first()) .copied() - .unwrap_or(usize::MAX); + .unwrap_or(u32::MAX); for (part_id, part) in message.parts.iter().take(MAX_MESSAGE_PARTS).enumerate() { + let part_id = part_id as u32; match &part.body { mail_parser::PartType::Text(text) => { if part_id == preview_part_id { @@ -533,7 +536,7 @@ impl IndexMessage for BatchBuilder { raw_headers: message .raw_message .as_ref() - .get(root_part.offset_header..root_part.offset_body) + .get(root_part.offset_header as usize..root_part.offset_body as usize) .unwrap_or_default() .to_vec(), contents: vec![], @@ -833,8 +836,14 @@ pub enum AddressElement { GroupName, } -impl HeaderValue { - pub fn visit_addresses(&self, mut visitor: impl FnMut(AddressElement, &str)) { +pub trait VisitText { + fn visit_addresses(&self, visitor: impl FnMut(AddressElement, &str)); + fn visit_text<'x>(&'x self, visitor: impl FnMut(&'x str)); + fn into_visit_text(self, visitor: impl FnMut(String)); +} + +impl VisitText for HeaderValue<'_> { + fn visit_addresses(&self, mut visitor: impl FnMut(AddressElement, &str)) { match self { HeaderValue::Address(Address::List(addr_list)) => { for addr in addr_list { @@ -866,7 +875,7 @@ impl HeaderValue { } } - pub fn visit_text<'x>(&'x self, mut visitor: impl FnMut(&'x str)) { + fn visit_text<'x>(&'x self, mut visitor: impl FnMut(&'x str)) { match &self { HeaderValue::Text(text) => { visitor(text.as_ref()); @@ -880,14 +889,14 @@ impl HeaderValue { } } - pub fn into_visit_text(self, mut visitor: impl FnMut(String)) { + fn into_visit_text(self, mut visitor: impl FnMut(String)) { match self { HeaderValue::Text(text) => { - visitor(text); + visitor(text.into_owned()); } HeaderValue::TextList(texts) => { for text in texts { - visitor(text); + visitor(text.into_owned()); } } _ => (), @@ -895,7 +904,12 @@ impl HeaderValue { } } -impl ArchivedHeaderValue { +pub trait VisitTextArchived { + fn visit_addresses(&self, visitor: impl FnMut(AddressElement, &str)); + fn visit_text(&self, visitor: impl FnMut(&str)); +} + +impl VisitTextArchived for ArchivedHeaderValue<'static> { fn visit_addresses(&self, mut visitor: impl FnMut(AddressElement, &str)) { match self { ArchivedHeaderValue::Address(ArchivedAddress::List(addr_list)) => { @@ -947,7 +961,7 @@ pub trait TrimTextValue { fn trim_text(self, length: usize) -> Self; } -impl TrimTextValue for HeaderValue { +impl TrimTextValue for HeaderValue<'_> { fn trim_text(self, length: usize) -> Self { match self { HeaderValue::Address(Address::List(v)) => { @@ -963,7 +977,7 @@ impl TrimTextValue for HeaderValue { } } -impl TrimTextValue for Addr { +impl TrimTextValue for Addr<'_> { fn trim_text(self, length: usize) -> Self { Self { name: self.name.map(|v| v.trim_text(length)), @@ -972,7 +986,7 @@ impl TrimTextValue for Addr { } } -impl TrimTextValue for Group { +impl TrimTextValue for Group<'_> { fn trim_text(self, length: usize) -> Self { Self { name: self.name.map(|v| v.trim_text(length)), @@ -1000,7 +1014,7 @@ impl TrimTextValue for &str { } } -impl TrimTextValue for String { +impl TrimTextValue for Cow<'_, str> { fn trim_text(self, length: usize) -> Self { if self.len() < length { self @@ -1012,7 +1026,7 @@ impl TrimTextValue for String { } result.push(c); } - result + result.into() } } } @@ -1058,71 +1072,3 @@ pub fn property_from_archived_header(header: &ArchivedHeaderName) -> Property { _ => unreachable!(), } } - -pub trait VisitValues<'x> { - fn visit_addresses<'y: 'x>(&'y self, visitor: impl FnMut(AddressElement, &'x str)); - fn visit_text<'y: 'x>(&'y self, visitor: impl FnMut(&'x str)); - fn into_visit_text(self, visitor: impl FnMut(String)); -} - -impl<'x> VisitValues<'x> for mail_parser::HeaderValue<'x> { - fn visit_addresses<'y: 'x>(&'y self, mut visitor: impl FnMut(AddressElement, &'x str)) { - match self { - mail_parser::HeaderValue::Address(mail_parser::Address::List(addr_list)) => { - for addr in addr_list { - if let Some(name) = &addr.name { - visitor(AddressElement::Name, name); - } - if let Some(addr) = &addr.address { - visitor(AddressElement::Address, addr); - } - } - } - mail_parser::HeaderValue::Address(mail_parser::Address::Group(groups)) => { - for group in groups { - if let Some(name) = &group.name { - visitor(AddressElement::GroupName, name); - } - - for addr in &group.addresses { - if let Some(name) = &addr.name { - visitor(AddressElement::Name, name); - } - if let Some(addr) = &addr.address { - visitor(AddressElement::Address, addr); - } - } - } - } - _ => (), - } - } - - fn visit_text<'y: 'x>(&'y self, mut visitor: impl FnMut(&'x str)) { - match &self { - mail_parser::HeaderValue::Text(text) => { - visitor(text.as_ref()); - } - mail_parser::HeaderValue::TextList(texts) => { - for text in texts { - visitor(text.as_ref()); - } - } - _ => (), - } - } - - fn into_visit_text(self, mut visitor: impl FnMut(String)) { - match self { - mail_parser::HeaderValue::Text(text) => { - visitor(text.into_owned()); - } - mail_parser::HeaderValue::TextList(texts) => { - for text in texts { - visitor(text.into_owned()); - } - } - _ => (), - } - } -} diff --git a/crates/email/src/message/ingest.rs b/crates/email/src/message/ingest.rs index 8958ad35..2cb07a23 100644 --- a/crates/email/src/message/ingest.rs +++ b/crates/email/src/message/ingest.rs @@ -13,7 +13,7 @@ use crate::{ mailbox::{INBOX_ID, JUNK_ID, UidMailbox}, message::{ crypto::EncryptionParams, - index::{IndexMessage, MAX_ID_LENGTH, VisitValues}, + index::{IndexMessage, MAX_ID_LENGTH, VisitText}, metadata::MessageData, }, }; @@ -145,7 +145,7 @@ impl EmailIngest for Server { value: HeaderValue::Text(deliver_to.into()), offset_field: 0, offset_start: 13, - offset_end: extra_headers.len(), + offset_end: extra_headers.len() as u32, }); } @@ -238,9 +238,9 @@ impl EmailIngest for Server { [offset_start + 1..extra_headers.len() - 2] .into(), ), - offset_field, - offset_start, - offset_end: extra_headers.len(), + offset_field: offset_field as u32, + offset_start: offset_start as u32, + offset_end: extra_headers.len() as u32, }); } } @@ -376,15 +376,15 @@ impl EmailIngest for Server { if let Some(part) = part_iter.next() { // Increment header offsets for header in part.headers.iter_mut() { - header.offset_field += offset_start; - header.offset_start += offset_start; - header.offset_end += offset_start; + header.offset_field += offset_start as u32; + header.offset_start += offset_start as u32; + header.offset_end += offset_start as u32; } // Adjust part offsets - part.offset_body += offset_start; - part.offset_end += offset_start; - part.offset_header += offset_start; + part.offset_body += offset_start as u32; + part.offset_end += offset_start as u32; + part.offset_header += offset_start as u32; if let PartType::Message(sub_message) = &mut part.body { if sub_message.root_part().offset_header != 0 { diff --git a/crates/email/src/message/metadata.rs b/crates/email/src/message/metadata.rs index da26e356..0efd9579 100644 --- a/crates/email/src/message/metadata.rs +++ b/crates/email/src/message/metadata.rs @@ -4,12 +4,13 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use std::{borrow::Cow, collections::VecDeque, fmt::Display}; - +use crate::mailbox::{ArchivedUidMailbox, UidMailbox}; use common::storage::index::IndexableAndSerializableObject; use jmap_proto::types::keyword::{ArchivedKeyword, Keyword}; use mail_parser::{ - PartType, + ArchivedContentType, ArchivedEncoding, ArchivedHeaderName, ArchivedHeaderValue, DateTime, + Encoding, Header, HeaderName, HeaderValue, PartType, + core::rkyv::ArchivedGetHeader, decoders::{ base64::base64_decode, charsets::map::charset_decoder, quoted_printable::quoted_printable_decode, @@ -17,14 +18,12 @@ use mail_parser::{ }; use rkyv::{ rend::{u16_le, u32_le}, - string::ArchivedString, vec::ArchivedVec, }; +use std::{borrow::Cow, collections::VecDeque}; use store::{SERIALIZE_MSGDATA_V1, SERIALIZE_MSGMETADATA_V1, SerializedVersion}; use utils::BlobHash; -use crate::mailbox::{ArchivedUidMailbox, UidMailbox}; - #[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug)] pub struct MessageData { pub mailboxes: Vec, @@ -68,7 +67,7 @@ pub struct MessageMetadataContents { #[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug)] pub struct MessageMetadataPart { - pub headers: Vec
, + pub headers: Vec>, pub is_encoding_problem: bool, pub body: MetadataPartType, pub encoding: Encoding, @@ -78,14 +77,6 @@ pub struct MessageMetadataPart { pub offset_end: u32, } -#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, Default)] -pub enum Encoding { - #[default] - None = 0, - QuotedPrintable = 1, - Base64 = 2, -} - #[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug)] pub enum MetadataPartType { Text, @@ -96,109 +87,6 @@ pub enum MetadataPartType { Multipart(Vec), } -#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone)] -pub struct Header { - pub name: HeaderName, - pub value: HeaderValue, - pub offset_field: u32, - pub offset_start: u32, - pub offset_end: u32, -} - -#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone)] -pub struct Addr { - pub name: Option, - pub address: Option, -} - -#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone)] -pub struct Group { - pub name: Option, - pub addresses: Vec, -} - -#[derive( - rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone, PartialOrd, Ord, -)] -#[rkyv(derive(PartialEq, Debug))] -pub enum HeaderName { - Subject, - From, - To, - Cc, - Date, - Bcc, - ReplyTo, - Sender, - Comments, - InReplyTo, - Keywords, - Received, - MessageId, - References, - ReturnPath, - MimeVersion, - ContentDescription, - ContentId, - ContentLanguage, - ContentLocation, - ContentTransferEncoding, - ContentType, - ContentDisposition, - ResentTo, - ResentFrom, - ResentBcc, - ResentCc, - ResentSender, - ResentDate, - ResentMessageId, - ListArchive, - ListHelp, - ListId, - ListOwner, - ListPost, - ListSubscribe, - ListUnsubscribe, - Other(String), - DkimSignature, - ArcAuthenticationResults, - ArcMessageSignature, - ArcSeal, -} - -#[derive( - rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone, Default, -)] -pub enum HeaderValue { - Address(Address), - Text(String), - TextList(Vec), - DateTime(CompactDateTime), - ContentType(ContentType), - #[default] - Empty, -} - -#[derive( - rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone, Default, -)] -pub struct CompactDateTime(pub u64); - -#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone)] -pub enum Address { - List(Vec), - Group(Vec), -} - -#[derive( - rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Debug, PartialEq, Eq, Clone, Default, -)] -pub struct ContentType { - pub c_type: String, - pub c_subtype: Option, - pub attributes: Option>, -} - impl MessageMetadataContents { pub fn root_part(&self) -> &MessageMetadataPart { &self.parts[0] @@ -444,7 +332,7 @@ impl MessageMetadata { messages.push_back(message); message_id += 1; - (message_len, MetadataPartType::Message(message_id)) + (message_len as usize, MetadataPartType::Message(message_id)) } PartType::Multipart(parts) => ( 0, @@ -459,47 +347,46 @@ impl MessageMetadata { .map(|hdr| Header { value: if matches!( &hdr.name, - mail_parser::HeaderName::Subject - | mail_parser::HeaderName::From - | mail_parser::HeaderName::To - | mail_parser::HeaderName::Cc - | mail_parser::HeaderName::Date - | mail_parser::HeaderName::Bcc - | mail_parser::HeaderName::ReplyTo - | mail_parser::HeaderName::Sender - | mail_parser::HeaderName::Comments - | mail_parser::HeaderName::InReplyTo - | mail_parser::HeaderName::Keywords - | mail_parser::HeaderName::MessageId - | mail_parser::HeaderName::References - | mail_parser::HeaderName::ResentMessageId - | mail_parser::HeaderName::ContentDescription - | mail_parser::HeaderName::ContentId - | mail_parser::HeaderName::ContentLanguage - | mail_parser::HeaderName::ContentLocation - | mail_parser::HeaderName::ContentTransferEncoding - | mail_parser::HeaderName::ContentType - | mail_parser::HeaderName::ContentDisposition - | mail_parser::HeaderName::ListId + HeaderName::Subject + | HeaderName::From + | HeaderName::To + | HeaderName::Cc + | HeaderName::Date + | HeaderName::Bcc + | HeaderName::ReplyTo + | HeaderName::Sender + | HeaderName::Comments + | HeaderName::InReplyTo + | HeaderName::Keywords + | HeaderName::MessageId + | HeaderName::References + | HeaderName::ResentMessageId + | HeaderName::ContentDescription + | HeaderName::ContentId + | HeaderName::ContentLanguage + | HeaderName::ContentLocation + | HeaderName::ContentTransferEncoding + | HeaderName::ContentType + | HeaderName::ContentDisposition + | HeaderName::ListId ) { - hdr.value + hdr.value.into_owned() } else { - mail_parser::HeaderValue::Empty - } - .into(), - name: hdr.name.into(), - offset_field: hdr.offset_field as u32, - offset_start: hdr.offset_start as u32, - offset_end: hdr.offset_end as u32, + HeaderValue::Empty + }, + name: hdr.name.into_owned(), + offset_field: hdr.offset_field, + offset_start: hdr.offset_start, + offset_end: hdr.offset_end, }) .collect(), is_encoding_problem: part.is_encoding_problem, - encoding: part.encoding.into(), + encoding: part.encoding, body, size: size as u32, - offset_header: part.offset_header as u32, - offset_body: part.offset_body as u32, - offset_end: part.offset_end as u32, + offset_header: part.offset_header, + offset_body: part.offset_body, + offset_end: part.offset_end, }); } self.contents.push(contents); @@ -509,139 +396,6 @@ impl MessageMetadata { } } -impl From for Encoding { - fn from(value: mail_parser::Encoding) -> Self { - match value { - mail_parser::Encoding::None => Encoding::None, - mail_parser::Encoding::QuotedPrintable => Encoding::QuotedPrintable, - mail_parser::Encoding::Base64 => Encoding::Base64, - } - } -} - -impl From> for HeaderName { - fn from(value: mail_parser::HeaderName<'_>) -> Self { - match value { - mail_parser::HeaderName::Subject => HeaderName::Subject, - mail_parser::HeaderName::From => HeaderName::From, - mail_parser::HeaderName::To => HeaderName::To, - mail_parser::HeaderName::Cc => HeaderName::Cc, - mail_parser::HeaderName::Date => HeaderName::Date, - mail_parser::HeaderName::Bcc => HeaderName::Bcc, - mail_parser::HeaderName::ReplyTo => HeaderName::ReplyTo, - mail_parser::HeaderName::Sender => HeaderName::Sender, - mail_parser::HeaderName::Comments => HeaderName::Comments, - mail_parser::HeaderName::InReplyTo => HeaderName::InReplyTo, - mail_parser::HeaderName::Keywords => HeaderName::Keywords, - mail_parser::HeaderName::Received => HeaderName::Received, - mail_parser::HeaderName::MessageId => HeaderName::MessageId, - mail_parser::HeaderName::References => HeaderName::References, - mail_parser::HeaderName::ReturnPath => HeaderName::ReturnPath, - mail_parser::HeaderName::MimeVersion => HeaderName::MimeVersion, - mail_parser::HeaderName::ContentDescription => HeaderName::ContentDescription, - mail_parser::HeaderName::ContentId => HeaderName::ContentId, - mail_parser::HeaderName::ContentLanguage => HeaderName::ContentLanguage, - mail_parser::HeaderName::ContentLocation => HeaderName::ContentLocation, - mail_parser::HeaderName::ContentTransferEncoding => HeaderName::ContentTransferEncoding, - mail_parser::HeaderName::ContentType => HeaderName::ContentType, - mail_parser::HeaderName::ContentDisposition => HeaderName::ContentDisposition, - mail_parser::HeaderName::ResentTo => HeaderName::ResentTo, - mail_parser::HeaderName::ResentFrom => HeaderName::ResentFrom, - mail_parser::HeaderName::ResentBcc => HeaderName::ResentBcc, - mail_parser::HeaderName::ResentCc => HeaderName::ResentCc, - mail_parser::HeaderName::ResentSender => HeaderName::ResentSender, - mail_parser::HeaderName::ResentDate => HeaderName::ResentDate, - mail_parser::HeaderName::ResentMessageId => HeaderName::ResentMessageId, - mail_parser::HeaderName::ListArchive => HeaderName::ListArchive, - mail_parser::HeaderName::ListHelp => HeaderName::ListHelp, - mail_parser::HeaderName::ListId => HeaderName::ListId, - mail_parser::HeaderName::ListOwner => HeaderName::ListOwner, - mail_parser::HeaderName::ListPost => HeaderName::ListPost, - mail_parser::HeaderName::ListSubscribe => HeaderName::ListSubscribe, - mail_parser::HeaderName::ListUnsubscribe => HeaderName::ListUnsubscribe, - mail_parser::HeaderName::Other(other) => HeaderName::Other(other.into_owned()), - mail_parser::HeaderName::DkimSignature => HeaderName::DkimSignature, - mail_parser::HeaderName::ArcAuthenticationResults => { - HeaderName::ArcAuthenticationResults - } - mail_parser::HeaderName::ArcMessageSignature => HeaderName::ArcMessageSignature, - mail_parser::HeaderName::ArcSeal => HeaderName::ArcSeal, - _ => unreachable!(), - } - } -} - -impl From> for HeaderValue { - fn from(value: mail_parser::HeaderValue) -> Self { - match value { - mail_parser::HeaderValue::Address(address) => HeaderValue::Address(address.into()), - mail_parser::HeaderValue::Text(cow) => HeaderValue::Text(cow.into_owned()), - mail_parser::HeaderValue::TextList(cows) => { - HeaderValue::TextList(cows.into_iter().map(|cow| cow.into_owned()).collect()) - } - mail_parser::HeaderValue::DateTime(date_time) => { - HeaderValue::DateTime(date_time.into()) - } - mail_parser::HeaderValue::ContentType(content_type) => { - HeaderValue::ContentType(content_type.into()) - } - mail_parser::HeaderValue::Received(_) | mail_parser::HeaderValue::Empty => { - HeaderValue::Empty - } - } - } -} - -impl From> for ContentType { - fn from(value: mail_parser::ContentType<'_>) -> Self { - ContentType { - c_type: value.c_type.into_owned(), - c_subtype: value.c_subtype.map(|cow| cow.into_owned()), - attributes: value.attributes.map(|attrs| { - attrs - .into_iter() - .map(|(k, v)| (k.into_owned(), v.into_owned())) - .collect() - }), - } - } -} - -impl From> for Address { - fn from(value: mail_parser::Address<'_>) -> Self { - match value { - mail_parser::Address::List(addrs) => { - Address::List(addrs.into_iter().map(|addr| addr.into()).collect()) - } - mail_parser::Address::Group(groups) => { - Address::Group(groups.into_iter().map(|group| group.into()).collect()) - } - } - } -} - -impl From> for Addr { - fn from(value: mail_parser::Addr<'_>) -> Self { - Addr { - name: value.name.map(|cow| cow.into_owned()), - address: value.address.map(|cow| cow.into_owned()), - } - } -} - -impl From> for Group { - fn from(value: mail_parser::Group<'_>) -> Self { - Group { - name: value.name.map(|cow| cow.into_owned()), - addresses: value - .addresses - .into_iter() - .map(|addr| addr.into()) - .collect(), - } - } -} - impl ArchivedMessageMetadataPart { pub fn is_message(&self) -> bool { matches!(self.body, ArchivedMetadataPartType::Message(_)) @@ -661,8 +415,8 @@ impl ArchivedMessageMetadataPart { pub fn header_values( &self, - name: ArchivedHeaderName, - ) -> impl Iterator + Sync + Send { + name: ArchivedHeaderName<'static>, + ) -> impl Iterator> + Sync + Send { self.headers.iter().filter_map(move |header| { if header.name == name { Some(&header.value) @@ -678,10 +432,11 @@ impl ArchivedMessageMetadataPart { .and_then(|header| header.as_text()) } - pub fn date(&self) -> Option { + pub fn date(&self) -> Option { self.headers .header_value(&ArchivedHeaderName::Date) .and_then(|header| header.as_datetime()) + .map(|dt| dt.into()) } pub fn message_id(&self) -> Option<&str> { @@ -690,7 +445,7 @@ impl ArchivedMessageMetadataPart { .and_then(|header| header.as_text()) } - pub fn in_reply_to(&self) -> &ArchivedHeaderValue { + pub fn in_reply_to(&self) -> &ArchivedHeaderValue<'static> { self.headers .header_value(&ArchivedHeaderName::InReplyTo) .unwrap_or(&ArchivedHeaderValue::Empty) @@ -702,7 +457,7 @@ impl ArchivedMessageMetadataPart { .and_then(|header| header.as_text()) } - pub fn content_disposition(&self) -> Option<&ArchivedContentType> { + pub fn content_disposition(&self) -> Option<&ArchivedContentType<'static>> { self.headers .header_value(&ArchivedHeaderName::ContentDisposition) .and_then(|header| header.as_content_type()) @@ -720,13 +475,13 @@ impl ArchivedMessageMetadataPart { .and_then(|header| header.as_text()) } - pub fn content_type(&self) -> Option<&ArchivedContentType> { + pub fn content_type(&self) -> Option<&ArchivedContentType<'static>> { self.headers .header_value(&ArchivedHeaderName::ContentType) .and_then(|header| header.as_content_type()) } - pub fn content_language(&self) -> &ArchivedHeaderValue { + pub fn content_language(&self) -> &ArchivedHeaderValue<'static> { self.headers .header_value(&ArchivedHeaderName::ContentLanguage) .unwrap_or(&ArchivedHeaderValue::Empty) @@ -745,509 +500,12 @@ impl ArchivedMessageMetadataPart { } } -pub trait GetHeader { - fn header_value(&self, name: &HeaderName) -> Option<&HeaderValue>; - fn header(&self, name: impl Into) -> Option<&Header>; -} - -impl GetHeader for Vec
{ - fn header_value(&self, name: &HeaderName) -> Option<&HeaderValue> { - self.iter() - .rev() - .find(|header| &header.name == name) - .map(|header| &header.value) - } - - fn header(&self, name: impl Into) -> Option<&Header> { - let name = name.into(); - self.iter().rev().find(|header| header.name == name) - } -} - -pub trait ArchivedGetHeader { - fn header_value(&self, name: &ArchivedHeaderName) -> Option<&ArchivedHeaderValue>; - fn header(&self, name: impl Into) -> Option<&ArchivedHeader>; - fn convert_header( - &self, - header_name: &ArchivedHeaderName, - ) -> Option>; -} - -impl ArchivedGetHeader for ArchivedVec { - fn header_value(&self, name: &ArchivedHeaderName) -> Option<&ArchivedHeaderValue> { - self.iter() - .rev() - .find(|header| &header.name == name) - .map(|header| &header.value) - } - - fn header(&self, name: impl Into) -> Option<&ArchivedHeader> { - let name = name.into(); - self.iter().rev().find(|header| header.name == name) - } - - fn convert_header( - &self, - header_name: &ArchivedHeaderName, - ) -> Option> { - for header in self.iter().rev() { - if header.name == *header_name { - return Some(mail_parser::HeaderValue::from(&header.value)); - } - } - None - } -} - -impl HeaderValue { - pub fn as_text(&self) -> Option<&str> { - match *self { - HeaderValue::Text(ref s) => Some(s), - HeaderValue::TextList(ref l) => l.last().map(|s| s.as_str()), - _ => None, - } - } - - pub fn as_content_type(&self) -> Option<&ContentType> { - match *self { - HeaderValue::ContentType(ref c) => Some(c), - _ => None, - } - } -} - -impl ArchivedHeaderValue { - pub fn as_text(&self) -> Option<&str> { - match *self { - ArchivedHeaderValue::Text(ref s) => Some(s), - ArchivedHeaderValue::TextList(ref l) => l.last().map(|s| s.as_str()), - _ => None, - } - } - - pub fn as_content_type(&self) -> Option<&ArchivedContentType> { - match *self { - ArchivedHeaderValue::ContentType(ref c) => Some(c), - _ => None, - } - } - - pub fn as_text_list(&self) -> Option<&[ArchivedString]> { - match *self { - ArchivedHeaderValue::Text(ref s) => Some(std::slice::from_ref(s)), - ArchivedHeaderValue::TextList(ref l) => Some(l.as_slice()), - _ => None, - } - } - - pub fn as_datetime(&self) -> Option { - match self { - ArchivedHeaderValue::DateTime(d) => Some(d.into()), - _ => None, - } - } -} - -impl HeaderName { - pub fn id(&self) -> u8 { - match self { - HeaderName::Subject => 0, - HeaderName::From => 1, - HeaderName::To => 2, - HeaderName::Cc => 3, - HeaderName::Date => 4, - HeaderName::Bcc => 5, - HeaderName::ReplyTo => 6, - HeaderName::Sender => 7, - HeaderName::Comments => 8, - HeaderName::InReplyTo => 9, - HeaderName::Keywords => 10, - HeaderName::Received => 11, - HeaderName::MessageId => 12, - HeaderName::References => 13, - HeaderName::ReturnPath => 14, - HeaderName::MimeVersion => 15, - HeaderName::ContentDescription => 16, - HeaderName::ContentId => 17, - HeaderName::ContentLanguage => 18, - HeaderName::ContentLocation => 19, - HeaderName::ContentTransferEncoding => 20, - HeaderName::ContentType => 21, - HeaderName::ContentDisposition => 22, - HeaderName::ResentTo => 23, - HeaderName::ResentFrom => 24, - HeaderName::ResentBcc => 25, - HeaderName::ResentCc => 26, - HeaderName::ResentSender => 27, - HeaderName::ResentDate => 28, - HeaderName::ResentMessageId => 29, - HeaderName::ListArchive => 30, - HeaderName::ListHelp => 31, - HeaderName::ListId => 32, - HeaderName::ListOwner => 33, - HeaderName::ListPost => 34, - HeaderName::ListSubscribe => 35, - HeaderName::ListUnsubscribe => 36, - HeaderName::Other(_) => 37, - HeaderName::ArcAuthenticationResults => 38, - HeaderName::ArcMessageSignature => 39, - HeaderName::ArcSeal => 40, - HeaderName::DkimSignature => 41, - } - } -} - -impl ArchivedHeaderName { - pub fn id(&self) -> u8 { - match self { - ArchivedHeaderName::Subject => 0, - ArchivedHeaderName::From => 1, - ArchivedHeaderName::To => 2, - ArchivedHeaderName::Cc => 3, - ArchivedHeaderName::Date => 4, - ArchivedHeaderName::Bcc => 5, - ArchivedHeaderName::ReplyTo => 6, - ArchivedHeaderName::Sender => 7, - ArchivedHeaderName::Comments => 8, - ArchivedHeaderName::InReplyTo => 9, - ArchivedHeaderName::Keywords => 10, - ArchivedHeaderName::Received => 11, - ArchivedHeaderName::MessageId => 12, - ArchivedHeaderName::References => 13, - ArchivedHeaderName::ReturnPath => 14, - ArchivedHeaderName::MimeVersion => 15, - ArchivedHeaderName::ContentDescription => 16, - ArchivedHeaderName::ContentId => 17, - ArchivedHeaderName::ContentLanguage => 18, - ArchivedHeaderName::ContentLocation => 19, - ArchivedHeaderName::ContentTransferEncoding => 20, - ArchivedHeaderName::ContentType => 21, - ArchivedHeaderName::ContentDisposition => 22, - ArchivedHeaderName::ResentTo => 23, - ArchivedHeaderName::ResentFrom => 24, - ArchivedHeaderName::ResentBcc => 25, - ArchivedHeaderName::ResentCc => 26, - ArchivedHeaderName::ResentSender => 27, - ArchivedHeaderName::ResentDate => 28, - ArchivedHeaderName::ResentMessageId => 29, - ArchivedHeaderName::ListArchive => 30, - ArchivedHeaderName::ListHelp => 31, - ArchivedHeaderName::ListId => 32, - ArchivedHeaderName::ListOwner => 33, - ArchivedHeaderName::ListPost => 34, - ArchivedHeaderName::ListSubscribe => 35, - ArchivedHeaderName::ListUnsubscribe => 36, - ArchivedHeaderName::Other(_) => 37, - ArchivedHeaderName::ArcAuthenticationResults => 38, - ArchivedHeaderName::ArcMessageSignature => 39, - ArchivedHeaderName::ArcSeal => 40, - ArchivedHeaderName::DkimSignature => 41, - } - } - - pub fn as_str(&self) -> &str { - match self { - ArchivedHeaderName::Subject => "Subject", - ArchivedHeaderName::From => "From", - ArchivedHeaderName::To => "To", - ArchivedHeaderName::Cc => "Cc", - ArchivedHeaderName::Date => "Date", - ArchivedHeaderName::Bcc => "Bcc", - ArchivedHeaderName::ReplyTo => "Reply-To", - ArchivedHeaderName::Sender => "Sender", - ArchivedHeaderName::Comments => "Comments", - ArchivedHeaderName::InReplyTo => "In-Reply-To", - ArchivedHeaderName::Keywords => "Keywords", - ArchivedHeaderName::Received => "Received", - ArchivedHeaderName::MessageId => "Message-ID", - ArchivedHeaderName::References => "References", - ArchivedHeaderName::ReturnPath => "Return-Path", - ArchivedHeaderName::MimeVersion => "MIME-Version", - ArchivedHeaderName::ContentDescription => "Content-Description", - ArchivedHeaderName::ContentId => "Content-ID", - ArchivedHeaderName::ContentLanguage => "Content-Language", - ArchivedHeaderName::ContentLocation => "Content-Location", - ArchivedHeaderName::ContentTransferEncoding => "Content-Transfer-Encoding", - ArchivedHeaderName::ContentType => "Content-Type", - ArchivedHeaderName::ContentDisposition => "Content-Disposition", - ArchivedHeaderName::ResentTo => "Resent-To", - ArchivedHeaderName::ResentFrom => "Resent-From", - ArchivedHeaderName::ResentBcc => "Resent-Bcc", - ArchivedHeaderName::ResentCc => "Resent-Cc", - ArchivedHeaderName::ResentSender => "Resent-Sender", - ArchivedHeaderName::ResentDate => "Resent-Date", - ArchivedHeaderName::ResentMessageId => "Resent-Message-ID", - ArchivedHeaderName::ListArchive => "List-Archive", - ArchivedHeaderName::ListHelp => "List-Help", - ArchivedHeaderName::ListId => "List-ID", - ArchivedHeaderName::ListOwner => "List-Owner", - ArchivedHeaderName::ListPost => "List-Post", - ArchivedHeaderName::ListSubscribe => "List-Subscribe", - ArchivedHeaderName::ListUnsubscribe => "List-Unsubscribe", - ArchivedHeaderName::ArcAuthenticationResults => "ARC-Authentication-Results", - ArchivedHeaderName::ArcMessageSignature => "ARC-Message-Signature", - ArchivedHeaderName::ArcSeal => "ARC-Seal", - ArchivedHeaderName::DkimSignature => "DKIM-Signature", - ArchivedHeaderName::Other(v) => v.as_str(), - } - } - - pub fn is_mime_header(&self) -> bool { - matches!( - self, - ArchivedHeaderName::ContentDescription - | ArchivedHeaderName::ContentId - | ArchivedHeaderName::ContentLanguage - | ArchivedHeaderName::ContentLocation - | ArchivedHeaderName::ContentTransferEncoding - | ArchivedHeaderName::ContentType - | ArchivedHeaderName::ContentDisposition - ) - } -} - -impl Display for ArchivedHeaderName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.as_str()) - } -} - -impl ArchivedContentType { - pub fn ctype(&self) -> &str { - &self.c_type - } - - pub fn subtype(&self) -> Option<&str> { - self.c_subtype.as_deref() - } - - pub fn attribute(&self, name: &str) -> Option<&str> { - self.attributes - .as_ref()? - .iter() - .find(|k| k.0 == name)? - .1 - .as_ref() - .into() - } -} - impl ArchivedMessageMetadataContents { pub fn root_part(&self) -> &ArchivedMessageMetadataPart { &self.parts[0] } } -impl ArchivedAddress { - pub fn iter(&self) -> Box + '_ + Sync + Send> { - match self { - ArchivedAddress::List(list) => Box::new(list.iter()), - ArchivedAddress::Group(group) => { - Box::new(group.iter().flat_map(|group| group.addresses.iter())) - } - } - } -} - -impl ArchivedAddr { - pub fn name(&self) -> Option<&str> { - self.name.as_deref() - } - - pub fn address(&self) -> Option<&str> { - self.address.as_deref() - } -} - -impl From<&ArchivedHeaderName> for mail_parser::HeaderName<'static> { - fn from(value: &ArchivedHeaderName) -> Self { - match value { - ArchivedHeaderName::Subject => mail_parser::HeaderName::Subject, - ArchivedHeaderName::From => mail_parser::HeaderName::From, - ArchivedHeaderName::To => mail_parser::HeaderName::To, - ArchivedHeaderName::Cc => mail_parser::HeaderName::Cc, - ArchivedHeaderName::Date => mail_parser::HeaderName::Date, - ArchivedHeaderName::Bcc => mail_parser::HeaderName::Bcc, - ArchivedHeaderName::ReplyTo => mail_parser::HeaderName::ReplyTo, - ArchivedHeaderName::Sender => mail_parser::HeaderName::Sender, - ArchivedHeaderName::Comments => mail_parser::HeaderName::Comments, - ArchivedHeaderName::InReplyTo => mail_parser::HeaderName::InReplyTo, - ArchivedHeaderName::Keywords => mail_parser::HeaderName::Keywords, - ArchivedHeaderName::Received => mail_parser::HeaderName::Received, - ArchivedHeaderName::MessageId => mail_parser::HeaderName::MessageId, - ArchivedHeaderName::References => mail_parser::HeaderName::References, - ArchivedHeaderName::ReturnPath => mail_parser::HeaderName::ReturnPath, - ArchivedHeaderName::MimeVersion => mail_parser::HeaderName::MimeVersion, - ArchivedHeaderName::ContentDescription => mail_parser::HeaderName::ContentDescription, - ArchivedHeaderName::ContentId => mail_parser::HeaderName::ContentId, - ArchivedHeaderName::ContentLanguage => mail_parser::HeaderName::ContentLanguage, - ArchivedHeaderName::ContentLocation => mail_parser::HeaderName::ContentLocation, - ArchivedHeaderName::ContentTransferEncoding => { - mail_parser::HeaderName::ContentTransferEncoding - } - ArchivedHeaderName::ContentType => mail_parser::HeaderName::ContentType, - ArchivedHeaderName::ContentDisposition => mail_parser::HeaderName::ContentDisposition, - ArchivedHeaderName::ResentTo => mail_parser::HeaderName::ResentTo, - ArchivedHeaderName::ResentFrom => mail_parser::HeaderName::ResentFrom, - ArchivedHeaderName::ResentBcc => mail_parser::HeaderName::ResentBcc, - ArchivedHeaderName::ResentCc => mail_parser::HeaderName::ResentCc, - ArchivedHeaderName::ResentSender => mail_parser::HeaderName::ResentSender, - ArchivedHeaderName::ResentDate => mail_parser::HeaderName::ResentDate, - ArchivedHeaderName::ResentMessageId => mail_parser::HeaderName::ResentMessageId, - ArchivedHeaderName::ListArchive => mail_parser::HeaderName::ListArchive, - ArchivedHeaderName::ListHelp => mail_parser::HeaderName::ListHelp, - ArchivedHeaderName::ListId => mail_parser::HeaderName::ListId, - ArchivedHeaderName::ListOwner => mail_parser::HeaderName::ListOwner, - ArchivedHeaderName::ListPost => mail_parser::HeaderName::ListPost, - ArchivedHeaderName::ListSubscribe => mail_parser::HeaderName::ListSubscribe, - ArchivedHeaderName::ListUnsubscribe => mail_parser::HeaderName::ListUnsubscribe, - ArchivedHeaderName::Other(other) => { - mail_parser::HeaderName::Other(other.to_string().into()) - } - ArchivedHeaderName::ArcAuthenticationResults => { - mail_parser::HeaderName::ArcAuthenticationResults - } - ArchivedHeaderName::ArcMessageSignature => mail_parser::HeaderName::ArcMessageSignature, - ArchivedHeaderName::ArcSeal => mail_parser::HeaderName::ArcSeal, - ArchivedHeaderName::DkimSignature => mail_parser::HeaderName::DkimSignature, - } - } -} - -impl From<&ArchivedHeaderValue> for mail_parser::HeaderValue<'static> { - fn from(value: &ArchivedHeaderValue) -> Self { - match value { - ArchivedHeaderValue::Text(s) => mail_parser::HeaderValue::Text(s.to_string().into()), - ArchivedHeaderValue::TextList(list) => mail_parser::HeaderValue::TextList( - list.iter().map(|s| s.to_string().into()).collect(), - ), - ArchivedHeaderValue::DateTime(d) => mail_parser::HeaderValue::DateTime(d.into()), - ArchivedHeaderValue::ContentType(ct) => { - mail_parser::HeaderValue::ContentType(ct.into()) - } - ArchivedHeaderValue::Empty => mail_parser::HeaderValue::Empty, - ArchivedHeaderValue::Address(a) => mail_parser::HeaderValue::Address(a.into()), - } - } -} - -impl From<&ArchivedAddress> for mail_parser::Address<'static> { - fn from(value: &ArchivedAddress) -> Self { - match value { - ArchivedAddress::List(list) => { - mail_parser::Address::List(list.iter().map(Into::into).collect()) - } - ArchivedAddress::Group(groups) => { - mail_parser::Address::Group(groups.iter().map(Into::into).collect()) - } - } - } -} - -impl From<&ArchivedContentType> for mail_parser::ContentType<'static> { - fn from(value: &ArchivedContentType) -> Self { - mail_parser::ContentType { - c_type: value.c_type.to_string().into(), - c_subtype: value.subtype().map(|s| s.to_string().into()), - attributes: value.attributes.as_ref().map(|attrs| { - attrs - .iter() - .map(|a| (a.0.to_string().into(), a.0.to_string().into())) - .collect() - }), - } - } -} - -impl From<&ArchivedGroup> for mail_parser::Group<'static> { - fn from(value: &ArchivedGroup) -> Self { - mail_parser::Group { - name: value.name.as_ref().map(|s| s.to_string().into()), - addresses: value.addresses.iter().map(|a| a.into()).collect(), - } - } -} - -impl From<&ArchivedAddr> for mail_parser::Addr<'static> { - fn from(value: &ArchivedAddr) -> Self { - mail_parser::Addr { - name: value.name().map(|s| s.to_string().into()), - address: value.address().map(|s| s.to_string().into()), - } - } -} - -impl Encoding { - pub fn id(&self) -> u8 { - match self { - Encoding::None => 0, - Encoding::QuotedPrintable => 1, - Encoding::Base64 => 2, - } - } -} - -impl ArchivedEncoding { - pub fn id(&self) -> u8 { - match self { - ArchivedEncoding::None => 0, - ArchivedEncoding::QuotedPrintable => 1, - ArchivedEncoding::Base64 => 2, - } - } -} - -impl From for CompactDateTime { - fn from(dt: mail_parser::DateTime) -> Self { - let mut value: u64 = 0; - value |= (dt.year as u64) << 48; - value |= (dt.month as u64) << 44; - value |= (dt.day as u64) << 39; - value |= (dt.hour as u64) << 34; - value |= (dt.minute as u64) << 28; - value |= (dt.second as u64) << 22; - value |= (if dt.tz_before_gmt { 1 } else { 0 }) << 21; - value |= (dt.tz_hour as u64) << 16; - value |= (dt.tz_minute as u64) << 10; - - CompactDateTime(value) - } -} - -impl From<&ArchivedCompactDateTime> for mail_parser::DateTime { - fn from(value: &ArchivedCompactDateTime) -> Self { - let value = u64::from(value.0); - mail_parser::DateTime { - year: (value >> 48) as u16, - month: ((value >> 44) & 0xF) as u8, - day: ((value >> 39) & 0x1F) as u8, - hour: ((value >> 34) & 0x1F) as u8, - minute: ((value >> 28) & 0x3F) as u8, - second: ((value >> 22) & 0x3F) as u8, - tz_before_gmt: ((value >> 21) & 0x1) == 1, - tz_hour: ((value >> 16) & 0x1F) as u8, - tz_minute: ((value >> 10) & 0x3F) as u8, - } - } -} - -impl From<&CompactDateTime> for mail_parser::DateTime { - fn from(value: &CompactDateTime) -> Self { - let value = value.0; - mail_parser::DateTime { - year: (value >> 48) as u16, - month: ((value >> 44) & 0xF) as u8, - day: ((value >> 39) & 0x1F) as u8, - hour: ((value >> 34) & 0x1F) as u8, - minute: ((value >> 28) & 0x3F) as u8, - second: ((value >> 22) & 0x3F) as u8, - tz_before_gmt: ((value >> 21) & 0x1) == 1, - tz_hour: ((value >> 16) & 0x1F) as u8, - tz_minute: ((value >> 10) & 0x3F) as u8, - } - } -} - impl MessageData { pub fn has_keyword(&self, keyword: &Keyword) -> bool { self.keywords.iter().any(|k| k == keyword) diff --git a/crates/email/src/sieve/ingest.rs b/crates/email/src/sieve/ingest.rs index 3bc59652..c26500f3 100644 --- a/crates/email/src/sieve/ingest.rs +++ b/crates/email/src/sieve/ingest.rs @@ -19,15 +19,16 @@ use common::{ use directory::{Permission, QueryBy}; use jmap_proto::types::{collection::Collection, id::Id, keyword::Keyword, property::Property}; use mail_parser::MessageParser; +use rkyv::util::AlignedVec; use sieve::{Envelope, Event, Input, Mailbox, Recipient, Sieve}; use std::future::Future; use std::{borrow::Cow, sync::Arc}; use store::{ - Deserialize, Serialize, SerializeInfallible, + Serialize, SerializeInfallible, ahash::AHashMap, dispatch::lookup::KeyValue, query::Filter, - write::{Archiver, BatchBuilder, BlobOp, LegacyBincode}, + write::{Archiver, BatchBuilder, BlobOp}, }; use trc::{AddContext, SieveEvent}; use utils::config::utils::ParseValue; @@ -634,12 +635,13 @@ impl SieveScriptIngest for Server { })?; // Obtain the precompiled script - if let Some(sieve) = script_bytes - .get(script_offset..) - .and_then(|bytes| LegacyBincode::::deserialize(bytes).ok()) - { + if let Some(script) = script_bytes.get(script_offset..).and_then(|bytes| { + let mut abytes = AlignedVec::<16>::with_capacity(bytes.len()); + abytes.extend_from_slice(bytes); + rkyv::from_bytes::(&abytes).ok() + }) { Ok(CompiledScript { - script: sieve.inner, + script, name: unarchived_script.name.as_str().into(), hash, }) @@ -655,8 +657,9 @@ impl SieveScriptIngest for Server { ) { Ok(sieve) => { // Store updated compiled sieve script - let sieve = LegacyBincode::new(sieve); - let compiled_bytes = sieve.serialize().caused_by(trc::location!())?; + let compiled_bytes = rkyv::to_bytes::(&sieve) + .map_err(Into::into) + .caused_by(trc::location!())?; let mut updated_sieve_bytes = Vec::with_capacity(script_offset + compiled_bytes.len()); updated_sieve_bytes.extend_from_slice(&script_bytes[0..script_offset]); @@ -697,7 +700,7 @@ impl SieveScriptIngest for Server { .caused_by(trc::location!())?; Ok(CompiledScript { - script: sieve.inner, + script: sieve, name: new_archive.into_inner().name, hash, }) diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index 66fe83b0..a4e36c13 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -20,9 +20,9 @@ jmap_proto = { path = "../jmap-proto" } directory = { path = "../directory" } services = { path = "../services" } smtp-proto = { version = "0.1" } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.6", features = ["generate"] } +mail-auth = { version = "0.7", features = ["generate"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } tokio = { version = "1.23", features = ["rt"] } hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } @@ -32,7 +32,7 @@ async-stream = "0.3.5" quick-xml = "0.37" serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" -x509-parser = "0.16.0" +x509-parser = "0.17.0" chrono = "0.4" base64 = "0.22" pkcs8 = { version = "0.10.2", features = ["alloc", "std"] } diff --git a/crates/http/src/management/report.rs b/crates/http/src/management/report.rs index f3f96732..a7f6d261 100644 --- a/crates/http/src/management/report.rs +++ b/crates/http/src/management/report.rs @@ -15,10 +15,12 @@ use mail_auth::report::{ tlsrpt::{FailureDetails, Policy, TlsReport}, }; use serde_json::json; -use smtp::reporting::analysis::IncomingReport; +use smtp::reporting::{ReportSerializer, analysis::IncomingReport}; use store::{ - Deserialize, IterateParams, U64_LEN, ValueKey, - write::{BatchBuilder, LegacyBincode, ReportClass, ValueClass, key::DeserializeBigEndian}, + Deserialize, IterateParams, Key, U64_LEN, ValueKey, + write::{ + AlignedBytes, Archive, BatchBuilder, ReportClass, ValueClass, key::DeserializeBigEndian, + }, }; use trc::AddContext; use utils::url_params::UrlParams; @@ -106,64 +108,57 @@ impl ManageReports for Server { if let Some(report_id) = parse_incoming_report_id(class, report_id.as_ref()) { match &report_id { - ReportClass::Tls { .. } => match self - .core - .storage - .data - .get_value::>>(ValueKey::from( - ValueClass::Report(report_id), - )) - .await? + ReportClass::Tls { .. } => match fetch_report::>( + self, + ValueKey::from(ValueClass::Report(report_id)), + ) + .await? { Some(report) if tenant_domains .as_ref() - .is_none_or(|domains| report.inner.has_domain(domains)) => + .is_none_or(|domains| report.has_domain(domains)) => { Ok(JsonResponse::new(json!({ - "data": report.inner, + "data": report, })) .into_http_response()) } _ => Err(trc::ResourceEvent::NotFound.into_err()), }, - ReportClass::Dmarc { .. } => match self - .core - .storage - .data - .get_value::>>( + ReportClass::Dmarc { .. } => { + match fetch_report::>( + self, ValueKey::from(ValueClass::Report(report_id)), ) .await? - { - Some(report) - if tenant_domains - .as_ref() - .is_none_or(|domains| report.inner.has_domain(domains)) => { - Ok(JsonResponse::new(json!({ - "data": report.inner, - })) - .into_http_response()) + Some(report) + if tenant_domains + .as_ref() + .is_none_or(|domains| report.has_domain(domains)) => + { + Ok(JsonResponse::new(json!({ + "data": report, + })) + .into_http_response()) + } + _ => Err(trc::ResourceEvent::NotFound.into_err()), } - _ => Err(trc::ResourceEvent::NotFound.into_err()), - }, - ReportClass::Arf { .. } => match self - .core - .storage - .data - .get_value::>>(ValueKey::from( - ValueClass::Report(report_id), - )) - .await? + } + ReportClass::Arf { .. } => match fetch_report::>( + self, + ValueKey::from(ValueClass::Report(report_id)), + ) + .await? { Some(report) if tenant_domains .as_ref() - .is_none_or(|domains| report.inner.has_domain(domains)) => + .is_none_or(|domains| report.has_domain(domains)) => { Ok(JsonResponse::new(json!({ - "data": report.inner, + "data": report, })) .into_http_response()) } @@ -236,34 +231,27 @@ impl ManageReports for Server { if let Some(report_id) = parse_incoming_report_id(class, report_id.as_ref()) { if let Some(domains) = &tenant_domains { let is_tenant_report = match &report_id { - ReportClass::Tls { .. } => self - .core - .storage - .data - .get_value::>>(ValueKey::from( - ValueClass::Report(report_id.clone()), - )) - .await? - .is_none_or( |report| report.inner.has_domain(domains)), - ReportClass::Dmarc { .. } => self - .core - .storage - .data - .get_value::>>( + ReportClass::Tls { .. } => fetch_report::>( + self, + ValueKey::from(ValueClass::Report(report_id.clone())), + ) + .await? + .is_none_or(|report| report.has_domain(domains)), + ReportClass::Dmarc { .. } => { + fetch_report::>( + self, ValueKey::from(ValueClass::Report(report_id.clone())), ) .await? - .is_none_or( |report| report.inner.has_domain(domains)), + .is_none_or(|report| report.has_domain(domains)) + } - ReportClass::Arf { .. } => self - .core - .storage - .data - .get_value::>>(ValueKey::from( - ValueClass::Report(report_id.clone()), - )) - .await? - .is_none_or( |report| report.inner.has_domain(domains)), + ReportClass::Arf { .. } => fetch_report::>( + self, + ValueKey::from(ValueClass::Report(report_id.clone())), + ) + .await? + .is_none_or(|report| report.has_domain(domains)), }; if !is_tenant_report { @@ -288,6 +276,30 @@ impl ManageReports for Server { } } +async fn fetch_report(server: &Server, key: impl Key) -> trc::Result> +where + T: rkyv::Archive + + for<'a> rkyv::Serialize< + rkyv::api::high::HighSerializer< + rkyv::util::AlignedVec, + rkyv::ser::allocator::ArenaHandle<'a>, + rkyv::rancor::Error, + >, + >, + T::Archived: for<'a> rkyv::bytecheck::CheckBytes> + + rkyv::Deserialize>, +{ + if let Some(tls) = server + .store() + .get_value::>(key) + .await? + { + tls.deserialize::>().map(|v| Some(v.0)) + } else { + Ok(None) + } +} + struct IncomingReports { ids: Vec<(u64, u64)>, total: usize, @@ -369,15 +381,15 @@ async fn fetch_incoming_reports( last_id = id; // TODO: Support filtering chunked records (over 10MB) on FDB + let archive = as Deserialize>::deserialize(value)?; let matches = if has_filters { match typ { ReportType::Dmarc => { let report = - LegacyBincode::>::deserialize( - value, - ) + archive + .deserialize::>>() .caused_by(trc::location!())? - .inner; + .0; filter.is_none_or( |f| report.contains(f)) && tenant_domains @@ -385,9 +397,11 @@ async fn fetch_incoming_reports( .is_none_or( |domains| report.has_domain(domains)) } ReportType::Tls => { - let report = LegacyBincode::>::deserialize(value) + let report = + archive + .deserialize::>>() .caused_by(trc::location!())? - .inner; + .0; filter.is_none_or( |f| report.contains(f)) && tenant_domains @@ -395,9 +409,12 @@ async fn fetch_incoming_reports( .is_none_or( |domains| report.has_domain(domains)) } ReportType::Arf => { - let report = LegacyBincode::>::deserialize(value) + let report = + archive + .deserialize::>>() .caused_by(trc::location!())? - .inner; + .0; + filter.is_none_or( |f| report.contains(f)) && tenant_domains diff --git a/crates/imap-proto/Cargo.toml b/crates/imap-proto/Cargo.toml index c5dac71d..f50b1424 100644 --- a/crates/imap-proto/Cargo.toml +++ b/crates/imap-proto/Cargo.toml @@ -7,7 +7,7 @@ resolver = "2" [dependencies] jmap_proto = { path = "../jmap-proto" } store = { path = "../store" } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } ahash = { version = "0.8" } chrono = { version = "0.4"} trc = { path = "../trc" } diff --git a/crates/imap-proto/src/parser/append.rs b/crates/imap-proto/src/parser/append.rs index 834b4188..5a01ecae 100644 --- a/crates/imap-proto/src/parser/append.rs +++ b/crates/imap-proto/src/parser/append.rs @@ -127,7 +127,12 @@ impl Request { } } }, - _ => return Err(bad(self.tag.to_compact_string(), "Invalid arguments.")), + _ => { + return Err(bad( + self.tag.to_compact_string(), + "Invalid arguments.", + )); + } } } diff --git a/crates/imap-proto/src/protocol/acl.rs b/crates/imap-proto/src/protocol/acl.rs index 850061ed..7b10a31c 100644 --- a/crates/imap-proto/src/protocol/acl.rs +++ b/crates/imap-proto/src/protocol/acl.rs @@ -35,7 +35,6 @@ use std::fmt::Display; - use jmap_proto::types::acl::Acl; use crate::utf7::utf7_encode; @@ -249,7 +248,6 @@ impl From for Acl { #[cfg(test)] mod tests { - use crate::protocol::acl::{GetAclResponse, ListRightsResponse, MyRightsResponse, Rights}; diff --git a/crates/imap-proto/src/protocol/append.rs b/crates/imap-proto/src/protocol/append.rs index 343242e6..24f13bdf 100644 --- a/crates/imap-proto/src/protocol/append.rs +++ b/crates/imap-proto/src/protocol/append.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::Flag; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/authenticate.rs b/crates/imap-proto/src/protocol/authenticate.rs index d85dc729..8be74653 100644 --- a/crates/imap-proto/src/protocol/authenticate.rs +++ b/crates/imap-proto/src/protocol/authenticate.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, diff --git a/crates/imap-proto/src/protocol/copy_move.rs b/crates/imap-proto/src/protocol/copy_move.rs index 3657a608..669af0ac 100644 --- a/crates/imap-proto/src/protocol/copy_move.rs +++ b/crates/imap-proto/src/protocol/copy_move.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::Sequence; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/create.rs b/crates/imap-proto/src/protocol/create.rs index 064feeb3..32962541 100644 --- a/crates/imap-proto/src/protocol/create.rs +++ b/crates/imap-proto/src/protocol/create.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::list::Attribute; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/delete.rs b/crates/imap-proto/src/protocol/delete.rs index 1df766da..8cbd6e32 100644 --- a/crates/imap-proto/src/protocol/delete.rs +++ b/crates/imap-proto/src/protocol/delete.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, diff --git a/crates/imap-proto/src/protocol/enable.rs b/crates/imap-proto/src/protocol/enable.rs index 379b6aa1..eec6b1b0 100644 --- a/crates/imap-proto/src/protocol/enable.rs +++ b/crates/imap-proto/src/protocol/enable.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::{ImapResponse, capability::Capability}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/fetch.rs b/crates/imap-proto/src/protocol/fetch.rs index 9e1f3548..09d6a687 100644 --- a/crates/imap-proto/src/protocol/fetch.rs +++ b/crates/imap-proto/src/protocol/fetch.rs @@ -6,7 +6,6 @@ use std::borrow::Cow; - use mail_parser::DateTime; use super::{ @@ -917,7 +916,6 @@ impl ImapResponse for Response<'_> { #[cfg(test)] mod tests { - use mail_parser::DateTime; use crate::protocol::{Flag, ImapResponse}; diff --git a/crates/imap-proto/src/protocol/list.rs b/crates/imap-proto/src/protocol/list.rs index a4268c2c..ed6f93fb 100644 --- a/crates/imap-proto/src/protocol/list.rs +++ b/crates/imap-proto/src/protocol/list.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use crate::utf7::utf7_encode; use super::{ @@ -277,7 +275,6 @@ impl ImapResponse for Response { #[cfg(test)] mod tests { - use crate::protocol::{ ImapResponse, diff --git a/crates/imap-proto/src/protocol/login.rs b/crates/imap-proto/src/protocol/login.rs index a7fd8182..84c92c1a 100644 --- a/crates/imap-proto/src/protocol/login.rs +++ b/crates/imap-proto/src/protocol/login.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, diff --git a/crates/imap-proto/src/protocol/namespace.rs b/crates/imap-proto/src/protocol/namespace.rs index 8610daa6..25d76bfb 100644 --- a/crates/imap-proto/src/protocol/namespace.rs +++ b/crates/imap-proto/src/protocol/namespace.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::{ImapResponse, quoted_string}; pub struct Response { diff --git a/crates/imap-proto/src/protocol/quota.rs b/crates/imap-proto/src/protocol/quota.rs index 41e0caa2..76c19256 100644 --- a/crates/imap-proto/src/protocol/quota.rs +++ b/crates/imap-proto/src/protocol/quota.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::{ImapResponse, capability::QuotaResourceName, quoted_string}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/rename.rs b/crates/imap-proto/src/protocol/rename.rs index 6a462f47..26e139ea 100644 --- a/crates/imap-proto/src/protocol/rename.rs +++ b/crates/imap-proto/src/protocol/rename.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, diff --git a/crates/imap-proto/src/protocol/search.rs b/crates/imap-proto/src/protocol/search.rs index 1e193c8f..7658c4f5 100644 --- a/crates/imap-proto/src/protocol/search.rs +++ b/crates/imap-proto/src/protocol/search.rs @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - use store::fts::{FilterItem, FilterType}; use super::{Flag, Sequence, quoted_string, serialize_sequence}; diff --git a/crates/imap-proto/src/protocol/select.rs b/crates/imap-proto/src/protocol/select.rs index 0e4357a5..9a91abad 100644 --- a/crates/imap-proto/src/protocol/select.rs +++ b/crates/imap-proto/src/protocol/select.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use crate::{ResponseCode, StatusResponse}; use super::{ImapResponse, Sequence, list::ListItem}; diff --git a/crates/imap-proto/src/protocol/status.rs b/crates/imap-proto/src/protocol/status.rs index 106082e1..7185ca39 100644 --- a/crates/imap-proto/src/protocol/status.rs +++ b/crates/imap-proto/src/protocol/status.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use crate::utf7::utf7_encode; use super::quoted_string; diff --git a/crates/imap-proto/src/protocol/store.rs b/crates/imap-proto/src/protocol/store.rs index c59dc789..eddc4458 100644 --- a/crates/imap-proto/src/protocol/store.rs +++ b/crates/imap-proto/src/protocol/store.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::{Flag, ImapResponse, Sequence, fetch::FetchItem}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap-proto/src/protocol/subscribe.rs b/crates/imap-proto/src/protocol/subscribe.rs index 1df766da..8cbd6e32 100644 --- a/crates/imap-proto/src/protocol/subscribe.rs +++ b/crates/imap-proto/src/protocol/subscribe.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Arguments { pub tag: String, diff --git a/crates/imap-proto/src/protocol/thread.rs b/crates/imap-proto/src/protocol/thread.rs index 2c6a1768..33c36197 100644 --- a/crates/imap-proto/src/protocol/thread.rs +++ b/crates/imap-proto/src/protocol/thread.rs @@ -4,8 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ - - use super::{ImapResponse, search::Filter}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml index e26d5035..fa0a6507 100644 --- a/crates/imap/Cargo.toml +++ b/crates/imap/Cargo.toml @@ -14,7 +14,7 @@ common = { path = "../common" } email = { path = "../email" } nlp = { path = "../nlp" } utils = { path = "../utils" } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } rustls-pemfile = "2.0" diff --git a/crates/imap/src/op/fetch.rs b/crates/imap/src/op/fetch.rs index dc4097d5..c7de2ee2 100644 --- a/crates/imap/src/op/fetch.rs +++ b/crates/imap/src/op/fetch.rs @@ -15,7 +15,6 @@ use directory::Permission; use email::{ cache::{MessageCacheFetch, email::MessageCacheAccess}, message::metadata::{ - ArchivedAddress, ArchivedGetHeader, ArchivedHeaderName, ArchivedHeaderValue, ArchivedMessageMetadata, ArchivedMessageMetadataContents, ArchivedMetadataPartType, DecodedParts, MessageData, MessageMetadata, }, @@ -40,6 +39,9 @@ use jmap_proto::types::{ keyword::Keyword, property::Property, }; +use mail_parser::{ + ArchivedAddress, ArchivedHeaderName, ArchivedHeaderValue, core::rkyv::ArchivedGetHeader, +}; use std::{borrow::Cow, sync::Arc, time::Instant}; use store::{ query::log::{Change, Query}, @@ -663,7 +665,7 @@ impl AsImapDataItemPart for ArchivedMessageMetadataContents { fields.body_parameters = content_type.as_ref().and_then(|ct| { ct.attributes.as_ref().map(|at| { at.iter() - .map(|k| (k.0.as_ref().into(), k.1.as_ref().into())) + .map(|k| (k.name.as_ref().into(), k.value.as_ref().into())) .collect::>() }) }) @@ -722,7 +724,7 @@ impl AsImapDataItemPart for ArchivedMessageMetadataContents { .as_ref() .map(|at| { at.iter() - .map(|k| (k.0.as_ref().into(), k.1.as_ref().into())) + .map(|k| (k.name.as_ref().into(), k.value.as_ref().into())) .collect::>() }) .unwrap_or_default(), @@ -1197,7 +1199,7 @@ trait AsImapAddress { fn as_imap_address(&self) -> Vec; } -impl AsImapAddress for ArchivedHeaderValue { +impl AsImapAddress for ArchivedHeaderValue<'_> { fn as_imap_address(&self) -> Vec { let mut addresses = Vec::new(); diff --git a/crates/jmap-proto/Cargo.toml b/crates/jmap-proto/Cargo.toml index 7e358cc7..af51eec2 100644 --- a/crates/jmap-proto/Cargo.toml +++ b/crates/jmap-proto/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" store = { path = "../store" } utils = { path = "../utils" } trc = { path = "../trc" } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } fast-float = "0.2.0" serde = { version = "1.0", features = ["derive"]} ahash = { version = "0.8.2", features = ["serde"] } diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index befd21cc..bca24217 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -18,18 +18,17 @@ trc = { path = "../trc" } spam-filter = { path = "../spam-filter" } email = { path = "../email" } smtp-proto = { version = "0.1" } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } mail-builder = { version = "0.4" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } -mail-auth = { version = "0.6", features = ["generate"] } -sieve-rs = { version = "0.6" } +mail-auth = { version = "0.7", features = ["generate"] } +sieve-rs = { version = "0.7", features = ["rkyv"] } serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } hyper-util = { version = "0.1.1", features = ["tokio"] } http-body-util = "0.1.0" tokio = { version = "1.23", features = ["rt"] } -bincode = "1.3.3" futures-util = "0.3.28" async-stream = "0.3.5" base64 = "0.22" diff --git a/crates/jmap/src/email/body.rs b/crates/jmap/src/email/body.rs index 7610077d..93aa144e 100644 --- a/crates/jmap/src/email/body.rs +++ b/crates/jmap/src/email/body.rs @@ -4,22 +4,20 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use email::message::metadata::{ - ArchivedHeaderValue, ArchivedMessageMetadataContents, ArchivedMetadataPartType, -}; +use email::message::metadata::{ArchivedMessageMetadataContents, ArchivedMetadataPartType}; use jmap_proto::types::{ blob::BlobId, property::Property, value::{Object, Value}, }; -use mail_parser::{HeaderValue, MessagePart, MimeHeaders, PartType}; +use mail_parser::{ArchivedHeaderValue, HeaderValue, MessagePart, MimeHeaders, PartType}; use super::headers::HeaderToValue; pub trait ToBodyPart { fn to_body_part( &self, - part_id: usize, + part_id: u32, properties: &[Property], raw_message: &[u8], blob_id: &BlobId, @@ -29,7 +27,7 @@ pub trait ToBodyPart { impl ToBodyPart for Vec> { fn to_body_part( &self, - part_id: usize, + part_id: u32, properties: &[Property], raw_message: &[u8], blob_id: &BlobId, @@ -39,7 +37,10 @@ impl ToBodyPart for Vec> { let mut subparts = Vec::with_capacity(1); loop { - if let Some((part_id, part)) = parts.next().map(|part_id| (part_id, &self[part_id])) { + if let Some((part_id, part)) = parts + .next() + .map(|part_id| (part_id, &self[part_id as usize])) + { let mut values = Object::with_capacity(properties.len()); let multipart = if let PartType::Multipart(parts) = &part.body { parts.into() @@ -55,8 +56,8 @@ impl ToBodyPart for Vec> { BlobId::new_section( blob_id.hash.clone(), blob_id.class.clone(), - part.offset_body + base_offset, - part.offset_end + base_offset, + part.offset_body as usize + base_offset, + part.offset_end as usize + base_offset, part.encoding as u8, ) .into() @@ -64,7 +65,7 @@ impl ToBodyPart for Vec> { Property::Size if multipart.is_none() => match &part.body { PartType::Text(text) | PartType::Html(text) => text.len(), PartType::Binary(bin) | PartType::InlineBinary(bin) => bin.len(), - PartType::Message(message) => message.root_part().raw_len(), + PartType::Message(message) => message.root_part().raw_len() as usize, PartType::Multipart(_) => 0, } .into(), @@ -140,7 +141,7 @@ impl ToBodyPart for Vec> { impl ToBodyPart for ArchivedMessageMetadataContents { fn to_body_part( &self, - part_id: usize, + part_id: u32, properties: &[Property], raw_message: &[u8], blob_id: &BlobId, @@ -150,8 +151,9 @@ impl ToBodyPart for ArchivedMessageMetadataContents { let mut subparts = Vec::with_capacity(1); loop { - if let Some((part_id, part)) = - parts.next().map(|part_id| (part_id, &self.parts[part_id])) + if let Some((part_id, part)) = parts + .next() + .map(|part_id| (part_id, &self.parts[part_id as usize])) { let mut values = Object::with_capacity(properties.len()); let multipart = if let ArchivedMetadataPartType::Multipart(parts) = &part.body { @@ -229,7 +231,7 @@ impl ToBodyPart for ArchivedMessageMetadataContents { if let Some(multipart) = multipart { let multipart = multipart .iter() - .map(|id| u16::from(id) as usize) + .map(|id| u16::from(id) as u32) .collect::>(); parts_stack.push(( parts, diff --git a/crates/jmap/src/email/get.rs b/crates/jmap/src/email/get.rs index 1b500496..eb02d3cc 100644 --- a/crates/jmap/src/email/get.rs +++ b/crates/jmap/src/email/get.rs @@ -14,9 +14,7 @@ use crate::{ use common::{Server, auth::AccessToken}; use email::{ cache::{MessageCacheFetch, email::MessageCacheAccess}, - message::metadata::{ - ArchivedGetHeader, ArchivedHeaderName, ArchivedMetadataPartType, MessageMetadata, - }, + message::metadata::{ArchivedMetadataPartType, MessageMetadata}, }; use jmap_proto::{ method::get::{GetRequest, GetResponse}, @@ -31,6 +29,7 @@ use jmap_proto::{ value::{Object, Value}, }, }; +use mail_parser::{ArchivedHeaderName, HeaderValue, core::rkyv::ArchivedGetHeader}; use std::{borrow::Cow, future::Future}; use store::BlobClass; use trc::{AddContext, StoreEvent}; @@ -262,8 +261,8 @@ impl EmailGet for Server { Property::Subject, root_part .headers - .convert_header(&ArchivedHeaderName::Subject) - .map(|value| value.into_form(&HeaderForm::Text)) + .header_value(&ArchivedHeaderName::Subject) + .map(|value| HeaderValue::from(value).into_form(&HeaderForm::Text)) .unwrap_or_default(), ); } @@ -272,8 +271,8 @@ impl EmailGet for Server { Property::SentAt, root_part .headers - .convert_header(&ArchivedHeaderName::Date) - .map(|value| value.into_form(&HeaderForm::Date)) + .header_value(&ArchivedHeaderName::Date) + .map(|value| HeaderValue::from(value).into_form(&HeaderForm::Date)) .unwrap_or_default(), ); } @@ -282,13 +281,15 @@ impl EmailGet for Server { property.clone(), root_part .headers - .convert_header(&match property { + .header_value(&match property { Property::MessageId => ArchivedHeaderName::MessageId, Property::InReplyTo => ArchivedHeaderName::InReplyTo, Property::References => ArchivedHeaderName::References, _ => unreachable!(), }) - .map(|value| value.into_form(&HeaderForm::MessageIds)) + .map(|value| { + HeaderValue::from(value).into_form(&HeaderForm::MessageIds) + }) .unwrap_or_default(), ); } @@ -303,7 +304,7 @@ impl EmailGet for Server { property.clone(), root_part .headers - .convert_header(&match property { + .header_value(&match property { Property::Sender => ArchivedHeaderName::Sender, Property::From => ArchivedHeaderName::From, Property::To => ArchivedHeaderName::To, @@ -312,7 +313,9 @@ impl EmailGet for Server { Property::ReplyTo => ArchivedHeaderName::ReplyTo, _ => unreachable!(), }) - .map(|value| value.into_form(&HeaderForm::Addresses)) + .map(|value| { + HeaderValue::from(value).into_form(&HeaderForm::Addresses) + }) .unwrap_or_default(), ); } @@ -340,7 +343,7 @@ impl EmailGet for Server { property.clone(), list.map(|part_id| { contents.to_body_part( - u16::from(part_id) as usize, + u16::from(part_id) as u32, &body_properties, &raw_message, &blob_id, diff --git a/crates/jmap/src/email/headers.rs b/crates/jmap/src/email/headers.rs index 97413908..c5d90184 100644 --- a/crates/jmap/src/email/headers.rs +++ b/crates/jmap/src/email/headers.rs @@ -6,7 +6,6 @@ use std::borrow::Cow; -use email::message::metadata::{ArchivedHeader, ArchivedHeaderValue}; use jmap_proto::types::{ property::{HeaderForm, HeaderProperty, Property}, value::{Object, Value}, @@ -22,7 +21,10 @@ use mail_builder::{ url::URL, }, }; -use mail_parser::{Addr, Header, HeaderName, HeaderValue, parsers::MessageStream}; +use mail_parser::{ + Addr, ArchivedHeader, ArchivedHeaderValue, Header, HeaderName, HeaderValue, + parsers::MessageStream, +}; use store::rkyv::vec::ArchivedVec; pub trait IntoForm { @@ -74,7 +76,7 @@ impl HeaderToValue for Vec> { if header.name.as_str().eq_ignore_ascii_case(header_name) { let header_value = if is_raw || matches!(header.value, HeaderValue::Empty) { raw_message - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .map_or(HeaderValue::Empty, |bytes| match form { HeaderForm::Raw => { HeaderValue::Text(String::from_utf8_lossy(bytes.trim_end())) @@ -116,7 +118,7 @@ impl HeaderToValue for Vec> { Property::Value, String::from_utf8_lossy( raw_message - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default() .trim_end(), ) @@ -339,7 +341,7 @@ impl BuildHeader for MessageBuilder<'_> { } } -impl HeaderToValue for ArchivedVec { +impl HeaderToValue for ArchivedVec> { fn header_to_value(&self, property: &Property, raw_message: &[u8]) -> Value { let (header_name, form, all) = match property { Property::Header(header) => ( diff --git a/crates/jmap/src/email/parse.rs b/crates/jmap/src/email/parse.rs index 17abbdfe..eeda917c 100644 --- a/crates/jmap/src/email/parse.rs +++ b/crates/jmap/src/email/parse.rs @@ -124,6 +124,7 @@ impl EmailParse for Server { email.append( Property::HasAttachment, Value::Bool(message.parts.iter().enumerate().any(|(part_id, part)| { + let part_id = part_id as u32; match &part.body { PartType::Html(_) | PartType::Text(_) => { !message.text_body.contains(&part_id) @@ -142,7 +143,7 @@ impl EmailParse for Server { .text_body .first() .or_else(|| message.html_body.first()) - .and_then(|idx| message.parts.get(*idx)) + .and_then(|idx| message.parts.get(*idx as usize)) .map(|part| &part.body) { Some(PartType::Text(text)) => { @@ -215,6 +216,7 @@ impl EmailParse for Server { Property::BodyValues => { let mut body_values = Object::with_capacity(message.parts.len()); for (part_id, part) in message.parts.iter().enumerate() { + let part_id = part_id as u32; if ((message.html_body.contains(&part_id) && (fetch_all_body_values || fetch_html_body_values)) || (message.text_body.contains(&part_id) diff --git a/crates/jmap/src/email/snippet.rs b/crates/jmap/src/email/snippet.rs index 6ab5872d..8b4f1204 100644 --- a/crates/jmap/src/email/snippet.rs +++ b/crates/jmap/src/email/snippet.rs @@ -8,10 +8,7 @@ use crate::blob::download::BlobDownload; use common::{Server, auth::AccessToken}; use email::{ cache::{MessageCacheFetch, email::MessageCacheAccess}, - message::metadata::{ - ArchivedGetHeader, ArchivedHeaderName, ArchivedMetadataPartType, DecodedPartContent, - MessageMetadata, - }, + message::metadata::{ArchivedMetadataPartType, DecodedPartContent, MessageMetadata}, }; use jmap_proto::{ method::{ @@ -20,7 +17,9 @@ use jmap_proto::{ }, types::{acl::Acl, collection::Collection, property::Property}, }; -use mail_parser::decoders::html::html_to_text; +use mail_parser::{ + ArchivedHeaderName, core::rkyv::ArchivedGetHeader, decoders::html::html_to_text, +}; use nlp::language::{Language, search_snippet::generate_snippet, stemmer::Stemmer}; use std::future::Future; use store::backend::MAX_TOKEN_LENGTH; diff --git a/crates/jmap/src/sieve/set.rs b/crates/jmap/src/sieve/set.rs index 5efc3be0..72bbdb7c 100644 --- a/crates/jmap/src/sieve/set.rs +++ b/crates/jmap/src/sieve/set.rs @@ -32,10 +32,10 @@ use jmap_proto::{ use rand::distr::Alphanumeric; use sieve::compiler::ErrorType; use store::{ - BlobClass, Serialize, + BlobClass, query::Filter, rand::{Rng, rng}, - write::{Archive, BatchBuilder, LegacyBincode}, + write::{Archive, BatchBuilder}, }; use trc::AddContext; @@ -468,7 +468,7 @@ impl SieveScriptSet for Server { match self.core.sieve.untrusted_compiler.compile(&bytes) { Ok(script) => { changes.size = bytes.len() as u32; - bytes.extend(&LegacyBincode::new(script).serialize().unwrap_or_default()); + bytes.extend(rkyv::to_bytes::(&script)?.iter()); bytes.into() } Err(err) => { diff --git a/crates/jmap/src/submission/set.rs b/crates/jmap/src/submission/set.rs index 13dd3d58..961cf048 100644 --- a/crates/jmap/src/submission/set.rs +++ b/crates/jmap/src/submission/set.rs @@ -14,7 +14,7 @@ use common::{ use email::{ identity::Identity, - message::metadata::{ArchivedHeaderName, ArchivedHeaderValue, MessageMetadata}, + message::metadata::MessageMetadata, submission::{Address, Delivered, DeliveryStatus, EmailSubmission, UndoStatus}, }; use jmap_proto::{ @@ -35,6 +35,7 @@ use jmap_proto::{ value::{MaybePatchValue, Object, SetValue, Value}, }, }; +use mail_parser::{ArchivedHeaderName, ArchivedHeaderValue}; use smtp::{ core::{Session, SessionData}, queue::spool::SmtpSpool, diff --git a/crates/jmap/src/vacation/set.rs b/crates/jmap/src/vacation/set.rs index 438eb92c..96e4b775 100644 --- a/crates/jmap/src/vacation/set.rs +++ b/crates/jmap/src/vacation/set.rs @@ -27,10 +27,7 @@ use jmap_proto::{ use mail_builder::MessageBuilder; use mail_parser::decoders::html::html_to_text; use std::future::Future; -use store::{ - Serialize, - write::{BatchBuilder, LegacyBincode}, -}; +use store::write::BatchBuilder; use trc::AddContext; pub trait VacationResponseSet: Sync + Send { @@ -439,11 +436,7 @@ impl VacationResponseSet for Server { obj.size = script.len() as u32; // Serialize script - script.extend( - LegacyBincode::new(compiled_script) - .serialize() - .unwrap_or_default(), - ); + script.extend(rkyv::to_bytes::(&compiled_script)?.iter()); Ok(script) } diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml index 81b91601..c2c680e5 100644 --- a/crates/managesieve/Cargo.toml +++ b/crates/managesieve/Cargo.toml @@ -14,9 +14,9 @@ store = { path = "../store" } utils = { path = "../utils" } email = { path = "../email" } trc = { path = "../trc" } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } -sieve-rs = { version = "0.6" } +sieve-rs = { version = "0.7", features = ["rkyv"] } rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } rustls-pemfile = "2.0" tokio = { version = "1.23", features = ["full"] } @@ -24,9 +24,8 @@ tokio-rustls = { version = "0.26", default-features = false, features = ["ring", parking_lot = "0.12" ahash = { version = "0.8" } md5 = "0.7.0" -bincode = "1.3.3" compact_str = "0.9.0" - +rkyv = { version = "0.8.10", features = ["little_endian"] } [features] test_mode = [] diff --git a/crates/managesieve/src/op/putscript.rs b/crates/managesieve/src/op/putscript.rs index 87c7d80d..a80beb1d 100644 --- a/crates/managesieve/src/op/putscript.rs +++ b/crates/managesieve/src/op/putscript.rs @@ -4,23 +4,17 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use std::time::Instant; - +use crate::core::{Command, ResponseCode, Session, StatusResponse}; use common::{listener::SessionStream, storage::index::ObjectIndexBuilder}; use directory::Permission; use email::sieve::SieveScript; use imap_proto::receiver::Request; use jmap_proto::types::{collection::Collection, property::Property}; use sieve::compiler::ErrorType; -use store::{ - Serialize, - query::Filter, - write::{BatchBuilder, LegacyBincode}, -}; +use std::time::Instant; +use store::{query::Filter, write::BatchBuilder}; use trc::AddContext; -use crate::core::{Command, ResponseCode, Session, StatusResponse}; - impl Session { pub async fn handle_putscript(&mut self, request: Request) -> trc::Result> { // Validate access @@ -81,9 +75,10 @@ impl Session { { Ok(compiled_script) => { script_bytes.extend( - LegacyBincode::new(compiled_script) - .serialize() - .unwrap_or_default(), + rkyv::to_bytes::(&compiled_script) + .map_err(Into::into) + .caused_by(trc::location!())? + .iter(), ); } Err(err) => { diff --git a/crates/nlp/Cargo.toml b/crates/nlp/Cargo.toml index d4e6460a..3367c38a 100644 --- a/crates/nlp/Cargo.toml +++ b/crates/nlp/Cargo.toml @@ -10,7 +10,6 @@ xxhash-rust = { version = "0.8.5", features = ["xxh3"] } farmhash = "1.1.5" siphasher = "1.0" serde = { version = "1.0", features = ["derive"]} -bincode = "1.3.3" nohash = "0.2.0" ahash = { version = "0.8.3", features = ["serde"] } whatlang = "0.16" # Language detection @@ -28,3 +27,4 @@ test_mode = [] [dev-dependencies] tokio = { version = "1.23", features = ["full"] } +bincode = "1.3.3" diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml index 0429013e..3fe48480 100644 --- a/crates/pop3/Cargo.toml +++ b/crates/pop3/Cargo.toml @@ -13,7 +13,7 @@ utils = { path = "../utils" } trc = { path = "../trc" } jmap_proto = { path = "../jmap-proto" } email = { path = "../email" } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } tokio = { version = "1.23", features = ["full"] } diff --git a/crates/services/Cargo.toml b/crates/services/Cargo.toml index 8bcc12fe..11ba4e72 100644 --- a/crates/services/Cargo.toml +++ b/crates/services/Cargo.toml @@ -14,7 +14,7 @@ smtp = { path = "../smtp" } jmap_proto = { path = "../jmap-proto" } directory = { path = "../directory" } tokio = { version = "1.23", features = ["rt"] } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" memory-stats = "1.2.0" diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 2374243e..a76e917d 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -20,19 +20,19 @@ common = { path = "../common" } email = { path = "../email" } spam-filter = { path = "../spam-filter" } trc = { path = "../trc" } -mail-auth = { version = "0.6" } +mail-auth = { version = "0.7", features = ["rkyv"] } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } smtp-proto = { version = "0.1.6", features = ["rkyv"] } -sieve-rs = { version = "0.6" } +sieve-rs = { version = "0.7", features = ["rkyv"] } ahash = { version = "0.8" } rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } rustls-pemfile = "2.0" rustls-pki-types = { version = "1" } tokio = { version = "1.23", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } -webpki-roots = { version = "0.26"} +webpki-roots = { version = "1.0"} hyper = { version = "1.0.1", features = ["server", "http1", "http2"] } hyper-util = { version = "0.1.1", features = ["tokio"] } http-body-util = "0.1.0" @@ -46,12 +46,11 @@ regex = "1.7.0" blake3 = "1.3" lru-cache = "0.1.2" rand = "0.9.0" -x509-parser = "0.16.0" +x509-parser = "0.17.0" reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] } serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" num_cpus = "1.15.0" -bincode = "1.3.1" chrono = "0.4" rkyv = { version = "0.8.10", features = ["little_endian"] } compact_str = "0.9.0" diff --git a/crates/smtp/src/inbound/ehlo.rs b/crates/smtp/src/inbound/ehlo.rs index 8bf932b1..cce6ef19 100644 --- a/crates/smtp/src/inbound/ehlo.rs +++ b/crates/smtp/src/inbound/ehlo.rs @@ -20,11 +20,7 @@ use smtp_proto::*; use trc::SmtpEvent; impl Session { - pub async fn handle_ehlo( - &mut self, - domain: String, - is_extended: bool, - ) -> Result<(), ()> { + pub async fn handle_ehlo(&mut self, domain: String, is_extended: bool) -> Result<(), ()> { // Set EHLO domain if domain != self.data.helo_domain { diff --git a/crates/smtp/src/inbound/hooks/mod.rs b/crates/smtp/src/inbound/hooks/mod.rs index 6434630e..f48c5748 100644 --- a/crates/smtp/src/inbound/hooks/mod.rs +++ b/crates/smtp/src/inbound/hooks/mod.rs @@ -176,10 +176,7 @@ pub enum Modification { #[serde(rename = "replaceContents")] ReplaceContents { value: String }, #[serde(rename = "addHeader")] - AddHeader { - name: String, - value: String, - }, + AddHeader { name: String, value: String }, #[serde(rename = "insertHeader")] InsertHeader { index: u32, diff --git a/crates/smtp/src/inbound/milter/protocol.rs b/crates/smtp/src/inbound/milter/protocol.rs index 906715b9..902d0b5d 100644 --- a/crates/smtp/src/inbound/milter/protocol.rs +++ b/crates/smtp/src/inbound/milter/protocol.rs @@ -6,8 +6,6 @@ use std::net::IpAddr; - - use crate::inbound::milter::Action; use super::{Command, Error, Modification, Options, Response}; @@ -462,10 +460,7 @@ impl Response { } } -fn read_nul_terminated( - bytes: &mut std::slice::Iter, - expected_len: usize, -) -> Option { +fn read_nul_terminated(bytes: &mut std::slice::Iter, expected_len: usize) -> Option { let mut buf = Vec::with_capacity(expected_len); loop { match bytes.next()? { diff --git a/crates/smtp/src/outbound/dane/dnssec.rs b/crates/smtp/src/outbound/dane/dnssec.rs index da10231f..b15e8e61 100644 --- a/crates/smtp/src/outbound/dane/dnssec.rs +++ b/crates/smtp/src/outbound/dane/dnssec.rs @@ -12,11 +12,7 @@ use mail_auth::{ common::resolver::IntoFqdn, hickory_resolver::{ Name, - error::ResolveErrorKind, - proto::{ - error::ProtoErrorKind, - rr::rdata::tlsa::{CertUsage, Matching, Selector}, - }, + proto::rr::rdata::tlsa::{CertUsage, Matching, Selector}, }, }; use std::{future::Future, sync::Arc}; @@ -44,72 +40,68 @@ impl TlsaLookup for Server { } let mut entries = Vec::new(); - let tlsa_lookup = match self + let tlsa_lookup = self .core .smtp .resolvers .dnssec .resolver .tlsa_lookup(Name::from_str_relaxed(key.as_ref())?) - .await - { - Ok(tlsa_lookup) => tlsa_lookup, - Err(err) => { - return match &err.kind() { - ResolveErrorKind::Proto(proto_err) - if matches!(proto_err.kind(), ProtoErrorKind::RrsigsNotPresent { .. }) => - { - Ok(None) - } - _ => Err(err.into()), - }; - } - }; + .await?; let mut has_end_entities = false; let mut has_intermediates = false; + let mut found_insecure = false; for record in tlsa_lookup.as_lookup().record_iter() { - if let Some(tlsa) = record.data().and_then(|r| r.as_tlsa()) { - let is_end_entity = match tlsa.cert_usage() { - CertUsage::DomainIssued => true, - CertUsage::TrustAnchor => false, - _ => continue, - }; - if is_end_entity { - has_end_entities = true; + if let Some(tlsa) = record.data().as_tlsa() { + if record.proof().is_secure() { + let is_end_entity = match tlsa.cert_usage() { + CertUsage::DaneEe => true, + CertUsage::DaneTa => false, + _ => continue, + }; + if is_end_entity { + has_end_entities = true; + } else { + has_intermediates = true; + } + entries.push(TlsaEntry { + is_end_entity, + is_sha256: match tlsa.matching() { + Matching::Sha256 => true, + Matching::Sha512 => false, + _ => continue, + }, + is_spki: match tlsa.selector() { + Selector::Spki => true, + Selector::Full => false, + _ => continue, + }, + data: tlsa.cert_data().to_vec(), + }); } else { - has_intermediates = true; + found_insecure = true; } - entries.push(TlsaEntry { - is_end_entity, - is_sha256: match tlsa.matching() { - Matching::Sha256 => true, - Matching::Sha512 => false, - _ => continue, - }, - is_spki: match tlsa.selector() { - Selector::Spki => true, - Selector::Full => false, - _ => continue, - }, - data: tlsa.cert_data().to_vec(), - }); } } - let tlsa = Arc::new(Tlsa { - entries, - has_end_entities, - has_intermediates, - }); + if !entries.is_empty() || !found_insecure { + let tlsa = Arc::new(Tlsa { + entries, + has_end_entities, + has_intermediates, + }); - self.inner.cache.dns_tlsa.insert_with_expiry( - key.into_owned(), - tlsa.clone(), - tlsa_lookup.valid_until(), - ); + self.inner.cache.dns_tlsa.insert_with_expiry( + key.into_owned(), + tlsa.clone(), + tlsa_lookup.valid_until(), + ); - Ok(Some(tlsa)) + Ok(Some(tlsa)) + } else { + Ok(None) + } } } diff --git a/crates/smtp/src/reporting/analysis.rs b/crates/smtp/src/reporting/analysis.rs index 1d480513..b5244564 100644 --- a/crates/smtp/src/reporting/analysis.rs +++ b/crates/smtp/src/reporting/analysis.rs @@ -4,28 +4,27 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use std::{ - borrow::Cow, - collections::hash_map::Entry, - io::{Cursor, Read}, -}; - use ahash::AHashMap; use common::Server; - use mail_auth::{ flate2::read::GzDecoder, report::{ActionDisposition, DmarcResult, Feedback, Report, tlsrpt::TlsReport}, zip, }; use mail_parser::{Message, MimeHeaders, PartType}; - +use std::{ + borrow::Cow, + collections::hash_map::Entry, + io::{Cursor, Read}, +}; use store::{ Serialize, - write::{BatchBuilder, LegacyBincode, ReportClass, ValueClass, now}, + write::{Archiver, BatchBuilder, ReportClass, ValueClass, now}, }; use trc::IncomingReportEvent; +use super::ReportSerializer; + enum Compression { None, Gzip, @@ -44,7 +43,7 @@ struct ReportData<'x> { data: &'x [u8], } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, serde::Serialize)] pub struct IncomingReport { pub from: String, pub to: Vec, @@ -282,12 +281,12 @@ impl AnalyzeReport for Server { Format::Dmarc(report) => { batch.set( ValueClass::Report(ReportClass::Dmarc { id, expires }), - LegacyBincode::new(IncomingReport { + Archiver::new(ReportSerializer(IncomingReport { from, to, subject, report, - }) + })) .serialize() .unwrap_or_default(), ); @@ -295,12 +294,12 @@ impl AnalyzeReport for Server { Format::Tls(report) => { batch.set( ValueClass::Report(ReportClass::Tls { id, expires }), - LegacyBincode::new(IncomingReport { + Archiver::new(ReportSerializer(IncomingReport { from, to, subject, report, - }) + })) .serialize() .unwrap_or_default(), ); @@ -308,12 +307,12 @@ impl AnalyzeReport for Server { Format::Arf(report) => { batch.set( ValueClass::Report(ReportClass::Arf { id, expires }), - LegacyBincode::new(IncomingReport { + Archiver::new(ReportSerializer(IncomingReport { from, to, subject, report, - }) + })) .serialize() .unwrap_or_default(), ); diff --git a/crates/smtp/src/reporting/dmarc.rs b/crates/smtp/src/reporting/dmarc.rs index 3e90a392..9942f70f 100644 --- a/crates/smtp/src/reporting/dmarc.rs +++ b/crates/smtp/src/reporting/dmarc.rs @@ -24,7 +24,7 @@ use mail_auth::{ }; use store::{ Deserialize, IterateParams, Serialize, ValueKey, - write::{BatchBuilder, LegacyBincode, QueueClass, ReportEvent, ValueClass}, + write::{AlignedBytes, Archive, Archiver, BatchBuilder, QueueClass, ReportEvent, ValueClass}, }; use trc::{AddContext, OutgoingReportEvent}; use utils::config::Rate; @@ -35,9 +35,18 @@ use crate::{ reporting::SmtpReporting, }; -use super::{AggregateTimestamp, SerializedSize}; +use super::{AggregateTimestamp, ReportSerializer, SerializedSize}; -#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[derive( + Debug, + PartialEq, + Eq, + rkyv::Serialize, + rkyv::Deserialize, + rkyv::Archive, + serde::Serialize, + serde::Deserialize, +)] pub struct DmarcFormat { pub rua: Vec, pub policy: PolicyPublished, @@ -466,15 +475,13 @@ impl DmarcReporting for Server { ) -> trc::Result> { // Deserialize report let dmarc = match self - .core - .storage - .data - .get_value::>(ValueKey::from(ValueClass::Queue( + .store() + .get_value::>(ValueKey::from(ValueClass::Queue( QueueClass::DmarcReportHeader(event.clone()), ))) .await? { - Some(dmarc) => dmarc.inner, + Some(dmarc) => dmarc.deserialize::>()?.0, None => { return Ok(None); } @@ -543,9 +550,10 @@ impl DmarcReporting for Server { self.core .storage .data - .iterate( - IterateParams::new(from_key, to_key).ascending(), - |_, v| match record_map.entry(LegacyBincode::::deserialize(v)?.inner) { + .iterate(IterateParams::new(from_key, to_key).ascending(), |_, v| { + let archive = as Deserialize>::deserialize(v)?; + + match record_map.entry(archive.deserialize::>()?.0) { Entry::Occupied(mut e) => { *e.get_mut() += 1; Ok(true) @@ -563,8 +571,8 @@ impl DmarcReporting for Server { Ok(false) } } - }, - ) + } + }) .await .caused_by(trc::location!())?; @@ -652,8 +660,8 @@ impl DmarcReporting for Server { // Write report builder.set( ValueClass::Queue(QueueClass::DmarcReportHeader(report_event.clone())), - match LegacyBincode::new(entry).serialize() { - Ok(data) => data, + match Archiver::new(ReportSerializer(entry)).serialize() { + Ok(data) => data.to_vec(), Err(err) => { trc::error!( err.caused_by(trc::location!()) @@ -669,8 +677,8 @@ impl DmarcReporting for Server { report_event.seq_id = self.inner.data.queue_id_gen.generate(); builder.set( ValueClass::Queue(QueueClass::DmarcReportEvent(report_event)), - match LegacyBincode::new(event.report_record).serialize() { - Ok(data) => data, + match Archiver::new(ReportSerializer(event.report_record)).serialize() { + Ok(data) => data.to_vec(), Err(err) => { trc::error!( err.caused_by(trc::location!()) diff --git a/crates/smtp/src/reporting/mod.rs b/crates/smtp/src/reporting/mod.rs index 3c8be044..b0b545b0 100644 --- a/crates/smtp/src/reporting/mod.rs +++ b/crates/smtp/src/reporting/mod.rs @@ -19,7 +19,10 @@ use mail_auth::{ }; use mail_parser::DateTime; -use store::write::{ReportEvent, key::KeySerializer}; +use store::{ + SERIALIZE_REPORT_V1, SerializedVersion, + write::{ReportEvent, key::KeySerializer}, +}; use tokio::io::{AsyncRead, AsyncWrite}; use crate::{ @@ -353,3 +356,32 @@ impl ReportLock for ReportEvent { .finalize() } } + +#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)] +#[repr(transparent)] +pub struct ReportSerializer(pub T) +where + T: rkyv::Archive + + for<'a> rkyv::Serialize< + rkyv::api::high::HighSerializer< + rkyv::util::AlignedVec, + rkyv::ser::allocator::ArenaHandle<'a>, + rkyv::rancor::Error, + >, + >; + +impl SerializedVersion for ReportSerializer +where + T: rkyv::Archive + + for<'a> rkyv::Serialize< + rkyv::api::high::HighSerializer< + rkyv::util::AlignedVec, + rkyv::ser::allocator::ArenaHandle<'a>, + rkyv::rancor::Error, + >, + >, +{ + fn serialize_version() -> u8 { + SERIALIZE_REPORT_V1 + } +} diff --git a/crates/smtp/src/reporting/tls.rs b/crates/smtp/src/reporting/tls.rs index 30ae61e4..b0e0a73b 100644 --- a/crates/smtp/src/reporting/tls.rs +++ b/crates/smtp/src/reporting/tls.rs @@ -29,13 +29,13 @@ use reqwest::header::CONTENT_TYPE; use std::fmt::Write; use store::{ Deserialize, IterateParams, Serialize, ValueKey, - write::{BatchBuilder, LegacyBincode, QueueClass, ReportEvent, ValueClass}, + write::{AlignedBytes, Archive, Archiver, BatchBuilder, QueueClass, ReportEvent, ValueClass}, }; use trc::{AddContext, OutgoingReportEvent}; use crate::{queue::RecipientDomain, reporting::SmtpReporting}; -use super::{AggregateTimestamp, SerializedSize}; +use super::{AggregateTimestamp, ReportSerializer, SerializedSize}; #[derive(Debug, Clone)] pub struct TlsRptOptions { @@ -43,7 +43,7 @@ pub struct TlsRptOptions { pub interval: AggregateFrequency, } -#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[derive(Debug, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, serde::Serialize)] pub struct TlsFormat { pub rua: Vec, pub policy: PolicyDetails, @@ -297,15 +297,13 @@ impl TlsReporting for Server { for event in events { let tls = if let Some(tls) = self - .core - .storage - .data - .get_value::>(ValueKey::from(ValueClass::Queue( + .store() + .get_value::>(ValueKey::from(ValueClass::Queue( QueueClass::TlsReportHeader(event.clone()), ))) .await? { - tls.inner + tls.deserialize::>()?.0 } else { continue; }; @@ -338,8 +336,10 @@ impl TlsReporting for Server { .storage .data .iterate(IterateParams::new(from_key, to_key).ascending(), |_, v| { - if let Some(failure_details) = - LegacyBincode::>::deserialize(v)?.inner + let archive = as Deserialize>::deserialize(v)?; + if let Some(failure_details) = archive + .deserialize::>>()? + .0 { match record_map.entry(failure_details) { Entry::Occupied(mut e) => { @@ -492,8 +492,8 @@ impl TlsReporting for Server { // Write report builder.set( ValueClass::Queue(QueueClass::TlsReportHeader(report_event.clone())), - match LegacyBincode::new(entry).serialize() { - Ok(data) => data, + match Archiver::new(ReportSerializer(entry)).serialize() { + Ok(data) => data.to_vec(), Err(err) => { trc::error!( err.caused_by(trc::location!()) @@ -509,8 +509,8 @@ impl TlsReporting for Server { report_event.seq_id = self.inner.data.queue_id_gen.generate(); builder.set( ValueClass::Queue(QueueClass::TlsReportEvent(report_event)), - match LegacyBincode::new(event.failure).serialize() { - Ok(data) => data, + match Archiver::new(ReportSerializer(event.failure)).serialize() { + Ok(data) => data.to_vec(), Err(err) => { trc::error!( err.caused_by(trc::location!()) diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml index 9fa11fca..1c89cfcb 100644 --- a/crates/spam-filter/Cargo.toml +++ b/crates/spam-filter/Cargo.toml @@ -11,9 +11,9 @@ store = { path = "../store" } trc = { path = "../trc" } common = { path = "../common" } smtp-proto = { version = "0.1", features = ["rkyv"] } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.6" } +mail-auth = { version = "0.7" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } tokio = { version = "1.23", features = ["net", "macros"] } psl = "2" @@ -22,7 +22,7 @@ idna = "1.0" reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2", "stream"]} decancer = "3.0.1" unicode-security = "0.1.0" -infer = "0.16" +infer = "0.19" sha1 = "0.10" sha2 = "0.10.6" compact_str = "0.9.0" diff --git a/crates/spam-filter/src/analysis/domain.rs b/crates/spam-filter/src/analysis/domain.rs index 7c734f52..87a6b690 100644 --- a/crates/spam-filter/src/analysis/domain.rs +++ b/crates/spam-filter/src/analysis/domain.rs @@ -86,7 +86,7 @@ impl SpamFilterAnalyzeDomain for Server { ctx.input .message .raw_message - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(), ) .parse_address() @@ -143,6 +143,7 @@ impl SpamFilterAnalyzeDomain for Server { // Add emails found in the message for (part_id, part) in ctx.output.text_parts.iter().enumerate() { + let part_id = part_id as u32; let is_body = ctx.input.message.text_body.contains(&part_id) || ctx.input.message.html_body.contains(&part_id); let tokens = match part { diff --git a/crates/spam-filter/src/analysis/from.rs b/crates/spam-filter/src/analysis/from.rs index a98e7c70..013be8af 100644 --- a/crates/spam-filter/src/analysis/from.rs +++ b/crates/spam-filter/src/analysis/from.rs @@ -35,7 +35,7 @@ impl SpamFilterAnalyzeFrom for Server { .input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(); } HeaderName::Other(name) => { diff --git a/crates/spam-filter/src/analysis/headers.rs b/crates/spam-filter/src/analysis/headers.rs index c7d2dbf9..4d71c007 100644 --- a/crates/spam-filter/src/analysis/headers.rs +++ b/crates/spam-filter/src/analysis/headers.rs @@ -59,7 +59,7 @@ impl SpamFilterAnalyzeHeaders for Server { ctx.result.add_tag("MULTIPLE_UNIQUE_HEADERS"); } - if !matches!(raw_message.get(header.offset_start), Some(b' ')) { + if !matches!(raw_message.get(header.offset_start as usize), Some(b' ')) { ctx.result.add_tag("HEADER_EMPTY_DELIMITER"); } } diff --git a/crates/spam-filter/src/analysis/html.rs b/crates/spam-filter/src/analysis/html.rs index 4104d2c1..fdebc274 100644 --- a/crates/spam-filter/src/analysis/html.rs +++ b/crates/spam-filter/src/analysis/html.rs @@ -40,6 +40,7 @@ impl SpamFilterAnalyzeHtml for Server { } for (part_id, part) in ctx.output.text_parts.iter().enumerate() { + let part_id = part_id as u32; let is_body_part = ctx.input.message.text_body.contains(&part_id) || ctx.input.message.html_body.contains(&part_id); diff --git a/crates/spam-filter/src/analysis/ip.rs b/crates/spam-filter/src/analysis/ip.rs index 6ec7c678..6c7bf398 100644 --- a/crates/spam-filter/src/analysis/ip.rs +++ b/crates/spam-filter/src/analysis/ip.rs @@ -58,6 +58,7 @@ impl SpamFilterAnalyzeIp for Server { // Obtain IP addresses from the message body for (part_id, part) in ctx.output.text_parts.iter().enumerate() { + let part_id = part_id as u32; let is_body = ctx.input.message.text_body.contains(&part_id) || ctx.input.message.html_body.contains(&part_id); match part { diff --git a/crates/spam-filter/src/analysis/messageid.rs b/crates/spam-filter/src/analysis/messageid.rs index fac567c7..758a772e 100644 --- a/crates/spam-filter/src/analysis/messageid.rs +++ b/crates/spam-filter/src/analysis/messageid.rs @@ -27,7 +27,8 @@ impl SpamFilterAnalyzeMid for Server { if let (HeaderName::MessageId, value) = (&header.name, &header.value) { mid = value.as_text().unwrap_or_default(); mid_raw = std::str::from_utf8( - &ctx.input.message.raw_message()[header.offset_start..header.offset_end], + &ctx.input.message.raw_message() + [header.offset_start as usize..header.offset_end as usize], ) .unwrap_or_default() .trim(); diff --git a/crates/spam-filter/src/analysis/mime.rs b/crates/spam-filter/src/analysis/mime.rs index d9a81fcc..bddc6a1e 100644 --- a/crates/spam-filter/src/analysis/mime.rs +++ b/crates/spam-filter/src/analysis/mime.rs @@ -40,7 +40,7 @@ impl SpamFilterAnalyzeMime for Server { .input .message .raw_message() - .get(header.offset_field..header.offset_start - 1) + .get(header.offset_field as usize..header.offset_start as usize - 1) != Some(b"MIME-Version") { ctx.result.add_tag("MV_CASE"); @@ -99,6 +99,7 @@ impl SpamFilterAnalyzeMime for Server { let mut num_parts_size = 0; for (part_id, part) in ctx.input.message.parts.iter().enumerate() { + let part_id = part_id as u32; let mut ct = None; let mut cd = None; let mut ct_type = String::new(); @@ -127,7 +128,7 @@ impl SpamFilterAnalyzeMime for Server { } if raw_message - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .and_then(|s| s.trim_ascii_end().last()) == Some(&b';') { @@ -171,7 +172,10 @@ impl SpamFilterAnalyzeMime for Server { let mut html_part_words = vec![]; let mut html_part_uris = 0; - for text_part in part_ids.iter().map(|id| &ctx.output.text_parts[*id]) { + for text_part in part_ids + .iter() + .map(|id| &ctx.output.text_parts[*id as usize]) + { let (tokens, words, uri_count) = match text_part { TextPart::Plain { tokens, .. } if !has_plain_part => { has_plain_part = true; @@ -233,7 +237,7 @@ impl SpamFilterAnalyzeMime for Server { for (sub_part_id, sub_part) in part_ids .iter() - .map(|id| (*id, &ctx.input.message.parts[*id])) + .map(|id| (*id, &ctx.input.message.parts[*id as usize])) { let ctype = sub_part .content_type() @@ -267,7 +271,9 @@ impl SpamFilterAnalyzeMime for Server { match cte.as_str() { "" | "7bit" => { if raw_message - .get(part.raw_body_offset()..part.raw_end_offset()) + .get( + part.raw_body_offset() as usize..part.raw_end_offset() as usize, + ) .is_some_and(|bytes| !bytes.is_ascii()) { // MIME text part claims to be ASCII but isn't @@ -300,7 +306,7 @@ impl SpamFilterAnalyzeMime for Server { if ctx .output .text_parts - .get(part_id) + .get(part_id as usize) .filter(|_| { ctx.input.message.text_body.contains(&part_id) || ctx.input.message.html_body.contains(&part_id) diff --git a/crates/spam-filter/src/analysis/mod.rs b/crates/spam-filter/src/analysis/mod.rs index 35f961fb..1c3a3d80 100644 --- a/crates/spam-filter/src/analysis/mod.rs +++ b/crates/spam-filter/src/analysis/mod.rs @@ -46,7 +46,7 @@ impl SpamFilterInput<'_> { pub fn header_as_address(&self, header: &Header<'_>) -> Option> { self.message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .map(|bytes| MessageStream::new(bytes).parse_address()) .and_then(|addr| addr.into_address()) .and_then(|addr| addr.into_list().into_iter().next()) @@ -70,7 +70,7 @@ impl SpamFilterContext<'_> { .text_body .first() .or_else(|| self.input.message.html_body.first()) - .and_then(|idx| self.output.text_parts.get(*idx)) + .and_then(|idx| self.output.text_parts.get(*idx as usize)) .and_then(|part| match part { TextPart::Plain { text_body, .. } => Some(*text_body), TextPart::Html { text_body, .. } => Some(text_body.as_str()), diff --git a/crates/spam-filter/src/analysis/received.rs b/crates/spam-filter/src/analysis/received.rs index 82e176be..8c4f2c62 100644 --- a/crates/spam-filter/src/analysis/received.rs +++ b/crates/spam-filter/src/analysis/received.rs @@ -30,7 +30,7 @@ impl SpamFilterAnalyzeReceived for Server { .input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default() .is_ascii() { diff --git a/crates/spam-filter/src/analysis/recipient.rs b/crates/spam-filter/src/analysis/recipient.rs index f492f91e..1e8bebcc 100644 --- a/crates/spam-filter/src/analysis/recipient.rs +++ b/crates/spam-filter/src/analysis/recipient.rs @@ -35,7 +35,7 @@ impl SpamFilterAnalyzeRecipient for Server { .input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(); match header.name { HeaderName::To => to_raw = raw, diff --git a/crates/spam-filter/src/analysis/replyto.rs b/crates/spam-filter/src/analysis/replyto.rs index 974ff5fc..5a2b3a66 100644 --- a/crates/spam-filter/src/analysis/replyto.rs +++ b/crates/spam-filter/src/analysis/replyto.rs @@ -30,7 +30,7 @@ impl SpamFilterAnalyzeReplyTo for Server { .input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(); } HeaderName::ListUnsubscribe | HeaderName::ListId => { diff --git a/crates/spam-filter/src/analysis/rules.rs b/crates/spam-filter/src/analysis/rules.rs index ed9a3e17..04f8e743 100644 --- a/crates/spam-filter/src/analysis/rules.rs +++ b/crates/spam-filter/src/analysis/rules.rs @@ -125,7 +125,7 @@ impl SpamFilterAnalyzeRules for Server { ctx.input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(), ); let header_resolver = EmailHeader { @@ -155,6 +155,7 @@ impl SpamFilterAnalyzeRules for Server { TextPart::Html { text_body, .. } => text_body.as_str(), TextPart::None => continue, }; + let idx = idx as u32; let location = if ctx.input.message.text_body.contains(&idx) { Location::BodyText } else if ctx.input.message.html_body.contains(&idx) { diff --git a/crates/spam-filter/src/analysis/subject.rs b/crates/spam-filter/src/analysis/subject.rs index e98a670b..acaa9227 100644 --- a/crates/spam-filter/src/analysis/subject.rs +++ b/crates/spam-filter/src/analysis/subject.rs @@ -30,7 +30,7 @@ impl SpamFilterAnalyzeSubject for Server { .input .message .raw_message() - .get(header.offset_start..header.offset_end) + .get(header.offset_start as usize..header.offset_end as usize) .unwrap_or_default(); break; } diff --git a/crates/spam-filter/src/analysis/url.rs b/crates/spam-filter/src/analysis/url.rs index a9636e34..a0d66391 100644 --- a/crates/spam-filter/src/analysis/url.rs +++ b/crates/spam-filter/src/analysis/url.rs @@ -58,6 +58,7 @@ impl SpamFilterAnalyzeUrl for Server { _ => None, })); for (part_id, part) in ctx.output.text_parts.iter().enumerate() { + let part_id = part_id as u32; let is_body = ctx.input.message.text_body.contains(&part_id) || ctx.input.message.html_body.contains(&part_id); diff --git a/crates/spam-filter/src/modules/bayes.rs b/crates/spam-filter/src/modules/bayes.rs index 65fedbf1..12117cc1 100644 --- a/crates/spam-filter/src/modules/bayes.rs +++ b/crates/spam-filter/src/modules/bayes.rs @@ -90,7 +90,7 @@ impl BayesClassifier for Server { .html_body .first() .or_else(|| ctx.input.message.text_body.first()) - .and_then(|idx| ctx.output.text_parts.get(*idx)) + .and_then(|idx| ctx.output.text_parts.get(*idx as usize)) { Some(TextPart::Html { text_body, tokens, .. @@ -249,7 +249,7 @@ impl BayesClassifier for Server { .html_body .first() .or_else(|| ctx.input.message.text_body.first()) - .and_then(|idx| ctx.output.text_parts.get(*idx)) + .and_then(|idx| ctx.output.text_parts.get(*idx as usize)) { Some(TextPart::Html { text_body, tokens, .. diff --git a/crates/spam-filter/src/modules/expression.rs b/crates/spam-filter/src/modules/expression.rs index 49213da5..5453ebac 100644 --- a/crates/spam-filter/src/modules/expression.rs +++ b/crates/spam-filter/src/modules/expression.rs @@ -211,7 +211,7 @@ impl ResolveVariable for SpamFilterResolver<'_, T> { .message .html_body .first() - .and_then(|idx| self.ctx.output.text_parts.get(*idx)) + .and_then(|idx| self.ctx.output.text_parts.get(*idx as usize)) .map(|part| { if let TextPart::Html { text_body, .. } = part { text_body.as_str() @@ -247,7 +247,7 @@ impl ResolveVariable for SpamFilterResolver<'_, T> { .message .html_body .first() - .and_then(|idx| self.ctx.output.text_parts.get(*idx)) + .and_then(|idx| self.ctx.output.text_parts.get(*idx as usize)) .map(|part| match part { TextPart::Plain { tokens, .. } | TextPart::Html { tokens, .. } => tokens .iter() @@ -343,7 +343,11 @@ impl ResolveVariable for EmailHeader<'_> { ct.attributes() .map(|attr| { attr.iter() - .map(|(k, v)| Variable::from(format_compact!("{k}={v}"))) + .map(|attr| { + Variable::from(format_compact!( + "{}={}", attr.name, attr.value + )) + }) .collect::>() }) .unwrap_or_default(), diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 4fb8a6a8..562efaa0 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -10,8 +10,8 @@ nlp = { path = "../nlp" } trc = { path = "../trc" } rocksdb = { version = "0.23", optional = true, features = ["multi-threaded-cf"] } foundationdb = { version = "0.9.2", features = ["embedded-fdb-include", "fdb-7_3"], optional = true } -rusqlite = { version = "0.34", features = ["bundled"], optional = true } -rust-s3 = { version = "=0.35.0-alpha.2", default-features = false, features = ["tokio-rustls-tls", "no-verify-ssl"], optional = true } +rusqlite = { version = "0.35", features = ["bundled"], optional = true } +rust-s3 = { version = "0.35", default-features = false, features = ["tokio-rustls-tls", "no-verify-ssl"], optional = true } azure_core = { version = "0.21.0", optional = true } azure_storage = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true } azure_storage_blobs = { version = "0.21.0", default-features = false, features = ["enable_reqwest_rustls", "hmac_rust"], optional = true } @@ -38,7 +38,7 @@ rustls = { version = "0.23.5", optional = true, default-features = false, featur rustls-pki-types = { version = "1", optional = true } ring = { version = "0.17", optional = true } bytes = { version = "1.0", optional = true } -mysql_async = { version = "=0.34.1", default-features = false, features = ["default-rustls"], optional = true } +mysql_async = { version = "0.36", default-features = false, features = ["default-rustls-ring", "minimal"], optional = true } elasticsearch = { version = "8.5.0-alpha.1", default-features = false, features = ["rustls-tls"], optional = true } serde_json = {version = "1.0.64", optional = true } regex = "1.7.0" @@ -46,7 +46,6 @@ flate2 = "1.0" async-trait = "0.1.68" redis = { version = "0.29", features = [ "tokio-comp", "tokio-rustls-comp", "tls-rustls-insecure", "tls-rustls-webpki-roots", "cluster-async"], optional = true } deadpool = { version = "0.12", features = ["managed"], optional = true } -bincode = "1.3.3" arc-swap = "1.6.0" bitpacking = "0.9.2" memchr = { version = "2" } diff --git a/crates/store/src/backend/s3/mod.rs b/crates/store/src/backend/s3/mod.rs index bdf66892..bdb54dd8 100644 --- a/crates/store/src/backend/s3/mod.rs +++ b/crates/store/src/backend/s3/mod.rs @@ -13,7 +13,7 @@ use utils::{ }; pub struct S3Store { - bucket: Bucket, + bucket: Box, prefix: Option, max_retries: u32, } diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 1fa794fd..f38a99f2 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -88,6 +88,7 @@ pub const SERIALIZE_CALENDAR_V1: u8 = 13; pub const SERIALIZE_ADDRESSBOOK_V1: u8 = 14; pub const SERIALIZE_CALENDAREVENT_V1: u8 = 15; pub const SERIALIZE_PRINCIPAL_V1: u8 = 16; +pub const SERIALIZE_REPORT_V1: u8 = 17; pub trait SerializedVersion { fn serialize_version() -> u8; diff --git a/crates/store/src/write/mod.rs b/crates/store/src/write/mod.rs index 5d806679..cb5f70f3 100644 --- a/crates/store/src/write/mod.rs +++ b/crates/store/src/write/mod.rs @@ -60,14 +60,6 @@ where >, >; -#[derive(Debug)] -pub struct LegacyBincode { - pub inner: T, -} - -#[derive(Debug, PartialEq, Clone, Eq, Hash)] -pub struct DynamicDocumentId(pub usize); - #[derive(Debug, Default)] pub struct AssignedIds { pub counter_ids: Vec, diff --git a/crates/store/src/write/serialize.rs b/crates/store/src/write/serialize.rs index 0cec9930..0ee06c0a 100644 --- a/crates/store/src/write/serialize.rs +++ b/crates/store/src/write/serialize.rs @@ -4,13 +4,11 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use super::{ARCHIVE_ALIGNMENT, AlignedBytes, Archive, Archiver}; +use crate::{Deserialize, Serialize, SerializeInfallible, SerializedVersion, U32_LEN, Value}; use compact_str::format_compact; use rkyv::util::AlignedVec; -use crate::{Deserialize, Serialize, SerializeInfallible, SerializedVersion, U32_LEN, Value}; - -use super::{ARCHIVE_ALIGNMENT, AlignedBytes, Archive, Archiver, LegacyBincode}; - const MAGIC_MARKER: u8 = 1 << 7; const LZ4_COMPRESSED: u8 = 1 << 6; const ARCHIVE_UNCOMPRESSED: u8 = MAGIC_MARKER; @@ -483,55 +481,8 @@ impl Deserialize for () { } } -impl LegacyBincode { - pub fn new(inner: T) -> Self { - Self { inner } - } -} - -impl Serialize for LegacyBincode { - fn serialize(&self) -> trc::Result> { - bincode::serialize(&self.inner) - .map(|bytes| lz4_flex::compress_prepend_size(&bytes)) - .map_err(|err| { - trc::StoreEvent::DeserializeError - .caused_by(trc::location!()) - .reason(err) - }) - } -} - -impl Deserialize - for LegacyBincode -{ - fn deserialize(bytes: &[u8]) -> trc::Result { - lz4_flex::decompress_size_prepended(bytes) - .map_err(|err| { - trc::StoreEvent::DecompressError - .ctx(trc::Key::Value, bytes) - .caused_by(trc::location!()) - .reason(err) - }) - .and_then(|result| { - bincode::deserialize(&result).map_err(|err| { - trc::StoreEvent::DataCorruption - .ctx(trc::Key::Value, bytes) - .caused_by(trc::location!()) - .reason(err) - }) - }) - .map(|inner| Self { inner }) - } -} - impl From> for Archive { fn from(_: Value<'static>) -> Self { unimplemented!() } } - -impl From> for LegacyBincode { - fn from(_: Value<'static>) -> Self { - unimplemented!() - } -} diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index fae015dc..b17463b2 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -6,13 +6,12 @@ resolver = "2" [dependencies] event_macro = { path = "./event-macro" } -mail-auth = { version = "0.6" } -mail-parser = { version = "0.10", features = ["full_encoding"] } +mail-auth = { version = "0.7" } +mail-parser = { version = "0.11", features = ["full_encoding"] } base64 = "0.22.1" serde = "1.0" serde_json = "1.0.120" reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"]} -bincode = "1.3.3" rtrb = "0.3.1" parking_lot = "0.12.3" tokio = { version = "1.23", features = ["net", "macros"] } diff --git a/crates/trc/src/event/conv.rs b/crates/trc/src/event/conv.rs index 41366933..d68a31d7 100644 --- a/crates/trc/src/event/conv.rs +++ b/crates/trc/src/event/conv.rs @@ -205,10 +205,6 @@ impl EventType { .reason(err) } - pub fn from_bincode_error(self, err: bincode::Error) -> Error { - self.reason(err).details("Bincode deserialization failed") - } - pub fn from_http_str_error(self, err: reqwest::header::ToStrError) -> Error { self.reason(err) .details("Failed to convert header to string") diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 76071f75..8fecdf3a 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -12,7 +12,7 @@ rustls-pki-types = { version = "1" } tokio = { version = "1.23", features = ["net", "macros"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } serde = { version = "1.0", features = ["derive"]} -mail-auth = { version = "0.6" } +mail-auth = { version = "0.7" } smtp-proto = { version = "0.1" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } ahash = { version = "0.8", features = ["serde"] } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 0b5b3a5f..6245e429 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -42,11 +42,11 @@ trc = { path = "../crates/trc" } managesieve = { path = "../crates/managesieve", features = ["test_mode", "enterprise"] } smtp-proto = { version = "0.1" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } -mail-auth = { version = "0.6", features = ["test"] } -sieve-rs = { version = "0.6" } +mail-auth = { version = "0.7", features = ["test"] } +sieve-rs = { version = "0.7", features = ["rkyv"] } utils = { path = "../crates/utils", features = ["test_mode"] } jmap-client = { version = "0.3", features = ["websockets", "debug", "async"] } -mail-parser = { version = "0.10", features = ["full_encoding", "serde_support"] } +mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] } tokio = { version = "1.23", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"] } diff --git a/tests/src/imap/body_structure.rs b/tests/src/imap/body_structure.rs index a905a6e6..585b4b23 100644 --- a/tests/src/imap/body_structure.rs +++ b/tests/src/imap/body_structure.rs @@ -39,7 +39,10 @@ fn imap_test_body_structure() { raw_headers: message_ .raw_message .as_ref() - .get(message_.root_part().offset_header..message_.root_part().offset_body) + .get( + message_.root_part().offset_header as usize + ..message_.root_part().offset_body as usize, + ) .unwrap_or_default() .to_vec(), contents: vec![], diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs index 26b28580..490f3e40 100644 --- a/tests/src/jmap/mod.rs +++ b/tests/src/jmap/mod.rs @@ -102,7 +102,7 @@ async fn jmap_tests_() { .await; webhooks::test(&mut params).await; - /*email_query::test(&mut params, delete).await; + email_query::test(&mut params, delete).await; email_get::test(&mut params).await; email_set::test(&mut params).await; email_parse::test(&mut params).await; @@ -125,7 +125,7 @@ async fn jmap_tests_() { websocket::test(&mut params).await; quota::test(&mut params).await; crypto::test(&mut params).await; - blob::test(&mut params).await;*/ + blob::test(&mut params).await; permissions::test(¶ms).await; purge::test(&mut params).await; enterprise::test(&mut params).await; diff --git a/tests/src/smtp/inbound/milter.rs b/tests/src/smtp/inbound/milter.rs index 331e3d7a..11739329 100644 --- a/tests/src/smtp/inbound/milter.rs +++ b/tests/src/smtp/inbound/milter.rs @@ -604,7 +604,7 @@ async fn milter_client_test() { let r = client.headers(message.headers_raw()).await.unwrap(); println!("HEADERS: {:?}", r); let r = client - .body(&message.raw_message()[message.root_part().raw_body_offset()..]) + .body(&message.raw_message()[message.root_part().raw_body_offset() as usize..]) .await .unwrap(); println!("BODY: {:?}", r); diff --git a/tests/src/smtp/lookup/sql.rs b/tests/src/smtp/lookup/sql.rs index e94bbef2..b619451e 100644 --- a/tests/src/smtp/lookup/sql.rs +++ b/tests/src/smtp/lookup/sql.rs @@ -11,7 +11,6 @@ use common::{ expr::{tokenizer::TokenMap, *}, }; - use directory::{ QueryBy, Type, backend::internal::{PrincipalField, PrincipalSet, PrincipalValue, manage::ManageDirectory}, diff --git a/tests/src/smtp/mod.rs b/tests/src/smtp/mod.rs index 84599ec2..71433677 100644 --- a/tests/src/smtp/mod.rs +++ b/tests/src/smtp/mod.rs @@ -146,8 +146,8 @@ lookup = "{STORE}" type = "rocksdb" path = "{TMP}/queue.db" -[store."foundationdb"] -type = "foundationdb" +#[store."foundationdb"] +#type = "foundationdb" [store."postgresql"] type = "postgresql" diff --git a/tests/src/smtp/outbound/dane.rs b/tests/src/smtp/outbound/dane.rs index 836bb593..e575914b 100644 --- a/tests/src/smtp/outbound/dane.rs +++ b/tests/src/smtp/outbound/dane.rs @@ -4,16 +4,11 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use std::{ - collections::BTreeSet, - fs::{self, File}, - io::{BufRead, BufReader}, - num::ParseIntError, - path::PathBuf, - sync::Arc, - time::{Duration, Instant}, +use crate::smtp::{ + DnsCache, TestSMTP, + inbound::{TestMessage, TestQueueEvent, TestReportingEvent}, + session::{TestSession, VerifyResponse}, }; - use common::{ Core, config::{ @@ -26,21 +21,25 @@ use mail_auth::{ MX, MessageAuthenticator, common::parse::TxtRecordParser, hickory_resolver::{ - AsyncResolver, + TokioResolver, config::{ResolverConfig, ResolverOpts}, + name_server::TokioConnectionProvider, }, mta_sts::{ReportUri, TlsRpt}, report::tlsrpt::ResultType, }; use rustls_pki_types::CertificateDer; - -use crate::smtp::{ - DnsCache, TestSMTP, - inbound::{TestMessage, TestQueueEvent, TestReportingEvent}, - session::{TestSession, VerifyResponse}, -}; use smtp::outbound::dane::{dnssec::TlsaLookup, verify::TlsaVerify}; use smtp::queue::{Error, ErrorDetails, Status}; +use std::{ + collections::BTreeSet, + fs::{self, File}, + io::{BufRead, BufReader}, + num::ParseIntError, + path::PathBuf, + sync::Arc, + time::{Duration, Instant}, +}; const LOCAL: &str = r#" [session.rcpt] @@ -246,7 +245,9 @@ async fn dane_test() { core.smtp.resolvers = Resolvers { dns: MessageAuthenticator::new_cloudflare().unwrap(), dnssec: DnssecResolver { - resolver: AsyncResolver::tokio(conf, opts), + resolver: TokioResolver::builder_with_config(conf, TokioConnectionProvider::default()) + .with_options(opts) + .build(), }, }; let r = TestSMTP::from_core(core).build_smtp();