diff --git a/CHANGELOG.md b/CHANGELOG.md index 355a3522b..2dc1371d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ ## Unreleased +### Changes +- Refactor: Remove the remaining AsRef #3669 +- Small speedup #3780 + +### API-Changes +- Add Python API to send reactions #3762 +- jsonrpc: add message errors to MessageObject #3788 + +### Fixes +- Make sure malformed messsages will never block receiving further messages anymore #3771 +- strip leading/trailing whitespace from "Chat-Group-Name{,-Changed}:" headers content #3650 +- Assume all Thunderbird users prefer encryption #3774 +- refactor peerstate handling to ensure no duplicate peerstates #3776 + + +## 1.102.0 + ### Changes - If an email has multiple From addresses, handle this as if there was diff --git a/Cargo.lock b/Cargo.lock index 4b1e31dd3..b4044597e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aead" version = "0.3.2" @@ -39,7 +45,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core 0.6.3", ] [[package]] @@ -130,7 +136,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.7", "once_cell", "version_check 0.9.4", ] @@ -142,16 +148,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" dependencies = [ "cfg-if", - "getrandom 0.2.8", + "getrandom 0.2.7", "once_cell", "version_check 0.9.4", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -164,9 +170,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" dependencies = [ "libc", ] @@ -300,7 +306,7 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ - "concurrent-queue", + "concurrent-queue 1.2.4", "event-listener", "futures-core", ] @@ -342,13 +348,13 @@ dependencies = [ [[package]] name = "async-io" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" dependencies = [ "async-lock", "autocfg", - "concurrent-queue", + "concurrent-queue 2.0.0", "futures-lite", "libc", "log", @@ -357,7 +363,7 @@ dependencies = [ "slab", "socket2", "waker-fn", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -446,9 +452,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", @@ -503,7 +509,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -529,7 +535,7 @@ dependencies = [ "http", "http-body", "hyper", - "itoa 1.0.4", + "itoa 1.0.3", "matchit", "memchr", "mime", @@ -574,7 +580,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide 0.5.4", + "miniz_oxide", "object", "rustc-demangle", ] @@ -611,9 +617,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" -version = "1.5.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" [[package]] name = "bincode" @@ -661,7 +667,7 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e" dependencies = [ - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -688,9 +694,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "895adc16c8b3273fbbc32685a7d55227705eda08c01e77704020f3491924b44b" +checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" dependencies = [ "arrayref", "arrayvec", @@ -710,9 +716,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array", ] @@ -788,9 +794,9 @@ checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byte-pool" @@ -825,9 +831,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.12.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" +checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" [[package]] name = "byteorder" @@ -837,9 +843,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" dependencies = [ "serde", ] @@ -888,9 +894,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -967,9 +973,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ "iana-time-zone", "js-sys", @@ -1047,14 +1053,14 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.26" +version = "4.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" dependencies = [ - "atty", "bitflags", "clap_derive", "clap_lex", + "is-terminal", "once_cell", "strsim", "termcolor", @@ -1102,16 +1108,6 @@ dependencies = [ "cc", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "color_quant" version = "1.1.0" @@ -1127,6 +1123,15 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "concurrent-queue" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "config" version = "0.13.2" @@ -1148,9 +1153,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" [[package]] name = "constant_time_eq" @@ -1197,9 +1202,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -1301,22 +1306,23 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset", + "once_cell", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1324,11 +1330,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if", + "once_cell", ] [[package]] @@ -1344,7 +1351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core 0.6.3", "subtle", "zeroize", ] @@ -1425,7 +1432,7 @@ version = "3.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173" dependencies = [ - "nix 0.25.0", + "nix 0.25.1", "winapi", ] @@ -1450,55 +1457,11 @@ checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core 0.6.4", + "rand_core 0.6.3", "subtle", "zeroize", ] -[[package]] -name = "cxx" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "darling" version = "0.13.4" @@ -1511,12 +1474,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" dependencies = [ - "darling_core 0.14.2", - "darling_macro 0.14.2", + "darling_core 0.14.1", + "darling_macro 0.14.1", ] [[package]] @@ -1535,9 +1498,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" dependencies = [ "fnv", "ident_case", @@ -1560,26 +1523,25 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" dependencies = [ - "darling_core 0.14.2", + "darling_core 0.14.1", "quote", "syn", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" dependencies = [ "cfg-if", "hashbrown 0.12.3", "lock_api", - "once_cell", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.3", ] [[package]] @@ -1618,9 +1580,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "deflate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" +dependencies = [ + "adler32", +] + [[package]] name = "deltachat" -version = "1.101.0" +version = "1.102.0" dependencies = [ "ansi_term", "anyhow", @@ -1643,7 +1614,7 @@ dependencies = [ "futures", "futures-lite", "hex", - "humansize 1.1.1", + "humansize", "image", "iroh-resolver", "iroh-share", @@ -1691,18 +1662,18 @@ dependencies = [ "toml", "trust-dns-resolver", "url", - "uuid 1.2.2", + "uuid 1.2.1", ] [[package]] name = "deltachat-jsonrpc" -version = "1.101.0" +version = "1.102.0" dependencies = [ "anyhow", "async-channel", "axum", "deltachat", - "env_logger 0.9.3", + "env_logger 0.9.1", "futures", "log", "num-traits", @@ -1718,11 +1689,11 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.101.0" +version = "1.102.0" dependencies = [ "anyhow", "deltachat-jsonrpc", - "env_logger 0.9.3", + "env_logger 0.9.1", "futures-lite", "log", "serde", @@ -1741,7 +1712,7 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.101.0" +version = "1.102.0" dependencies = [ "anyhow", "deltachat", @@ -1823,7 +1794,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" dependencies = [ - "darling 0.14.2", + "darling 0.14.1", "proc-macro2", "quote", "syn", @@ -1859,11 +1830,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.2", "const-oid", "crypto-common", "subtle", @@ -1970,9 +1941,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" [[package]] name = "elliptic-curve" @@ -1983,14 +1954,14 @@ dependencies = [ "base16ct", "crypto-bigint", "der", - "digest 0.10.6", + "digest 0.10.5", "ff", "generic-array", "group", "hkdf", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", + "rand_core 0.6.3", "sec1", "subtle", "zeroize", @@ -2137,9 +2108,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" dependencies = [ "atty", "humantime 2.1.0", @@ -2245,13 +2216,13 @@ dependencies = [ [[package]] name = "fd-lock" -version = "3.0.8" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb21c69b9fea5e15dbc1049e4b77145dd0ba1c84019c488102de0dc4ea4b0a27" +checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517" dependencies = [ "cfg-if", - "rustix", - "windows-sys 0.42.0", + "rustix 0.35.7", + "windows-sys 0.36.1", ] [[package]] @@ -2260,20 +2231,20 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.6.3", "subtle", ] [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.36.1", ] [[package]] @@ -2290,7 +2261,7 @@ checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ "crc32fast", "libz-sys", - "miniz_oxide 0.5.4", + "miniz_oxide", ] [[package]] @@ -2468,9 +2439,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", @@ -2548,15 +2519,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core 0.6.3", "subtle", ] [[package]] name = "h2" -version = "0.3.15" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ "bytes", "fnv", @@ -2619,6 +2590,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -2666,7 +2646,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -2688,7 +2668,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.4", + "itoa 1.0.3", ] [[package]] @@ -2710,9 +2690,9 @@ checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" [[package]] name = "httparse" -version = "1.8.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" [[package]] name = "httpdate" @@ -2735,12 +2715,6 @@ dependencies = [ "uuid 0.8.2", ] -[[package]] -name = "humansize" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" - [[package]] name = "humansize" version = "2.1.2" @@ -2767,9 +2741,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ "bytes", "futures-channel", @@ -2780,7 +2754,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.4", + "itoa 1.0.3", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -2829,28 +2803,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" dependencies = [ "android_system_properties", "core-foundation-sys", - "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "winapi", ] -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2909,9 +2872,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.5" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +checksum = "bd8e4fb07cf672b1642304e731ef8a6a4c7891d67bb4fd4f5ce58cd6ed86803c" dependencies = [ "bytemuck", "byteorder", @@ -2934,9 +2897,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -2982,9 +2945,15 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d367024b3f3414d8e01f437f704f41a9f64ab36f9067fa73e526ad4c763c87" +checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" dependencies = [ "libc", "windows-sys 0.42.0", @@ -2992,21 +2961,21 @@ dependencies = [ [[package]] name = "ipconfig" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ "socket2", "widestring", "winapi", - "winreg", + "winreg 0.7.0", ] [[package]] name = "ipnet" -version = "2.5.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" [[package]] name = "iroh-bitswap" @@ -3032,8 +3001,8 @@ dependencies = [ "names", "num_enum", "once_cell", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", "smallvec", "thiserror", @@ -3080,7 +3049,7 @@ dependencies = [ "asynchronous-codec", "bytes", "cid", - "clap 4.0.26", + "clap 4.0.29", "config", "futures", "futures-util", @@ -3130,8 +3099,8 @@ dependencies = [ "multihash", "num_enum", "once_cell", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", "reqwest", "serde", @@ -3160,7 +3129,7 @@ dependencies = [ "iroh-util", "libp2p", "paste", - "prost 0.11.2", + "prost 0.11.3", "serde", "tokio", "toml", @@ -3177,8 +3146,8 @@ dependencies = [ "futures", "iroh-metrics", "paste", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-types 0.11.2", "serde_with", "tokio", @@ -3194,7 +3163,7 @@ dependencies = [ "bincode", "bytes", "cid", - "clap 4.0.26", + "clap 4.0.29", "futures", "iroh-metrics", "iroh-p2p", @@ -3225,7 +3194,7 @@ dependencies = [ "bytecheck", "bytes", "cid", - "clap 4.0.26", + "clap 4.0.29", "config", "ctrlc", "futures", @@ -3258,7 +3227,7 @@ dependencies = [ "ctrlc", "dirs-next", "futures", - "humansize 2.1.2", + "humansize", "rlimit", "serde", "sysinfo", @@ -3269,10 +3238,22 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.10.5" +name = "is-terminal" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes 1.0.3", + "rustix 0.36.4", + "windows-sys 0.42.0", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] @@ -3285,9 +3266,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "jobserver" @@ -3300,15 +3281,15 @@ dependencies = [ [[package]] name = "jpeg-decoder" -version = "0.3.0" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ "wasm-bindgen", ] @@ -3335,12 +3316,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] +checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" [[package]] name = "keyed_priority_queue" @@ -3500,9 +3478,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" [[package]] name = "libp2p" @@ -3512,7 +3490,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.8", + "getrandom 0.2.7", "instant", "libp2p-autonat", "libp2p-core", @@ -3553,8 +3531,8 @@ dependencies = [ "libp2p-request-response", "libp2p-swarm", "log", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", ] @@ -3578,8 +3556,8 @@ dependencies = [ "once_cell", "parking_lot 0.12.1", "pin-project", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", "ring", "rw-stream-sink", @@ -3606,8 +3584,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-codec", "thiserror", "void", @@ -3643,8 +3621,8 @@ dependencies = [ "libp2p-swarm", "log", "prometheus-client", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-codec", "rand 0.8.5", "regex", @@ -3668,8 +3646,8 @@ dependencies = [ "libp2p-swarm", "log", "lru", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-codec", "smallvec", "thiserror", @@ -3692,8 +3670,8 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", "serde", "sha2 0.10.6", @@ -3767,8 +3745,8 @@ dependencies = [ "libp2p-core", "log", "once_cell", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "rand 0.8.5", "sha2 0.10.6", "snow", @@ -3827,8 +3805,8 @@ dependencies = [ "libp2p-swarm", "log", "pin-project", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-codec", "rand 0.8.5", "smallvec", @@ -3933,8 +3911,8 @@ dependencies = [ "libp2p-noise", "log", "multihash", - "prost 0.11.2", - "prost-build 0.11.2", + "prost 0.11.3", + "prost-build 0.11.3", "prost-codec", "rand 0.8.5", "rcgen 0.9.3", @@ -4016,21 +3994,18 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] - [[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.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + [[package]] name = "linux-raw-sys" version = "0.1.3" @@ -4039,9 +4014,9 @@ checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ "autocfg", "scopeguard", @@ -4118,7 +4093,7 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -4136,15 +4111,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.16" @@ -4159,18 +4125,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", ] @@ -4226,7 +4183,7 @@ dependencies = [ "blake2s_simd", "blake3", "core2", - "digest 0.10.6", + "digest 0.10.5", "multihash-derive", "serde", "serde-big-array", @@ -4385,14 +4342,14 @@ dependencies = [ "bitflags", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset", ] [[package]] name = "nix" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", "bitflags", @@ -4458,9 +4415,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +checksum = "566d173b2f9406afbc5510a90925d5a2cd80cae4605631f1212303df265de011" dependencies = [ "byteorder", "lazy_static", @@ -4529,11 +4486,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -4605,9 +4562,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.42" +version = "0.10.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" dependencies = [ "bitflags", "cfg-if", @@ -4637,18 +4594,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.24.0+1.1.1s" +version = "111.22.0+1.1.1q" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd" +checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.77" +version = "0.9.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" dependencies = [ "autocfg", "cc", @@ -4680,7 +4637,7 @@ dependencies = [ "http", "opentelemetry", "opentelemetry-proto", - "prost 0.11.2", + "prost 0.11.3", "thiserror", "tokio", "tonic", @@ -4695,7 +4652,7 @@ dependencies = [ "futures", "futures-util", "opentelemetry", - "prost 0.11.2", + "prost 0.11.3", "tonic", "tonic-build", ] @@ -4756,18 +4713,18 @@ checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "os_type" -version = "2.6.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24d44c0eea30167516ed8f6daca4b5e3eebcde1bde1e4e6e08b809fb02c7ba5" +checksum = "c3df761f6470298359f84fcfb60d86db02acc22c251c37265c07a3d1057d2389" dependencies = [ "regex", ] [[package]] name = "ouroboros" -version = "0.15.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" +checksum = "7425ea87a1e31df63a27b6d31e21a35a9003268032a876465e8d43c2364b0de2" dependencies = [ "aliasable", "ouroboros_macro", @@ -4775,9 +4732,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.15.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" +checksum = "734aa7a4a6390b162112523cac2923a18e4f23b917880a68c826bf6e8bf48f06" dependencies = [ "Inflector", "proc-macro-error", @@ -4838,7 +4795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.3", ] [[package]] @@ -4857,15 +4814,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.36.1", ] [[package]] @@ -4912,9 +4869,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.4.1" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" dependencies = [ "thiserror", "ucd-trie", @@ -4922,9 +4879,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.4.1" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f" +checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" dependencies = [ "pest", "pest_generator", @@ -4932,9 +4889,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.4.1" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4" +checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" dependencies = [ "pest", "pest_meta", @@ -4945,9 +4902,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.4.1" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe" +checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" dependencies = [ "once_cell", "pest", @@ -4984,7 +4941,7 @@ dependencies = [ "crc24", "derive_builder", "des", - "digest 0.10.6", + "digest 0.10.5", "ed25519-dalek", "flate2", "generic-array", @@ -5011,18 +4968,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" dependencies = [ "proc-macro2", "quote", @@ -5071,15 +5028,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "plotters" -version = "0.3.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +checksum = "9428003b84df1496fb9d6eeee9c5f8145cb41ca375eb0dad204328888832811f" dependencies = [ "num-traits", "plotters-backend", @@ -5096,37 +5053,37 @@ checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +checksum = "e0918736323d1baff32ee0eade54984f6f201ad7e97d5cfb5d6ab4a358529615" dependencies = [ "plotters-backend", ] [[package]] name = "png" -version = "0.17.7" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" dependencies = [ "bitflags", "crc32fast", - "flate2", - "miniz_oxide 0.6.2", + "deflate", + "miniz_oxide", ] [[package]] name = "polling" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" +checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748" dependencies = [ "autocfg", "cfg-if", "libc", "log", "wepoll-ffi", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -5171,9 +5128,9 @@ checksum = "f6519412c9e0d4be579b9f0618364d19cb434b324fc6ddb1b27b1e682c7105ed" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "pretty_env_logger" @@ -5237,9 +5194,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] @@ -5251,7 +5208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", - "itoa 1.0.4", + "itoa 1.0.3", "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] @@ -5296,9 +5253,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" +checksum = "c0b18e655c21ff5ac2084a5ad0611e827b3f92badf79f4910b5a5c58f4d87ff0" dependencies = [ "bytes", "prost-derive 0.11.2", @@ -5328,9 +5285,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8b442418ea0822409d9e7d047cbf1e7e9e1760b172bf9982cf29d517c93511" +checksum = "e330bf1316db56b12c2bcfa399e8edddd4821965ea25ddb2c134b610b1c1c604" dependencies = [ "bytes", "heck", @@ -5340,7 +5297,7 @@ dependencies = [ "multimap", "petgraph", "prettyplease", - "prost 0.11.2", + "prost 0.11.3", "prost-types 0.11.2", "regex", "syn", @@ -5355,7 +5312,7 @@ source = "git+https://github.com/dignifiedquire/rust-libp2p?branch=iroh-0-50-1#3 dependencies = [ "asynchronous-codec", "bytes", - "prost 0.11.2", + "prost 0.11.3", "thiserror", "unsigned-varint", ] @@ -5403,7 +5360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" dependencies = [ "bytes", - "prost 0.11.2", + "prost 0.11.3", ] [[package]] @@ -5446,9 +5403,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.23.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +checksum = "9279fbdacaad3baf559d8cabe0acc3d06e30ea14931af31af79578ac0946decc" dependencies = [ "memchr", ] @@ -5549,7 +5506,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand_core 0.6.3", ] [[package]] @@ -5569,7 +5526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core 0.6.3", ] [[package]] @@ -5583,11 +5540,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.7", ] [[package]] @@ -5605,15 +5562,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.6.3", ] [[package]] name = "rayon" -version = "1.6.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ + "autocfg", "crossbeam-deque", "either", "rayon-core", @@ -5621,9 +5579,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -5671,7 +5629,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.7", "redox_syscall", "thiserror", ] @@ -5698,9 +5656,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -5759,7 +5717,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -5804,7 +5762,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -5864,19 +5822,19 @@ dependencies = [ [[package]] name = "rsa" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c" +checksum = "b0ecc3307be66bfb3574577895555bacfb9a37a8d5cd959444b72ff02495c618" dependencies = [ "byteorder", - "digest 0.10.6", + "digest 0.10.5", "num-bigint-dig", "num-integer", "num-iter", "num-traits", "pkcs1", "pkcs8", - "rand_core 0.6.4", + "rand_core 0.6.3", "signature", "smallvec", "subtle", @@ -5986,15 +5944,29 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.3" +version = "0.35.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1fbb4dfc4eb1d390c02df47760bb19a84bb80b301ecc947ab5406394d8223e" +checksum = "d51cc38aa10f6bbb377ed28197aa052aa4e2b762c22be9d3153d01822587e787" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 0.7.2", "libc", - "linux-raw-sys", + "linux-raw-sys 0.0.46", + "windows-sys 0.36.1", +] + +[[package]] +name = "rustix" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes 1.0.3", + "libc", + "linux-raw-sys 0.1.3", "windows-sys 0.42.0", ] @@ -6127,12 +6099,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - [[package]] name = "sct" version = "0.6.1" @@ -6187,9 +6153,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -6264,11 +6230,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ - "itoa 1.0.4", + "itoa 1.0.3", "ryu", "serde", ] @@ -6280,7 +6246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.4", + "itoa 1.0.3", "ryu", "serde", ] @@ -6307,7 +6273,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa" dependencies = [ - "darling 0.14.2", + "darling 0.14.1", "proc-macro2", "quote", "syn", @@ -6334,7 +6300,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -6345,7 +6311,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -6369,7 +6335,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.5", ] [[package]] @@ -6378,7 +6344,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "digest 0.10.6", + "digest 0.10.5", "keccak", ] @@ -6412,8 +6378,8 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest 0.10.6", - "rand_core 0.6.4", + "digest 0.10.5", + "rand_core 0.6.3", ] [[package]] @@ -6447,7 +6413,7 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek 4.0.0-pre.1", - "rand_core 0.6.4", + "rand_core 0.6.3", "ring", "rustc_version", "sha2 0.10.6", @@ -6456,9 +6422,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", @@ -6516,7 +6482,7 @@ dependencies = [ "ed25519-dalek", "p256", "p384", - "rand_core 0.6.4", + "rand_core 0.6.3", "rsa", "sec1", "sha2 0.10.6", @@ -6645,9 +6611,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.26.7" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c375d5fd899e32847b8566e10598d6e9f1d9b55ec6de3cdf9e7da4bdc51371bc" +checksum = "29ddf41e393a9133c81d5f0974195366bd57082deac6e0eb02ed39b8341c2bb6" dependencies = [ "cfg-if", "core-foundation-sys", @@ -6783,7 +6749,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "itoa 1.0.4", + "itoa 1.0.3", "serde", "time-core", "time-macros", @@ -6831,9 +6797,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.22.0" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ "autocfg", "bytes", @@ -6940,9 +6906,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ "bytes", "futures-core", @@ -6982,7 +6948,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.11.2", + "prost 0.11.3", "prost-derive 0.11.2", "tokio", "tokio-stream", @@ -6996,13 +6962,13 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c6fd7c2581e36d63388a9e04c350c21beb7a8b059580b2e93993c526899ddc" +checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" dependencies = [ "prettyplease", "proc-macro2", - "prost-build 0.11.2", + "prost-build 0.11.3", "quote", "syn", ] @@ -7048,9 +7014,9 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" [[package]] name = "tower-service" @@ -7060,9 +7026,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if", "log", @@ -7073,9 +7039,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -7282,9 +7248,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -7300,9 +7266,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-linebreak" @@ -7316,18 +7282,18 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" @@ -7337,9 +7303,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "universal-hash" @@ -7398,16 +7364,16 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.7", ] [[package]] name = "uuid" -version = "1.2.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.7", "serde", ] @@ -7497,9 +7463,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -7507,9 +7473,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", "log", @@ -7522,9 +7488,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" dependencies = [ "cfg-if", "js-sys", @@ -7534,9 +7500,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7544,9 +7510,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", @@ -7557,9 +7523,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "wasm-timer" @@ -7578,9 +7544,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -7694,7 +7660,7 @@ dependencies = [ "p256", "p384", "rand 0.8.5", - "rand_core 0.6.4", + "rand_core 0.6.3", "rcgen 0.9.3", "ring", "rustls 0.19.1", @@ -7730,7 +7696,7 @@ dependencies = [ "tokio", "turn", "url", - "uuid 1.2.2", + "uuid 1.2.1", "waitgroup", "webrtc-mdns", "webrtc-util", @@ -8033,6 +7999,15 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi", +] + [[package]] name = "winreg" version = "0.10.1" @@ -8060,7 +8035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" dependencies = [ "curve25519-dalek 3.2.0", - "rand_core 0.6.4", + "rand_core 0.6.3", "zeroize", ] @@ -8171,7 +8146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f944ca6789bc55ddc86839478f6d49c9d2a66e130f69fd1f8d171b3108990" dependencies = [ "convert_case", - "darling 0.14.2", + "darling 0.14.1", "proc-macro2", "quote", "syn", @@ -8200,9 +8175,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.2+zstd.1.5.2" +version = "2.0.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24faa29d97c8ddca9b37b680e3bd2d5439d864a9cac3a0640d086b71c908bb83" +checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index a58956c5c..10b30919a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.101.0" +version = "1.102.0" authors = ["Delta Chat Developers (ML) "] edition = "2021" license = "MPL-2.0" @@ -57,7 +57,7 @@ quick-xml = "0.23" r2d2 = "0.8" r2d2_sqlite = "0.20" rand = "0.8" -regex = "1.6" +regex = "1.7" rusqlite = { version = "0.27", features = ["sqlcipher"] } rust-hsluv = "0.1" rustyline = { version = "10", optional = true } @@ -74,14 +74,14 @@ toml = "0.5" url = "2" uuid = { version = "1", features = ["serde", "v4"] } fast-socks5 = "0.8" -humansize = "1" +humansize = "2" qrcodegen = "1.7.0" tagger = "4.3.3" textwrap = "0.16.0" async-channel = "1.6.1" futures-lite = "1.12.0" tokio-stream = { version = "0.1.11", features = ["fs"] } -reqwest = { version = "0.11.12", features = ["json"] } +reqwest = { version = "0.11.13", features = ["json"] } async_zip = { version = "0.0.9", default-features = false, features = ["deflate"] } iroh-share = { git = "https://github.com/n0-computer/iroh", tag = "v0.1.1" } iroh-resolver = { git = "https://github.com/n0-computer/iroh", tag = "v0.1.1", default-features = false } diff --git a/README.md b/README.md index 204da5657..71a723eac 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,15 @@ $ cargo test -- --ignored - `vendored`: When using Openssl for TLS, this bundles a vendored version. - `nightly`: Enable nightly only performance and security related features. +## Update Provider Data + +To add the updates from the +[provider-db](https://github.com/deltachat/provider-db) to the core, run: + +``` +./src/provider/update.py ../provider-db/_providers/ > src/provider/data.rs +``` + ## Language bindings and frontend projects Language bindings are available for: diff --git a/benches/receive_emails.rs b/benches/receive_emails.rs index 1e9e5aa43..ece40985e 100644 --- a/benches/receive_emails.rs +++ b/benches/receive_emails.rs @@ -38,11 +38,64 @@ Hello {i}", context } +/// Receive 100 emails that remove charlie@example.com and add +/// him back +async fn recv_groupmembership_emails(context: Context) -> Context { + for i in 0..50 { + let imf_raw = format!( + "Subject: Benchmark +Message-ID: Gr.OssSYnOFkhR.{i}@testrun.org +Date: Sat, 07 Dec 2019 19:00:27 +0000 +To: alice@example.com, b@example.com, c@example.com, d@example.com, e@example.com, f@example.com +From: sender@testrun.org +Chat-Version: 1.0 +Chat-Disposition-Notification-To: sender@testrun.org +Chat-User-Avatar: 0 +Chat-Group-Member-Added: charlie@example.com +In-Reply-To: Gr.OssSYnOFkhR.{i_dec}@testrun.org +MIME-Version: 1.0 + +Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no + +Hello {i}", + i = i, + i_dec = i - 1, + ); + receive_imf(&context, black_box(imf_raw.as_bytes()), false) + .await + .unwrap(); + + let imf_raw = format!( + "Subject: Benchmark +Message-ID: Gr.OssSYnOFkhR.{i}@testrun.org +Date: Sat, 07 Dec 2019 19:00:27 +0000 +To: alice@example.com, b@example.com, c@example.com, d@example.com, e@example.com, f@example.com +From: sender@testrun.org +Chat-Version: 1.0 +Chat-Disposition-Notification-To: sender@testrun.org +Chat-User-Avatar: 0 +Chat-Group-Member-Removed: charlie@example.com +In-Reply-To: Gr.OssSYnOFkhR.{i_dec}@testrun.org +MIME-Version: 1.0 + +Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no + +Hello {i}", + i = i, + i_dec = i - 1, + ); + receive_imf(&context, black_box(imf_raw.as_bytes()), false) + .await + .unwrap(); + } + context +} + async fn create_context() -> Context { let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); let id = 100; - let context = Context::new(&dbfile, id, Events::new(), StockStrings::new()) + let context = Context::new(dbfile.as_path(), id, Events::new(), StockStrings::new()) .await .unwrap(); @@ -52,7 +105,7 @@ async fn create_context() -> Context { if backup.exists() { println!("Importing backup"); - imex(&context, ImexMode::ImportBackup, &backup, None) + imex(&context, ImexMode::ImportBackup, backup.as_path(), None) .await .unwrap(); } @@ -83,6 +136,20 @@ fn criterion_benchmark(c: &mut Criterion) { } }); }); + group.bench_function( + "Receive 100 Chat-Group-Member-{Added|Removed} messages", + |b| { + let rt = tokio::runtime::Runtime::new().unwrap(); + let context = rt.block_on(create_context()); + + b.to_async(&rt).iter(|| { + let ctx = context.clone(); + async move { + recv_groupmembership_emails(black_box(ctx)).await; + } + }); + }, + ); group.finish(); } diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index f949abf1e..6347abaa4 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.101.0" +version = "1.102.0" description = "Deltachat FFI" authors = ["Delta Chat Developers (ML) "] edition = "2018" diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index a89764c0d..b1f09e9e6 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1660,7 +1660,7 @@ pub unsafe extern "C" fn dc_set_chat_profile_image( let ctx = &*context; block_on(async move { - chat::set_chat_profile_image(ctx, ChatId::new(chat_id), to_string_lossy(image)) + chat::set_chat_profile_image(ctx, ChatId::new(chat_id), &to_string_lossy(image)) .await .map(|_| 1) .unwrap_or_log_default(ctx, "Failed to set profile image") diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 9c0e3040a..b914c6169 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.101.0" +version = "1.102.0" description = "DeltaChat JSON-RPC API" authors = ["Delta Chat Developers (ML) "] edition = "2021" @@ -23,7 +23,7 @@ async-channel = { version = "1.6.1" } futures = { version = "0.3.25" } serde_json = "1.0.87" yerpc = { version = "^0.3.1", features = ["anyhow_expose"] } -typescript-type-def = { version = "0.5.3", features = ["json_value"] } +typescript-type-def = { version = "0.5.5", features = ["json_value"] } tokio = { version = "1.21.2" } sanitize-filename = "0.4" walkdir = "2.3.2" diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index e00db7217..a311f8f07 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -733,7 +733,7 @@ impl CommandApi { image_path: Option, ) -> Result<()> { let ctx = self.get_context(account_id).await?; - chat::set_chat_profile_image(&ctx, ChatId::new(chat_id), image_path.unwrap_or_default()) + chat::set_chat_profile_image(&ctx, ChatId::new(chat_id), &image_path.unwrap_or_default()) .await } diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index a5899ac06..c7e9cfe8d 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -34,6 +34,9 @@ pub struct MessageObject { view_type: MessageViewtype, state: u32, + /// An error text, if there is one. + error: Option, + timestamp: i64, sort_timestamp: i64, received_timestamp: i64, @@ -167,6 +170,7 @@ impl MessageObject { .get_state() .to_u32() .ok_or_else(|| anyhow!("state conversion to number failed"))?, + error: message.error(), timestamp: message.get_timestamp(), sort_timestamp: message.get_sort_timestamp(), diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index 0f305e242..0335544e1 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -48,5 +48,5 @@ }, "type": "module", "types": "dist/deltachat.d.ts", - "version": "1.101.0" + "version": "1.102.0" } \ No newline at end of file diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 358744746..9ba9547e4 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-rpc-server" -version = "1.101.0" +version = "1.102.0" description = "DeltaChat JSON-RPC server" authors = ["Delta Chat Developers (ML) "] edition = "2021" diff --git a/package.json b/package.json index 351dad9a0..c65517f05 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,5 @@ "test:mocha": "mocha -r esm node/test/test.js --growl --reporter=spec --bail --exit" }, "types": "node/dist/index.d.ts", - "version": "1.101.0" + "version": "1.102.0" } \ No newline at end of file diff --git a/python/src/deltachat/_build.py b/python/src/deltachat/_build.py index 09795b3db..995dd34b8 100644 --- a/python/src/deltachat/_build.py +++ b/python/src/deltachat/_build.py @@ -156,6 +156,7 @@ def extract_defines(flags): | DC_KEY_GEN | DC_IMEX | DC_CONNECTIVITY + | DC_DOWNLOAD ) # End of prefix matching _[\w_]+ # Match the suffix, e.g. _RSA2048 in DC_KEY_GEN_RSA2048 ) # Close the capturing group, this contains diff --git a/python/src/deltachat/events.py b/python/src/deltachat/events.py index ccb9f877f..72b84a44a 100644 --- a/python/src/deltachat/events.py +++ b/python/src/deltachat/events.py @@ -192,6 +192,12 @@ class FFIEventTracker: return self.account.get_message_by_id(ev.data2) return None + def wait_next_reactions_changed(self): + """wait for and return next reactions-changed message""" + ev = self.get_matching("DC_EVENT_REACTIONS_CHANGED") + assert ev.data1 > 0 + return self.account.get_message_by_id(ev.data2) + def wait_msg_delivered(self, msg): ev = self.get_matching("DC_EVENT_MSG_DELIVERED") assert ev.data1 == msg.chat.id @@ -296,6 +302,10 @@ class EventThread(threading.Thread): "ac_incoming_message", dict(message=msg), ) + elif name == "DC_EVENT_REACTIONS_CHANGED": + assert ffi_event.data1 > 0 + msg = account.get_message_by_id(ffi_event.data2) + yield "ac_reactions_changed", dict(message=msg) elif name == "DC_EVENT_MSG_DELIVERED": msg = account.get_message_by_id(ffi_event.data2) yield "ac_message_delivered", dict(message=msg) diff --git a/python/src/deltachat/hookspec.py b/python/src/deltachat/hookspec.py index 2a76dafb8..4d2fe6960 100644 --- a/python/src/deltachat/hookspec.py +++ b/python/src/deltachat/hookspec.py @@ -49,6 +49,10 @@ class PerAccount: def ac_outgoing_message(self, message): """Called on each outgoing message (both system and "normal").""" + @account_hookspec + def ac_reactions_changed(self, message): + """Called when message reactions changed.""" + @account_hookspec def ac_message_delivered(self, message): """Called when an outgoing message has been delivered to SMTP. diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index 9ed5b132f..0891b46cf 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -9,6 +9,7 @@ from typing import Optional, Union from . import const, props from .capi import ffi, lib from .cutil import as_dc_charpointer, from_dc_charpointer, from_optional_dc_charpointer +from .reactions import Reactions class Message(object): @@ -161,6 +162,17 @@ class Message(object): ) ) + def send_reaction(self, reaction: str): + """Send a reaction to message and return the resulting Message instance.""" + msg_id = lib.dc_send_reaction(self.account._dc_context, self.id, as_dc_charpointer(reaction)) + if msg_id == 0: + raise ValueError("reaction could not be send") + return Message.from_db(self.account, msg_id) + + def get_reactions(self) -> Reactions: + """Get :class:`deltachat.reactions.Reactions` to the message.""" + return Reactions.from_msg(self) + def is_system_message(self): """return True if this message is a system/info message.""" return bool(lib.dc_msg_is_info(self._dc_msg)) @@ -449,6 +461,17 @@ class Message(object): """mark this message as seen.""" self.account.mark_seen_messages([self.id]) + # + # Message download state + # + @property + def download_state(self): + assert self.id > 0 + + # load message from db to get a fresh/current state + dc_msg = ffi.gc(lib.dc_get_msg(self.account._dc_context, self.id), lib.dc_msg_unref) + return lib.dc_msg_get_download_state(dc_msg) + # some code for handling DC_MSG_* view types diff --git a/python/src/deltachat/reactions.py b/python/src/deltachat/reactions.py new file mode 100644 index 000000000..9e9ed9555 --- /dev/null +++ b/python/src/deltachat/reactions.py @@ -0,0 +1,43 @@ +""" The Reactions object. """ + +from .capi import ffi, lib +from .cutil import from_dc_charpointer, iter_array + + +class Reactions(object): + """Reactions object. + + You obtain instances of it through :class:`deltachat.message.Message`. + """ + + def __init__(self, account, dc_reactions): + assert isinstance(account._dc_context, ffi.CData) + assert isinstance(dc_reactions, ffi.CData) + assert dc_reactions != ffi.NULL + self.account = account + self._dc_reactions = dc_reactions + + def __repr__(self): + return "".format(self._dc_reactions) + + @classmethod + def from_msg(cls, msg): + assert msg.id > 0 + return cls( + msg.account, + ffi.gc(lib.dc_get_msg_reactions(msg.account._dc_context, msg.id), lib.dc_reactions_unref), + ) + + def get_contacts(self) -> list: + """Get list of contacts reacted to the message. + + :returns: list of :class:`deltachat.contact.Contact` objects for this reaction. + """ + from .contact import Contact + + dc_array = ffi.gc(lib.dc_reactions_get_contacts(self._dc_reactions), lib.dc_array_unref) + return list(iter_array(dc_array, lambda x: Contact(self.account, x))) + + def get_by_contact(self, contact) -> str: + """Get a string containing space-separated reactions of a single :class:`deltachat.contact.Contact`.""" + return from_dc_charpointer(lib.dc_reactions_get_by_contact_id(self._dc_reactions, contact.id)) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 2a7f1d78b..39cbae48c 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -405,6 +405,29 @@ def test_forward_own_message(acfactory, lp): assert msg_in.is_forwarded() +def test_long_group_name(acfactory, lp): + """See bug https://github.com/deltachat/deltachat-core-rust/issues/3650 "Space added before long + group names after MIME serialization/deserialization". + + When the mailadm bot creates a group with botadmin, the bot creates is as + "pytest-supportuser-282@x.testrun.org support group" (for example). But in the botadmin's + account object, the group chat is called " pytest-supportuser-282@x.testrun.org support group" + (with an additional space character in the beginning). + """ + ac1, ac2 = acfactory.get_online_accounts(2) + + lp.sec("ac1: creating group chat and sending a message") + group_name = "pytest-supportuser-282@x.testrun.org support group" + group = ac1.create_group_chat(group_name) + group.add_contact(ac2) + group.send_text("message") + + # wait for other account to receive + ev = ac2._evtracker.get_matching("DC_EVENT_INCOMING_MSG") + msg_in = ac2.get_message_by_id(ev.data2) + assert msg_in.chat.get_name() == group_name + + def test_send_self_message(acfactory, lp): ac1 = acfactory.new_online_configuring_account(mvbox_move=True) acfactory.bring_accounts_online() @@ -1267,6 +1290,66 @@ def test_send_and_receive_image(acfactory, lp, data): assert m == msg_in +def test_reaction_to_partially_fetched_msg(acfactory, lp, tmpdir): + """See https://github.com/deltachat/deltachat-core-rust/issues/3688 "Partially downloaded + messages are received out of order". + + If the Inbox contains X small messages followed by Y large messages followed by Z small + messages, Delta Chat first downloaded a batch of X+Z messages, and then a batch of Y messages. + + This bug was discovered by @Simon-Laux while testing reactions PR #3644 and can be reproduced + with online test as follows: + - Bob enables download limit and goes offline. + - Alice sends a large message to Bob and reacts to this message with a thumbs-up. + - Bob goes online + - Bob first processes a reaction message and throws it away because there is no corresponding + message, then processes a partially downloaded message. + - As a result, Bob does not see a reaction + """ + download_limit = 32768 + ac1, ac2 = acfactory.get_online_accounts(2) + ac1_addr = ac1.get_config("addr") + chat = ac1.create_chat(ac2) + ac2.set_config("download_limit", str(download_limit)) + ac2.stop_io() + + reactions_queue = queue.Queue() + + class InPlugin: + @account_hookimpl + def ac_reactions_changed(self, message): + reactions_queue.put(message) + + ac2.add_account_plugin(InPlugin()) + + lp.sec("sending small+large messages from ac1 to ac2") + msgs = [] + msgs.append(chat.send_text("hi")) + path = tmpdir.join("large") + with open(path, "wb") as fout: + fout.write(os.urandom(download_limit + 1)) + msgs.append(chat.send_file(path.strpath)) + + lp.sec("sending a reaction to the large message from ac1 to ac2") + react_str = "\N{THUMBS UP SIGN}" + msgs.append(msgs[-1].send_reaction(react_str)) + + for m in msgs: + ac1._evtracker.wait_msg_delivered(m) + ac2.start_io() + + lp.sec("wait for ac2 to receive a reaction") + msg2 = ac2._evtracker.wait_next_reactions_changed() + assert msg2.get_sender_contact().addr == ac1_addr + assert msg2.download_state == const.DC_DOWNLOAD_AVAILABLE + assert reactions_queue.get() == msg2 + reactions = msg2.get_reactions() + contacts = reactions.get_contacts() + assert len(contacts) == 1 + assert contacts[0].addr == ac1_addr + assert reactions.get_by_contact(contacts[0]) == react_str + + def test_import_export_online_all(acfactory, tmpdir, data, lp): (ac1,) = acfactory.get_online_accounts(1) diff --git a/src/authres.rs b/src/authres.rs index 5620b1cb4..f9f9d11fb 100644 --- a/src/authres.rs +++ b/src/authres.rs @@ -13,8 +13,6 @@ use once_cell::sync::Lazy; use crate::config::Config; use crate::context::Context; use crate::headerdef::HeaderDef; -use crate::mimeparser; -use crate::mimeparser::ParserErrorExt; use crate::tools::time; use crate::tools::EmailAddress; @@ -32,23 +30,19 @@ pub(crate) async fn handle_authres( mail: &ParsedMail<'_>, from: &str, message_time: i64, -) -> mimeparser::ParserResult { +) -> Result { let from_domain = match EmailAddress::new(from) { Ok(email) => email.domain, Err(e) => { // This email is invalid, but don't return an error, we still want to // add a stub to the database so that it's not downloaded again - return Err(anyhow::format_err!("invalid email {}: {:#}", from, e)).map_err_malformed(); + return Err(anyhow::format_err!("invalid email {}: {:#}", from, e)); } }; let authres = parse_authres_headers(&mail.get_headers(), &from_domain); - update_authservid_candidates(context, &authres) - .await - .map_err_sql()?; - compute_dkim_results(context, authres, &from_domain, message_time) - .await - .map_err_sql() + update_authservid_candidates(context, &authres).await?; + compute_dkim_results(context, authres, &from_domain, message_time).await } #[derive(Default, Debug)] diff --git a/src/chat.rs b/src/chat.rs index 6e58d1d2d..9d1693924 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2188,7 +2188,7 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re let mut msg = Message::new(Viewtype::VideochatInvitation); msg.param.set(Param::WebrtcRoom, &instance); msg.text = Some( - stock_str::videochat_invite_msg_body(context, Message::parse_webrtc_instance(&instance).1) + stock_str::videochat_invite_msg_body(context, &Message::parse_webrtc_instance(&instance).1) .await, ); send_msg(context, chat_id, &mut msg).await @@ -2563,7 +2563,7 @@ pub async fn create_group_chat( let chat_id = ChatId::new(u32::try_from(row_id)?); if !is_contact_in_chat(context, chat_id, ContactId::SELF).await? { - add_to_chat_contacts_table(context, chat_id, ContactId::SELF).await?; + add_to_chat_contacts_table(context, chat_id, &[ContactId::SELF]).await?; } context.emit_msgs_changed_without_ids(); @@ -2624,19 +2624,25 @@ pub async fn create_broadcast_list(context: &Context) -> Result { Ok(chat_id) } -/// Adds a contact to the `chats_contacts` table. +/// Adds contacts to the `chats_contacts` table. pub(crate) async fn add_to_chat_contacts_table( context: &Context, chat_id: ChatId, - contact_id: ContactId, + contact_ids: &[ContactId], ) -> Result<()> { context .sql - .execute( - "INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)", - paramsv![chat_id, contact_id], - ) + .transaction(move |transaction| { + for contact_id in contact_ids { + transaction.execute( + "INSERT OR IGNORE INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)", + paramsv![chat_id, contact_id], + )?; + } + Ok(()) + }) .await?; + Ok(()) } @@ -2738,7 +2744,7 @@ pub(crate) async fn add_contact_to_chat_ex( if is_contact_in_chat(context, chat_id, contact_id).await? { return Ok(false); } - add_to_chat_contacts_table(context, chat_id, contact_id).await?; + add_to_chat_contacts_table(context, chat_id, &[contact_id]).await?; } if chat.typ == Chattype::Group && chat.is_promoted() { msg.viewtype = Viewtype::Text; @@ -3005,7 +3011,7 @@ pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) - pub async fn set_chat_profile_image( context: &Context, chat_id: ChatId, - new_image: impl AsRef, // XXX use PathBuf + new_image: &str, // XXX use PathBuf ) -> Result<()> { ensure!(!chat_id.is_special(), "Invalid chat ID"); let mut chat = Chat::load_from_db(context, chat_id).await?; @@ -3023,13 +3029,12 @@ pub async fn set_chat_profile_image( let mut msg = Message::new(Viewtype::Text); msg.param .set_int(Param::Cmd, SystemMessage::GroupImageChanged as i32); - if new_image.as_ref().is_empty() { + if new_image.is_empty() { chat.param.remove(Param::ProfileImage); msg.param.remove(Param::Arg); msg.text = Some(stock_str::msg_grp_img_deleted(context, ContactId::SELF).await); } else { - let mut image_blob = - BlobObject::new_from_path(context, Path::new(new_image.as_ref())).await?; + let mut image_blob = BlobObject::new_from_path(context, Path::new(new_image)).await?; image_blob.recode_to_avatar_size(context).await?; chat.param.set(Param::ProfileImage, image_blob.as_name()); msg.param.set(Param::Arg, image_blob.as_name()); diff --git a/src/config.rs b/src/config.rs index e516c0b27..259c3e063 100644 --- a/src/config.rs +++ b/src/config.rs @@ -194,20 +194,20 @@ pub enum Config { impl Context { pub async fn config_exists(&self, key: Config) -> Result { - Ok(self.sql.get_raw_config(key).await?.is_some()) + Ok(self.sql.get_raw_config(key.as_ref()).await?.is_some()) } /// Get a configuration key. Returns `None` if no value is set, and no default value found. pub async fn get_config(&self, key: Config) -> Result> { let value = match key { Config::Selfavatar => { - let rel_path = self.sql.get_raw_config(key).await?; + let rel_path = self.sql.get_raw_config(key.as_ref()).await?; rel_path.map(|p| get_abs_path(self, &p).to_string_lossy().into_owned()) } Config::SysVersion => Some((*DC_VERSION_STR).clone()), Config::SysMsgsizeMaxRecommended => Some(format!("{}", RECOMMENDED_FILE_SIZE)), Config::SysConfigKeys => Some(get_config_keys_string()), - _ => self.sql.get_raw_config(key).await?, + _ => self.sql.get_raw_config(key.as_ref()).await?, }; if value.is_some() { @@ -297,26 +297,30 @@ impl Context { Some(value) => { let mut blob = BlobObject::new_from_path(self, value.as_ref()).await?; blob.recode_to_avatar_size(self).await?; - self.sql.set_raw_config(key, Some(blob.as_name())).await?; + self.sql + .set_raw_config(key.as_ref(), Some(blob.as_name())) + .await?; } None => { - self.sql.set_raw_config(key, None).await?; + self.sql.set_raw_config(key.as_ref(), None).await?; } } self.emit_event(EventType::SelfavatarChanged); } Config::DeleteDeviceAfter => { - let ret = self.sql.set_raw_config(key, value).await; + let ret = self.sql.set_raw_config(key.as_ref(), value).await; // Interrupt ephemeral loop to delete old messages immediately. self.interrupt_ephemeral_task().await; ret? } Config::Displayname => { let value = value.map(improve_single_line_input); - self.sql.set_raw_config(key, value.as_deref()).await?; + self.sql + .set_raw_config(key.as_ref(), value.as_deref()) + .await?; } _ => { - self.sql.set_raw_config(key, value).await?; + self.sql.set_raw_config(key.as_ref(), value).await?; } } Ok(()) diff --git a/src/configure.rs b/src/configure.rs index 40e78023a..6717c7dc6 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -87,7 +87,7 @@ impl Context { self, // We are using Anyhow's .context() and to show the // inner error, too, we need the {:#}: - format!("{:#}", err), + &format!("{:#}", err), ) .await ) @@ -153,7 +153,7 @@ async fn on_configure_completed( if !addr_cmp(&new_addr, &old_addr) { let mut msg = Message::new(Viewtype::Text); msg.text = - Some(stock_str::aeap_explanation_and_link(context, old_addr, new_addr).await); + Some(stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await); chat::add_device_msg(context, None, Some(&mut msg)) .await .ok_or_log_msg(context, "Cannot add AEAP explanation"); diff --git a/src/decrypt.rs b/src/decrypt.rs index cf3e66b98..8c57cdd36 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -5,7 +5,7 @@ use std::collections::HashSet; use anyhow::{Context as _, Result}; use mailparse::ParsedMail; -use crate::aheader::Aheader; +use crate::aheader::{Aheader, EncryptPreference}; use crate::authres; use crate::authres::handle_authres; use crate::contact::addr_cmp; @@ -13,7 +13,6 @@ use crate::context::Context; use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey}; use crate::keyring::Keyring; use crate::log::LogExt; -use crate::mimeparser::{self, ParserErrorExt}; use crate::peerstate::Peerstate; use crate::pgp; @@ -61,11 +60,18 @@ pub(crate) async fn prepare_decryption( mail: &ParsedMail<'_>, from: &str, message_time: i64, -) -> mimeparser::ParserResult { - let autocrypt_header = Aheader::from_headers(from, &mail.headers) + is_thunderbird: bool, +) -> Result { + let mut autocrypt_header = Aheader::from_headers(from, &mail.headers) .ok_or_log_msg(context, "Failed to parse Autocrypt header") .flatten(); + if is_thunderbird { + if let Some(autocrypt_header) = &mut autocrypt_header { + autocrypt_header.prefer_encrypt = EncryptPreference::Mutual; + } + } + let dkim_results = handle_authres(context, mail, from, message_time).await?; let peerstate = get_autocrypt_peerstate( @@ -76,8 +82,7 @@ pub(crate) async fn prepare_decryption( // Disallowing keychanges is disabled for now: true, // dkim_results.allow_keychange, ) - .await - .map_err_sql()?; + .await?; Ok(DecryptionInfo { from: from.to_string(), @@ -301,7 +306,7 @@ pub(crate) async fn get_autocrypt_peerstate( if addr_cmp(&peerstate.addr, from) { if allow_change { peerstate.apply_header(header, message_time); - peerstate.save_to_db(&context.sql, false).await?; + peerstate.save_to_db(&context.sql).await?; } else { info!( context, @@ -317,7 +322,7 @@ pub(crate) async fn get_autocrypt_peerstate( // to the database. } else { let p = Peerstate::from_header(header, message_time); - p.save_to_db(&context.sql, true).await?; + p.save_to_db(&context.sql).await?; peerstate = Some(p); } } else { diff --git a/src/e2ee.rs b/src/e2ee.rs index cd92c5a3d..311894a04 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -147,7 +147,6 @@ mod tests { use crate::chat; use crate::message::{Message, Viewtype}; use crate::param::Param; - use crate::peerstate::ToSave; use crate::test_utils::{bob_keypair, TestContext}; use super::*; @@ -297,7 +296,6 @@ Sent with my Delta Chat Messenger: https://delta.chat"; gossip_key_fingerprint: Some(pub_key.fingerprint()), verified_key: Some(pub_key.clone()), verified_key_fingerprint: Some(pub_key.fingerprint()), - to_save: Some(ToSave::All), fingerprint_changed: false, }; vec![(Some(peerstate), addr)] diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 18e1be385..a65e1636c 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -226,13 +226,13 @@ pub(crate) async fn stock_ephemeral_timer_changed( Timer::Disabled => stock_str::msg_ephemeral_timer_disabled(context, from_id).await, Timer::Enabled { duration } => match duration { 0..=59 => { - stock_str::msg_ephemeral_timer_enabled(context, timer.to_string(), from_id).await + stock_str::msg_ephemeral_timer_enabled(context, &timer.to_string(), from_id).await } 60 => stock_str::msg_ephemeral_timer_minute(context, from_id).await, 61..=3599 => { stock_str::msg_ephemeral_timer_minutes( context, - format!("{}", (f64::from(duration) / 6.0).round() / 10.0), + &format!("{}", (f64::from(duration) / 6.0).round() / 10.0), from_id, ) .await @@ -241,7 +241,7 @@ pub(crate) async fn stock_ephemeral_timer_changed( 3601..=86399 => { stock_str::msg_ephemeral_timer_hours( context, - format!("{}", (f64::from(duration) / 360.0).round() / 10.0), + &format!("{}", (f64::from(duration) / 360.0).round() / 10.0), from_id, ) .await @@ -250,7 +250,7 @@ pub(crate) async fn stock_ephemeral_timer_changed( 86401..=604_799 => { stock_str::msg_ephemeral_timer_days( context, - format!("{}", (f64::from(duration) / 8640.0).round() / 10.0), + &format!("{}", (f64::from(duration) / 8640.0).round() / 10.0), from_id, ) .await @@ -259,7 +259,7 @@ pub(crate) async fn stock_ephemeral_timer_changed( _ => { stock_str::msg_ephemeral_timer_weeks( context, - format!("{}", (f64::from(duration) / 60480.0).round() / 10.0), + &format!("{}", (f64::from(duration) / 60480.0).round() / 10.0), from_id, ) .await diff --git a/src/imap.rs b/src/imap.rs index fc540d888..91948e0db 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1364,7 +1364,9 @@ impl Imap { /// Fetches a list of messages by server UID. /// - /// Returns the last uid fetch successfully and the info about each downloaded message. + /// Returns the last UID fetched successfully and the info about each downloaded message. + /// If the message is incorrect or there is a failure to write a message to the database, + /// it is skipped and the error is logged. pub(crate) async fn fetch_many_msgs( &mut self, context: &Context, @@ -1474,12 +1476,12 @@ impl Imap { if let Some(m) = received_msg { received_msgs.push(m); } - last_uid = Some(server_uid) } Err(err) => { warn!(context, "receive_imf error: {:#}", err); } }; + last_uid = Some(server_uid) } } diff --git a/src/login_param.rs b/src/login_param.rs index 6d3d724fe..b6749f24f 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -169,7 +169,7 @@ impl LoginParam { async fn from_database(context: &Context, prefix: &str) -> Result { let sql = &context.sql; - let key = format!("{}addr", prefix); + let key = &format!("{}addr", prefix); let addr = sql .get_raw_config(key) .await? @@ -177,26 +177,26 @@ impl LoginParam { .trim() .to_string(); - let key = format!("{}mail_server", prefix); + let key = &format!("{}mail_server", prefix); let mail_server = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}mail_port", prefix); + let key = &format!("{}mail_port", prefix); let mail_port = sql.get_raw_config_int(key).await?.unwrap_or_default(); - let key = format!("{}mail_user", prefix); + let key = &format!("{}mail_user", prefix); let mail_user = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}mail_pw", prefix); + let key = &format!("{}mail_pw", prefix); let mail_pw = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}mail_security", prefix); + let key = &format!("{}mail_security", prefix); let mail_security = sql .get_raw_config_int(key) .await? .and_then(num_traits::FromPrimitive::from_i32) .unwrap_or_default(); - let key = format!("{}imap_certificate_checks", prefix); + let key = &format!("{}imap_certificate_checks", prefix); let imap_certificate_checks = if let Some(certificate_checks) = sql.get_raw_config_int(key).await? { num_traits::FromPrimitive::from_i32(certificate_checks).unwrap() @@ -204,26 +204,26 @@ impl LoginParam { Default::default() }; - let key = format!("{}send_server", prefix); + let key = &format!("{}send_server", prefix); let send_server = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}send_port", prefix); + let key = &format!("{}send_port", prefix); let send_port = sql.get_raw_config_int(key).await?.unwrap_or_default(); - let key = format!("{}send_user", prefix); + let key = &format!("{}send_user", prefix); let send_user = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}send_pw", prefix); + let key = &format!("{}send_pw", prefix); let send_pw = sql.get_raw_config(key).await?.unwrap_or_default(); - let key = format!("{}send_security", prefix); + let key = &format!("{}send_security", prefix); let send_security = sql .get_raw_config_int(key) .await? .and_then(num_traits::FromPrimitive::from_i32) .unwrap_or_default(); - let key = format!("{}smtp_certificate_checks", prefix); + let key = &format!("{}smtp_certificate_checks", prefix); let smtp_certificate_checks = if let Some(certificate_checks) = sql.get_raw_config_int(key).await? { num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default() @@ -231,11 +231,11 @@ impl LoginParam { Default::default() }; - let key = format!("{}server_flags", prefix); + let key = &format!("{}server_flags", prefix); let server_flags = sql.get_raw_config_int(key).await?.unwrap_or_default(); let oauth2 = matches!(server_flags & DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2); - let key = format!("{}provider", prefix); + let key = &format!("{}provider", prefix); let provider = sql .get_raw_config(key) .await? @@ -275,50 +275,50 @@ impl LoginParam { context.set_primary_self_addr(&self.addr).await?; - let key = format!("{}mail_server", prefix); + let key = &format!("{}mail_server", prefix); sql.set_raw_config(key, Some(&self.imap.server)).await?; - let key = format!("{}mail_port", prefix); + let key = &format!("{}mail_port", prefix); sql.set_raw_config_int(key, i32::from(self.imap.port)) .await?; - let key = format!("{}mail_user", prefix); + let key = &format!("{}mail_user", prefix); sql.set_raw_config(key, Some(&self.imap.user)).await?; - let key = format!("{}mail_pw", prefix); + let key = &format!("{}mail_pw", prefix); sql.set_raw_config(key, Some(&self.imap.password)).await?; - let key = format!("{}mail_security", prefix); + let key = &format!("{}mail_security", prefix); sql.set_raw_config_int(key, self.imap.security as i32) .await?; - let key = format!("{}imap_certificate_checks", prefix); + let key = &format!("{}imap_certificate_checks", prefix); sql.set_raw_config_int(key, self.imap.certificate_checks as i32) .await?; - let key = format!("{}send_server", prefix); + let key = &format!("{}send_server", prefix); sql.set_raw_config(key, Some(&self.smtp.server)).await?; - let key = format!("{}send_port", prefix); + let key = &format!("{}send_port", prefix); sql.set_raw_config_int(key, i32::from(self.smtp.port)) .await?; - let key = format!("{}send_user", prefix); + let key = &format!("{}send_user", prefix); sql.set_raw_config(key, Some(&self.smtp.user)).await?; - let key = format!("{}send_pw", prefix); + let key = &format!("{}send_pw", prefix); sql.set_raw_config(key, Some(&self.smtp.password)).await?; - let key = format!("{}send_security", prefix); + let key = &format!("{}send_security", prefix); sql.set_raw_config_int(key, self.smtp.security as i32) .await?; - let key = format!("{}smtp_certificate_checks", prefix); + let key = &format!("{}smtp_certificate_checks", prefix); sql.set_raw_config_int(key, self.smtp.certificate_checks as i32) .await?; // The OAuth2 flag is either set for both IMAP and SMTP or not at all. - let key = format!("{}server_flags", prefix); + let key = &format!("{}server_flags", prefix); let server_flags = match self.imap.oauth2 { true => DC_LP_AUTH_OAUTH2, false => DC_LP_AUTH_NORMAL, @@ -326,7 +326,7 @@ impl LoginParam { sql.set_raw_config_int(key, server_flags).await?; if let Some(provider) = self.provider { - let key = format!("{}provider", prefix); + let key = &format!("{}provider", prefix); sql.set_raw_config(key, Some(provider.id)).await?; } diff --git a/src/mimefactory.rs b/src/mimefactory.rs index a53739d04..2dc6a3d1a 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -429,7 +429,7 @@ impl<'a> MimeFactory<'a> { } } - let self_name = match context.get_config(Config::Displayname).await? { + let self_name = &match context.get_config(Config::Displayname).await? { Some(name) => name, None => context.get_config(Config::Addr).await?.unwrap_or_default(), }; @@ -1261,7 +1261,7 @@ impl<'a> MimeFactory<'a> { .truncated_text(32) .to_string() }; - let p2 = stock_str::read_rcpt_mail_body(context, p1).await; + let p2 = stock_str::read_rcpt_mail_body(context, &p1).await; let message_text = format!("{}\r\n", format_flowed(&p2)); message = message.child( PartBuilder::new() diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 7dec08f53..2e811ebb9 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -157,38 +157,9 @@ impl Default for SystemMessage { const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup"; -#[derive(Debug, thiserror::Error)] -pub(crate) enum ParserError { - #[error("{}", _0)] - Malformed(anyhow::Error), - - #[error("{:#}", _0)] - Sql(anyhow::Error), -} - -pub(crate) type ParserResult = std::result::Result; - -pub(crate) trait ParserErrorExt -where - Self: std::marker::Sized, -{ - fn map_err_malformed(self) -> ParserResult; - fn map_err_sql(self) -> ParserResult; -} - -impl> ParserErrorExt for Result { - fn map_err_malformed(self) -> ParserResult { - self.map_err(|e| ParserError::Malformed(e.into())) - } - - fn map_err_sql(self) -> ParserResult { - self.map_err(|e| ParserError::Sql(e.into())) - } -} - impl MimeMessage { pub async fn from_bytes(context: &Context, body: &[u8]) -> Result { - Ok(MimeMessage::from_bytes_with_partial(context, body, None).await?) + MimeMessage::from_bytes_with_partial(context, body, None).await } /// Parse a mime message. @@ -199,8 +170,8 @@ impl MimeMessage { context: &Context, body: &[u8], partial: Option, - ) -> ParserResult { - let mail = mailparse::parse_mail(body).map_err_malformed()?; + ) -> Result { + let mail = mailparse::parse_mail(body)?; let message_time = mail .headers @@ -227,7 +198,7 @@ impl MimeMessage { ); // Parse hidden headers. - let mimetype = mail.ctype.mimetype.parse::().map_err_malformed()?; + let mimetype = mail.ctype.mimetype.parse::()?; if mimetype.type_() == mime::MULTIPART && mimetype.subtype().as_str() == "mixed" { if let Some(part) = mail.subparts.first() { for field in &part.headers { @@ -245,9 +216,16 @@ impl MimeMessage { headers.remove("secure-join-fingerprint"); headers.remove("chat-verified"); - let from = from.context("No from in message").map_err_malformed()?; + let is_thunderbird = headers + .get("user-agent") + .map_or(false, |user_agent| user_agent.contains("Thunderbird")); + if is_thunderbird { + info!(context, "Detected Thunderbird"); + } + + let from = from.context("No from in message")?; let mut decryption_info = - prepare_decryption(context, &mail, &from.addr, message_time).await?; + prepare_decryption(context, &mail, &from.addr, message_time, is_thunderbird).await?; // Memory location for a possible decrypted message. let mut mail_raw = Vec::new(); @@ -265,7 +243,7 @@ impl MimeMessage { // autocrypt message. mail_raw = raw; - let decrypted_mail = mailparse::parse_mail(&mail_raw).map_err_malformed()?; + let decrypted_mail = mailparse::parse_mail(&mail_raw)?; if std::env::var(crate::DCC_MIME_DEBUG).is_ok() { info!(context, "decrypted message mime-body:"); println!("{}", String::from_utf8_lossy(&mail_raw)); @@ -279,8 +257,7 @@ impl MimeMessage { decrypted_mail.headers.get_all_values("Autocrypt-Gossip"); gossiped_addr = update_gossip_peerstates(context, message_time, &mail, gossip_headers) - .await - .map_err_sql()?; + .await?; } // let known protected headers from the decrypted @@ -333,10 +310,7 @@ impl MimeMessage { // && decryption_info.dkim_results.allow_keychange { peerstate.degrade_encryption(message_time); - peerstate - .save_to_db(&context.sql, false) - .await - .map_err_sql()?; + peerstate.save_to_db(&context.sql).await?; } } (Ok(mail), HashSet::new(), false) @@ -380,15 +354,11 @@ impl MimeMessage { Some(org_bytes) => { parser .create_stub_from_partial_download(context, org_bytes) - .await - .map_err_sql()?; + .await?; } None => match mail { Ok(mail) => { - parser - .parse_mime_recursive(context, &mail, false) - .await - .map_err_malformed()?; + parser.parse_mime_recursive(context, &mail, false).await?; } Err(err) => { let msg_body = stock_str::cant_decrypt_msg_body(context).await; @@ -409,7 +379,7 @@ impl MimeMessage { parser.maybe_remove_bad_parts(); parser.maybe_remove_inline_mailinglist_footer(); parser.heuristically_parse_ndn(context).await; - parser.parse_headers(context).await.map_err_malformed()?; + parser.parse_headers(context).await?; // Disallowing keychanges is disabled for now // if !decryption_info.dkim_results.allow_keychange { @@ -427,14 +397,11 @@ impl MimeMessage { parser.decoded_data = mail_raw; } - crate::peerstate::maybe_do_aeap_transition(context, &mut decryption_info, &parser) - .await - .map_err_sql()?; + crate::peerstate::maybe_do_aeap_transition(context, &mut decryption_info, &parser).await?; if let Some(peerstate) = decryption_info.peerstate { peerstate .handle_fingerprint_change(context, message_time) - .await - .map_err_sql()?; + .await?; } Ok(parser) @@ -1619,11 +1586,11 @@ async fn update_gossip_peerstates( let peerstate; if let Some(mut p) = Peerstate::from_addr(context, &header.addr).await? { p.apply_gossip(&header, message_time); - p.save_to_db(&context.sql, false).await?; + p.save_to_db(&context.sql).await?; peerstate = p; } else { let p = Peerstate::from_gossip(&header, message_time); - p.save_to_db(&context.sql, true).await?; + p.save_to_db(&context.sql).await?; peerstate = p; }; peerstate @@ -2196,7 +2163,7 @@ mod tests { let mimeparser = MimeMessage::from_bytes_with_partial(&context.ctx, &raw[..], None).await; - assert!(matches!(mimeparser, Err(ParserError::Malformed(_)))); + assert!(mimeparser.is_err()); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/src/peerstate.rs b/src/peerstate.rs index 165fd05fc..e9591c789 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; use std::fmt; use crate::aheader::{Aheader, EncryptPreference}; -use crate::chat::{self, is_contact_in_chat, Chat}; +use crate::chat::{self, Chat}; use crate::chatlist::Chatlist; use crate::constants::Chattype; use crate::contact::{addr_cmp, Contact, Origin}; @@ -46,7 +46,6 @@ pub struct Peerstate { pub gossip_key_fingerprint: Option, pub verified_key: Option, pub verified_key_fingerprint: Option, - pub to_save: Option, pub fingerprint_changed: bool, } @@ -63,7 +62,6 @@ impl PartialEq for Peerstate { && self.gossip_key_fingerprint == other.gossip_key_fingerprint && self.verified_key == other.verified_key && self.verified_key_fingerprint == other.verified_key_fingerprint - && self.to_save == other.to_save && self.fingerprint_changed == other.fingerprint_changed } } @@ -84,19 +82,11 @@ impl fmt::Debug for Peerstate { .field("gossip_key_fingerprint", &self.gossip_key_fingerprint) .field("verified_key", &self.verified_key) .field("verified_key_fingerprint", &self.verified_key_fingerprint) - .field("to_save", &self.to_save) .field("fingerprint_changed", &self.fingerprint_changed) .finish() } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] -#[repr(u8)] -pub enum ToSave { - Timestamps = 0x01, - All = 0x02, -} - impl Peerstate { pub fn from_header(header: &Aheader, message_time: i64) -> Self { Peerstate { @@ -111,7 +101,6 @@ impl Peerstate { gossip_timestamp: 0, verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, } } @@ -137,7 +126,6 @@ impl Peerstate { gossip_timestamp: message_time, verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, } } @@ -229,7 +217,6 @@ impl Peerstate { .map(|s| s.parse::()) .transpose() .unwrap_or_default(), - to_save: None, fingerprint_changed: false, }; @@ -248,14 +235,10 @@ impl Peerstate { let old_public_fingerprint = self.public_key_fingerprint.take(); self.public_key_fingerprint = Some(public_key.fingerprint()); - if old_public_fingerprint.is_none() - || self.public_key_fingerprint.is_none() - || old_public_fingerprint != self.public_key_fingerprint + if old_public_fingerprint.is_some() + && old_public_fingerprint != self.public_key_fingerprint { - self.to_save = Some(ToSave::All); - if old_public_fingerprint.is_some() { - self.fingerprint_changed = true; - } + self.fingerprint_changed = true; } } @@ -267,8 +250,6 @@ impl Peerstate { || self.gossip_key_fingerprint.is_none() || old_gossip_fingerprint != self.gossip_key_fingerprint { - self.to_save = Some(ToSave::All); - // Warn about gossip key change only if there is no public key obtained from // Autocrypt header, which overrides gossip key. if old_gossip_fingerprint.is_some() && self.public_key_fingerprint.is_none() { @@ -281,7 +262,6 @@ impl Peerstate { pub fn degrade_encryption(&mut self, message_time: i64) { self.prefer_encrypt = EncryptPreference::Reset; self.last_seen = message_time; - self.to_save = Some(ToSave::All); } pub fn apply_header(&mut self, header: &Aheader, message_time: i64) { @@ -292,19 +272,16 @@ impl Peerstate { if message_time > self.last_seen { self.last_seen = message_time; self.last_seen_autocrypt = message_time; - self.to_save = Some(ToSave::Timestamps); if (header.prefer_encrypt == EncryptPreference::Mutual || header.prefer_encrypt == EncryptPreference::NoPreference) && header.prefer_encrypt != self.prefer_encrypt { self.prefer_encrypt = header.prefer_encrypt; - self.to_save = Some(ToSave::All) } if self.public_key.as_ref() != Some(&header.public_key) { self.public_key = Some(header.public_key.clone()); self.recalc_fingerprint(); - self.to_save = Some(ToSave::All); } } } @@ -316,11 +293,9 @@ impl Peerstate { if message_time > self.gossip_timestamp { self.gossip_timestamp = message_time; - self.to_save = Some(ToSave::Timestamps); if self.gossip_key.as_ref() != Some(&gossip_header.public_key) { self.gossip_key = Some(gossip_header.public_key.clone()); self.recalc_fingerprint(); - self.to_save = Some(ToSave::All) } // This is non-standard. @@ -339,7 +314,6 @@ impl Peerstate { && gossip_header.prefer_encrypt == EncryptPreference::Mutual { self.prefer_encrypt = EncryptPreference::Mutual; - self.to_save = Some(ToSave::All); } }; } @@ -395,7 +369,6 @@ impl Peerstate { if self.public_key_fingerprint.is_some() && self.public_key_fingerprint.as_ref().unwrap() == fingerprint { - self.to_save = Some(ToSave::All); self.verified_key = self.public_key.clone(); self.verified_key_fingerprint = self.public_key_fingerprint.clone(); true @@ -407,7 +380,6 @@ impl Peerstate { if self.gossip_key_fingerprint.is_some() && self.gossip_key_fingerprint.as_ref().unwrap() == fingerprint { - self.to_save = Some(ToSave::All); self.verified_key = self.gossip_key.clone(); self.verified_key_fingerprint = self.gossip_key_fingerprint.clone(); true @@ -421,66 +393,48 @@ impl Peerstate { } } - pub async fn save_to_db(&self, sql: &Sql, create: bool) -> Result<()> { - if self.to_save == Some(ToSave::All) || create { - sql.execute( - if create { - "INSERT INTO acpeerstates ( \ - last_seen, \ - last_seen_autocrypt, \ - prefer_encrypted, \ - public_key, \ - gossip_timestamp, \ - gossip_key, \ - public_key_fingerprint, \ - gossip_key_fingerprint, \ - verified_key, \ - verified_key_fingerprint, \ - addr \ - ) VALUES(?,?,?,?,?,?,?,?,?,?,?)" - } else { - "UPDATE acpeerstates \ - SET last_seen=?, \ - last_seen_autocrypt=?, \ - prefer_encrypted=?, \ - public_key=?, \ - gossip_timestamp=?, \ - gossip_key=?, \ - public_key_fingerprint=?, \ - gossip_key_fingerprint=?, \ - verified_key=?, \ - verified_key_fingerprint=? \ - WHERE addr=?" - }, - paramsv![ - self.last_seen, - self.last_seen_autocrypt, - self.prefer_encrypt as i64, - self.public_key.as_ref().map(|k| k.to_bytes()), - self.gossip_timestamp, - self.gossip_key.as_ref().map(|k| k.to_bytes()), - self.public_key_fingerprint.as_ref().map(|fp| fp.hex()), - self.gossip_key_fingerprint.as_ref().map(|fp| fp.hex()), - self.verified_key.as_ref().map(|k| k.to_bytes()), - self.verified_key_fingerprint.as_ref().map(|fp| fp.hex()), - self.addr, - ], - ) - .await?; - } else if self.to_save == Some(ToSave::Timestamps) { - sql.execute( - "UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \ - WHERE addr=?;", - paramsv![ - self.last_seen, - self.last_seen_autocrypt, - self.gossip_timestamp, - self.addr - ], - ) - .await?; - } - + pub async fn save_to_db(&self, sql: &Sql) -> Result<()> { + sql.execute( + "INSERT INTO acpeerstates ( + last_seen, + last_seen_autocrypt, + prefer_encrypted, + public_key, + gossip_timestamp, + gossip_key, + public_key_fingerprint, + gossip_key_fingerprint, + verified_key, + verified_key_fingerprint, + addr) + VALUES (?,?,?,?,?,?,?,?,?,?,?) + ON CONFLICT (addr) + DO UPDATE SET + last_seen = excluded.last_seen, + last_seen_autocrypt = excluded.last_seen_autocrypt, + prefer_encrypted = excluded.prefer_encrypted, + public_key = excluded.public_key, + gossip_timestamp = excluded.gossip_timestamp, + gossip_key = excluded.gossip_key, + public_key_fingerprint = excluded.public_key_fingerprint, + gossip_key_fingerprint = excluded.gossip_key_fingerprint, + verified_key = excluded.verified_key, + verified_key_fingerprint = excluded.verified_key_fingerprint", + paramsv![ + self.last_seen, + self.last_seen_autocrypt, + self.prefer_encrypt as i64, + self.public_key.as_ref().map(|k| k.to_bytes()), + self.gossip_timestamp, + self.gossip_key.as_ref().map(|k| k.to_bytes()), + self.public_key_fingerprint.as_ref().map(|fp| fp.hex()), + self.gossip_key_fingerprint.as_ref().map(|fp| fp.hex()), + self.verified_key.as_ref().map(|k| k.to_bytes()), + self.verified_key_fingerprint.as_ref().map(|fp| fp.hex()), + self.addr, + ], + ) + .await?; Ok(()) } @@ -520,7 +474,7 @@ impl Peerstate { let chats = Chatlist::try_load(context, 0, None, Some(contact_id)).await?; let msg = match &change { PeerstateChange::FingerprintChange => { - stock_str::contact_setup_changed(context, self.addr.clone()).await + stock_str::contact_setup_changed(context, &self.addr).await } PeerstateChange::Aeap(new_addr) => { let old_contact = Contact::load_from_db(context, contact_id).await?; @@ -569,9 +523,7 @@ impl Peerstate { let (new_contact_id, _) = Contact::add_or_lookup(context, "", new_addr, Origin::IncomingUnknownFrom) .await?; - if !is_contact_in_chat(context, *chat_id, new_contact_id).await? { - chat::add_to_chat_contacts_table(context, *chat_id, new_contact_id).await?; - } + chat::add_to_chat_contacts_table(context, *chat_id, &[new_contact_id]).await?; context.emit_event(EventType::ChatModified(*chat_id)); } @@ -651,14 +603,8 @@ pub async fn maybe_do_aeap_transition( "Internal error: Tried to do an AEAP transition without an autocrypt header??", )?; peerstate.apply_header(header, info.message_time); - peerstate.to_save = Some(ToSave::All); - // We don't know whether a peerstate with this address already existed, or a - // new one should be created, so just try both create=false and create=true, - // and if this fails, create=true, one will succeed (this is a very cold path, - // so performance doesn't really matter). - peerstate.save_to_db(&context.sql, true).await?; - peerstate.save_to_db(&context.sql, false).await?; + peerstate.save_to_db(&context.sql).await?; } } @@ -710,7 +656,7 @@ mod tests { let pub_key = alice_keypair().public; - let mut peerstate = Peerstate { + let peerstate = Peerstate { addr: addr.into(), last_seen: 10, last_seen_autocrypt: 11, @@ -722,12 +668,11 @@ mod tests { gossip_key_fingerprint: Some(pub_key.fingerprint()), verified_key: Some(pub_key.clone()), verified_key_fingerprint: Some(pub_key.fingerprint()), - to_save: Some(ToSave::All), fingerprint_changed: false, }; assert!( - peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(), + peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(), "failed to save to db" ); @@ -736,8 +681,6 @@ mod tests { .expect("failed to load peerstate from db") .expect("no peerstate found in the database"); - // clear to_save, as that is not persissted - peerstate.to_save = None; assert_eq!(peerstate, peerstate_new); let peerstate_new2 = Peerstate::from_fingerprint(&ctx.ctx, &pub_key.fingerprint()) .await @@ -764,16 +707,15 @@ mod tests { gossip_key_fingerprint: None, verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, }; assert!( - peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(), + peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(), "failed to save" ); assert!( - peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(), + peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(), "double-call with create failed" ); } @@ -785,7 +727,7 @@ mod tests { let pub_key = alice_keypair().public; - let mut peerstate = Peerstate { + let peerstate = Peerstate { addr: addr.into(), last_seen: 10, last_seen_autocrypt: 11, @@ -797,12 +739,11 @@ mod tests { gossip_key_fingerprint: None, verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, }; assert!( - peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(), + peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(), "failed to save" ); @@ -810,8 +751,6 @@ mod tests { .await .expect("failed to load peerstate from db"); - // clear to_save, as that is not persissted - peerstate.to_save = None; assert_eq!(Some(peerstate), peerstate_new); } @@ -862,7 +801,6 @@ mod tests { gossip_key_fingerprint: None, verified_key: None, verified_key_fingerprint: None, - to_save: None, fingerprint_changed: false, }; assert_eq!(peerstate.prefer_encrypt, EncryptPreference::NoPreference); diff --git a/src/qr.rs b/src/qr.rs index c025eca34..46e479484 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -659,7 +659,6 @@ mod tests { use crate::aheader::EncryptPreference; use crate::chat::{create_group_chat, ProtectionStatus}; use crate::key::DcKey; - use crate::peerstate::ToSave; use crate::securejoin::get_securejoin_qr; use crate::test_utils::{alice_keypair, TestContext}; use anyhow::Result; @@ -912,11 +911,10 @@ mod tests { gossip_key_fingerprint: None, verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, }; assert!( - peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(), + peerstate.save_to_db(&ctx.ctx.sql).await.is_ok(), "failed to save peerstate" ); diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 08e29b7de..02560ba8f 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -28,7 +28,7 @@ use crate::message::{ self, rfc724_mid_exists, Message, MessageState, MessengerMessage, MsgId, Viewtype, }; use crate::mimeparser::{ - parse_message_ids, AvatarAction, MailinglistType, MimeMessage, ParserError, SystemMessage, + parse_message_ids, AvatarAction, MailinglistType, MimeMessage, SystemMessage, }; use crate::param::{Param, Params}; use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus}; @@ -72,15 +72,13 @@ pub async fn receive_imf( /// Receive a message and add it to the database. /// -/// Returns an error on recoverable errors, e.g. database errors. In this case, -/// message parsing should be retried later. +/// Returns an error on database failure or if the message is broken, +/// e.g. has nonstandard MIME structure. /// -/// If message itself is wrong, logs -/// the error and returns success: -/// - If possible, creates a database entry to prevent the message from being -/// downloaded again, sets `chat_id=DC_CHAT_ID_TRASH` and returns `Ok(Some(…))` -/// - If the message is so wrong that we didn't even create a database entry, -/// returns `Ok(None)` +/// If possible, creates a database entry to prevent the message from being +/// downloaded again, sets `chat_id=DC_CHAT_ID_TRASH` and returns `Ok(Some(…))`. +/// If the message is so wrong that we didn't even create a database entry, +/// returns `Ok(None)`. /// /// If `is_partial_download` is set, it contains the full message size in bytes. /// Do not confuse that with `replace_partial_download` that will be set when the full message is loaded later. @@ -101,9 +99,8 @@ pub(crate) async fn receive_imf_inner( let mut mime_parser = match MimeMessage::from_bytes_with_partial(context, imf_raw, is_partial_download).await { - Err(ParserError::Malformed(err)) => { + Err(err) => { warn!(context, "receive_imf: can't parse MIME: {}", err); - let msg_ids; if !rfc724_mid.starts_with(GENERATED_PREFIX) { let row_id = context @@ -127,7 +124,6 @@ pub(crate) async fn receive_imf_inner( needs_delete_job: false, })); } - Err(ParserError::Sql(err)) => return Err(err), Ok(mime_parser) => mime_parser, }; @@ -1514,7 +1510,10 @@ async fn create_or_lookup_group( let grpname = mime_parser .get_header(HeaderDef::ChatGroupName) - .context("Chat-Group-Name vanished")?; + .context("Chat-Group-Name vanished")? + // W/a for "Space added before long group names after MIME serialization/deserialization + // #3650" issue. DC itself never creates group names with leading/trailing whitespace. + .trim(); let new_chat_id = ChatId::create_multiuser_record( context, Chattype::Group, @@ -1531,19 +1530,13 @@ async fn create_or_lookup_group( chat_id_blocked = create_blocked; // Create initial member list. - chat::add_to_chat_contacts_table(context, new_chat_id, ContactId::SELF).await?; - if !from_id.is_special() && !chat::is_contact_in_chat(context, new_chat_id, from_id).await? - { - chat::add_to_chat_contacts_table(context, new_chat_id, from_id).await?; - } - for &to_id in to_ids.iter() { - info!(context, "adding to={:?} to chat id={}", to_id, new_chat_id); - if to_id != ContactId::SELF - && !chat::is_contact_in_chat(context, new_chat_id, to_id).await? - { - chat::add_to_chat_contacts_table(context, new_chat_id, to_id).await?; - } + let mut members = vec![ContactId::SELF]; + if !from_id.is_special() { + members.push(from_id); } + members.extend(to_ids); + members.dedup(); + chat::add_to_chat_contacts_table(context, new_chat_id, &members).await?; // once, we have protected-chats explained in UI, we can uncomment the following lines. // ("verified groups" did not add a message anyway) @@ -1622,9 +1615,15 @@ async fn apply_group_changes( { better_msg = Some(stock_str::msg_add_member(context, &added_member, from_id).await); recreate_member_list = true; - } else if let Some(old_name) = mime_parser.get_header(HeaderDef::ChatGroupNameChanged) { + } else if let Some(old_name) = mime_parser + .get_header(HeaderDef::ChatGroupNameChanged) + // See create_or_lookup_group() for explanation + .map(|s| s.trim()) + { if let Some(grpname) = mime_parser .get_header(HeaderDef::ChatGroupName) + // See create_or_lookup_group() for explanation + .map(|grpname| grpname.trim()) .filter(|grpname| grpname.len() < 200) { if chat_id @@ -1693,6 +1692,7 @@ async fn apply_group_changes( .update_timestamp(context, Param::MemberListTimestamp, sent_timestamp) .await? { + let mut members_to_add = vec![]; if removed_id.is_some() || !chat::is_contact_in_chat(context, chat_id, ContactId::SELF).await? { @@ -1707,26 +1707,23 @@ async fn apply_group_changes( ) .await?; - if removed_id != Some(ContactId::SELF) { - chat::add_to_chat_contacts_table(context, chat_id, ContactId::SELF).await?; - } + members_to_add.push(ContactId::SELF); } - if !from_id.is_special() - && from_id != ContactId::SELF - && !chat::is_contact_in_chat(context, chat_id, from_id).await? - && removed_id != Some(from_id) - { - chat::add_to_chat_contacts_table(context, chat_id, from_id).await?; + + if !from_id.is_special() { + members_to_add.push(from_id); } - for &to_id in to_ids.iter() { - if to_id != ContactId::SELF - && !chat::is_contact_in_chat(context, chat_id, to_id).await? - && removed_id != Some(to_id) - { - info!(context, "adding to={:?} to chat id={}", to_id, chat_id); - chat::add_to_chat_contacts_table(context, chat_id, to_id).await?; - } + members_to_add.extend(to_ids); + if let Some(removed_id) = removed_id { + members_to_add.retain(|id| *id != removed_id); } + members_to_add.dedup(); + + info!( + context, + "adding {:?} to chat id={}", members_to_add, chat_id + ); + chat::add_to_chat_contacts_table(context, chat_id, &members_to_add).await?; send_event_chat_modified = true; } } @@ -1878,7 +1875,7 @@ async fn create_or_lookup_mailinglist( ) })?; - chat::add_to_chat_contacts_table(context, chat_id, ContactId::SELF).await?; + chat::add_to_chat_contacts_table(context, chat_id, &[ContactId::SELF]).await?; Ok(Some((chat_id, Blocked::Request))) } else { info!(context, "creating list forbidden by caller"); @@ -2008,9 +2005,7 @@ async fn create_adhoc_group( None, ) .await?; - for &member_id in member_ids.iter() { - chat::add_to_chat_contacts_table(context, new_chat_id, member_id).await?; - } + chat::add_to_chat_contacts_table(context, new_chat_id, member_ids).await?; context.emit_event(EventType::ChatModified(new_chat_id)); @@ -2124,7 +2119,7 @@ async fn check_verified_properties( &fp, PeerstateVerifiedStatus::BidirectVerified, ); - peerstate.save_to_db(&context.sql, false).await?; + peerstate.save_to_db(&context.sql).await?; is_verified = true; } } @@ -2272,6 +2267,7 @@ mod tests { use super::*; + use crate::aheader::EncryptPreference; use crate::chat::get_chat_contacts; use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility}; use crate::chatlist::Chatlist; @@ -2309,7 +2305,7 @@ mod tests { \n\ hello\x00"; let mimeparser = MimeMessage::from_bytes_with_partial(&context.ctx, &raw[..], None).await; - assert!(matches!(mimeparser, Err(ParserError::Malformed(_)))); + assert!(mimeparser.is_err()); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -5154,13 +5150,10 @@ Reply from different address chat::add_to_chat_contacts_table( &bob, group_id, - bob.add_or_lookup_contact(&alice1).await.id, - ) - .await?; - chat::add_to_chat_contacts_table( - &bob, - group_id, - Contact::create(&bob, "", "charlie@example.org").await?, + &[ + bob.add_or_lookup_contact(&alice1).await.id, + Contact::create(&bob, "", "charlie@example.org").await?, + ], ) .await?; @@ -5241,7 +5234,7 @@ Reply from different address chat::add_to_chat_contacts_table( &bob, group_id, - bob.add_or_lookup_contact(&alice).await.id, + &[bob.add_or_lookup_contact(&alice).await.id], ) .await?; @@ -5294,4 +5287,20 @@ Reply from different address Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_thunderbird_autocrypt() -> Result<()> { + let t = TestContext::new_bob().await; + t.set_config(Config::ShowEmails, Some("2")).await?; + + let raw = include_bytes!("../test-data/message/thunderbird_with_autocrypt.eml"); + receive_imf(&t, raw, false).await?; + + let peerstate = Peerstate::from_addr(&t, "alice@example.org") + .await? + .unwrap(); + assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Mutual); + + Ok(()) + } } diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index ac2300ad1..9ca9fb263 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -12,7 +12,7 @@ use crate::tools::time; use crate::{config::Config, scheduler::Scheduler, stock_str, tools}; use crate::{context::Context, log::LogExt}; use anyhow::{anyhow, Result}; -use humansize::{file_size_opts, FileSize}; +use humansize::{format_size, BINARY}; #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumProperty, PartialOrd, Ord)] pub enum Connectivity { @@ -448,7 +448,7 @@ impl Context { // [======67%===== ] // ============================================================================================= - let domain = tools::EmailAddress::new(&self.get_primary_self_addr().await?)?.domain; + let domain = &tools::EmailAddress::new(&self.get_primary_self_addr().await?)?.domain; let storage_on_domain = stock_str::storage_on_domain(self, domain).await; ret += &format!("

