diff --git a/Cargo.lock b/Cargo.lock index 9aeb830..67a1268 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ "async-channel 2.5.0", "async-compression", "base64 0.22.1", - "bytes 1.11.1", + "bytes 1.12.0", "chrono", "futures", "imap-proto", @@ -299,7 +299,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bichon-admin" -version = "1.6.1" +version = "1.6.2" dependencies = [ "bichon-core", "bichon-memdb", @@ -323,7 +323,7 @@ dependencies = [ "crc32fast", "criterion", "lz4_flex", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "tempfile", @@ -334,7 +334,7 @@ dependencies = [ [[package]] name = "bichon-cli" -version = "1.6.1" +version = "1.6.2" dependencies = [ "base64 0.22.1", "bichon-core", @@ -356,13 +356,13 @@ dependencies = [ [[package]] name = "bichon-core" -version = "1.6.1" +version = "1.6.2" dependencies = [ "async-imap", "base64 0.22.1", "bichon-memdb", "blake3", - "bytes 1.11.1", + "bytes 1.12.0", "chrono", "clap", "codepage-strings", @@ -389,8 +389,8 @@ dependencies = [ "oauth2", "outlook-pst", "poem-openapi", - "quick-xml 0.40.0", - "rand 0.10.1", + "quick-xml 0.41.0", + "rand 0.10.2", "regex", "reqwest", "ring", @@ -432,7 +432,7 @@ dependencies = [ [[package]] name = "bichon-server" -version = "1.6.1" +version = "1.6.2" dependencies = [ "bichon-core", "bichon-smtp", @@ -457,7 +457,7 @@ dependencies = [ [[package]] name = "bichon-smtp" -version = "1.6.1" +version = "1.6.2" dependencies = [ "base64 0.22.1", "bichon-core", @@ -577,6 +577,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +dependencies = [ + "memchr", + "serde_core", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -609,9 +619,9 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" [[package]] name = "byteview" @@ -819,7 +829,7 @@ version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "memchr", ] @@ -870,9 +880,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", @@ -895,6 +905,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -979,13 +999,14 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "cron" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5877d3fbf742507b66bc2a1945106bd30dd8504019d596901ddd012a4dd01740" +checksum = "a5dcd6f69605c2956916ce24e8af637b754964c9a83f4662d3a2361654cdba09" dependencies = [ "chrono", "once_cell", - "winnow 0.6.26", + "phf 0.11.3", + "winnow 0.7.15", ] [[package]] @@ -1290,18 +1311,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "enum_dispatch" version = "0.3.13" @@ -1397,9 +1406,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fjall" -version = "3.1.5" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038acd422d607e0eca09e093f299f9eccf9bd097554343d93746afff81a45113" +checksum = "9fcdc69609906151dff9b534e30eaf8515082055d36f628e382bd0b5d6a1d362" dependencies = [ "byteorder-lite", "byteview", @@ -1649,11 +1658,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1692,7 +1703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", - "bytes 1.11.1", + "bytes 1.12.0", "fnv", "futures-core", "futures-sink", @@ -1771,7 +1782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ "base64 0.22.1", - "bytes 1.11.1", + "bytes 1.12.0", "headers-core", "http", "httpdate", @@ -1807,28 +1818,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-proto" -version = "0.26.0-alpha.1" +name = "hickory-net" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62d7684f766b0f96344be88c023f9b6650039aea09d526b4974cce302eb61b1" +checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183" dependencies = [ "async-trait", "aws-lc-rs", "bitflags", - "bytes 1.11.1", + "bytes 1.12.0", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", + "hickory-proto", "idna", "ipnet", - "once_cell", - "rand 0.9.2", - "ring", + "jni", + "lru-cache", + "parking_lot", + "rand 0.10.2", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "thiserror 2.0.18", "time", "tinyvec", @@ -1839,22 +1852,51 @@ dependencies = [ ] [[package]] -name = "hickory-resolver" -version = "0.26.0-alpha.1" +name = "hickory-proto" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbab5e26a7f82341145ba1fbd1f1858d0490624fcc46270db2d3c4a101f763f4" +checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643" +dependencies = [ + "aws-lc-rs", + "bitflags", + "data-encoding", + "idna", + "ipnet", + "jni", + "once_cell", + "prefix-trie", + "rand 0.10.2", + "ring", + "rustls-pki-types", + "thiserror 2.0.18", + "time", + "tinyvec", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni", "moka", + "ndk-context", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.10.2", "resolv-conf", "rustls", "smallvec", + "system-configuration", "thiserror 2.0.18", "tokio", "tokio-rustls", @@ -1906,7 +1948,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "itoa", ] @@ -1916,7 +1958,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "http", ] @@ -1926,7 +1968,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "futures-core", "http", "http-body", @@ -1952,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", - "bytes 1.11.1", + "bytes 1.12.0", "futures-channel", "futures-core", "h2", @@ -1990,7 +2032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", - "bytes 1.11.1", + "bytes 1.12.0", "futures-channel", "futures-util", "http", @@ -2168,9 +2210,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.18.4" +version = "0.18.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c" dependencies = [ "console", "portable-atomic", @@ -2215,6 +2257,9 @@ name = "ipnet" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +dependencies = [ + "serde", +] [[package]] name = "iri-string" @@ -2402,6 +2447,12 @@ version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2447,6 +2498,15 @@ dependencies = [ "hashbrown 0.17.0", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2455,12 +2515,12 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "lsm-tree" -version = "3.1.5" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ef86c3c797c10eefcc73407c43ae48c19d4df686131a8334b2895a513e91df4" +checksum = "39ca67401338b98d58447387dd5230552d2241bc388206e491d137b18dfea9d6" dependencies = [ "byteorder-lite", - "bytes 1.11.1", + "bytes 1.12.0", "byteview", "crossbeam-skiplist", "enum_dispatch", @@ -2487,20 +2547,23 @@ dependencies = [ [[package]] name = "mail-auth" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f026538d37471da028cd5c6a907777c3de2d84e2c71b2b47ae301a10977c5e6" +checksum = "a88908ddf3a07fa2e76873f84d28476d3c802173fee0a44f6c5e5472523e6986" dependencies = [ "aws-lc-rs", "flate2", + "getrandom 0.2.17", + "getrandom 0.4.2", "hashify", "hickory-resolver", "mail-builder", "mail-parser", - "quick-xml 0.39.2", + "quick-xml 0.41.0", "rustls-pki-types", "serde", "serde_json", + "similar", "zip", ] @@ -2526,9 +2589,9 @@ dependencies = [ [[package]] name = "mail-send" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06f18f6ad15354b83645a05466570ced7bf770a17b138742e705d54407d83ba" +checksum = "dc851b8321041a68cc3b017135b6b8d2789a8b6e455aaebe60594bd6a39b2268" dependencies = [ "base64 0.22.1", "gethostname", @@ -2660,7 +2723,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "encoding_rs", "futures-util", "http", @@ -2754,6 +2817,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3115,6 +3184,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ + "phf_macros", "phf_shared 0.11.3", ] @@ -3134,10 +3204,20 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator", + "phf_generator 0.13.1", "phf_shared 0.13.1", ] +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.6", +] + [[package]] name = "phf_generator" version = "0.13.1" @@ -3148,6 +3228,19 @@ dependencies = [ "phf_shared 0.13.1", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "phf_shared" version = "0.11.3" @@ -3259,7 +3352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f977080932c87287147dca052951c3e2696f8759863f6b4e4c0c9ffe7a4cc8b" dependencies = [ "async-compression", - "bytes 1.11.1", + "bytes 1.12.0", "futures-util", "headers", "hex", @@ -3316,7 +3409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ccbcc395bf4dd03df1da32da351b6b6732e4074ce27ddec315650e52a2be44c" dependencies = [ "base64 0.22.1", - "bytes 1.11.1", + "bytes 1.12.0", "derive_more", "email_address", "futures-util", @@ -3390,6 +3483,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prefix-trie" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" +dependencies = [ + "either", + "ipnet", + "num-traits", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -3456,18 +3560,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7315c86b26aaef0321fba33c9dcc160da659c6a9d278f0f6a5656d6561c03b" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", "serde", @@ -3489,7 +3584,7 @@ version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "cfg_aliases", "pin-project-lite", "quinn-proto", @@ -3509,7 +3604,7 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "getrandom 0.3.4", "lru-slab", "rand 0.9.2", @@ -3588,9 +3683,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.2", @@ -3747,7 +3842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", - "bytes 1.11.1", + "bytes 1.12.0", "futures-channel", "futures-core", "futures-util", @@ -3931,9 +4026,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "web-time", "zeroize", @@ -3945,7 +4040,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", @@ -4021,7 +4116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -4227,6 +4322,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "similar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6505efef05804732ed8a3f2d4f279429eb485bd69d5b0cc6b19cc02005cda16" +dependencies = [ + "bstr", +] + [[package]] name = "siphasher" version = "1.0.2" @@ -4372,7 +4476,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator", + "phf_generator 0.13.1", "phf_shared 0.13.1", "proc-macro2", "quote", @@ -4453,6 +4557,27 @@ dependencies = [ "windows", ] +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tagptr" version = "0.2.0" @@ -4685,9 +4810,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", "libc", @@ -4707,9 +4832,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -4717,9 +4842,9 @@ dependencies = [ [[package]] name = "timeago" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86660b0935ca5912eb155f5b3794e2f8f1a09d8c00c9efd5c1075ca26403638" +checksum = "46c29b13d230e9cd58513d38701a661fc06e1215398937532a2d938ecca6f219" dependencies = [ "chrono", "isolang", @@ -4766,7 +4891,7 @@ version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "libc", "mio", "parking_lot", @@ -4837,7 +4962,7 @@ version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ - "bytes 1.11.1", + "bytes 1.12.0", "futures-core", "futures-io", "futures-sink", @@ -4927,7 +5052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", - "bytes 1.11.1", + "bytes 1.12.0", "futures-util", "http", "http-body", @@ -5774,20 +5899,14 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[package]] -name = "winnow" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 158e422..c8f94c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.6.1" +version = "1.6.2" edition = "2021" [workspace.dependencies] @@ -51,46 +51,46 @@ tokio-rustls = { version = "0.26.4", default-features = false, features = [ "ring", "tls12", ] } -timeago = "0.6.0" +timeago = "0.6.1" oauth2 = { version = "5.0.0", features = ["reqwest-blocking"] } url = { version = "2.5.8", features = ["serde"] } sysinfo = "0.39.4" num_cpus = "1.17.0" -rand = "0.10.1" +rand = "0.10.2" encoding_rs = "0.8.35" webpki-roots = "1.0.8" rustls = { version = "0.23.41", default-features = false, features = ["ring"] } -rustls-pki-types = "1.14.1" +rustls-pki-types = "1.15.0" tokio-io-timeout = "1.2.1" semver = "1.0.28" governor = "0.10.4" lru = "0.18.0" mime_guess = "2.0.5" hex = "0.4.3" -time = { version = "0.3.51", features = [ +time = { version = "0.3.53", features = [ "formatting", "parsing", "local-offset", ] } -rust-embed = "8.11.0" +rust-embed = "8.12.0" murmur3 = "0.5.2" urlencoding = "2.1.3" dashmap = "6.2.1" gethostname = "1.1.0" itoa = "1.0.18" html2text = "0.17.1" -bytes = "1.11.1" +bytes = "1.12.0" dialoguer = "0.12.0" -console = "0.16.3" -mail-send = "0.6.0" +console = "0.16.4" +mail-send = "0.6.1" rcgen = "0.14.8" rustls-pemfile = "2.2.0" blake3 = "1.8.5" uuid = { version = "1.23.4", features = ["v4", "serde"] } -fjall = { version = "3.1.5", features = ["lz4", "metrics", "bytes_1"] } +fjall = { version = "3.1.6", features = ["lz4", "metrics", "bytes_1"] } tracing-log = "0.2.0" tokio-util = "0.7.18" -indicatif = "0.18.4" +indicatif = "0.18.6" [profile.release] strip = true diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 801c630..1b92d13 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -69,9 +69,9 @@ tokio-util.workspace = true whichlang = "0.1.1" deunicode = "1.6.2" scopeguard = "1.2.0" -cron = "0.15" -quick-xml = { version = "0.40.0", features = ["serialize"] } -hickory-resolver = "0.26.0-alpha.1" +cron = "0.17" +quick-xml = { version = "0.41.0", features = ["serialize"] } +hickory-resolver = "0.26.1" memmap2 = "0.9.10" outlook-pst = { git = "https://github.com/rustmailer/outlook-pst-rs.git", branch = "main" } compressed-rtf = "1.0.1" diff --git a/crates/core/src/autoconfig/client.rs b/crates/core/src/autoconfig/client.rs index 1bc5656..3ce4b15 100644 --- a/crates/core/src/autoconfig/client.rs +++ b/crates/core/src/autoconfig/client.rs @@ -16,9 +16,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use hickory_resolver::name_server::TokioConnectionProvider; +use hickory_resolver::net::runtime::TokioRuntimeProvider; use hickory_resolver::proto::rr::RData; -use hickory_resolver::proto::rr::RecordType; use hickory_resolver::TokioResolver; use quick_xml::de::from_str; use reqwest::Client; @@ -108,28 +107,29 @@ async fn fetch_xml(client: &Client, url: &str) -> Option { } async fn lookup_srv(domain: &str) -> Option { - let resolver = TokioResolver::builder(TokioConnectionProvider::default()) + let resolver = TokioResolver::builder(TokioRuntimeProvider::default()) .ok()? - .build(); + .build() + .ok()?; let imap_srv = format!("_imaps._tcp.{}.", domain); - let imap_lookup = resolver.lookup(imap_srv, RecordType::SRV).await.ok()?; - let imap_record = imap_lookup.iter().next()?; - let (imap_host, imap_port) = match imap_record { + let imap_lookup = resolver.srv_lookup(imap_srv).await.ok()?; + let imap_record = imap_lookup.answers().first()?; + let (imap_host, imap_port) = match &imap_record.data { RData::SRV(srv) => { - let host = srv.target().to_string().trim_end_matches('.').to_string(); - (host, srv.port()) + let host = srv.target.to_string().trim_end_matches('.').to_string(); + (host, srv.port) } _ => return None, }; let smtp_srv = format!("_submission._tcp.{}.", domain); - let smtp_lookup = resolver.lookup(smtp_srv, RecordType::SRV).await.ok()?; - let smtp_record = smtp_lookup.iter().next()?; - let (smtp_host, smtp_port) = match smtp_record { + let smtp_lookup = resolver.srv_lookup(smtp_srv).await.ok()?; + let smtp_record = smtp_lookup.answers().first()?; + let (smtp_host, smtp_port) = match &smtp_record.data { RData::SRV(srv) => { - let host = srv.target().to_string().trim_end_matches('.').to_string(); - (host, srv.port()) + let host = srv.target.to_string().trim_end_matches('.').to_string(); + (host, srv.port) } _ => return None, }; @@ -177,13 +177,19 @@ pub async fn fetch(domain: &str) -> BichonResult { .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; // ── ISP autoconfig (HTTPS, then HTTP) ────────────────────────── - if let Some(config) = - fetch_xml(&client, &format!("https://autoconfig.{domain}/mail/config-v1.1.xml")).await + if let Some(config) = fetch_xml( + &client, + &format!("https://autoconfig.{domain}/mail/config-v1.1.xml"), + ) + .await { return Ok(config); } - if let Some(config) = - fetch_xml(&client, &format!("http://autoconfig.{domain}/mail/config-v1.1.xml")).await + if let Some(config) = fetch_xml( + &client, + &format!("http://autoconfig.{domain}/mail/config-v1.1.xml"), + ) + .await { return Ok(config); } @@ -212,8 +218,11 @@ pub async fn fetch(domain: &str) -> BichonResult { } // ── Thunderbird central ISPDB ────────────────────────────────── - if let Some(config) = - fetch_xml(&client, &format!("https://autoconfig.thunderbird.net/v1.1/{domain}")).await + if let Some(config) = fetch_xml( + &client, + &format!("https://autoconfig.thunderbird.net/v1.1/{domain}"), + ) + .await { return Ok(config); } @@ -245,20 +254,29 @@ async fn fetch_for_mx(client: &Client, domain: &str) -> Option { } // Try ISPDB for the MX domain - if let Some(config) = - fetch_xml(client, &format!("https://autoconfig.thunderbird.net/v1.1/{mx_domain}")).await + if let Some(config) = fetch_xml( + client, + &format!("https://autoconfig.thunderbird.net/v1.1/{mx_domain}"), + ) + .await { return Some(config); } // Try ISP autoconfig for the MX domain (HTTPS then HTTP) - if let Some(config) = - fetch_xml(client, &format!("https://autoconfig.{mx_domain}/mail/config-v1.1.xml")).await + if let Some(config) = fetch_xml( + client, + &format!("https://autoconfig.{mx_domain}/mail/config-v1.1.xml"), + ) + .await { return Some(config); } - if let Some(config) = - fetch_xml(client, &format!("http://autoconfig.{mx_domain}/mail/config-v1.1.xml")).await + if let Some(config) = fetch_xml( + client, + &format!("http://autoconfig.{mx_domain}/mail/config-v1.1.xml"), + ) + .await { return Some(config); } @@ -268,12 +286,16 @@ async fn fetch_for_mx(client: &Client, domain: &str) -> Option { /// DNS MX lookup → extract the second-level domain of the first MX hostname. async fn lookup_mx_domain(domain: &str) -> Option { - let resolver = TokioResolver::builder(TokioConnectionProvider::default()) + let resolver = TokioResolver::builder(TokioRuntimeProvider::default()) .ok()? - .build(); + .build() + .ok()?; let lookup = resolver.mx_lookup(domain).await.ok()?; - let record = lookup.iter().next()?; - let mx_host = record.to_string().trim_end_matches('.').to_string(); + let record = lookup.answers().first()?; + let mx_host = match &record.data { + RData::MX(mx) => mx.exchange.to_string().trim_end_matches('.').to_string(), + _ => return None, + }; // Extract a reasonable base domain from the MX hostname. // E.g., "aspmx.l.google.com" → "google.com" @@ -336,4 +358,95 @@ mod tests { } } } + + #[test] + fn test_parse_autoconfig_xml() { + let xml = r#" + + + example.com + + imap.example.com + 993 + SSL + %EMAILADDRESS% + password-cleartext + + + smtp.example.com + 587 + STARTTLS + %EMAILADDRESS% + + +"#; + + let config = parse_autoconfig_xml(xml).expect("should parse valid XML"); + assert_eq!(config.incoming.len(), 1); + assert_eq!(config.incoming[0].protocol, "imap"); + assert_eq!(config.incoming[0].hostname, "imap.example.com"); + assert_eq!(config.incoming[0].port, 993); + assert_eq!(config.incoming[0].socket_type, "SSL"); + assert_eq!(config.incoming[0].username, "%EMAILADDRESS%"); + assert_eq!(config.incoming[0].authentication, "password-cleartext"); + + assert_eq!(config.outgoing.len(), 1); + assert_eq!(config.outgoing[0].protocol, "smtp"); + assert_eq!(config.outgoing[0].hostname, "smtp.example.com"); + assert_eq!(config.outgoing[0].port, 587); + assert_eq!(config.outgoing[0].socket_type, "STARTTLS"); + assert_eq!(config.outgoing[0].username, "%EMAILADDRESS%"); + } + + #[test] + fn test_parse_autoconfig_xml_invalid() { + assert!(parse_autoconfig_xml("not xml").is_none()); + assert!(parse_autoconfig_xml("").is_none()); + } + + #[test] + fn test_extract_base_domain() { + assert_eq!( + extract_base_domain("aspmx.l.google.com"), + Some("google.com".to_string()) + ); + assert_eq!( + extract_base_domain("company.mail.protection.outlook.com"), + Some("outlook.com".to_string()) + ); + assert_eq!( + extract_base_domain("mx.example.com"), + Some("example.com".to_string()) + ); + assert_eq!( + extract_base_domain("example.com"), + Some("example.com".to_string()) + ); + assert_eq!(extract_base_domain("localhost"), None); + } + + #[tokio::test] + async fn test_lookup_srv_gmail() { + // Gmail should have SRV records for IMAPS and SMTP submission + let config = lookup_srv("gmail.com").await; + assert!(config.is_some(), "Gmail should have SRV records"); + let config = config.unwrap(); + assert_eq!(config.incoming.len(), 1); + assert_eq!(config.incoming[0].protocol, "imap"); + assert_eq!(config.incoming[0].socket_type, "SSL"); + assert!(!config.incoming[0].hostname.is_empty()); + assert!(config.incoming[0].port > 0); + assert_eq!(config.outgoing.len(), 1); + assert_eq!(config.outgoing[0].protocol, "smtp"); + assert_eq!(config.outgoing[0].socket_type, "STARTTLS"); + assert!(!config.outgoing[0].hostname.is_empty()); + assert!(config.outgoing[0].port > 0); + } + + #[tokio::test] + async fn test_lookup_srv_nonexistent() { + // A domain without SRV records should return None + let config = lookup_srv("this-domain-definitely-does-not-exist-12345.com").await; + assert!(config.is_none()); + } }