diff --git a/Cargo.lock b/Cargo.lock index 12b2365..4ac80bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,60 +8,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", -] - [[package]] name = "ahash" version = "0.8.12" @@ -204,7 +150,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror 2.0.18", - "time 0.3.47", + "time", ] [[package]] @@ -265,35 +211,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-executor" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.4.1", - "futures-lite 2.6.1", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite 2.6.1", - "once_cell", -] - [[package]] name = "async-imap" version = "0.11.2" @@ -316,67 +233,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.1", - "parking", - "polling", - "rustix", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 2.6.1", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -400,22 +256,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "autoconfig" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3dc5ca11ac66da7ba331bd707c8d6bca90a559c107aada6ee6abf1d4d5dbc2c" -dependencies = [ - "bytes 1.11.1", - "futures", - "regex", - "serde", - "serde-xml-rs", - "surf", - "trust-dns-proto", - "trust-dns-resolver", -] - [[package]] name = "aws-lc-rs" version = "1.16.3" @@ -439,12 +279,6 @@ dependencies = [ "fs_extra", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.1" @@ -506,7 +340,6 @@ name = "bichon-core" version = "1.0.0" dependencies = [ "async-imap", - "autoconfig", "base64 0.22.1", "blake3", "bytes 1.11.1", @@ -519,6 +352,7 @@ dependencies = [ "fjall", "futures", "governor", + "hickory-resolver", "html2text", "itertools", "itoa", @@ -530,6 +364,7 @@ dependencies = [ "num_cpus", "oauth2", "poem-openapi", + "quick-xml 0.40.0", "rand 0.10.1", "regex", "reqwest", @@ -542,7 +377,7 @@ dependencies = [ "snafu", "sysinfo", "tantivy", - "time 0.3.47", + "time", "tokio", "tokio-io-timeout", "tokio-rustls", @@ -567,7 +402,7 @@ dependencies = [ "chrono", "email_address", "governor", - "http 1.4.0", + "http", "mimalloc", "poem", "poem-derive", @@ -650,15 +485,6 @@ dependencies = [ "cpufeatures 0.3.0", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -668,19 +494,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel 2.5.0", - "async-task", - "futures-io", - "futures-lite 2.6.1", - "piper", -] - [[package]] name = "bon" version = "3.9.1" @@ -795,7 +608,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.28", + "semver", "serde", "serde_json", ] @@ -855,15 +668,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - [[package]] name = "clap" version = "4.6.1" @@ -892,7 +696,7 @@ version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.117", @@ -1006,12 +810,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "const_fn" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413d67b29ef1021b4d60f4aa1e925ca031751e213832b4b1d588fae623c05c60" - [[package]] name = "constant_time_eq" version = "0.4.2" @@ -1027,23 +825,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.1", - "hkdf", - "hmac", - "percent-encoding", - "rand 0.8.6", - "sha2 0.9.9", - "time 0.2.27", - "version_check", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -1078,12 +859,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crc32fast" version = "1.5.0" @@ -1159,56 +934,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - -[[package]] -name = "curl" -version = "0.4.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fc3b6dd0b87ba36e565715bf9a2ced221311db47bd18011676f24a6066edbc" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe 0.1.6", - "openssl-sys", - "schannel", - "socket2", - "windows-sys 0.59.0", -] - -[[package]] -name = "curl-sys" -version = "0.4.87+curl-8.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a460380f0ef783703dcbe909107f39c162adeac050d73c850055118b5b6327" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.59.0", -] - [[package]] name = "darling" version = "0.20.11" @@ -1346,7 +1071,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.1", + "rustc_version", "syn 2.0.117", "unicode-xid", ] @@ -1369,31 +1094,16 @@ dependencies = [ "zeroize", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "crypto-common", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dispatch2" version = "0.3.1" @@ -1467,25 +1177,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "enum-as-inner" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.117", @@ -1572,15 +1270,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.4.1" @@ -1602,7 +1291,7 @@ dependencies = [ "byteorder-lite", "byteview", "dashmap", - "flume 0.12.0", + "flume", "log", "lsm-tree", "lz4_flex", @@ -1620,17 +1309,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flume" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" -dependencies = [ - "futures-core", - "futures-sink", - "spinning_top 0.2.5", -] - [[package]] name = "flume" version = "0.12.0" @@ -1746,34 +1424,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand 2.4.1", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.32" @@ -1852,17 +1502,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -1872,7 +1511,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1904,34 +1543,12 @@ dependencies = [ "wasip3", ] -[[package]] -name = "ghash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "governor" version = "0.10.4" @@ -1951,7 +1568,7 @@ dependencies = [ "quanta", "rand 0.9.2", "smallvec", - "spinning_top 0.3.0", + "spinning_top", "web-time", ] @@ -1966,7 +1583,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap", "slab", "tokio", @@ -2032,10 +1649,10 @@ dependencies = [ "base64 0.22.1", "bytes 1.11.1", "headers-core", - "http 1.4.0", + "http", "httpdate", "mime", - "sha1 0.10.6", + "sha1", ] [[package]] @@ -2044,15 +1661,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.4.0", + "http", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2083,11 +1694,11 @@ dependencies = [ "bytes 1.11.1", "cfg-if", "data-encoding", - "enum-as-inner 0.6.1", + "enum-as-inner", "futures-channel", "futures-io", "futures-util", - "idna 1.1.0", + "idna", "ipnet", "once_cell", "rand 0.9.2", @@ -2095,7 +1706,7 @@ dependencies = [ "rustls", "rustls-pki-types", "thiserror 2.0.18", - "time 0.3.47", + "time", "tinyvec", "tokio", "tokio-rustls", @@ -2126,26 +1737,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "hostname" version = "0.4.2" @@ -2185,17 +1776,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes 1.11.1", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.4.0" @@ -2213,7 +1793,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes 1.11.1", - "http 1.4.0", + "http", ] [[package]] @@ -2224,47 +1804,11 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes 1.11.1", "futures-core", - "http 1.4.0", + "http", "http-body", "pin-project-lite", ] -[[package]] -name = "http-client" -version = "6.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "http-types", - "isahc", - "log", -] - -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel 1.9.0", - "async-std", - "base64 0.13.1", - "cookie", - "futures-lite 1.13.0", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", -] - [[package]] name = "httparse" version = "1.10.1" @@ -2288,7 +1832,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http", "http-body", "httparse", "httpdate", @@ -2305,7 +1849,7 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.0", + "http", "hyper", "hyper-util", "rustls", @@ -2325,7 +1869,7 @@ dependencies = [ "bytes 1.11.1", "futures-channel", "futures-util", - "http 1.4.0", + "http", "http-body", "hyper", "ipnet", @@ -2456,17 +2000,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.1.0" @@ -2522,21 +2055,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "interval-heap" version = "0.0.5" @@ -2590,29 +2108,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "isahc" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" -dependencies = [ - "bytes 0.5.6", - "crossbeam-utils", - "curl", - "curl-sys", - "flume 0.9.2", - "futures-lite 1.13.0", - "http 0.2.12", - "log", - "once_cell", - "slab", - "sluice", - "tracing", - "tracing-futures", - "url", - "waker-fn", -] - [[package]] name = "isolang" version = "2.4.0" @@ -2662,7 +2157,7 @@ checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ "proc-macro2", "quote", - "rustc_version 0.4.1", + "rustc_version", "simd_cesu8", "syn 2.0.117", ] @@ -2708,15 +2203,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -2738,11 +2224,11 @@ dependencies = [ "base64 0.22.1", "email-encoding", "email_address", - "fastrand 2.4.1", + "fastrand", "futures-util", "hostname", "httpdate", - "idna 1.1.0", + "idna", "mime", "native-tls", "nom 8.0.0", @@ -2774,34 +2260,6 @@ dependencies = [ "cc", ] -[[package]] -name = "libnghttp2-sys" -version = "0.1.13+1.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492e00167f1418c15648144f42bbfc63099806ecee9bf8d09a6353d6b4856b3c" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[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" @@ -2828,9 +2286,6 @@ name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -dependencies = [ - "value-bag", -] [[package]] name = "lru" @@ -2850,15 +2305,6 @@ 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" @@ -2976,12 +2422,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "md5" version = "0.8.0" @@ -3072,7 +2512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.61.2", ] @@ -3102,7 +2542,7 @@ dependencies = [ "bytes 1.11.1", "encoding_rs", "futures-util", - "http 1.4.0", + "http", "httparse", "memchr", "mime", @@ -3132,7 +2572,7 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.2.1", + "openssl-probe", "openssl-sys", "schannel", "security-framework", @@ -3150,7 +2590,7 @@ dependencies = [ "native_model", "redb 1.5.1", "redb 2.6.3", - "semver 1.0.28", + "semver", "serde", "skeptic", "thiserror 1.0.69", @@ -3316,13 +2756,13 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.17", - "http 1.4.0", + "http", "rand 0.8.6", "reqwest", "serde", "serde_json", "serde_path_to_error", - "sha2 0.10.9", + "sha2", "thiserror 1.0.69", "url", ] @@ -3425,12 +2865,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.78" @@ -3457,12 +2891,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - [[package]] name = "openssl-probe" version = "0.2.1" @@ -3589,7 +3017,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ - "fastrand 2.4.1", + "fastrand", "phf_shared 0.13.1", ] @@ -3663,17 +3091,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" -dependencies = [ - "atomic-waker", - "fastrand 2.4.1", - "futures-io", -] - [[package]] name = "pkg-config" version = "0.3.33" @@ -3691,7 +3108,7 @@ dependencies = [ "futures-util", "headers", "hex", - "http 1.4.0", + "http", "http-body-util", "hyper", "hyper-util", @@ -3771,7 +3188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41273b691a3d467a8c44d05506afba9f7b6bd56c9cdf80123de13fe52d7ec587" dependencies = [ "darling 0.20.11", - "http 1.4.0", + "http", "indexmap", "mime", "proc-macro-crate", @@ -3782,31 +3199,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "polyval" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] - [[package]] name = "portable-atomic" version = "1.13.1" @@ -3862,12 +3254,6 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.106" @@ -3898,7 +3284,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] @@ -3922,6 +3308,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7315c86b26aaef0321fba33c9dcc160da659c6a9d278f0f6a5656d6561c03b" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick_cache" version = "0.6.21" @@ -4014,19 +3410,6 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.6" @@ -4059,16 +3442,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -4089,15 +3462,6 @@ dependencies = [ "rand_core 0.9.5", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -4122,15 +3486,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "raw-cpuid" version = "11.6.0" @@ -4169,7 +3524,7 @@ dependencies = [ "pem", "ring", "rustls-pki-types", - "time 0.3.47", + "time", "x509-parser", "yasna", ] @@ -4241,7 +3596,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.4.0", + "http", "http-body", "http-body-util", "hyper", @@ -4331,7 +3686,7 @@ version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ - "sha2 0.10.9", + "sha2", "walkdir", ] @@ -4351,22 +3706,13 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.28", + "semver", ] [[package]] @@ -4413,7 +3759,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe 0.2.1", + "openssl-probe", "rustls-pki-types", "schannel", "security-framework", @@ -4542,15 +3888,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.28" @@ -4561,12 +3898,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.228" @@ -4577,18 +3908,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-xml-rs" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" -dependencies = [ - "log", - "serde", - "thiserror 1.0.69", - "xml-rs", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -4633,17 +3952,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_spanned" version = "1.1.1" @@ -4689,15 +3997,6 @@ dependencies = [ "xxhash-rust", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.6" @@ -4706,26 +4005,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] @@ -4736,7 +4016,7 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest 0.10.7", + "digest", ] [[package]] @@ -4782,7 +4062,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" dependencies = [ - "rustc_version 0.4.1", + "rustc_version", "simdutf8", ] @@ -4828,17 +4108,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" -[[package]] -name = "sluice" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" -dependencies = [ - "async-channel 1.9.0", - "futures-core", - "futures-io", -] - [[package]] name = "smallvec" version = "1.15.1" @@ -4866,7 +4135,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54254b8531cafa275c5e096f62d48c81435d1015405a91198ddb11e967301d40" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.117", @@ -4891,15 +4160,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spinning_top" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" -dependencies = [ - "lock_api", -] - [[package]] name = "spinning_top" version = "0.3.0" @@ -4927,64 +4187,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stop-token" version = "0.7.0" @@ -5033,29 +4235,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "surf" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "encoding_rs", - "futures-util", - "getrandom 0.2.17", - "http-client", - "http-types", - "log", - "mime_guess", - "once_cell", - "pin-project-lite", - "serde", - "serde_json", - "web-sys", -] - [[package]] name = "symlink" version = "0.1.0" @@ -5175,7 +4354,7 @@ dependencies = [ "tantivy-tokenizer-api", "tempfile", "thiserror 2.0.18", - "time 0.3.47", + "time", "typetag", "uuid", "winapi", @@ -5217,7 +4396,7 @@ dependencies = [ "byteorder", "ownedbytes", "serde", - "time 0.3.47", + "time", ] [[package]] @@ -5283,7 +4462,7 @@ version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "fastrand 2.4.1", + "fastrand", "getrandom 0.4.2", "once_cell", "rustix", @@ -5349,21 +4528,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi", -] - [[package]] name = "time" version = "0.3.47" @@ -5378,7 +4542,7 @@ dependencies = [ "powerfmt", "serde_core", "time-core", - "time-macros 0.2.27", + "time-macros", ] [[package]] @@ -5387,16 +4551,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - [[package]] name = "time-macros" version = "0.2.27" @@ -5407,19 +4561,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] - [[package]] name = "timeago" version = "0.6.0" @@ -5624,7 +4765,7 @@ dependencies = [ "bitflags", "bytes 1.11.1", "futures-util", - "http 1.4.0", + "http", "http-body", "iri-string", "pin-project-lite", @@ -5651,7 +4792,6 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5666,7 +4806,7 @@ dependencies = [ "crossbeam-channel", "symlink", "thiserror 2.0.18", - "time 0.3.47", + "time", "tracing-subscriber", ] @@ -5691,16 +4831,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project 1.1.11", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -5743,51 +4873,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner 0.5.1", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand 0.8.6", - "smallvec", - "thiserror 1.0.69", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "lru-cache", - "parking_lot", - "resolv-conf", - "smallvec", - "thiserror 1.0.69", - "tokio", - "tracing", - "trust-dns-proto", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -5857,27 +4942,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-normalization" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.13.2" @@ -5902,16 +4972,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" -[[package]] -name = "universal-hash" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -5937,7 +4997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna 1.1.0", + "idna", "percent-encoding", "serde", "serde_derive", @@ -6002,12 +5062,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - [[package]] name = "varint-rs" version = "2.2.0" @@ -6026,12 +5080,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -6051,12 +5099,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -6180,7 +5222,7 @@ dependencies = [ "bitflags", "hashbrown 0.15.5", "indexmap", - "semver 1.0.28", + "semver", ] [[package]] @@ -6605,7 +5647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "wit-parser", ] @@ -6616,7 +5658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "indexmap", "prettyplease", "syn 2.0.117", @@ -6669,7 +5711,7 @@ dependencies = [ "id-arena", "indexmap", "log", - "semver 1.0.28", + "semver", "serde", "serde_derive", "serde_json", @@ -6698,15 +5740,9 @@ dependencies = [ "ring", "rusticata-macros", "thiserror 2.0.18", - "time 0.3.47", + "time", ] -[[package]] -name = "xml-rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" - [[package]] name = "xxhash-rust" version = "0.8.15" @@ -6720,7 +5756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ "bit-vec", - "time 0.3.47", + "time", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cab5e88..4b992fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,6 @@ time = { version = "0.3.47", features = [ ] } rust-embed = "8.11.0" murmur3 = "0.5.2" -autoconfig = "0.4.0" urlencoding = "2.1.3" dashmap = "6.1.0" gethostname = "1.1.0" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index bffd804..4ae44ba 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -56,7 +56,6 @@ governor.workspace = true lru.workspace = true time.workspace = true murmur3.workspace = true -autoconfig.workspace = true dashmap.workspace = true itoa.workspace = true html2text.workspace = true @@ -70,3 +69,5 @@ tokio-util.workspace = true whichlang = "0.1.1" deunicode = "1.6.2" scopeguard = "1.2.0" +quick-xml = { version = "0.40.0", features = ["serialize"] } +hickory-resolver = "0.26.0-alpha.1" diff --git a/crates/core/src/autoconfig/client.rs b/crates/core/src/autoconfig/client.rs new file mode 100644 index 0000000..dcc1d1a --- /dev/null +++ b/crates/core/src/autoconfig/client.rs @@ -0,0 +1,255 @@ +// +// Copyright (c) 2025-2026 rustmailer.com (https://rustmailer.com) +// +// This file is part of the Bichon Email Archiving Project +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// 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::proto::rr::RData; +use hickory_resolver::proto::rr::RecordType; +use hickory_resolver::TokioResolver; +use quick_xml::de::from_str; +use reqwest::Client; +use serde::Deserialize; + +use crate::error::code::ErrorCode; +use crate::error::BichonResult; +use crate::raise_error; + +/// Parsed result from Thunderbird-style autoconfig XML or DNS SRV fallback. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct MailConfig { + pub incoming: Vec, + pub outgoing: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)] +pub struct IncomingServer { + #[serde(rename = "@type")] + pub protocol: String, + pub hostname: String, + #[serde(default)] + pub port: u16, + #[serde(rename = "socketType")] + pub socket_type: String, + pub username: String, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)] +pub struct OutgoingServer { + #[serde(rename = "@type")] + pub protocol: String, + pub hostname: String, + #[serde(default)] + pub port: u16, + #[serde(rename = "socketType")] + pub socket_type: String, + pub username: String, +} + +// --------------------------------------------------------------------------- +// Internal XML wrapper structs matching the Thunderbird config-v1.1 schema: +// / +// --------------------------------------------------------------------------- + +#[derive(Debug, Deserialize)] +#[serde(rename = "clientConfig")] +struct ClientConfig { + #[serde(rename = "emailProvider", default)] + email_providers: Vec, +} + +#[derive(Debug, Deserialize)] +struct EmailProvider { + #[serde(rename = "incomingServer", default)] + incoming_servers: Vec, + #[serde(rename = "outgoingServer", default)] + outgoing_servers: Vec, +} + +/// Parse Thunderbird autoconfig XML into a `MailConfig`. +/// Exposed for unit testing. +pub(crate) fn parse_autoconfig_xml(xml: &str) -> Option { + let client_config: ClientConfig = from_str(xml).ok()?; + let provider = client_config.email_providers.into_iter().next()?; + Some(MailConfig { + incoming: provider.incoming_servers, + outgoing: provider.outgoing_servers, + }) +} + +// --------------------------------------------------------------------------- +// Network helpers +// --------------------------------------------------------------------------- + +async fn fetch_xml(client: &Client, url: &str) -> Option { + let resp = client.get(url).send().await.ok()?; + if !resp.status().is_success() { + return None; + } + let text = resp.text().await.ok()?; + parse_autoconfig_xml(&text) +} + +async fn lookup_srv(domain: &str) -> Option { + let resolver = TokioResolver::builder(TokioConnectionProvider::default()) + .ok()? + .build(); + + 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 { + RData::SRV(srv) => { + 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 { + RData::SRV(srv) => { + let host = srv.target().to_string().trim_end_matches('.').to_string(); + (host, srv.port()) + } + _ => return None, + }; + + Some(MailConfig { + incoming: vec![IncomingServer { + protocol: "imap".to_string(), + hostname: imap_host, + port: imap_port, + socket_type: "SSL".to_string(), + username: "%EMAILADDRESS%".to_string(), + }], + outgoing: vec![OutgoingServer { + protocol: "smtp".to_string(), + hostname: smtp_host, + port: smtp_port, + socket_type: "STARTTLS".to_string(), + username: "%EMAILADDRESS%".to_string(), + }], + }) +} + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +/// Discover mail server configuration for a domain using the Thunderbird +/// autoconfig protocol (ISPDB) and DNS SRV fallback. +/// +/// Probe order: +/// 1. `https://autoconfig.{domain}/mail/config-v1.1.xml` +/// 2. `https://{domain}/.well-known/autoconfig/mail/config-v1.1.xml` +/// 3. DNS SRV records (`_imaps._tcp` / `_submission._tcp`) +/// 4. Thunderbird central ISPDB (`https://autoconfig.thunderbird.net/v1.1/{domain}`) +pub async fn fetch(domain: &str) -> BichonResult { + let client = Client::builder() + .timeout(std::time::Duration::from_secs(10)) + .build() + .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?; + + // 1. Try autoconfig subdomain + if let Some(config) = fetch_xml( + &client, + &format!("https://autoconfig.{domain}/mail/config-v1.1.xml"), + ) + .await + { + return Ok(config); + } + + // 2. Try well-known path + if let Some(config) = fetch_xml( + &client, + &format!("https://{domain}/.well-known/autoconfig/mail/config-v1.1.xml"), + ) + .await + { + return Ok(config); + } + + // 3. Try DNS SRV records + if let Some(config) = lookup_srv(domain).await { + return Ok(config); + } + + // 4. Fall back to Thunderbird central database + if let Some(config) = fetch_xml( + &client, + &format!("https://autoconfig.thunderbird.net/v1.1/{domain}"), + ) + .await + { + return Ok(config); + } + + Err(raise_error!( + format!("No autoconfig found for domain: {domain}"), + ErrorCode::InternalError + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_fetch_valid_domain() { + let domains = vec![ + // North America + ("gmail.com", "Google Gmail"), + ("outlook.com", "Microsoft Outlook"), + ("hotmail.com", "Microsoft Hotmail"), + ("yahoo.com", "Yahoo Mail"), + ("icloud.com", "Apple iCloud"), + ("aol.com", "AOL Mail"), + ("protonmail.com", "ProtonMail"), + ("zoho.com", "Zoho Mail"), + ("fastmail.com", "FastMail"), + // Europe + ("gmx.de", "GMX Germany"), + ("gmx.net", "GMX International"), + ("web.de", "Web.de Germany"), + ("freenet.de", "Freenet Germany"), + ("mail.ru", "Mail.ru Russia"), + ("yandex.ru", "Yandex Russia"), + ("orange.fr", "Orange France"), + ("laposte.net", "La Poste France"), + ("libero.it", "Libero Italy"), + ("tiscali.it", "Tiscali Italy"), + ("telenet.be", "Telenet Belgium"), + // Asia Pacific + ("qq.com", "Tencent QQ"), + ("163.com", "NetEase 163"), + ("126.com", "NetEase 126"), + ("sina.com", "Sina Mail"), + ("naver.com", "Naver Korea"), + ]; + + for (domain, label) in &domains { + let result = fetch(domain).await; + match result { + Ok(config) => println!("✅ [{label}] {domain}: {config:#?}"), + Err(e) => println!("⚠️ [{label}] {domain}: {e:?}"), + } + } + } +} diff --git a/crates/core/src/autoconfig/entity.rs b/crates/core/src/autoconfig/entity.rs index af053e2..1a29e87 100644 --- a/crates/core/src/autoconfig/entity.rs +++ b/crates/core/src/autoconfig/entity.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - -use autoconfig::config::OAuth2Config as XOAuth2Config; use serde::{Deserialize, Serialize}; use crate::account::entity::Encryption; @@ -55,18 +53,6 @@ pub struct OAuth2Config { /// URL of the authorization server's token endpoint pub token_url: String, } - -impl From<&XOAuth2Config> for OAuth2Config { - fn from(value: &XOAuth2Config) -> Self { - Self { - issuer: value.issuer().into(), - scope: value.scope().into_iter().map(Into::into).collect(), - auth_url: value.auth_url().into(), - token_url: value.token_url().into(), - } - } -} - #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)] #[cfg_attr(feature = "web-api", derive(poem_openapi::Object))] pub struct MailServerConfig { diff --git a/crates/core/src/autoconfig/load.rs b/crates/core/src/autoconfig/load.rs index b02f8d8..9cf89ef 100644 --- a/crates/core/src/autoconfig/load.rs +++ b/crates/core/src/autoconfig/load.rs @@ -16,17 +16,50 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use crate::account::entity::Encryption; +use crate::autoconfig::client::{self, MailConfig}; use crate::autoconfig::entity::{MailServerConfig, ServerConfig}; +use crate::autoconfig::CachedMailSettings; use crate::error::code::ErrorCode; -use crate::{ - raise_error, - {account::entity::Encryption, autoconfig::CachedMailSettings, error::BichonResult}, -}; -use autoconfig::config::{Server, ServerType}; +use crate::error::BichonResult; +use crate::raise_error; use email_address::EmailAddress; use std::str::FromStr; use tracing::error; +/// Map an autoconfig XML `socketType` value to our `Encryption` enum. +pub(crate) fn socket_type_to_encryption(raw: &str) -> Encryption { + match raw.to_ascii_uppercase().as_str() { + "SSL" | "TLS" => Encryption::Ssl, + "STARTTLS" => Encryption::StartTls, + _ => Encryption::None, + } +} + +/// Convert the raw `MailConfig` discovered by `client::fetch` into a +/// `MailServerConfig` suitable for account provisioning. +pub(crate) fn mail_config_to_server_config(config: &MailConfig) -> Option { + let imap = config.incoming.iter().find(|s| { + let p = s.protocol.to_ascii_lowercase(); + p == "imap" || p == "imaps" + })?; + + let encryption = socket_type_to_encryption(&imap.socket_type); + let port = if imap.port != 0 { + imap.port + } else { + match encryption { + Encryption::Ssl => 993, + _ => 143, + } + }; + + Some(MailServerConfig { + imap: ServerConfig::new(imap.hostname.clone(), port, encryption), + oauth2: None, + }) +} + pub async fn resolve_autoconfig(email: impl AsRef) -> BichonResult> { let email = email.as_ref(); let email_address = EmailAddress::from_str(email).map_err(|error| { @@ -37,73 +70,38 @@ pub async fn resolve_autoconfig(email: impl AsRef) -> BichonResult imap, - None => return Ok(None), - }; - - let get_encryption = |server: &Server| { - server - .security_type() - .map_or(Encryption::None, |encryption| match encryption { - autoconfig::config::SecurityType::Plain => Encryption::None, - autoconfig::config::SecurityType::Starttls => Encryption::StartTls, - autoconfig::config::SecurityType::Tls => Encryption::Ssl, - }) - }; - - let get_port = |server: &Server, encryption: &Encryption, tls_port: u16, non_tls_port: u16| { - server.port().map_or_else( - || match encryption { - Encryption::StartTls => tls_port, - _ => non_tls_port, - }, - ToOwned::to_owned, + let config = client::fetch(domain).await.map_err(|e| { + error!( + email = %email, + domain = %domain, + error = ?e, + "Autoconfig fetch failed" + ); + raise_error!( + format!( + "Failed to fetch autoconfig for email '{}': {:#?}", + email_address.email(), + e + ), + ErrorCode::AutoconfigFetchFailed ) - }; + })?; - let get_hostname = |server: &Server, default_prefix: &str| { - server.hostname().map_or_else( - || format!("{}.{}", default_prefix, domain), - ToOwned::to_owned, + let result = mail_config_to_server_config(&config).ok_or_else(|| { + raise_error!( + format!( + "No IMAP server found in autoconfig for email: {}", + email_address.email() + ), + ErrorCode::ResourceNotFound ) - }; + })?; - let imap_encryption = get_encryption(imap_server); - let imap_config = ServerConfig::new( - get_hostname(imap_server, "imap"), - get_port(imap_server, &imap_encryption, 993, 143), - imap_encryption, - ); - let result = MailServerConfig { - imap: imap_config, - oauth2: config.oauth2().map(|f| f.into()), - }; CachedMailSettings::add(domain.into(), result.clone())?; Ok(Some(result)) } diff --git a/crates/core/src/autoconfig/mod.rs b/crates/core/src/autoconfig/mod.rs index 87d3417..3980974 100644 --- a/crates/core/src/autoconfig/mod.rs +++ b/crates/core/src/autoconfig/mod.rs @@ -22,6 +22,7 @@ use crate::database::{find_impl, MemDbModel}; use crate::{autoconfig::entity::MailServerConfig, error::BichonResult, utc_now}; use serde::{Deserialize, Serialize}; +pub mod client; pub mod entity; pub mod load; #[cfg(test)] diff --git a/crates/core/src/autoconfig/tests.rs b/crates/core/src/autoconfig/tests.rs index 9f1903f..a721116 100644 --- a/crates/core/src/autoconfig/tests.rs +++ b/crates/core/src/autoconfig/tests.rs @@ -16,9 +16,293 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use crate::account::entity::Encryption; +use crate::autoconfig::client::{self, IncomingServer, MailConfig}; +use crate::autoconfig::load::{mail_config_to_server_config, socket_type_to_encryption}; -#[tokio::test] -async fn test() { - let config = autoconfig::from_addr("test@gmail.com").await.unwrap(); - println!("{:#?}", config); +// --------------------------------------------------------------------------- +// XML parsing tests +// --------------------------------------------------------------------------- + +fn make_valid_xml() -> String { + r#" + + + example.com + Example Mail + + imap.example.com + 993 + SSL + %EMAILADDRESS% + + + smtp.example.com + 587 + STARTTLS + %EMAILADDRESS% + + +"# + .to_string() +} + +#[test] +fn parse_valid_xml() { + let xml = make_valid_xml(); + let config = client::parse_autoconfig_xml(&xml).expect("should parse valid XML"); + + assert_eq!(config.incoming.len(), 1); + let imap = &config.incoming[0]; + assert_eq!(imap.protocol, "imap"); + assert_eq!(imap.hostname, "imap.example.com"); + assert_eq!(imap.port, 993); + assert_eq!(imap.socket_type, "SSL"); + assert_eq!(imap.username, "%EMAILADDRESS%"); + + assert_eq!(config.outgoing.len(), 1); + let smtp = &config.outgoing[0]; + assert_eq!(smtp.protocol, "smtp"); + assert_eq!(smtp.hostname, "smtp.example.com"); + assert_eq!(smtp.port, 587); + assert_eq!(smtp.socket_type, "STARTTLS"); +} + +#[test] +fn parse_xml_empty_body() { + let xml = r#""#; + let config = client::parse_autoconfig_xml(xml); + assert!(config.is_none(), "no emailProvider → None"); +} + +#[test] +fn parse_xml_no_incoming_servers() { + let xml = r#" + + + example.com + +"#; + let config = client::parse_autoconfig_xml(xml).expect("should parse"); + assert!(config.incoming.is_empty()); + assert!(config.outgoing.is_empty()); +} + +#[test] +fn parse_xml_garbage() { + let config = client::parse_autoconfig_xml("not xml at all"); + assert!(config.is_none()); +} + +#[test] +fn parse_xml_missing_port_defaults_to_zero() { + let xml = r#" + + + + imap.example.com + SSL + %EMAILADDRESS% + + +"#; + let config = client::parse_autoconfig_xml(xml).expect("should parse"); + assert_eq!(config.incoming[0].port, 0); +} + +#[test] +fn parse_xml_multiple_providers_picks_first() { + let xml = r#" + + + + imap.first.example.com + 993 + SSL + %EMAILADDRESS% + + + + + imap.second.example.com + 143 + STARTTLS + %EMAILADDRESS% + + +"#; + let config = client::parse_autoconfig_xml(xml).expect("should parse"); + assert_eq!(config.incoming[0].hostname, "imap.first.example.com"); +} + +// --------------------------------------------------------------------------- +// socket_type → Encryption mapping tests +// --------------------------------------------------------------------------- + +#[test] +fn encryption_ssl_uppercase() { + assert_eq!(socket_type_to_encryption("SSL"), Encryption::Ssl); +} + +#[test] +fn encryption_ssl_lowercase() { + assert_eq!(socket_type_to_encryption("ssl"), Encryption::Ssl); +} + +#[test] +fn encryption_tls() { + assert_eq!(socket_type_to_encryption("TLS"), Encryption::Ssl); +} + +#[test] +fn encryption_starttls() { + assert_eq!(socket_type_to_encryption("STARTTLS"), Encryption::StartTls); +} + +#[test] +fn encryption_starttls_lowercase() { + assert_eq!(socket_type_to_encryption("starttls"), Encryption::StartTls); +} + +#[test] +fn encryption_starttls_mixed_case() { + assert_eq!(socket_type_to_encryption("StartTls"), Encryption::StartTls); +} + +#[test] +fn encryption_plain() { + assert_eq!(socket_type_to_encryption("plain"), Encryption::None); +} + +#[test] +fn encryption_empty_string() { + assert_eq!(socket_type_to_encryption(""), Encryption::None); +} + +#[test] +fn encryption_unknown_value() { + assert_eq!(socket_type_to_encryption("WPA2-ENTERPRISE"), Encryption::None); +} + +// --------------------------------------------------------------------------- +// MailConfig → MailServerConfig conversion tests +// --------------------------------------------------------------------------- + +fn make_imap_server(host: &str, port: u16, socket_type: &str) -> IncomingServer { + IncomingServer { + protocol: "imap".to_string(), + hostname: host.to_string(), + port, + socket_type: socket_type.to_string(), + username: "%EMAILADDRESS%".to_string(), + } +} + +#[test] +fn convert_basic_imap_ssl() { + let config = MailConfig { + incoming: vec![make_imap_server("imap.example.com", 993, "SSL")], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should convert"); + assert_eq!(result.imap.host, "imap.example.com"); + assert_eq!(result.imap.port, 993); + assert_eq!(result.imap.encryption, Encryption::Ssl); + assert!(result.oauth2.is_none()); +} + +#[test] +fn convert_imap_starttls_with_default_port() { + let config = MailConfig { + incoming: vec![make_imap_server("imap.example.com", 0, "STARTTLS")], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should convert"); + assert_eq!(result.imap.port, 143, "default port for STARTTLS → 143"); + assert_eq!(result.imap.encryption, Encryption::StartTls); +} + +#[test] +fn convert_imap_ssl_with_default_port() { + let config = MailConfig { + incoming: vec![make_imap_server("imap.example.com", 0, "SSL")], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should convert"); + assert_eq!(result.imap.port, 993, "default port for SSL → 993"); +} + +#[test] +fn convert_no_imap_only_pop3() { + let config = MailConfig { + incoming: vec![IncomingServer { + protocol: "pop3".to_string(), + hostname: "pop.example.com".to_string(), + port: 995, + socket_type: "SSL".to_string(), + username: "%EMAILADDRESS%".to_string(), + }], + outgoing: vec![], + }; + assert!(mail_config_to_server_config(&config).is_none()); +} + +#[test] +fn convert_empty_incoming() { + let config = MailConfig { + incoming: vec![], + outgoing: vec![], + }; + assert!(mail_config_to_server_config(&config).is_none()); +} + +#[test] +fn convert_picks_imap_over_pop3() { + let config = MailConfig { + incoming: vec![ + IncomingServer { + protocol: "pop3".to_string(), + hostname: "pop.example.com".to_string(), + port: 995, + socket_type: "SSL".to_string(), + username: "%EMAILADDRESS%".to_string(), + }, + make_imap_server("imap.example.com", 993, "SSL"), + ], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should find IMAP"); + assert_eq!(result.imap.host, "imap.example.com"); +} + +#[test] +fn convert_imaps_protocol_variant() { + let config = MailConfig { + incoming: vec![IncomingServer { + protocol: "imaps".to_string(), + hostname: "imap.example.com".to_string(), + port: 993, + socket_type: "SSL".to_string(), + username: "%EMAILADDRESS%".to_string(), + }], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should recognize 'imaps'"); + assert_eq!(result.imap.host, "imap.example.com"); +} + +#[test] +fn convert_case_insensitive_protocol() { + let config = MailConfig { + incoming: vec![IncomingServer { + protocol: "IMAP".to_string(), + hostname: "imap.example.com".to_string(), + port: 143, + socket_type: "STARTTLS".to_string(), + username: "%EMAILADDRESS%".to_string(), + }], + outgoing: vec![], + }; + let result = mail_config_to_server_config(&config).expect("should recognize 'IMAP'"); + assert_eq!(result.imap.host, "imap.example.com"); }