{}

    ", storage_on_domain); let quota = self.quota.read().await; @@ -473,8 +473,8 @@ impl Context { let messages = stock_str::messages(self).await; let part_of_total_used = stock_str::part_of_total_used( self, - resource.usage.to_string(), - resource.limit.to_string(), + &resource.usage.to_string(), + &resource.limit.to_string(), ) .await; ret += &match &resource.name { @@ -495,12 +495,8 @@ impl Context { // - the string is not longer than the other strings that way (minus title, plus units) - // additional linebreaks on small displays are unlikely therefore // - most times, this is the only item anyway - let usage = (resource.usage * 1024) - .file_size(file_size_opts::BINARY) - .unwrap_or_default(); - let limit = (resource.limit * 1024) - .file_size(file_size_opts::BINARY) - .unwrap_or_default(); + let usage = &format_size(resource.usage * 1024, BINARY); + let limit = &format_size(resource.limit * 1024, BINARY); stock_str::part_of_total_used(self, usage, limit).await } }; diff --git a/src/securejoin.rs b/src/securejoin.rs index 81d0bd78d..08822a5a1 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -18,7 +18,7 @@ use crate::key::{DcKey, Fingerprint, SignedPublicKey}; use crate::message::{Message, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::param::Param; -use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus, ToSave}; +use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus}; use crate::qr::check_qr; use crate::stock_str; use crate::token; @@ -640,11 +640,7 @@ async fn mark_peer_as_verified(context: &Context, fingerprint: &Fingerprint) -> PeerstateVerifiedStatus::BidirectVerified, ) { peerstate.prefer_encrypt = EncryptPreference::Mutual; - peerstate.to_save = Some(ToSave::All); - peerstate - .save_to_db(&context.sql, false) - .await - .unwrap_or_default(); + peerstate.save_to_db(&context.sql).await.unwrap_or_default(); return Ok(()); } } @@ -932,10 +928,9 @@ mod tests { gossip_key_fingerprint: Some(alice_pubkey.fingerprint()), verified_key: None, verified_key_fingerprint: None, - to_save: Some(ToSave::All), fingerprint_changed: false, }; - peerstate.save_to_db(&bob.ctx.sql, true).await?; + peerstate.save_to_db(&bob.ctx.sql).await?; // Step 1: Generate QR-code, ChatId(0) indicates setup-contact let qr = get_securejoin_qr(&alice.ctx, None).await?; diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index a0f048b83..9162220ca 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -60,7 +60,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul // TODO: how does this group become usable? let group_chat_id = state.joining_chat_id(context).await?; if !is_contact_in_chat(context, group_chat_id, invite.contact_id()).await? { - chat::add_to_chat_contacts_table(context, group_chat_id, invite.contact_id()) + chat::add_to_chat_contacts_table(context, group_chat_id, &[invite.contact_id()]) .await?; } let msg = stock_str::secure_join_started(context, invite.contact_id()).await; diff --git a/src/sql.rs b/src/sql.rs index ce31b5995..4dacb5daf 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -280,7 +280,7 @@ impl Sql { for addr in &addrs { if let Some(ref mut peerstate) = Peerstate::from_addr(context, addr).await? { peerstate.recalc_fingerprint(); - peerstate.save_to_db(self, false).await?; + peerstate.save_to_db(self).await?; } } } @@ -432,7 +432,7 @@ impl Sql { pub async fn transaction(&self, callback: G) -> Result where H: Send + 'static, - G: Send + 'static + FnOnce(&mut rusqlite::Transaction<'_>) -> Result, + G: Send + FnOnce(&mut rusqlite::Transaction<'_>) -> Result, { let mut conn = self.get_conn().await?; tokio::task::block_in_place(move || { @@ -528,9 +528,7 @@ impl Sql { /// /// Setting `None` deletes the value. On failure an error message /// will already have been logged. - pub async fn set_raw_config(&self, key: impl AsRef, value: Option<&str>) -> Result<()> { - let key = key.as_ref(); - + pub async fn set_raw_config(&self, key: &str, value: Option<&str>) -> Result<()> { let mut lock = self.config_cache.write().await; if let Some(value) = value { let exists = self @@ -564,9 +562,9 @@ impl Sql { } /// Get configuration options from the database. - pub async fn get_raw_config(&self, key: impl AsRef) -> Result> { + pub async fn get_raw_config(&self, key: &str) -> Result> { let lock = self.config_cache.read().await; - let cached = lock.get(key.as_ref()).cloned(); + let cached = lock.get(key).cloned(); drop(lock); if let Some(c) = cached { @@ -575,48 +573,42 @@ impl Sql { let mut lock = self.config_cache.write().await; let value = self - .query_get_value( - "SELECT value FROM config WHERE keyname=?;", - paramsv![key.as_ref()], - ) + .query_get_value("SELECT value FROM config WHERE keyname=?;", paramsv![key]) .await - .context(format!("failed to fetch raw config: {}", key.as_ref()))?; - lock.insert(key.as_ref().to_string(), value.clone()); + .context(format!("failed to fetch raw config: {}", key))?; + lock.insert(key.to_string(), value.clone()); drop(lock); Ok(value) } - pub async fn set_raw_config_int(&self, key: impl AsRef, value: i32) -> Result<()> { + pub async fn set_raw_config_int(&self, key: &str, value: i32) -> Result<()> { self.set_raw_config(key, Some(&format!("{}", value))).await } - pub async fn get_raw_config_int(&self, key: impl AsRef) -> Result> { + pub async fn get_raw_config_int(&self, key: &str) -> Result> { self.get_raw_config(key) .await .map(|s| s.and_then(|s| s.parse().ok())) } - pub async fn get_raw_config_bool(&self, key: impl AsRef) -> Result { + pub async fn get_raw_config_bool(&self, key: &str) -> Result { // Not the most obvious way to encode bool as string, but it is matter // of backward compatibility. let res = self.get_raw_config_int(key).await?; Ok(res.unwrap_or_default() > 0) } - pub async fn set_raw_config_bool(&self, key: T, value: bool) -> Result<()> - where - T: AsRef, - { + pub async fn set_raw_config_bool(&self, key: &str, value: bool) -> Result<()> { let value = if value { Some("1") } else { None }; self.set_raw_config(key, value).await } - pub async fn set_raw_config_int64(&self, key: impl AsRef, value: i64) -> Result<()> { + pub async fn set_raw_config_int64(&self, key: &str, value: i64) -> Result<()> { self.set_raw_config(key, Some(&format!("{}", value))).await } - pub async fn get_raw_config_int64(&self, key: impl AsRef) -> Result> { + pub async fn get_raw_config_int64(&self, key: &str) -> Result> { self.get_raw_config(key) .await .map(|s| s.and_then(|r| r.parse().ok())) @@ -728,7 +720,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { |row| row.get::<_, String>(0), |rows| { for row in rows { - maybe_add_file(&mut files_in_use, row?); + maybe_add_file(&mut files_in_use, &row?); } Ok(()) }, @@ -819,8 +811,8 @@ fn is_file_in_use(files_in_use: &HashSet, namespc_opt: Option<&str>, nam files_in_use.contains(name_to_check) } -fn maybe_add_file(files_in_use: &mut HashSet, file: impl AsRef) { - if let Some(file) = file.as_ref().strip_prefix("$BLOBDIR/") { +fn maybe_add_file(files_in_use: &mut HashSet, file: &str) { + if let Some(file) = file.strip_prefix("$BLOBDIR/") { files_in_use.insert(file.to_string()); } } diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index a32bd0abd..0b5a46da8 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -320,11 +320,11 @@ ALTER TABLE msgs ADD COLUMN ephemeral_timestamp INTEGER DEFAULT 0;"#, if dbversion < 67 { for prefix in &["", "configured_"] { if let Some(server_flags) = sql - .get_raw_config_int(format!("{}server_flags", prefix)) + .get_raw_config_int(&format!("{}server_flags", prefix)) .await? { let imap_socket_flags = server_flags & 0x700; - let key = format!("{}mail_security", prefix); + let key = &format!("{}mail_security", prefix); match imap_socket_flags { 0x100 => sql.set_raw_config_int(key, 2).await?, // STARTTLS 0x200 => sql.set_raw_config_int(key, 1).await?, // SSL/TLS @@ -332,7 +332,7 @@ ALTER TABLE msgs ADD COLUMN ephemeral_timestamp INTEGER DEFAULT 0;"#, _ => sql.set_raw_config_int(key, 0).await?, } let smtp_socket_flags = server_flags & 0x70000; - let key = format!("{}send_security", prefix); + let key = &format!("{}send_security", prefix); match smtp_socket_flags { 0x10000 => sql.set_raw_config_int(key, 2).await?, // STARTTLS 0x20000 => sql.set_raw_config_int(key, 1).await?, // SSL/TLS @@ -616,6 +616,50 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid); ) .await?; } + if dbversion < 94 { + sql.execute_migration( + // Create new `acpeerstates` table, same as before but with unique constraint. + // + // This allows to use `UPSERT` to update existing or insert a new peerstate + // depending on whether one exists already. + "CREATE TABLE new_acpeerstates ( + id INTEGER PRIMARY KEY, + addr TEXT DEFAULT '' COLLATE NOCASE, + last_seen INTEGER DEFAULT 0, + last_seen_autocrypt INTEGER DEFAULT 0, + public_key, + prefer_encrypted INTEGER DEFAULT 0, + gossip_timestamp INTEGER DEFAULT 0, + gossip_key, + public_key_fingerprint TEXT DEFAULT '', + gossip_key_fingerprint TEXT DEFAULT '', + verified_key, + verified_key_fingerprint TEXT DEFAULT '', + UNIQUE (addr) -- Only one peerstate per address + ); + INSERT OR IGNORE INTO new_acpeerstates SELECT * FROM acpeerstates; + DROP TABLE acpeerstates; + ALTER TABLE new_acpeerstates RENAME TO acpeerstates; + CREATE INDEX acpeerstates_index1 ON acpeerstates (addr); + CREATE INDEX acpeerstates_index3 ON acpeerstates (public_key_fingerprint); + CREATE INDEX acpeerstates_index4 ON acpeerstates (gossip_key_fingerprint); + CREATE INDEX acpeerstates_index5 ON acpeerstates (verified_key_fingerprint); + ", + 94, + ) + .await?; + } + if dbversion < 95 { + sql.execute_migration( + "CREATE TABLE new_chats_contacts (chat_id INTEGER, contact_id INTEGER, UNIQUE(chat_id, contact_id));\ + INSERT OR IGNORE INTO new_chats_contacts SELECT * FROM chats_contacts;\ + DROP TABLE chats_contacts;\ + ALTER TABLE new_chats_contacts RENAME TO chats_contacts;\ + CREATE INDEX chats_contacts_index1 ON chats_contacts (chat_id);\ + CREATE INDEX chats_contacts_index2 ON chats_contacts (contact_id);", + 95 + ).await?; + } let new_version = sql .get_raw_config_int(VERSION_CFG) diff --git a/src/stock_str.rs b/src/stock_str.rs index f1b7894db..e58de954d 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -17,7 +17,7 @@ use crate::context::Context; use crate::message::{Message, Viewtype}; use crate::param::Param; use crate::tools::timestamp_to_str; -use humansize::{file_size_opts, FileSize}; +use humansize::{format_size, BINARY}; #[derive(Debug, Clone)] pub struct StockStrings { @@ -466,33 +466,33 @@ async fn translated(context: &Context, id: StockMessage) -> String { /// Helper trait only meant to be implemented for [`String`]. trait StockStringMods: AsRef + Sized { /// Substitutes the first replacement value if one is present. - fn replace1(&self, replacement: impl AsRef) -> String { + fn replace1(&self, replacement: &str) -> String { self.as_ref() - .replacen("%1$s", replacement.as_ref(), 1) - .replacen("%1$d", replacement.as_ref(), 1) - .replacen("%1$@", replacement.as_ref(), 1) + .replacen("%1$s", replacement, 1) + .replacen("%1$d", replacement, 1) + .replacen("%1$@", replacement, 1) } /// Substitutes the second replacement value if one is present. /// /// Be aware you probably should have also called [`StockStringMods::replace1`] if /// you are calling this. - fn replace2(&self, replacement: impl AsRef) -> String { + fn replace2(&self, replacement: &str) -> String { self.as_ref() - .replacen("%2$s", replacement.as_ref(), 1) - .replacen("%2$d", replacement.as_ref(), 1) - .replacen("%2$@", replacement.as_ref(), 1) + .replacen("%2$s", replacement, 1) + .replacen("%2$d", replacement, 1) + .replacen("%2$@", replacement, 1) } /// Substitutes the third replacement value if one is present. /// /// Be aware you probably should have also called [`StockStringMods::replace1`] and /// [`StockStringMods::replace2`] if you are calling this. - fn replace3(&self, replacement: impl AsRef) -> String { + fn replace3(&self, replacement: &str) -> String { self.as_ref() - .replacen("%3$s", replacement.as_ref(), 1) - .replacen("%3$d", replacement.as_ref(), 1) - .replacen("%3$@", replacement.as_ref(), 1) + .replacen("%3$s", replacement, 1) + .replacen("%3$d", replacement, 1) + .replacen("%3$@", replacement, 1) } } @@ -551,8 +551,8 @@ pub(crate) async fn file(context: &Context) -> String { /// Stock string: `Group name changed from "%1$s" to "%2$s".`. pub(crate) async fn msg_grp_name( context: &Context, - from_group: impl AsRef, - to_group: impl AsRef, + from_group: &str, + to_group: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -565,7 +565,7 @@ pub(crate) async fn msg_grp_name( .await .replace1(from_group) .replace2(to_group) - .replace3(by_contact.get_stock_name(context).await) + .replace3(&by_contact.get_stock_name(context).await) } } @@ -575,7 +575,7 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId } else { translated(context, StockMessage::MsgGrpImgChangedBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -585,11 +585,11 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId /// contacts to combine with the display name. pub(crate) async fn msg_add_member( context: &Context, - added_member_addr: impl AsRef, + added_member_addr: &str, by_contact: ContactId, ) -> String { - let addr = added_member_addr.as_ref(); - let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { + let addr = added_member_addr; + let who = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id) .await .map(|contact| contact.get_name_n_addr()) @@ -604,7 +604,7 @@ pub(crate) async fn msg_add_member( translated(context, StockMessage::MsgAddMemberBy) .await .replace1(who) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } @@ -614,11 +614,11 @@ pub(crate) async fn msg_add_member( /// the contacts to combine with the display name. pub(crate) async fn msg_del_member( context: &Context, - removed_member_addr: impl AsRef, + removed_member_addr: &str, by_contact: ContactId, ) -> String { - let addr = removed_member_addr.as_ref(); - let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { + let addr = removed_member_addr; + let who = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id) .await .map(|contact| contact.get_name_n_addr()) @@ -633,7 +633,7 @@ pub(crate) async fn msg_del_member( translated(context, StockMessage::MsgDelMemberBy) .await .replace1(who) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } @@ -644,7 +644,7 @@ pub(crate) async fn msg_group_left(context: &Context, by_contact: ContactId) -> } else { translated(context, StockMessage::MsgGroupLeftBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -684,7 +684,7 @@ pub(crate) async fn read_rcpt(context: &Context) -> String { } /// Stock string: `This is a return receipt for the message "%1$s".`. -pub(crate) async fn read_rcpt_mail_body(context: &Context, message: impl AsRef) -> String { +pub(crate) async fn read_rcpt_mail_body(context: &Context, message: &str) -> String { translated(context, StockMessage::ReadRcptMailBody) .await .replace1(message) @@ -697,7 +697,7 @@ pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ContactId } else { translated(context, StockMessage::MsgGrpImgDeletedBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -714,7 +714,7 @@ pub(crate) async fn secure_join_started( if let Ok(contact) = Contact::get_by_id(context, inviter_contact_id).await { translated(context, StockMessage::SecureJoinStarted) .await - .replace1(contact.get_name_n_addr()) + .replace1(&contact.get_name_n_addr()) .replace2(contact.get_display_name()) } else { format!( @@ -741,7 +741,7 @@ pub(crate) async fn setup_contact_qr_description( display_name: &str, addr: &str, ) -> String { - let name = if display_name == addr { + let name = &if display_name == addr { addr.to_owned() } else { format!("{} ({})", display_name, addr) @@ -760,7 +760,7 @@ pub(crate) async fn secure_join_group_qr_description(context: &Context, chat: &C /// Stock string: `%1$s verified.`. pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> String { - let addr = contact.get_name_n_addr(); + let addr = &contact.get_name_n_addr(); translated(context, StockMessage::ContactVerified) .await .replace1(addr) @@ -768,17 +768,14 @@ pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> St /// Stock string: `Cannot verify %1$s`. pub(crate) async fn contact_not_verified(context: &Context, contact: &Contact) -> String { - let addr = contact.get_name_n_addr(); + let addr = &contact.get_name_n_addr(); translated(context, StockMessage::ContactNotVerified) .await .replace1(addr) } /// Stock string: `Changed setup for %1$s`. -pub(crate) async fn contact_setup_changed( - context: &Context, - contact_addr: impl AsRef, -) -> String { +pub(crate) async fn contact_setup_changed(context: &Context, contact_addr: &str) -> String { translated(context, StockMessage::ContactSetupChanged) .await .replace1(contact_addr) @@ -810,7 +807,7 @@ pub(crate) async fn sync_msg_body(context: &Context) -> String { } /// Stock string: `Cannot login as \"%1$s\". Please check...`. -pub(crate) async fn cannot_login(context: &Context, user: impl AsRef) -> String { +pub(crate) async fn cannot_login(context: &Context, user: &str) -> String { translated(context, StockMessage::CannotLogin) .await .replace1(user) @@ -828,7 +825,7 @@ pub(crate) async fn msg_location_enabled_by(context: &Context, contact: ContactI } else { translated(context, StockMessage::MsgLocationEnabledBy) .await - .replace1(contact.get_stock_name(context).await) + .replace1(&contact.get_stock_name(context).await) } } @@ -874,17 +871,14 @@ pub(crate) async fn unknown_sender_for_chat(context: &Context) -> String { /// Stock string: `Message from %1$s`. // TODO: This can compute `self_name` itself instead of asking the caller to do this. -pub(crate) async fn subject_for_new_contact( - context: &Context, - self_name: impl AsRef, -) -> String { +pub(crate) async fn subject_for_new_contact(context: &Context, self_name: &str) -> String { translated(context, StockMessage::SubjectForNewContact) .await .replace1(self_name) } /// Stock string: `Failed to send message to %1$s.`. -pub(crate) async fn failed_sending_to(context: &Context, name: impl AsRef) -> String { +pub(crate) async fn failed_sending_to(context: &Context, name: &str) -> String { translated(context, StockMessage::FailedSendingTo) .await .replace1(name) @@ -900,14 +894,14 @@ pub(crate) async fn msg_ephemeral_timer_disabled( } else { translated(context, StockMessage::MsgEphemeralTimerDisabledBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } /// Stock string: `Message deletion timer is set to %1$s s.`. pub(crate) async fn msg_ephemeral_timer_enabled( context: &Context, - timer: impl AsRef, + timer: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -918,7 +912,7 @@ pub(crate) async fn msg_ephemeral_timer_enabled( translated(context, StockMessage::MsgEphemeralTimerEnabledBy) .await .replace1(timer) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } @@ -929,7 +923,7 @@ pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: Co } else { translated(context, StockMessage::MsgEphemeralTimerMinuteBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -940,7 +934,7 @@ pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: Cont } else { translated(context, StockMessage::MsgEphemeralTimerHourBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -951,7 +945,7 @@ pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: Conta } else { translated(context, StockMessage::MsgEphemeralTimerDayBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -962,7 +956,7 @@ pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: Cont } else { translated(context, StockMessage::MsgEphemeralTimerWeekBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -972,14 +966,14 @@ pub(crate) async fn videochat_invitation(context: &Context) -> String { } /// Stock string: `You are invited to a video chat, click %1$s to join.`. -pub(crate) async fn videochat_invite_msg_body(context: &Context, url: impl AsRef) -> String { +pub(crate) async fn videochat_invite_msg_body(context: &Context, url: &str) -> String { translated(context, StockMessage::VideochatInviteMsgBody) .await .replace1(url) } /// Stock string: `Error:\n\n“%1$s”`. -pub(crate) async fn configuration_failed(context: &Context, details: impl AsRef) -> String { +pub(crate) async fn configuration_failed(context: &Context, details: &str) -> String { translated(context, StockMessage::ConfigurationFailed) .await .replace1(details) @@ -987,7 +981,7 @@ pub(crate) async fn configuration_failed(context: &Context, details: impl AsRef< /// Stock string: `⚠️ Date or time of your device seem to be inaccurate (%1$s)...`. // TODO: This could compute now itself. -pub(crate) async fn bad_time_msg_body(context: &Context, now: impl AsRef) -> String { +pub(crate) async fn bad_time_msg_body(context: &Context, now: &str) -> String { translated(context, StockMessage::BadTimeMsgBody) .await .replace1(now) @@ -1010,7 +1004,7 @@ pub(crate) async fn protection_enabled(context: &Context, by_contact: ContactId) } else { translated(context, StockMessage::ProtectionEnabledBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -1021,7 +1015,7 @@ pub(crate) async fn protection_disabled(context: &Context, by_contact: ContactId } else { translated(context, StockMessage::ProtectionDisabledBy) .await - .replace1(by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name(context).await) } } @@ -1043,7 +1037,7 @@ pub(crate) async fn delete_server_turned_off(context: &Context) -> String { /// Stock string: `Message deletion timer is set to %1$s minutes.`. pub(crate) async fn msg_ephemeral_timer_minutes( context: &Context, - minutes: impl AsRef, + minutes: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -1054,14 +1048,14 @@ pub(crate) async fn msg_ephemeral_timer_minutes( translated(context, StockMessage::MsgEphemeralTimerMinutesBy) .await .replace1(minutes) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } /// Stock string: `Message deletion timer is set to %1$s hours.`. pub(crate) async fn msg_ephemeral_timer_hours( context: &Context, - hours: impl AsRef, + hours: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -1072,14 +1066,14 @@ pub(crate) async fn msg_ephemeral_timer_hours( translated(context, StockMessage::MsgEphemeralTimerHoursBy) .await .replace1(hours) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } /// Stock string: `Message deletion timer is set to %1$s days.`. pub(crate) async fn msg_ephemeral_timer_days( context: &Context, - days: impl AsRef, + days: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -1090,14 +1084,14 @@ pub(crate) async fn msg_ephemeral_timer_days( translated(context, StockMessage::MsgEphemeralTimerDaysBy) .await .replace1(days) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } /// Stock string: `Message deletion timer is set to %1$s weeks.`. pub(crate) async fn msg_ephemeral_timer_weeks( context: &Context, - weeks: impl AsRef, + weeks: &str, by_contact: ContactId, ) -> String { if by_contact == ContactId::SELF { @@ -1108,7 +1102,7 @@ pub(crate) async fn msg_ephemeral_timer_weeks( translated(context, StockMessage::MsgEphemeralTimerWeeksBy) .await .replace1(weeks) - .replace2(by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name(context).await) } } @@ -1121,15 +1115,13 @@ pub(crate) async fn forwarded(context: &Context) -> String { pub(crate) async fn quota_exceeding(context: &Context, highest_usage: u64) -> String { translated(context, StockMessage::QuotaExceedingMsgBody) .await - .replace1(format!("{}", highest_usage)) + .replace1(&format!("{}", highest_usage)) .replace("%%", "%") } /// Stock string: `%1$s message` with placeholder replaced by human-readable size. pub(crate) async fn partial_download_msg_body(context: &Context, org_bytes: u32) -> String { - let size = org_bytes - .file_size(file_size_opts::BINARY) - .unwrap_or_default(); + let size = &format_size(org_bytes, BINARY); translated(context, StockMessage::PartialDownloadMsgBody) .await .replace1(size) @@ -1139,7 +1131,7 @@ pub(crate) async fn partial_download_msg_body(context: &Context, org_bytes: u32) pub(crate) async fn download_availability(context: &Context, timestamp: i64) -> String { translated(context, StockMessage::DownloadAvailability) .await - .replace1(timestamp_to_str(timestamp)) + .replace1(×tamp_to_str(timestamp)) } /// Stock string: `Incoming Messages`. @@ -1154,7 +1146,7 @@ pub(crate) async fn outgoing_messages(context: &Context) -> String { /// Stock string: `Storage on %1$s`. /// `%1$s` will be replaced by the domain of the configured email-address. -pub(crate) async fn storage_on_domain(context: &Context, domain: impl AsRef) -> String { +pub(crate) async fn storage_on_domain(context: &Context, domain: &str) -> String { translated(context, StockMessage::StorageOnDomain) .await .replace1(domain) @@ -1192,7 +1184,7 @@ pub(crate) async fn last_msg_sent_successfully(context: &Context) -> String { /// Stock string: `Error: %1$s…`. /// `%1$s` will be replaced by a possibly more detailed, typically english, error description. -pub(crate) async fn error(context: &Context, error: impl AsRef) -> String { +pub(crate) async fn error(context: &Context, error: &str) -> String { translated(context, StockMessage::Error) .await .replace1(error) @@ -1210,11 +1202,7 @@ pub(crate) async fn messages(context: &Context) -> String { } /// Stock string: `%1$s of %2$s used`. -pub(crate) async fn part_of_total_used( - context: &Context, - part: impl AsRef, - total: impl AsRef, -) -> String { +pub(crate) async fn part_of_total_used(context: &Context, part: &str, total: &str) -> String { translated(context, StockMessage::PartOfTotallUsed) .await .replace1(part) @@ -1230,9 +1218,9 @@ pub(crate) async fn broadcast_list(context: &Context) -> String { /// Stock string: `%1$s changed their address from %2$s to %3$s`. pub(crate) async fn aeap_addr_changed( context: &Context, - contact_name: impl AsRef, - old_addr: impl AsRef, - new_addr: impl AsRef, + contact_name: &str, + old_addr: &str, + new_addr: &str, ) -> String { translated(context, StockMessage::AeapAddrChanged) .await @@ -1243,8 +1231,8 @@ pub(crate) async fn aeap_addr_changed( pub(crate) async fn aeap_explanation_and_link( context: &Context, - old_addr: impl AsRef, - new_addr: impl AsRef, + old_addr: &str, + new_addr: &str, ) -> String { translated(context, StockMessage::AeapExplanationAndLink) .await diff --git a/src/test_utils.rs b/src/test_utils.rs index 243edf325..472087563 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -979,7 +979,7 @@ fn print_event(event: &Event) { /// Logs an individual message to stdout. /// /// This includes a bunch of the message meta-data as well. -async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { +async fn log_msg(context: &Context, prefix: &str, msg: &Message) { let contact = match Contact::get_by_id(context, msg.get_from_id()).await { Ok(contact) => contact, Err(e) => { @@ -1001,7 +1001,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { let msgtext = msg.get_text(); println!( "{}{}{}{}: {} (Contact#{}): {} {}{}{}{}{}", - prefix.as_ref(), + prefix, msg.get_id(), if msg.get_showpadlock() { "🔒" } else { "" }, if msg.has_location() { "📍" } else { "" }, diff --git a/src/tests/aeap.rs b/src/tests/aeap.rs index 7391e87b1..fbccd401a 100644 --- a/src/tests/aeap.rs +++ b/src/tests/aeap.rs @@ -341,9 +341,8 @@ async fn mark_as_verified(this: &TestContext, other: &TestContext) { peerstate.verified_key = peerstate.public_key.clone(); peerstate.verified_key_fingerprint = peerstate.public_key_fingerprint.clone(); - peerstate.to_save = Some(peerstate::ToSave::All); - peerstate.save_to_db(&this.sql, false).await.unwrap(); + peerstate.save_to_db(&this.sql).await.unwrap(); } async fn get_last_info_msg(t: &TestContext, chat_id: ChatId) -> Option { diff --git a/src/tools.rs b/src/tools.rs index ee05e86ea..5bcd24097 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -206,7 +206,7 @@ async fn maybe_warn_on_bad_time(context: &Context, now: i64, known_past_timestam msg.text = Some( stock_str::bad_time_msg_body( context, - Local + &Local .timestamp_opt(now, 0) .unwrap() .format("%Y-%m-%d %H:%M:%S") @@ -324,8 +324,8 @@ pub(crate) fn extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> { } // the returned suffix is lower-case -pub fn get_filesuffix_lc(path_filename: impl AsRef) -> Option { - Path::new(path_filename.as_ref()) +pub fn get_filesuffix_lc(path_filename: &str) -> Option { + Path::new(path_filename) .extension() .map(|p| p.to_string_lossy().to_lowercase()) } diff --git a/test-data/message/thunderbird_with_autocrypt.eml b/test-data/message/thunderbird_with_autocrypt.eml new file mode 100644 index 000000000..ef9ec15c8 --- /dev/null +++ b/test-data/message/thunderbird_with_autocrypt.eml @@ -0,0 +1,93 @@ +From - Thu, 24 Nov 2022 19:06:16 GMT +X-Mozilla-Status: 0001 +X-Mozilla-Status2: 00800000 +Message-ID: <0bb9ffe1-2596-d997-95b4-1fef8cc4808e@example.org> +Date: Thu, 24 Nov 2022 20:05:57 +0100 +MIME-Version: 1.0 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 + Thunderbird/102.4.2 +From: Alice +To: bob@example.net +Content-Language: en-US +Autocrypt: addr=alice@example.org; keydata= + xjMEXlh13RYJKwYBBAHaRw8BAQdAzfVIAleCXMJrq8VeLlEVof6ITCviMktKjmcBKAu4m5DN + GUFsaWNlIDxhbGljZUBleGFtcGxlLm9yZz7CkAQTFggAOBYhBC5vossjtTLXKGNLWGSwj2Gp + 7ZRDBQJeWHXdAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEGSwj2Gp7ZRDE3oA/i4M + CyDMTsjWqDZoQwX/A/GoTO2/V0wKPhjJJy/8m2pMAPkBjOnGOtx2SZpQvJGTa9h804RY6iDr + RuI8A/8tEEXAA844BF5Ydd0SCisGAQQBl1UBBQEBB0AG7cjWy2SFAU8KnltlubVW67rFiyfp + 01JrRe6Xqy22HQMBCAfCeAQYFggAIBYhBC5vossjtTLXKGNLWGSwj2Gp7ZRDBQJeWHXdAhsM + AAoJEGSwj2Gp7ZRDLo8BAObE8GnsGVwKzNqCvHeWgJsqhjS3C6gvSlV3tEm9XmF6AQDXucIy + VfoBwoyMh2h6cSn/ATn5QJb35pgo+ivp3jsMAg== +Subject: ... +Content-Type: multipart/encrypted; + protocol="application/pgp-encrypted"; + boundary="------------EOdOT2kJUL5hgCilmIhYyVZg" + +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156) +--------------EOdOT2kJUL5hgCilmIhYyVZg +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME version identification + +Version: 1 + +--------------EOdOT2kJUL5hgCilmIhYyVZg +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Description: OpenPGP encrypted message +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- + +wV4D5tq63hTeebASAQdA1dVUsUjGZCOIfCnYtVdmOvKs/BNovI3sG8w1IH4ymTMwAZzgwVbGS5KL ++e1VTD5mUTeVSEYe1cd3VozH4KbNJa1tBlcO0nzGwCPpsTVDMoxIwcBMA+PY3JvEjuMiAQf/d2yj +t0+GyaptwX26bgSqo6vj21W8mcWS5vXOi8wjGwRbPaKKjS4kq1xDOz04eHrE8HUPD8otcXoI8CLz +etJpRbFs0XJP4Cozbsr72dgoWhozRg/iSpBndxWOddTl7Yqo8m/fyhU5uzKZ41m2T8mha6KkKWD8 +QecGdOgieYBucNBjHwWc71p9G6jTnzfy4S4GtGS2gwOSMxpwO7HxpKzsHI4POqFSQbxrl/YRwWSC +f5WqyYcerasIiR/fnOIw8lnvCeQ5rB90eGEDR70YFGt0t4rFBjfGrSPUiWYaTaC1Zvpd+t5sy7zy +FpsS2/aTkwP/UpGqmtFaD/brSouRf9hijNLI0QFTaVmSoI3BKzF8B4zwvtEbOLZjyDb+Va/fZJ3w +nYd2Q/5PPPL+pE4pWKN+jl0TZNzAaqBgvggXomgUqQ7QiksUzym+yuFKrJX0RF2awdrgjQIxjnda +Qp3UFphnFTyYUJpIU9iewjOfVxgPzv7PyuCHYwoP3kh7MJZ6bgbDmOkeFSnjEDJpdf1m9xC9LlBL +beC8scmPs6kx9GARBYSHvyPQ025gN3+XEHh4OrTxHZ91U3IlTfd2kACwOOAXEuhItSHmcNOV0K4M +nI2PH6gW8HgBkWlAPm40K4jUyo3nl1usDiI6ouvYqvW7YUc2hTtPTej1l2/mS57tTt+PFurKs555 +5R9DD/xg9Nx7OuQKy5bIdlXM20UmwuZTOhRJ5kpHFRzLxaHDbSzW+orhRW4llJSevBSAH3cLOjIQ +gh87j+MxG9j0TD2K2A0rcUcxdrnflw+mxcDVaL4payeqmOa+bJyhlftTqH+vqq5DhR68rX5VW+z7 +riqH3o8VbvO2y0XSpYHf1jowkfJj3vr8pynAUIv1dbylUSF5wtrHvzWOprw4bNrdtwQNRNy+JcVF +dUKeNmHaL6XOe4LUWpiI11beRyCpAG52khMCEAO3Q6+4e24cEipbu6suSOtv3OpYDZeHjwNrQIhi +rJg7i9TpMqwOeCvFWK+9UZ+P2n6h9g0/JO2+I82BFGUjVa5IvCTNOgv01GqxWY9ecdtaJjTc+dF2 +OAcRoKwvmtMJlxKEEgveui3BvPA4tuNdSrcoZBrQeo0ZHWVugXPvEZnwfZMcqwwPA+a/sUbZFg0P +Pr0AR0ZHpytnQE9OXE8wEUgT8H1yofQ+5QoZdgMpeAb8zGs+RuviLxcDkb9NtXUAiQ49ooWuFP3L +K9wMlaoWFTq7R+n5JVuSEYRCHC0l0bCV1/+awalT7XltXVCupI4lWzjYs52FZGGzuHG7S50Eufad +m4CQTPVgVaVn8WW2dmpMR8Gj8WbbZdyv21wMGOWjfgT0u3oiDnddGrFOoMNnZHch6rN3FRppoh7h +0U0fi8xxU1+EhUKq+fSIxZNr2iWN2if3Pipbxi9tyK9M41Y6aVF3HWjD58/OEql3aZjJZ1bqpXcE +qsPeFoXX78+7mTDvL75olMk2s/mg4mLqAAWQvTuoiOmj+SgMIFuTtFR+4r/TIFNdamz6AQ3RcmWG +ZcdRii+V27dtMA836vlAwxXRmJyE1LCL1kvUTq+J+AVsZi3xmBLFNlKPTlxswu7vSBrP1DlYOaBq +AgA0lKnkQdeXyDk/VdbTml7ywMW1g6HkFSqKGW/IIAObmBumBcIyHE6dWEHumRQomlJssIlEFSe+ +XEQ0rwedLetJXi5A0AXT1we1wvaKCEg0Pb0ZUxygwNPDrj6MmdodH7gDfyx0mW/7mEMCtIJb5MB+ +TRGPEa/vqdJb8uGtNXUy9UlwMhJ3tYoT7NXY4+IlNjbDH/yleMdwtWP2H2WH8oC+ysXPYXjlT8eU +poxRfJzPMVUn5SA3cvdGXDJWdX8U91j5sf9wuoYE5RBVrrJif3D3l0FpMrlWWoGw7wtZbMC2FaeT +QvdMS5c54IoXBtBTM+/AsTAw7WEE1QSmaQGHnh6xLL5Ns8olsWeKOMlVXdO9jSDbjOGBLr7mWukW +YzLXkH3TtJPQcbVN79af3YPhaHdMYITVKIwfg+vxZlLFHWLJQnkTl+9Qi7u2gKqkNeU7Zqs4E3CR +9K4dHrJMyAZLZ2HA1XQEj0/tMnbTpAzZhj02JRcFobLXK9SQfw7dzGZwMRky8cHcBHoK14P5RIEV +hr+38HSBM6wXtge5gL6DomAACvuORQO4X9x/CTjRt/J8uN3lKK5p+wi3ULeb319CEWiCiqmC1M+C +TADUhPUhUmTinSAVkTEn+BdbH/97dVaJnvd6HtLmdSlw4xqdWUfVL9Qd7+/5L6iwlOzGLKRv97c/ +gCRw+hzXyAom+5C18slSwanMuyPgIyrrFy/kp9Romk9SQr/c0CUF2am99t8G5qvVi/TiJGHyKEXD +aUYd4V7lqNlHMiiasvFHeq8blwmFr7rGEvbZzLNplc6sRUVlYhY2unRfyWsq9mqk3NDRW12Fa0J2 +YxQJlnXHQhNE8EyM/zsD9jCVNwsRZJ9/e5KS+ignmu6gKIR+ItDTwRfNI+NG/YmTgENUTyuO+vQC +CUKS3PCwpP+OEC966ARl7OCMdfn1hEyiAxsZnp1RmFngR6FM+mlGgfUoWNoHvnR1/YyQ4F4dadiA +QINwuSm5faw75F1EeL8Qi+LHKuqt05Pi/V9GJ6TzIkIsEbyyJ5sKHrp4QsU4C1p7ZhPjddz8De8k +6ZdwMIeXxi27WKtsFLcr8JKOBe0imIilKdMBOPS31pc1iJe4472WbWM0aBwdEYmnz9+xfOqnjHtO +0XTMjff7pzV6Y7t/u8J/zm3JS3ykote9HNRQvhZZNeVClVWd0fYFzat5ESnTojZTwHcc/BFTPnhz +VgLyw1KEIy2r3ZyGHu1b8GSYivzl33MOK/NVBQPZUIEfdcQ5vhkAvj+Yx340IYykRFEChwioprXD +LrIbTou7TNT5fTFA+beidHFsL+OE002/LMs6C3erSUW5C/LNjAQMS7cAV2yCyjX+/2GBmmDqnC4r +Ja2x5yik+fbOUPh3kk/md1YvrodlX/JkQeoWRrrVJsX2dr3BgivPJavaN0Jz1eHyxAYKNqlrfd1T +YWEDIisWerTxAVY/rEruZ6+OqLqOtZtn+4SOajOq8KFusglaMZqoYuM+LhPZck9PlZXwRqX08Vlv +8jX5V75BFWRhFd5/LYbnQHI6ZW80Wb2sBNngLL2QJT9yXGCDJb5qCdFwGd3i655pvRJXabeyCtDD +7I2PJcYRDd4stdq07BHyHJmye6vas8mG5QUygyWyUQv78za0m4gLMrRZBgoBDcVpWJUc+cPXzzfG +7PvLZu/Y0SaD5hqTp0LBB1PFxTpzdVeJ21gzVNQ6D4XGLTtdv4K4fOEYoeKEuzGoBaUDtIqz47gd +5rwfQ3ps2slkxfbtQcdKEACKvsCwzqHlgwsxD8QNOFzXYLiiiJBX22fIRoiJeSDMKSZyuFtpykCm +7bOpybPSHv3E7EIr8sIOr9MOe/R5HSthU2IgW1L5Ynr2t9HUnCA8CenkzIQjg0h5sruxcGWCYLx7 +q0f1AQs4Z7SebVbq1SCWVJNX/vc1bVjnjYfri7RX5WMmjJkuSnuIoP6a42cqJcAg7m0STB0elFAy +oO4vW9/JEmFUqLyQmWnoLJHX3IKtWa9CPvE= +=OA6b +-----END PGP MESSAGE----- + +--------------EOdOT2kJUL5hgCilmIhYyVZg--