Index: Cargo.lock ================================================================== --- Cargo.lock +++ Cargo.lock @@ -14,10 +14,19 @@ [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] [[package]] name = "anyhow" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -35,22 +44,10 @@ "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "ascii_utils" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" - [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" @@ -77,11 +74,11 @@ checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", - "pin-project-lite 0.2.15", + "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.1" @@ -88,12 +85,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.2.0", - "futures-lite 2.5.0", + "fastrand", + "futures-lite", "slab", ] [[package]] name = "async-global-executor" @@ -101,112 +98,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.4.0", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.5.0", + "futures-lite", "once_cell", "tokio", ] -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - [[package]] name = "async-io" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ - "async-lock 3.4.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.5.0", + "futures-lite", "parking", - "polling 3.7.4", - "rustix 0.38.41", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.59.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", - "pin-project-lite 0.2.15", -] - -[[package]] -name = "async-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" -dependencies = [ - "async-channel 2.3.1", - "async-io 2.4.0", - "async-lock 3.4.0", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.3.1", - "futures-lite 2.5.0", - "rustix 0.38.41", - "tracing", -] - -[[package]] -name = "async-signal" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io 2.4.0", - "async-lock 3.4.0", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.41", - "signal-hook-registry", - "slab", - "windows-sys 0.59.0", + "pin-project-lite", ] [[package]] name = "async-std" version = "1.13.0" @@ -214,24 +145,23 @@ checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 2.4.0", - "async-lock 3.4.0", - "async-process", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.5.0", + "futures-lite", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", - "pin-project-lite 0.2.15", + "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] @@ -250,10 +180,36 @@ [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "aws-lc-rs" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47bb8cc16b669d267eeccf585aea077d0882f4777b1c1f740217885d6e6e5a3" +dependencies = [ + "aws-lc-sys", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2101df3813227bbaaaa0b04cd61c534c7954b22bd68d399b440be937dc63ff7" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -266,21 +222,47 @@ "object", "rustc-demangle", "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64-compat" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8d4d2746f89841e49230dd26917df1876050f95abafafbe34f47cb534b88d7" +dependencies = [ + "byteorder", +] + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.89", + "which", +] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -290,41 +272,41 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bitvec" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.5.0", + "futures-lite", "piper", ] +[[package]] +name = "bufstream-fresh" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c431e5d450eceb6f5096c371f502946ae1cc65407935bc2cae8f1d625a2035f" + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" @@ -333,12 +315,23 @@ name = "cc" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ + "jobserver", + "libc", "shlex", ] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -350,10 +343,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "num-traits", ] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +dependencies = [ + "cc", +] [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -367,11 +380,11 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" dependencies = [ "lazy_static", - "nom 7.1.3", + "nom", "pathdiff", "serde", "toml", ] @@ -469,10 +482,16 @@ checksum = "d81175dab5ec79c30e0576df2ed2c244e1721720c302000bb321b107e82e265c" dependencies = [ "futures", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" @@ -524,39 +543,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.15", + "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", - "pin-project-lite 0.2.15", -] - -[[package]] -name = "fast_chemail" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" -dependencies = [ - "ascii_utils", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", + "pin-project-lite", ] [[package]] name = "fastrand" version = "2.2.0" @@ -592,14 +593,14 @@ dependencies = [ "percent-encoding", ] [[package]] -name = "funty" -version = "1.1.0" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -645,36 +646,21 @@ name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[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 0.2.15", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ - "fastrand 2.2.0", + "fastrand", "futures-core", "futures-io", "parking", - "pin-project-lite 0.2.15", + "pin-project-lite", ] [[package]] name = "futures-macro" version = "0.3.31" @@ -709,11 +695,11 @@ "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.15", + "pin-project-lite", "pin-utils", "slab", ] [[package]] @@ -731,10 +717,16 @@ name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" @@ -764,13 +756,13 @@ "tracing", ] [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -781,24 +773,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", ] [[package]] name = "http" version = "0.2.12" @@ -816,11 +800,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.15", + "pin-project-lite", ] [[package]] name = "httparse" version = "1.9.5" @@ -847,12 +831,12 @@ "http", "http-body", "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.15", - "socket2 0.5.7", + "pin-project-lite", + "socket2", "tokio", "tower-service", "tracing", "want", ] @@ -864,11 +848,11 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] [[package]] @@ -1056,30 +1040,10 @@ dependencies = [ "equivalent", "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" @@ -1093,13 +1057,22 @@ "either", ] [[package]] name = "itoa" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] [[package]] name = "js-sys" version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1122,33 +1095,30 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "lexical-core" -version = "0.7.6" +name = "lazycell" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "cfg-if", - "ryu", - "static_assertions", -] +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "libloading" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1167,24 +1137,10 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] -[[package]] -name = "lozizol" -version = "0.5.3-dev" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1de289e1fa0dc1455520ce7bf80970ce57a5c7f091e55a371af48f307581d6" -dependencies = [ - "async-std", - "bytes", - "hex", - "log", - "memchr", - "num-traits", -] - [[package]] name = "mail-parser" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" @@ -1192,14 +1148,36 @@ "encoding_rs", "serde", ] [[package]] -name = "match_cfg" -version = "0.1.0" +name = "mailin" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "261c858a4b0f914d12dd9da38b9e55a7d991cd6c3e369f503344c4f1c2137fc4" +dependencies = [ + "base64-compat", + "either", + "log", + "nom", + "ternop", +] + +[[package]] +name = "mailin-embedded" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60f4b1d7bed01be9f6fa08ad92c50f1d53c61e1461a058b94197046bfc5844f" +dependencies = [ + "bufstream-fresh", + "cfg-if", + "log", + "mailin", + "rustls 0.23.19", + "rustls-pemfile 2.2.0", + "scoped_threadpool", +] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1263,23 +1241,10 @@ "security-framework", "security-framework-sys", "tempfile", ] -[[package]] -name = "nom" -version = "6.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" -dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" @@ -1360,42 +1325,21 @@ name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" - -[[package]] -name = "peg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" -dependencies = [ - "peg-macros", - "peg-runtime", -] - -[[package]] -name = "peg-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" -dependencies = [ - "peg-runtime", - "proc-macro2", - "quote", -] - -[[package]] -name = "peg-runtime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1419,16 +1363,10 @@ "proc-macro2", "quote", "syn 2.0.89", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" @@ -1444,60 +1382,43 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.2.0", + "fastrand", "futures-io", ] [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite 0.2.15", - "windows-sys 0.48.0", -] - [[package]] name = "polling" version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", - "pin-project-lite 0.2.15", - "rustix 0.38.41", + "pin-project-lite", + "rustix", "tracing", "windows-sys 0.59.0", ] [[package]] -name = "potential" -version = "2.2.1" +name = "prettyplease" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502a584b16465645760f83692eb99092c3d55dffcd8c961fd6522d19cc2222dc" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ - "futures-channel", - "futures-util", - "log", + "proc-macro2", + "syn 2.0.89", ] [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1538,32 +1459,55 @@ checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rc-box" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0690759eabf094030c2cdabc25ade1395bac02210d920d655053c1d49583fd8" dependencies = [ "erasable", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "reqwest" version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", @@ -1578,13 +1522,13 @@ "mime", "mime_guess", "native-tls", "once_cell", "percent-encoding", - "pin-project-lite 0.2.15", - "rustls", - "rustls-pemfile", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", @@ -1621,43 +1565,35 @@ name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustls" @@ -1665,111 +1601,96 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] + +[[package]] +name = "rustls" +version = "0.23.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.7", + "base64", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", ] +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", ] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "samotop" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eb682bb98a1f3f2a909e292c0e08293e541bdf2854b2b61449cffdc085374e9" -dependencies = [ - "log", - "samotop-core", - "samotop-delivery", - "samotop-parser", -] - -[[package]] -name = "samotop-core" -version = "0.13.1+smtp" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30fbe4107fd9f80333f487d3adc417e9aabe9cbee488e1e4d528e7eadc251bcd" -dependencies = [ - "async-std", - "futures-core", - "futures-io", - "futures-util", - "log", - "smol-timeout", -] - -[[package]] -name = "samotop-delivery" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4e67cec86eeac28c314613364338904eafead04f8c280e0c982530572ec1e9" -dependencies = [ - "async-std", - "base64 0.13.1", - "bytes", - "fast_chemail", - "hostname", - "log", - "lozizol", - "memchr", - "nom 6.1.2", - "pin-project", - "pin-utils", - "potential", - "samotop-core", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "uuid 0.8.2", -] - -[[package]] -name = "samotop-parser" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf2e91d7da63ae0e700a75c2e40b0d837cd9fe404a5b5fca39c5be7a4a918c1" -dependencies = [ - "log", - "peg", - "samotop-core", -] - [[package]] name = "schannel" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" @@ -1916,42 +1837,22 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smol-timeout" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "847d777e2c6c166bad26264479e80a9820f3d364fcb4a0e23cd57bbfa8e94961" -dependencies = [ - "async-io 1.13.0", - "pin-project-lite 0.1.12", -] - [[package]] name = "smtp2tg" -version = "0.2.5" +version = "0.3.0" dependencies = [ "anyhow", "async-std", "config", "mail-parser", - "samotop", + "mailin-embedded", "teloxide", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" @@ -1970,22 +1871,22 @@ name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" @@ -2054,16 +1955,10 @@ name = "takecell" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "teloxide" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f79dd283eb21b90451c03fa7c7f83b9985130efb876b33bad89a2c208ccbc16" @@ -2112,11 +2007,11 @@ "takecell", "thiserror", "tokio", "tokio-util", "url", - "uuid 1.11.0", + "uuid", "vecrem", ] [[package]] name = "tempfile" @@ -2123,16 +2018,22 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", - "fastrand 2.2.0", + "fastrand", "once_cell", - "rustix 0.38.41", + "rustix", "windows-sys 0.59.0", ] +[[package]] +name = "ternop" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4ae32d0a4605a89c28534371b056919c12e7a070ee07505af75130ff030111" + [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" @@ -2169,13 +2070,13 @@ dependencies = [ "backtrace", "bytes", "libc", "mio", - "pin-project-lite 0.2.15", + "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "windows-sys 0.52.0", ] [[package]] name = "tokio-native-tls" @@ -2191,11 +2092,11 @@ name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] [[package]] name = "tokio-stream" @@ -2202,11 +2103,11 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", - "pin-project-lite 0.2.15", + "pin-project-lite", "tokio", ] [[package]] name = "tokio-util" @@ -2215,11 +2116,11 @@ checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", - "pin-project-lite 0.2.15", + "pin-project-lite", "tokio", ] [[package]] name = "toml" @@ -2261,23 +2162,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "pin-project-lite 0.2.15", + "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] @@ -2326,19 +2227,10 @@ name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", -] - [[package]] name = "uuid" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" @@ -2368,16 +2260,10 @@ name = "version_check" 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 = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" @@ -2486,30 +2372,20 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] -name = "winapi" -version = "0.3.9" +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + "either", + "home", + "once_cell", + "rustix", +] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2686,16 +2562,10 @@ name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" @@ -2737,10 +2607,16 @@ "quote", "syn 2.0.89", "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,17 +1,17 @@ [package] name = "smtp2tg" -version = "0.2.5" +version = "0.3.0" authors = [ "arcade" ] edition = "2021" [dependencies] anyhow = "1.0.86" -async-std = { version = "1.12.0", features = [ "tokio1" ] } +async-std = { version = "1.12.0", features = [ "attributes", "tokio1" ] } config = { version = "=0.14.0", default-features = false, features = [ "toml" ] } # Rust 1.75 teloxide = { version = "0.13", features = [ "rustls", "throttle" ] } mail-parser = { version = "0.9.3", features = ["serde", "serde_support"] } -samotop = { version = "0.13.2", default-features = false, features = [ "delivery", "parser-peg" ] } +mailin-embedded = "^0" [profile.release] lto = true codegen-units = 1 Index: smtp2tg.toml.example ================================================================== --- smtp2tg.toml.example +++ smtp2tg.toml.example @@ -1,16 +1,17 @@ # Telegram API key api_key = "YOU_KNOW_WHERE_TO_GET_THIS" -# where SaMoToP stores incoming messages -maildir = "./maildir" -# where to listen on, say "socket" to listen on "./smtp2tg.sock" -#listen_on = "0.0.0.0:25" -listen_on = "socket" +# where to listen on (sockets are not supported since 0.3.0) +listen_on = "0.0.0.0:25" +# whether we need to handle unknown adresses +# - relay: send them to default one +# - deny: drop them +unknown = "relay" [recipients] # there should be default recipient, get's some debug info + mail that we -# couldn't deliver +# couldn't deliver (if enabled) _ = 1 # make sure you quote emails, as "@" can't go there unquoted. And by default # we need FQDNs "somebody@example.com" = 1 # user id's are positive "root@example.com" = -1 # group id's are negative Index: src/main.rs ================================================================== --- src/main.rs +++ src/main.rs @@ -1,21 +1,21 @@ +//! Simple SMTP-to-Telegram gateway. Can parse email and send them as telegram +//! messages to specified chats, generally you specify which email address is +//! available in configuration, everything else is sent to default address. + use anyhow::{ anyhow, + bail, Result, }; -use async_std::task; -use samotop::{ - mail::{ - Builder, - DebugService, - MailDir, - Name - }, - smtp::{ - SmtpParser, - Prudence, - }, +use async_std::{ + io::Error, + task, +}; +use mailin_embedded::{ + Response, + response::*, }; use teloxide::{ Bot, prelude::{ Requester, @@ -33,207 +33,33 @@ borrow::Cow, collections::{ HashMap, HashSet, }, - io::Read, - os::unix::fs::{ - FileTypeExt, - PermissionsExt, - }, - path::{ - Path, - PathBuf - }, - time::Duration, vec::Vec, }; -fn address_into_iter<'a>(addr: &'a mail_parser::Address<'a, >) -> impl Iterator> { - addr.clone().into_list().into_iter().map(|a| a.address.unwrap()) -} - -async fn relay_mails(maildir: &Path, core: &TelegramTransport) -> Result<()> { - let new_dir = maildir.join("new"); - - std::fs::create_dir_all(&new_dir)?; - - let files = std::fs::read_dir(new_dir)?; - for file in files { - let file = file?; - let mut buf: String = Default::default(); - std::fs::File::open(file.path())?.read_to_string(&mut buf)?; - - let mail = mail_parser::MessageParser::new().parse(&buf) - .ok_or(anyhow!("Failed to parse mail `{:?}`.", file))?; - - // Fetching address lists from fields we know - let mut to = HashSet::new(); - if let Some(addr) = mail.to() { - let _ = address_into_iter(addr).map(|x| to.insert(x)); - }; - if let Some(addr) = mail.header("X-Samotop-To") { - match addr { - mail_parser::HeaderValue::Address(addr) => { - let _ = address_into_iter(addr).map(|x| to.insert(x)); - }, - mail_parser::HeaderValue::Text(text) => { - to.insert(text.clone()); - }, - _ => {} - } - }; - - // Adding all known addresses to recipient list, for anyone else adding default - // Also if list is empty also adding default - let mut rcpt: HashSet<&ChatId> = HashSet::new(); - for item in to { - let item = item.into_owned(); - match core.recipients.get(&item) { - Some(addr) => rcpt.insert(addr), - None => { - core.debug(format!("Recipient [{}] not found.", &item)).await?; - rcpt.insert(core.recipients.get("_") - .ok_or(anyhow!("Missing default address in recipient table."))?) - } - }; - }; - if rcpt.is_empty() { - core.debug("No recipient or envelope address.").await?; - rcpt.insert(core.recipients.get("_") - .ok_or(anyhow!("Missing default address in recipient table."))?); - }; - - // prepating message header - let mut reply: Vec> = vec![]; - if let Some(subject) = mail.subject() { - reply.push(format!("**Subject:** `{}`", subject).into()); - } else if let Some(thread) = mail.thread_name() { - reply.push(format!("**Thread:** `{}`", thread).into()); - } - if let Some(from) = mail.from() { - reply.push(format!("**From:** `{:?}`", address_into_iter(from).collect::>().join(", ")).into()); - } - if let Some(sender) = mail.sender() { - reply.push(format!("**Sender:** `{:?}`", address_into_iter(sender).collect::>().join(", ")).into()); - } - reply.push("".into()); - let header_size = reply.join("\n").len() + 1; - - let html_parts = mail.html_body_count(); - let text_parts = mail.text_body_count(); - let attachments = mail.attachment_count(); - if html_parts != text_parts { - core.debug(format!("Hm, we have {} HTML parts and {} text parts.", html_parts, text_parts)).await?; - } - //let mut html_num = 0; - let mut text_num = 0; - let mut file_num = 0; - // let's display first html or text part as body - let mut body = "".into(); - /* - * actually I don't wanna parse that html stuff - if html_parts > 0 { - let text = mail.body_html(0).unwrap(); - if text.len() < 4096 - header_size { - body = text; - html_num = 1; - } - }; - */ - if body == "" && text_parts > 0 { - let text = mail.body_text(0) - .ok_or(anyhow!("Failed to extract text from message."))?; - if text.len() < 4096 - header_size { - body = text; - text_num = 1; - } - }; - reply.push("```".into()); - reply.extend(body.lines().map(|x| x.into())); - reply.push("```".into()); - - // and let's collect all other attachment parts - let mut files_to_send = vec![]; - /* - * let's just skip html parts for now, they just duplicate text? - while html_num < html_parts { - files_to_send.push(mail.html_part(html_num).unwrap()); - html_num += 1; - } - */ - while text_num < text_parts { - files_to_send.push(mail.text_part(text_num) - .ok_or(anyhow!("Failed to get text part from message"))?); - text_num += 1; - } - while file_num < attachments { - files_to_send.push(mail.attachment(file_num) - .ok_or(anyhow!("Failed to get file part from message"))?); - file_num += 1; - } - - let msg = reply.join("\n"); - for chat in rcpt { - if !files_to_send.is_empty() { - let mut files = vec![]; - let mut first_one = true; - for chunk in &files_to_send { - let data = chunk.contents(); - let mut filename: Option = None; - for header in chunk.headers() { - if header.name() == "Content-Type" { - match header.value() { - mail_parser::HeaderValue::ContentType(contenttype) => { - if let Some(fname) = contenttype.attribute("name") { - filename = Some(fname.to_owned()); - } - }, - _ => { - core.debug("Attachment has bad ContentType header.").await?; - }, - }; - }; - }; - let filename = if let Some(fname) = filename { - fname - } else { - "Attachment.txt".into() - }; - let item = teloxide::types::InputMediaDocument::new( - teloxide::types::InputFile::memory(data.to_vec()) - .file_name(filename)); - let item = if first_one { - first_one = false; - item.caption(&msg).parse_mode(MarkdownV2) - } else { - item - }; - files.push(InputMedia::Document(item)); - } - core.sendgroup(chat, files).await?; - } else { - core.send(chat, &msg).await?; - } - } - - std::fs::remove_file(file.path())?; - } - Ok(()) -} - -fn my_prudence() -> Prudence { - Prudence::default().with_read_timeout(Duration::from_secs(60)).with_banner_delay(Duration::from_secs(1)) -} - -pub struct TelegramTransport { - tg: teloxide::adaptors::DefaultParseMode>, - recipients: HashMap, +/// `SomeHeaders` object to store data through SMTP session +#[derive(Clone, Debug)] +struct SomeHeaders { + from: String, + to: Vec, +} + +/// `TelegramTransport` Central object with TG api and configuration +#[derive(Clone)] +struct TelegramTransport { + data: Vec, + headers: Option, + recipients: HashMap, + relay: bool, + tg: teloxide::adaptors::DefaultParseMode>, } impl TelegramTransport { - pub fn new(settings: config::Config) -> TelegramTransport { + /// Initialize API and read configuration + fn new(settings: config::Config) -> TelegramTransport { let tg = Bot::new(settings.get_string("api_key") .expect("[smtp2tg.toml] missing \"api_key\" parameter.\n")) .throttle(teloxide::adaptors::throttle::Limits::default()) .parse_mode(MarkdownV2); let recipients: HashMap = settings.get_table("recipients") @@ -243,101 +69,280 @@ ))).collect(); if !recipients.contains_key("_") { eprintln!("[smtp2tg.toml] \"recipient\" table misses \"default_recipient\".\n"); panic!("no default recipient"); } + let value = settings.get_string("unknown"); + let relay = match value { + Ok(value) => { + match value.as_str() { + "relay" => true, + "deny" => false, + _ => { + eprintln!("[smtp2tg.toml] \"unknown\" should be either \"relay\" or \"deny\".\n"); + panic!("bad setting"); + }, + } + }, + Err(err) => { + eprintln!("[smtp2tg.toml] can't get \"unknown\":\n {}\n", err); + panic!("bad setting"); + }, + }; TelegramTransport { - tg, + data: vec!(), + headers: None, recipients, + relay, + tg, } } - pub async fn debug<'b, S>(&self, msg: S) -> Result + /// Send message to default user, used for debug/log/info purposes + async fn debug<'b, S>(&self, msg: S) -> Result where S: Into { Ok(self.tg.send_message(*self.recipients.get("_").unwrap(), msg).await?) } - pub async fn send<'b, S>(&self, to: &ChatId, msg: S) -> Result + /// Send message to specified user + async fn send<'b, S>(&self, to: &ChatId, msg: S) -> Result where S: Into { Ok(self.tg.send_message(*to, msg).await?) } + /// Attempt to deliver one message + async fn relay_mail (&self) -> Result<()> { + if let Some(headers) = &self.headers { + let mail = mail_parser::MessageParser::new().parse(&self.data) + .ok_or(anyhow!("Failed to parse mail"))?; + + // Adding all known addresses to recipient list, for anyone else adding default + // Also if list is empty also adding default + let mut rcpt: HashSet<&ChatId> = HashSet::new(); + if headers.to.is_empty() { + bail!("No recipient addresses."); + } + for item in &headers.to { + match self.recipients.get(item) { + Some(addr) => rcpt.insert(addr), + None => { + self.debug(format!("Recipient [{}] not found.", &item)).await?; + rcpt.insert(self.recipients.get("_") + .ok_or(anyhow!("Missing default address in recipient table."))?) + } + }; + }; + if rcpt.is_empty() { + self.debug("No recipient or envelope address.").await?; + rcpt.insert(self.recipients.get("_") + .ok_or(anyhow!("Missing default address in recipient table."))?); + }; + + // prepating message header + let mut reply: Vec> = vec![]; + if let Some(subject) = mail.subject() { + reply.push(format!("**Subject:** `{}`", subject).into()); + } else if let Some(thread) = mail.thread_name() { + reply.push(format!("**Thread:** `{}`", thread).into()); + } + reply.push(format!("**From:** `{}`", headers.from).into()); + reply.push("".into()); + let header_size = reply.join("\n").len() + 1; + + let html_parts = mail.html_body_count(); + let text_parts = mail.text_body_count(); + let attachments = mail.attachment_count(); + if html_parts != text_parts { + self.debug(format!("Hm, we have {} HTML parts and {} text parts.", html_parts, text_parts)).await?; + } + //let mut html_num = 0; + let mut text_num = 0; + let mut file_num = 0; + // let's display first html or text part as body + let mut body = "".into(); + /* + * actually I don't wanna parse that html stuff + if html_parts > 0 { + let text = mail.body_html(0).unwrap(); + if text.len() < 4096 - header_size { + body = text; + html_num = 1; + } + }; + */ + if body == "" && text_parts > 0 { + let text = mail.body_text(0) + .ok_or(anyhow!("Failed to extract text from message."))?; + if text.len() < 4096 - header_size { + body = text; + text_num = 1; + } + }; + reply.push("```".into()); + reply.extend(body.lines().map(|x| x.into())); + reply.push("```".into()); + + // and let's collect all other attachment parts + let mut files_to_send = vec![]; + /* + * let's just skip html parts for now, they just duplicate text? + while html_num < html_parts { + files_to_send.push(mail.html_part(html_num).unwrap()); + html_num += 1; + } + */ + while text_num < text_parts { + files_to_send.push(mail.text_part(text_num) + .ok_or(anyhow!("Failed to get text part from message"))?); + text_num += 1; + } + while file_num < attachments { + files_to_send.push(mail.attachment(file_num) + .ok_or(anyhow!("Failed to get file part from message"))?); + file_num += 1; + } + + let msg = reply.join("\n"); + for chat in rcpt { + if !files_to_send.is_empty() { + let mut files = vec![]; + let mut first_one = true; + for chunk in &files_to_send { + let data = chunk.contents(); + let mut filename: Option = None; + for header in chunk.headers() { + if header.name() == "Content-Type" { + match header.value() { + mail_parser::HeaderValue::ContentType(contenttype) => { + if let Some(fname) = contenttype.attribute("name") { + filename = Some(fname.to_owned()); + } + }, + _ => { + self.debug("Attachment has bad ContentType header.").await?; + }, + }; + }; + }; + let filename = if let Some(fname) = filename { + fname + } else { + "Attachment.txt".into() + }; + let item = teloxide::types::InputMediaDocument::new( + teloxide::types::InputFile::memory(data.to_vec()) + .file_name(filename)); + let item = if first_one { + first_one = false; + item.caption(&msg).parse_mode(MarkdownV2) + } else { + item + }; + files.push(InputMedia::Document(item)); + } + self.sendgroup(chat, files).await?; + } else { + self.send(chat, &msg).await?; + } + } + } else { + bail!("No headers."); + } + Ok(()) + } + + /// Send media to specified user pub async fn sendgroup(&self, to: &ChatId, media: M) -> Result> where M: IntoIterator { Ok(self.tg.send_media_group(*to, media).await?) } } + +impl mailin_embedded::Handler for TelegramTransport { + /// Just deny login auth + fn auth_login (&mut self, _username: &str, _password: &str) -> Response { + INVALID_CREDENTIALS + } + + /// Just deny plain auth + fn auth_plain (&mut self, _authorization_id: &str, _authentication_id: &str, _password: &str) -> Response { + INVALID_CREDENTIALS + } + + /// Verify whether address is deliverable + fn rcpt (&mut self, to: &str) -> Response { + if self.relay { + OK + } else { + match self.recipients.get(to) { + Some(_) => OK, + None => { + if self.relay { + OK + } else { + NO_MAILBOX + } + } + } + } + } + + /// Save headers we need + fn data_start (&mut self, _domain: &str, from: &str, _is8bit: bool, to: &[String]) -> Response { + self.headers = Some(SomeHeaders{ + from: from.to_string(), + to: to.to_vec(), + }); + OK + } + + /// Save chunk(?) of data + fn data(&mut self, buf: &[u8]) -> Result<(), Error> { + self.data.append(buf.to_vec().as_mut()); + Ok(()) + } + + /// Attempt to send email, return temporary error if that fails + fn data_end(&mut self) -> Response { + let mut result = OK; + task::block_on(async { + // relay mail + if let Err(err) = self.relay_mail().await { + result = INTERNAL_ERROR; + // in case that fails - inform default recipient + if let Err(err) = self.debug(format!("Sending emails failed:\n{:?}", err)).await { + // in case that also fails - write some logs and bail + eprintln!("Failed to contact Telegram:\n{:?}", err); + }; + }; + }); + // clear - just in case + self.data = vec![]; + self.headers = None; + result + } +} #[async_std::main] -async fn main() { +async fn main() -> Result<()> { let settings: config::Config = config::Config::builder() + .set_default("listen_on", "0.0.0.0:1025").unwrap() + .set_default("hostname", "smtp.2.tg").unwrap() + .set_default("unknown", "relay").unwrap() .add_source(config::File::with_name("smtp2tg.toml")) .build() .expect("[smtp2tg.toml] there was an error reading config\n\ \tplease consult \"smtp2tg.toml.example\" for details"); - let maildir: PathBuf = settings.get_string("maildir") - .expect("[smtp2tg.toml] missing \"maildir\" parameter.\n").into(); - let listen_on = settings.get_string("listen_on") - .expect("[smtp2tg.toml] missing \"listen_on\" parameter.\n"); - let core = TelegramTransport::new(settings); - let sink = Builder + Name::new("smtp2tg") + DebugService + - my_prudence() + MailDir::new(maildir.clone()).unwrap(); - - task::spawn(async move { - loop { - // relay mails - if let Err(err) = relay_mails(&maildir, &core).await { - // in case that fails - inform default recipient - if let Err(err) = core.debug(format!("Sending emails failed:\n{:?}", err)).await { - // in case that also fails - write some logs and bail - eprintln!("Failed to contact Telegram:\n{:?}", err); - }; - task::sleep(Duration::from_secs(5 * 60)).await; - }; - task::sleep(Duration::from_secs(5)).await; - } - }); - - match listen_on.as_str() { - "socket" => { - let socket_path = "./smtp2tg.sock"; - match std::fs::symlink_metadata(socket_path) { - Ok(metadata) => { - if metadata.file_type().is_socket() { - std::fs::remove_file(socket_path) - .expect("[smtp2tg] failed to remove old socket.\n"); - } else { - eprintln!("[smtp2tg] \"./smtp2tg.sock\" we wanted to use is actually not a socket.\n\ - [smtp2tg] please check the file and remove it manually.\n"); - panic!("socket path unavailable"); - } - }, - Err(err) => { - match err.kind() { - std::io::ErrorKind::NotFound => {}, - _ => { - eprintln!("{:?}", err); - panic!("unhandled file type error"); - } - }; - } - }; - - let sink = sink + samotop::smtp::Lmtp.with(SmtpParser); - task::spawn(async move { - // Postpone mode change on the socket. I can't actually change - // other way, as UnixServer just grabs path, and blocks - task::sleep(Duration::from_secs(1)).await; - std::fs::set_permissions(socket_path, std::fs::Permissions::from_mode(0o777)).unwrap(); - }); - samotop::server::UnixServer::on(socket_path) - .serve(sink.build()).await.unwrap(); - }, - _ => { - let sink = sink + samotop::smtp::Esmtp.with(SmtpParser); - samotop::server::TcpServer::on(listen_on) - .serve(sink.build()).await.unwrap(); - }, - }; + let listen_on = settings.get_string("listen_on")?; + let server_name = settings.get_string("hostname")?; + let core = TelegramTransport::new(settings); + let mut server = mailin_embedded::Server::new(core); + + server.with_name(server_name) + .with_ssl(mailin_embedded::SslConfig::None).unwrap() + .with_addr(listen_on).unwrap(); + server.serve().unwrap(); + + Ok(()) }