diff --git a/CHANGELOG.md b/CHANGELOG.md index 69005da0cb..a7cae42caa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,95 @@ # Changelog +## [1.149.0] - 2024-11-05 + +### Build system + +- Update tokio to 1.41 and Android NDK to r27. +- `nix flake update android`. + +### Fixes + +- cargo: Update iroh to 0.28.1. + This fixes the problem with iroh not sending the `Host:` header and not being able to connect to relays behind nginx reverse proxy. + +## [1.148.7] - 2024-11-03 + +### API-Changes + +- Add API to reset contact encryption. + +### Features / Changes + +- Emit chatlist events only if message still exists. + +### Fixes + +- send_msg_to_smtp: Do not fail if the message does not exist anymore. +- Do not percent-encode dot when passing to autoconfig server. +- Save contact name from SecureJoin QR to `authname`, not to `name` ([#6115](https://github.com/deltachat/deltachat-core-rust/pull/6115)). +- Always exit fake IDLE after at most 60 seconds. +- Concat NDNs ([#6129](https://github.com/deltachat/deltachat-core-rust/pull/6129)). + +### Refactor + +- Remove `has_decrypted_pgp_armor()`. + +### Miscellaneous Tasks + +- Update dependencies. + +## [1.148.6] - 2024-10-31 + +### API-Changes + +- Add Message::new_text() ([#6123](https://github.com/deltachat/deltachat-core-rust/pull/6123)). +- Add `MessageSearchResult.chat_id` ([#6120](https://github.com/deltachat/deltachat-core-rust/pull/6120)). + +### Features / Changes + +- Enable Webxdc realtime by default ([#6125](https://github.com/deltachat/deltachat-core-rust/pull/6125)). + +### Fixes + +- Save full text to mime_headers for long outgoing messages ([#6091](https://github.com/deltachat/deltachat-core-rust/pull/6091)). +- Show root SMTP connection failure in connectivity view ([#6121](https://github.com/deltachat/deltachat-core-rust/pull/6121)). +- Skip IDLE if we got unsolicited FETCH ([#6130](https://github.com/deltachat/deltachat-core-rust/pull/6130)). + +### Miscellaneous Tasks + +- Silence another rust-analyzer false-positive ([#6124](https://github.com/deltachat/deltachat-core-rust/pull/6124)). +- cargo: Upgrade iroh to 0.26.0. + +### Refactor + +- Directly use connectives ([#6128](https://github.com/deltachat/deltachat-core-rust/pull/6128)). +- Use Message::new_text() more ([#6127](https://github.com/deltachat/deltachat-core-rust/pull/6127)). + +## [1.148.5] - 2024-10-27 + +### Fixes + +- Set Config::NotifyAboutWrongPw before saving configuration ([#5896](https://github.com/deltachat/deltachat-core-rust/pull/5896)). +- Do not take write lock for maybe_network_lost() and set_push_device_token(). +- Do not lock the account manager for the whole duration of background_fetch. + +### Features / Changes + +- Auto-restore 1:1 chat protection after receiving old unverified message. + +### CI + +- Take `CHATMAIL_DOMAIN` from variables instead of secrets. + +### Other + +- Revert "build: nix flake update fenix" to fix `nix build .#deltachat-rpc-server-armeabi-v7a-android`. + +### Refactor + +- Receive_imf::add_parts: Remove excessive `from_id == ContactId::SELF` checks. +- Factor out `add_gossip_peer_from_header()`. + ## [1.148.4] - 2024-10-24 ### Features / Changes @@ -5139,3 +5229,7 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed [1.148.2]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.1..v1.148.2 [1.148.3]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.2..v1.148.3 [1.148.4]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.3..v1.148.4 +[1.148.5]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.4..v1.148.5 +[1.148.6]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.5..v1.148.6 +[1.148.7]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.6..v1.148.7 +[1.149.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.7..v1.149.0 diff --git a/Cargo.lock b/Cargo.lock index 14069e547d..4f21d8fd91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" dependencies = [ "backtrace", ] @@ -221,7 +221,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", "synstructure", ] @@ -233,7 +233,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -338,14 +338,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] name = "async-smtp" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928ea96f04e1260036cb01f82c1e5dc7c3b478e7b9463c87712297784ce3cdc6" +checksum = "00d1f1a16e5abad3ada9f1f23dbc2f354b138121b90533381be62dada6cbf40a" dependencies = [ "anyhow", "base64 0.13.1", @@ -366,7 +366,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -377,13 +377,19 @@ checksum = "00b9f7252833d5ed4b00aa9604b563529dd5e11de9c23615de2dcdf91eb87b52" dependencies = [ "async-compression", "crc32fast", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "pin-project", "thiserror", "tokio", "tokio-util", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "attohttpc" version = "0.24.1" @@ -413,9 +419,9 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -448,7 +454,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -615,9 +621,9 @@ checksum = "78a6932c88f1d2c29533a3b8a5f5a2f84cc19c3339b431677c3160c5c2e6ca85" [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -685,9 +691,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] @@ -991,6 +997,16 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" +[[package]] +name = "cordyceps" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec10f0a762d93c4498d2e97a333805cb6250d60bead623f71d8034f9a4152ba3" +dependencies = [ + "loom", + "tracing", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1225,7 +1241,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1249,7 +1265,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1260,7 +1276,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1293,7 +1309,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.148.4" +version = "1.149.0" dependencies = [ "anyhow", "async-broadcast", @@ -1317,12 +1333,12 @@ dependencies = [ "fd-lock", "format-flowed", "futures", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "hex", "hickory-resolver", "http-body-util", "humansize", - "hyper 1.4.1", + "hyper", "hyper-util", "image", "iroh-gossip", @@ -1393,7 +1409,7 @@ dependencies = [ [[package]] name = "deltachat-jsonrpc" -version = "1.148.4" +version = "1.149.0" dependencies = [ "anyhow", "async-channel 2.3.1", @@ -1418,7 +1434,7 @@ dependencies = [ [[package]] name = "deltachat-repl" -version = "1.148.4" +version = "1.149.0" dependencies = [ "anyhow", "deltachat", @@ -1434,12 +1450,12 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.148.4" +version = "1.149.0" dependencies = [ "anyhow", "deltachat", "deltachat-jsonrpc", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "log", "serde", "serde_json", @@ -1458,12 +1474,12 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] name = "deltachat_ffi" -version = "1.148.4" +version = "1.149.0" dependencies = [ "anyhow", "deltachat", @@ -1513,7 +1529,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1544,7 +1560,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1554,27 +1570,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] name = "derive_more" -version = "1.0.0-beta.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3249c0372e72f5f93b5c0ca54c0ab76bbf6216b6f718925476fd9bc4ffabb4fe" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "1.0.0-beta.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27d919ced7590fc17b5d5a3c63b662e8a7d2324212c4e4dbbed975cafd22d16d" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", "unicode-xid", ] @@ -1587,6 +1603,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "diatomic-waker" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" + [[package]] name = "diff" version = "0.1.13" @@ -1634,7 +1656,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1905,7 +1927,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -1925,7 +1947,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -2197,9 +2219,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -2212,12 +2234,13 @@ dependencies = [ [[package]] name = "futures-buffered" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dcae03ee5afa5ea17b1aebc793806b8ddfc6dc500e0b8e8e1eb30b9dad22c0" +checksum = "34acda8ae8b63fbe0b2195c998b180cff89a8212fb2622a78b572a9f1c6f7684" dependencies = [ + "cordyceps", + "diatomic-waker", "futures-core", - "futures-util", "pin-project-lite", ] @@ -2254,9 +2277,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -2286,9 +2309,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ "fastrand 2.1.1", "futures-core", @@ -2305,7 +2328,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -2344,6 +2367,50 @@ dependencies = [ "slab", ] +[[package]] +name = "genawaiter" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0" +dependencies = [ + "futures-core", + "genawaiter-macro", + "genawaiter-proc-macro", + "proc-macro-hack", +] + +[[package]] +name = "genawaiter-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" + +[[package]] +name = "genawaiter-proc-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784f84eebc366e15251c4a8c3acee82a6a6f427949776ecb88377362a9621738" +dependencies = [ + "proc-macro-error", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2444,16 +2511,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -2636,17 +2703,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.0" @@ -2666,7 +2722,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "pin-project-lite", ] @@ -2684,9 +2740,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "human-panic" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c5a08ed290eac04006e21e63d32e90086b6182c7cd0452d10f4264def1fec9a" +checksum = "80b84a66a325082740043a6c28bbea400c129eac0d3a27673a1de971e44bf1f7" dependencies = [ "backtrace", "os_info", @@ -2713,39 +2769,16 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "httparse", "httpdate", "itoa", @@ -2763,7 +2796,7 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper", "hyper-util", "rustls", "rustls-pki-types", @@ -2775,16 +2808,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.4.1", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -2842,16 +2875,18 @@ dependencies = [ [[package]] name = "igd-next" -version = "0.14.3" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064d90fec10d541084e7b39ead8875a5a80d9114a2b18791565253bae25f49e4" +checksum = "76b0d7d4541def58a37bf8efc559683f21edce7c82f0d866c93ac21f7e098f93" dependencies = [ "async-trait", "attohttpc", "bytes", "futures", - "http 0.2.12", - "hyper 0.14.28", + "http 1.1.0", + "http-body-util", + "hyper", + "hyper-util", "log", "rand 0.8.5", "tokio", @@ -2861,9 +2896,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" dependencies = [ "bytemuck", "byteorder-lite", @@ -2878,12 +2913,12 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a84a25dcae3ac487bc24ef280f9e20c79c9b1a3e5e32cbed3041d1c514aa87c" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" dependencies = [ - "byteorder", - "thiserror", + "byteorder-lite", + "quick-error 2.0.1", ] [[package]] @@ -2943,9 +2978,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "iroh-base" -version = "0.25.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545424889bce87e44fd08dac9e6889635630fdbdaaa858a3c5a5f0adbb8d3779" +checksum = "1c21fd8eb71f166a172a9779c2244db992218e9a9bd929b9df6fc355d2b630c9" dependencies = [ "aead", "anyhow", @@ -2961,7 +2996,6 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "serde", - "serde-error", "ssh-key", "thiserror", "ttl_cache", @@ -2984,9 +3018,9 @@ dependencies = [ [[package]] name = "iroh-gossip" -version = "0.25.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5489a563e407fb2be654e950536da4230e46642111f12b16d7013228164aae" +checksum = "c078057037f0e741c5ef285c67fd9cfdb928163dd046fb547089898bdb02990e" dependencies = [ "anyhow", "async-channel 2.3.1", @@ -2994,17 +3028,19 @@ dependencies = [ "derive_more", "ed25519-dalek", "futures-concurrency", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "futures-util", "indexmap", "iroh-base", "iroh-blake3", "iroh-metrics", "iroh-net", + "iroh-router", "postcard", "rand 0.8.5", "rand_core 0.6.4", "serde", + "serde-error", "tokio", "tokio-util", "tracing", @@ -3012,14 +3048,14 @@ dependencies = [ [[package]] name = "iroh-metrics" -version = "0.25.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb6ab80f7cccde80be07a643308e1ff925d5be91721ec65ba96b261a0bcb5e5" +checksum = "e0d40f2ee3997489d47403d204a06514ed65373d224b5b43a8ea133f543e5db1" dependencies = [ "anyhow", "erased_set", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "once_cell", "prometheus-client", @@ -3033,9 +3069,9 @@ dependencies = [ [[package]] name = "iroh-net" -version = "0.25.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a099a60478cb9319153756a9cf2ff41aa03d18403690a91e60f049ad467b057" +checksum = "b40e1f1f9029e198c6d05bd232d3239814b0a66ac4668978729b709aeb6a44e2" dependencies = [ "anyhow", "backoff", @@ -3046,9 +3082,10 @@ dependencies = [ "duct", "futures-buffered", "futures-concurrency", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "futures-sink", "futures-util", + "genawaiter", "governor", "hex", "hickory-proto", @@ -3056,7 +3093,7 @@ dependencies = [ "hostname", "http 1.1.0", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "igd-next", "iroh-base", @@ -3069,11 +3106,13 @@ dependencies = [ "netlink-packet-core", "netlink-packet-route", "netlink-sys", + "netwatch", "num_enum", "once_cell", "parking_lot", "pin-project", "pkarr", + "portmapper", "postcard", "rand 0.8.5", "rcgen", @@ -3092,6 +3131,7 @@ dependencies = [ "time 0.3.36", "tokio", "tokio-rustls", + "tokio-stream", "tokio-tungstenite", "tokio-tungstenite-wasm", "tokio-util", @@ -3108,9 +3148,9 @@ dependencies = [ [[package]] name = "iroh-quinn" -version = "0.11.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd590a39a14cfc168efa4d894de5039d65641e62d8da4a80733018ababe3c33" +checksum = "35ba75a5c57cff299d2d7ca1ddee053f66339d1756bd79ec637bcad5aa61100e" dependencies = [ "bytes", "iroh-quinn-proto", @@ -3126,9 +3166,9 @@ dependencies = [ [[package]] name = "iroh-quinn-proto" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd0538ff12efe3d61ea1deda2d7913f4270873a519d43e6995c6e87a1558538" +checksum = "e2c869ba52683d3d067c83ab4c00a2fda18eaf13b1434d4c1352f428674d4a5d" dependencies = [ "bytes", "rand 0.8.5", @@ -3144,9 +3184,9 @@ dependencies = [ [[package]] name = "iroh-quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0619b59471fdd393ac8a6c047f640171119c1c8b41f7d2927db91776dcdbc5f" +checksum = "bfcfc0abc2fdf8cf18a6c72893b7cbebeac2274a3b1306c1760c48c0e10ac5e0" dependencies = [ "libc", "once_cell", @@ -3155,6 +3195,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "iroh-router" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd18ec6325dd3f01625f12c01acff50a4374ee1ab708e7b2078885fd63ad30" +dependencies = [ + "anyhow", + "futures-buffered", + "futures-lite 2.4.0", + "futures-util", + "iroh-net", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "is-terminal" version = "0.4.12" @@ -3232,9 +3288,9 @@ dependencies = [ [[package]] name = "kamadak-exif" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" +checksum = "99e7b00ff45df279c3e40f7fee99fad4f7eddbf9ed2d24e99133e8683330f0c7" dependencies = [ "mutate_once", ] @@ -3283,9 +3339,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libm" @@ -3350,6 +3406,19 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lru" version = "0.12.3" @@ -3382,6 +3451,26 @@ dependencies = [ "quoted_printable", ] +[[package]] +name = "mainline" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b751ffb57303217bcae8f490eee6044a5b40eadf6ca05ff476cad37e7b7970d" +dependencies = [ + "bytes", + "crc", + "ed25519-dalek", + "flume", + "lru", + "rand 0.8.5", + "serde", + "serde_bencode", + "serde_bytes", + "sha1_smol", + "thiserror", + "tracing", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -3455,13 +3544,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3579,6 +3669,35 @@ dependencies = [ "tokio", ] +[[package]] +name = "netwatch" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a639d52c0996ac640e2a7052a5265c8f71efdbdadc83188435ffc358b7ca931" +dependencies = [ + "anyhow", + "bytes", + "derive_more", + "futures-lite 2.4.0", + "futures-sink", + "futures-util", + "libc", + "netdev", + "netlink-packet-core", + "netlink-packet-route", + "netlink-sys", + "once_cell", + "rtnetlink", + "serde", + "socket2", + "thiserror", + "time 0.3.36", + "tokio", + "tracing", + "windows 0.51.1", + "wmi", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -3700,7 +3819,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -3761,7 +3880,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -3796,9 +3915,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -3835,7 +3954,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -4039,7 +4158,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -4119,22 +4238,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -4157,11 +4276,13 @@ checksum = "89f9e12544b00f5561253bbd3cb72a85ff3bc398483dc1bf82bdf095c774136b" dependencies = [ "bytes", "document-features", + "dyn-clone", "ed25519-dalek", "flume", "futures", "js-sys", "lru", + "mainline", "self_cell", "simple-dns", "thiserror", @@ -4246,7 +4367,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -4312,6 +4433,35 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +[[package]] +name = "portmapper" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d60045fdcfe8ff6b781cf1027fdbb08ed319d93aff7da4bedc018e3bc92226" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "derive_more", + "futures-lite 2.4.0", + "futures-util", + "igd-next", + "iroh-metrics", + "libc", + "netwatch", + "num_enum", + "rand 0.8.5", + "serde", + "smallvec", + "socket2", + "thiserror", + "time 0.3.36", + "tokio", + "tokio-util", + "tracing", + "url", +] + [[package]] name = "postcard" version = "1.0.8" @@ -4410,6 +4560,32 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "syn-mid", + "version_check", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -4429,9 +4605,15 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.86" @@ -4461,7 +4643,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -4523,11 +4705,17 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "ffbfb3ddf5364c9cfcd65549a1e7b801d0e8d1b14c1a1590a6408aa93cfbfa84" dependencies = [ "memchr", ] @@ -4835,9 +5023,9 @@ dependencies = [ "futures-core", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-util", "ipnet", @@ -4873,7 +5061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ "hostname", - "quick-error", + "quick-error 1.2.3", ] [[package]] @@ -5039,9 +5227,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", @@ -5077,9 +5265,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" @@ -5211,9 +5399,15 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.79", + "syn 2.0.86", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -5294,9 +5488,28 @@ dependencies = [ [[package]] name = "serde-error" -version = "0.1.2" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342110fb7a5d801060c885da03bf91bfa7c7ca936deafcc64bb6706375605d47" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bencode" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e988182713aeed6a619a88bca186f6d6407483485ffe44c869ee264f8eabd13f" +checksum = "a70dfc7b7438b99896e7f8992363ab8e2c4ba26aa5ec675d32d1c3c2c33d413e" +dependencies = [ + "serde", + "serde_bytes", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -5309,7 +5522,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -5320,14 +5533,14 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -5408,6 +5621,12 @@ dependencies = [ "sha1", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.8" @@ -5681,7 +5900,7 @@ dependencies = [ "proc-macro2", "quote", "struct_iterable_internal", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -5709,7 +5928,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -5771,15 +5990,26 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn-mid" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea305d57546cc8cd04feb14b62ec84bf17f50e3f7b12560d7bfa9265f39d9ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5800,7 +6030,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -5890,22 +6120,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -5987,21 +6217,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -6016,13 +6245,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -6207,7 +6436,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -6300,9 +6529,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typescript-type-def" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9a1ec7a0e59e03c7ab74e924abef19d2669aa9255b9821e55854b08453eb71" +checksum = "233ee5e596f41dbaf8c3e48a60b128eadf89395ee9e45fcedc3281c077c5a014" dependencies = [ "serde_json", "typescript-type-def-derive", @@ -6310,16 +6539,16 @@ dependencies = [ [[package]] name = "typescript-type-def-derive" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c1213de2386875250474a109f0985ce83333038c885d2fec4de79d9dfcee8c" +checksum = "912e6d6fed61bac90cd957093b11b5330d756ad4e7b8f309f71ae04b546a8513" dependencies = [ "darling", "ident_case", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -6445,9 +6674,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.12", "serde", @@ -6541,7 +6770,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", "wasm-bindgen-shared", ] @@ -6575,7 +6804,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6671,6 +6900,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows" version = "0.51.1" @@ -6719,7 +6957,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -6730,7 +6968,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -7036,7 +7274,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -7062,7 +7300,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -7082,7 +7320,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.86", ] [[package]] @@ -7093,9 +7331,9 @@ checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] name = "zune-jpeg" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index d9142aa5b0..b22863e063 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.148.4" +version = "1.149.0" edition = "2021" license = "MPL-2.0" rust-version = "1.77" @@ -46,7 +46,7 @@ async-native-tls = { version = "0.5", default-features = false, features = ["run async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] } async_zip = { version = "0.0.17", default-features = false, features = ["deflate", "tokio-fs"] } base64 = { workspace = true } -brotli = { version = "6", default-features=false, features = ["std"] } +brotli = { version = "7", default-features=false, features = ["std"] } bytes = "1" chrono = { workspace = true, features = ["alloc", "clock", "std"] } email = { git = "https://github.com/deltachat/rust-email", branch = "master" } @@ -61,11 +61,11 @@ hickory-resolver = "=0.25.0-alpha.2" http-body-util = "0.1.2" humansize = "2" hyper = "1" -hyper-util = "0.1.9" -image = { version = "0.25.1", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } -iroh-gossip = { version = "0.25.0", default-features = false, features = ["net"] } -iroh-net = { version = "0.25.0", default-features = false } -kamadak-exif = "0.5.3" +hyper-util = "0.1.10" +image = { version = "0.25.4", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } +iroh-gossip = { version = "0.28.1", default-features = false, features = ["net"] } +iroh-net = { version = "0.28.1", default-features = false } +kamadak-exif = "0.6.0" lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" } libc = { workspace = true } mailparse = "0.15" @@ -79,14 +79,14 @@ percent-encoding = "2.3" pgp = { version = "0.13.2", default-features = false } pin-project = "1" qrcodegen = "1.7.0" -quick-xml = "0.36" +quick-xml = "0.37" quoted_printable = "0.5" rand = { workspace = true } regex = { workspace = true } rusqlite = { workspace = true, features = ["sqlcipher"] } rust-hsluv = "0.1" -rustls-pki-types = "1.9.0" -rustls = { version = "0.23.13", default-features = false } +rustls-pki-types = "1.10.0" +rustls = { version = "0.23.14", default-features = false } sanitize-filename = { workspace = true } serde_json = { workspace = true } serde_urlencoded = "0.7.1" @@ -171,13 +171,13 @@ chrono = { version = "0.4.38", default-features = false } deltachat-contact-tools = { path = "deltachat-contact-tools" } deltachat-jsonrpc = { path = "deltachat-jsonrpc", default-features = false } deltachat = { path = ".", default-features = false } -futures = "0.3.30" -futures-lite = "2.3.0" +futures = "0.3.31" +futures-lite = "2.4.0" libc = "0.2" log = "0.4" nu-ansi-term = "0.46" num-traits = "0.2" -once_cell = "1.18.0" +once_cell = "1.20.2" rand = "0.8" regex = "1.10" rusqlite = "0.32" @@ -186,14 +186,7 @@ serde = "1.0" serde_json = "1" tempfile = "3.13.0" thiserror = "1" - -# 1.38 is the latest version before `mio` dependency update -# that broke compilation with Android NDK r23c and r24. -# Version 1.39.0 cannot be compiled using these NDKs, -# see issue -# for details. -tokio = "~1.38.1" - +tokio = "1" tokio-util = "0.7.11" tracing-subscriber = "0.3" yerpc = "0.6.2" diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 17dc4b71e3..598d359849 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.148.4" +version = "1.149.0" description = "Deltachat FFI" edition = "2018" readme = "README.md" diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 64a93405ba..0354aaeca2 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -530,8 +530,8 @@ char* dc_get_blobdir (const dc_context_t* context); * These keys go to backups and allow easy per-account settings when using @ref dc_accounts_t, * however, are not handled by the core otherwise. * - `webxdc_realtime_enabled` = Whether the realtime APIs should be enabled. - * 0 = WebXDC realtime API is disabled and behaves as noop (default). - * 1 = WebXDC realtime API is enabled. + * 0 = WebXDC realtime API is disabled and behaves as noop. + * 1 = WebXDC realtime API is enabled (default). * * If you want to retrieve a value, use dc_get_config(). * diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index e55c0e44c8..1150f0e5d2 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.148.4" +version = "1.149.0" description = "DeltaChat JSON-RPC API" edition = "2021" default-run = "deltachat-jsonrpc-server" @@ -25,7 +25,7 @@ async-channel = { workspace = true } futures = { workspace = true } serde_json = { workspace = true } yerpc = { workspace = true, features = ["anyhow_expose", "openrpc"] } -typescript-type-def = { version = "0.5.12", features = ["json_value"] } +typescript-type-def = { version = "0.5.13", features = ["json_value"] } tokio = { workspace = true } sanitize-filename = { workspace = true } walkdir = "2.5.0" diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 3afe60fe74..5fb0efed4c 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -1419,6 +1419,15 @@ impl CommandApi { Ok(()) } + /// Resets contact encryption. + async fn reset_contact_encryption(&self, account_id: u32, contact_id: u32) -> Result<()> { + let ctx = self.get_context(account_id).await?; + let contact_id = ContactId::new(contact_id); + + contact_id.reset_encryption(&ctx).await?; + Ok(()) + } + async fn change_contact_name( &self, account_id: u32, @@ -2118,8 +2127,7 @@ impl CommandApi { ) -> Result { let ctx = self.get_context(account_id).await?; - let mut msg = Message::new(Viewtype::Text); - msg.set_text(text); + let mut msg = Message::new_text(text); let message_id = deltachat::chat::send_msg(&ctx, ChatId::new(chat_id), &mut msg).await?; Ok(message_id.to_u32()) diff --git a/deltachat-jsonrpc/src/api/types/events.rs b/deltachat-jsonrpc/src/api/types/events.rs index fab754202e..34ccdf395e 100644 --- a/deltachat-jsonrpc/src/api/types/events.rs +++ b/deltachat-jsonrpc/src/api/types/events.rs @@ -409,6 +409,9 @@ impl From for EventType { }, CoreEventType::ChatlistChanged => ChatlistChanged, CoreEventType::EventChannelOverflow { n } => EventChannelOverflow { n }, + #[allow(unreachable_patterns)] + #[cfg(test)] + _ => unreachable!("This is just to silence a rust_analyzer false-positive"), } } } diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index 93e7593d0d..697cba35e9 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -490,6 +490,7 @@ pub struct MessageSearchResult { author_name: String, author_color: String, author_id: u32, + chat_id: u32, chat_profile_image: Option, chat_color: String, chat_name: String, @@ -529,6 +530,7 @@ impl MessageSearchResult { author_name, author_color: color_int_to_hex_string(sender.get_color()), author_id: sender.id.to_u32(), + chat_id: chat.id.to_u32(), chat_name: chat.get_name().to_owned(), chat_color, chat_type: chat.get_type().to_u32().context("unknown chat type id")?, diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index e00debc1b5..16f1ceeec3 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -58,5 +58,5 @@ }, "type": "module", "types": "dist/deltachat.d.ts", - "version": "1.148.4" + "version": "1.149.0" } diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index 44b98435d0..70a50b1529 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-repl" -version = "1.148.4" +version = "1.149.0" license = "MPL-2.0" edition = "2021" repository = "https://github.com/deltachat/deltachat-core-rust" diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index dd18839849..2f636ee867 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -1004,8 +1004,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ensure!(sel_chat.is_some(), "No chat selected."); if !arg1.is_empty() { - let mut draft = Message::new(Viewtype::Text); - draft.set_text(arg1.to_string()); + let mut draft = Message::new_text(arg1.to_string()); sel_chat .as_ref() .unwrap() @@ -1028,8 +1027,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu !arg1.is_empty(), "Please specify text to add as device message." ); - let mut msg = Message::new(Viewtype::Text); - msg.set_text(arg1.to_string()); + let mut msg = Message::new_text(arg1.to_string()); chat::add_device_msg(&context, None, Some(&mut msg)).await?; } "listmedia" => { diff --git a/deltachat-rpc-client/pyproject.toml b/deltachat-rpc-client/pyproject.toml index 0ed58c3b68..7398111132 100644 --- a/deltachat-rpc-client/pyproject.toml +++ b/deltachat-rpc-client/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "deltachat-rpc-client" -version = "1.148.4" +version = "1.149.0" description = "Python client for Delta Chat core JSON-RPC interface" classifiers = [ "Development Status :: 5 - Production/Stable", diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/contact.py b/deltachat-rpc-client/src/deltachat_rpc_client/contact.py index eefa474f10..81c4bba59d 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/contact.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/contact.py @@ -36,6 +36,10 @@ def delete(self) -> None: """Delete contact.""" self._rpc.delete_contact(self.account.id, self.id) + def reset_encryption(self) -> None: + """Reset contact encryption.""" + self._rpc.reset_contact_encryption(self.account.id, self.id) + def set_name(self, name: str) -> None: """Change the name of this contact.""" self._rpc.change_contact_name(self.account.id, self.id, name) diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 7f1a153520..22f22a6a4a 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -246,6 +246,7 @@ def test_contact(acfactory) -> None: assert repr(alice_contact_bob) alice_contact_bob.block() alice_contact_bob.unblock() + alice_contact_bob.reset_encryption() alice_contact_bob.set_name("new name") alice_contact_bob.get_encryption_info() snapshot = alice_contact_bob.get_snapshot() diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index e9e6b40523..827c3fbb83 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-rpc-server" -version = "1.148.4" +version = "1.149.0" description = "DeltaChat JSON-RPC server" edition = "2021" readme = "README.md" diff --git a/deltachat-rpc-server/npm-package/package.json b/deltachat-rpc-server/npm-package/package.json index 6724e7fa5b..76c47aa8aa 100644 --- a/deltachat-rpc-server/npm-package/package.json +++ b/deltachat-rpc-server/npm-package/package.json @@ -15,5 +15,5 @@ }, "type": "module", "types": "index.d.ts", - "version": "1.148.4" + "version": "1.149.0" } diff --git a/deny.toml b/deny.toml index 98352766b7..349e67314c 100644 --- a/deny.toml +++ b/deny.toml @@ -11,6 +11,10 @@ ignore = [ # Unmaintained encoding "RUSTSEC-2021-0153", + + # Unmaintained proc-macro-error + # + "RUSTSEC-2024-0370", ] [bans] @@ -28,10 +32,7 @@ skip = [ { name = "fastrand", version = "1.9.0" }, { name = "futures-lite", version = "1.13.0" }, { name = "getrandom", version = "<0.2" }, - { name = "h2", version = "0.3.26" }, - { name = "http-body", version = "0.4.6" }, { name = "http", version = "0.2.12" }, - { name = "hyper", version = "0.14.28" }, { name = "nix", version = "0.26.4" }, { name = "quick-error", version = "<2.0" }, { name = "rand_chacha", version = "<0.3" }, diff --git a/flake.lock b/flake.lock index 196d32bd2f..95b1fe5d85 100644 --- a/flake.lock +++ b/flake.lock @@ -3,15 +3,15 @@ "android": { "inputs": { "devshell": "devshell", - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1712088936, - "narHash": "sha256-mVjeSWQiR/t4UZ9fUawY9OEPAhY1R3meYG+0oh8DUBs=", + "lastModified": 1729628358, + "narHash": "sha256-2HDSc6BL+bE3S1l3Gn0Z8wWvvfBEUEjvXkNIQ11Aifk=", "owner": "tadfisher", "repo": "android-nixpkgs", - "rev": "2d8181caef279f19c4a33dc694723f89ffc195d4", + "rev": "52b9e0c0f9cff887d2bb4932f8be4e062ba0802d", "type": "github" }, "original": { @@ -22,18 +22,17 @@ }, "devshell": { "inputs": { - "flake-utils": "flake-utils", "nixpkgs": [ "android", "nixpkgs" ] }, "locked": { - "lastModified": 1711099426, - "narHash": "sha256-HzpgM/wc3aqpnHJJ2oDqPBkNsqWbW0WfWUO8lKu8nGk=", + "lastModified": 1728330715, + "narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=", "owner": "numtide", "repo": "devshell", - "rev": "2d45b54ca4a183f2fdcf4b19c895b64fbf620ee8", + "rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef", "type": "github" }, "original": { @@ -48,11 +47,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1729578683, - "narHash": "sha256-h0Wmvrkadbyi3IJXFLPi+QyYjCAKDr2xQ6dLxlQ8cXY=", + "lastModified": 1714112748, + "narHash": "sha256-jq6Cpf/pQH85p+uTwPPrGG8Ky/zUOTwMJ7mcqc5M4So=", "owner": "nix-community", "repo": "fenix", - "rev": "d66cda53e8193a878742dcadb5bb75f4df7c3c0a", + "rev": "3ae4b908a795b6a3824d401a0702e11a7157d7e1", "type": "github" }, "original": { @@ -66,11 +65,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -97,24 +96,6 @@ "type": "github" } }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "naersk": { "inputs": { "nixpkgs": "nixpkgs_3" @@ -150,11 +131,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1711703276, - "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "lastModified": 1729413321, + "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", "type": "github" }, "original": { @@ -166,11 +147,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1729256560, - "narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=", + "lastModified": 1713895582, + "narHash": "sha256-cfh1hi+6muQMbi9acOlju3V1gl8BEaZBXBR9jQfQi4U=", "owner": "nixos", "repo": "nixpkgs", - "rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0", + "rev": "572af610f6151fd41c212f897c71f7056e3fb518", "type": "github" }, "original": { @@ -213,7 +194,7 @@ "inputs": { "android": "android", "fenix": "fenix", - "flake-utils": "flake-utils_3", + "flake-utils": "flake-utils_2", "naersk": "naersk", "nix-filter": "nix-filter", "nixpkgs": "nixpkgs_4" @@ -222,11 +203,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1729533545, - "narHash": "sha256-A/AuEWcGwwjpfBCZqWDNNg5GwYrJduzLvlMe+A7xG5U=", + "lastModified": 1714031783, + "narHash": "sha256-xS/niQsq1CQPOe4M4jvVPO2cnXS/EIeRG5gIopUbk+Q=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "de2ff17bc513807412d7bbaba1d995a774938583", + "rev": "56bee2ddafa6177b19c631eedc88d43366553223", "type": "github" }, "original": { @@ -265,21 +246,6 @@ "repo": "default", "type": "github" } - }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index aa4b4c0511..5a21605988 100644 --- a/flake.nix +++ b/flake.nix @@ -18,9 +18,9 @@ manifest = (pkgs.lib.importTOML ./Cargo.toml).package; androidSdk = android.sdk.${system} (sdkPkgs: builtins.attrValues { - inherit (sdkPkgs) ndk-24-0-8215888 cmdline-tools-latest; + inherit (sdkPkgs) ndk-27-0-11902837 cmdline-tools-latest; }); - androidNdkRoot = "${androidSdk}/share/android-sdk/ndk/24.0.8215888"; + androidNdkRoot = "${androidSdk}/share/android-sdk/ndk/27.0.11902837"; rustSrc = nix-filter.lib { root = ./.; @@ -257,13 +257,21 @@ androidAttrs = { armeabi-v7a = { - cc = "armv7a-linux-androideabi19-clang"; + cc = "armv7a-linux-androideabi21-clang"; rustTarget = "armv7-linux-androideabi"; }; arm64-v8a = { cc = "aarch64-linux-android21-clang"; rustTarget = "aarch64-linux-android"; }; + x86 = { + cc = "i686-linux-android21-clang"; + rustTarget = "i686-linux-android"; + }; + x86_64 = { + cc = "x86_64-linux-android21-clang"; + rustTarget = "x86_64-linux-android"; + }; }; mkAndroidRustPackage = arch: packageName: diff --git a/package.json b/package.json index 5090585e71..fd6e1ba26d 100644 --- a/package.json +++ b/package.json @@ -55,5 +55,5 @@ "test:mocha": "mocha node/test/test.mjs --growl --reporter=spec --bail --exit" }, "types": "node/dist/index.d.ts", - "version": "1.148.4" + "version": "1.149.0" } diff --git a/python/pyproject.toml b/python/pyproject.toml index 464a2a996d..9181c13454 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "deltachat" -version = "1.148.4" +version = "1.149.0" description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat" readme = "README.rst" requires-python = ">=3.7" diff --git a/release-date.in b/release-date.in index fea15de727..b5fbb42cd6 100644 --- a/release-date.in +++ b/release-date.in @@ -1 +1 @@ -2024-10-24 \ No newline at end of file +2024-11-05 \ No newline at end of file diff --git a/src/chat.rs b/src/chat.rs index 1e924d4e2b..dca49002ea 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -817,8 +817,7 @@ impl ChatId { context.scheduler.interrupt_inbox().await; if chat.is_self_talk() { - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_str::self_deleted_msg_body(context).await; + let mut msg = Message::new_text(stock_str::self_deleted_msg_body(context).await); add_device_msg(context, None, Some(&mut msg)).await?; } chatlist_events::emit_chatlist_changed(context); @@ -2112,28 +2111,31 @@ impl Chat { EphemeralTimer::Enabled { duration } => time().saturating_add(duration.into()), }; + let (msg_text, was_truncated) = truncate_msg_text(context, msg.text.clone()).await?; let new_mime_headers = if msg.has_html() { - let html = if msg.param.exists(Param::Forwarded) { + if msg.param.exists(Param::Forwarded) { msg.get_id().get_html(context).await? } else { msg.param.get(Param::SendHtml).map(|s| s.to_string()) - }; - match html { - Some(html) => Some(tokio::task::block_in_place(move || { - buf_compress(new_html_mimepart(html).build().as_string().as_bytes()) - })?), - None => None, } } else { None }; + let new_mime_headers = new_mime_headers.or_else(|| match was_truncated { + true => Some(msg.text.clone()), + false => None, + }); + let new_mime_headers = match new_mime_headers { + Some(h) => Some(tokio::task::block_in_place(move || { + buf_compress(new_html_mimepart(h).build().as_string().as_bytes()) + })?), + None => None, + }; msg.chat_id = self.id; msg.from_id = ContactId::SELF; msg.rfc724_mid = new_rfc724_mid; msg.timestamp_sort = timestamp; - let (msg_text, was_truncated) = truncate_msg_text(context, msg.text.clone()).await?; - let mime_modified = new_mime_headers.is_some() | was_truncated; // add message to the database if let Some(update_msg_id) = update_msg_id { @@ -2162,7 +2164,7 @@ impl Chat { msg.hidden, msg.in_reply_to.as_deref().unwrap_or_default(), new_references, - mime_modified, + new_mime_headers.is_some(), new_mime_headers.unwrap_or_default(), location_id as i32, ephemeral_timer, @@ -2213,7 +2215,7 @@ impl Chat { msg.hidden, msg.in_reply_to.as_deref().unwrap_or_default(), new_references, - mime_modified, + new_mime_headers.is_some(), new_mime_headers.unwrap_or_default(), location_id as i32, ephemeral_timer, @@ -3136,8 +3138,7 @@ pub async fn send_text_msg( chat_id ); - let mut msg = Message::new(Viewtype::Text); - msg.text = text_to_send; + let mut msg = Message::new_text(text_to_send); send_msg(context, chat_id, &mut msg).await } @@ -4839,8 +4840,7 @@ mod tests { async fn test_get_draft() { let t = TestContext::new().await; let chat_id = &t.get_self_chat().await.id; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hello".to_string()); + let mut msg = Message::new_text("hello".to_string()); chat_id.set_draft(&t, Some(&mut msg)).await.unwrap(); let draft = chat_id.get_draft(&t).await.unwrap().unwrap(); @@ -4854,13 +4854,11 @@ mod tests { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hi!".to_string()); + let mut msg = Message::new_text("hi!".to_string()); chat_id.set_draft(&t, Some(&mut msg)).await?; assert!(chat_id.get_draft(&t).await?.is_some()); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("another".to_string()); + let mut msg = Message::new_text("another".to_string()); chat_id.set_draft(&t, Some(&mut msg)).await?; assert!(chat_id.get_draft(&t).await?.is_some()); @@ -4874,8 +4872,7 @@ mod tests { async fn test_forwarding_draft_failing() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = &t.get_self_chat().await.id; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hello".to_string()); + let mut msg = Message::new_text("hello".to_string()); chat_id.set_draft(&t, Some(&mut msg)).await?; assert_eq!(msg.id, chat_id.get_draft(&t).await?.unwrap().id); @@ -4888,8 +4885,7 @@ mod tests { async fn test_draft_stable_ids() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = &t.get_self_chat().await.id; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hello".to_string()); + let mut msg = Message::new_text("hello".to_string()); assert_eq!(msg.id, MsgId::new_unset()); assert!(chat_id.get_draft_msg_id(&t).await?.is_none()); @@ -4935,11 +4931,7 @@ mod tests { let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?; let msgs: Vec = (1..=1000) - .map(|i| { - let mut msg = Message::new(Viewtype::Text); - msg.set_text(i.to_string()); - msg - }) + .map(|i| Message::new_text(i.to_string())) .collect(); let mut tasks = Vec::new(); for mut msg in msgs { @@ -4972,8 +4964,7 @@ mod tests { .await?; // save a draft - let mut draft = Message::new(Viewtype::Text); - draft.set_text("draft text".to_string()); + let mut draft = Message::new_text("draft text".to_string()); chat_id.set_draft(&t, Some(&mut draft)).await?; let test = Message::load_from_db(&t, draft.id).await?; @@ -5026,29 +5017,25 @@ mod tests { let one2one_msg = Message::load_from_db(&alice, one2one_msg_id).await?; // quoting messages in same chat is okay - let mut msg = Message::new(Viewtype::Text); - msg.set_text("baz".to_string()); + let mut msg = Message::new_text("baz".to_string()); msg.set_quote(&alice, Some(&grp_msg)).await?; let result = send_msg(&alice, grp_chat_id, &mut msg).await; assert!(result.is_ok()); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("baz".to_string()); + let mut msg = Message::new_text("baz".to_string()); msg.set_quote(&alice, Some(&one2one_msg)).await?; let result = send_msg(&alice, one2one_chat_id, &mut msg).await; assert!(result.is_ok()); let one2one_quote_reply_msg_id = result.unwrap(); // quoting messages from groups to one-to-ones is okay ("reply privately") - let mut msg = Message::new(Viewtype::Text); - msg.set_text("baz".to_string()); + let mut msg = Message::new_text("baz".to_string()); msg.set_quote(&alice, Some(&grp_msg)).await?; let result = send_msg(&alice, one2one_chat_id, &mut msg).await; assert!(result.is_ok()); // quoting messages from one-to-one chats in groups is an error; usually this is also not allowed by UI at all ... - let mut msg = Message::new(Viewtype::Text); - msg.set_text("baz".to_string()); + let mut msg = Message::new_text("baz".to_string()); msg.set_quote(&alice, Some(&one2one_msg)).await?; let result = send_msg(&alice, grp_chat_id, &mut msg).await; assert!(result.is_err()); @@ -5540,13 +5527,11 @@ mod tests { let t = TestContext::new().await; // add two device-messages - let mut msg1 = Message::new(Viewtype::Text); - msg1.set_text("first message".to_string()); + let mut msg1 = Message::new_text("first message".to_string()); let msg1_id = add_device_msg(&t, None, Some(&mut msg1)).await; assert!(msg1_id.is_ok()); - let mut msg2 = Message::new(Viewtype::Text); - msg2.set_text("second message".to_string()); + let mut msg2 = Message::new_text("second message".to_string()); let msg2_id = add_device_msg(&t, None, Some(&mut msg2)).await; assert!(msg2_id.is_ok()); assert_ne!(msg1_id.as_ref().unwrap(), msg2_id.as_ref().unwrap()); @@ -5575,14 +5560,12 @@ mod tests { let t = TestContext::new().await; // add two device-messages with the same label (second attempt is not added) - let mut msg1 = Message::new(Viewtype::Text); - msg1.text = "first message".to_string(); + let mut msg1 = Message::new_text("first message".to_string()); let msg1_id = add_device_msg(&t, Some("any-label"), Some(&mut msg1)).await; assert!(msg1_id.is_ok()); assert!(!msg1_id.as_ref().unwrap().is_unset()); - let mut msg2 = Message::new(Viewtype::Text); - msg2.text = "second message".to_string(); + let mut msg2 = Message::new_text("second message".to_string()); let msg2_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await; assert!(msg2_id.is_ok()); assert!(msg2_id.as_ref().unwrap().is_unset()); @@ -5629,8 +5612,7 @@ mod tests { let res = add_device_msg(&t, Some("some-label"), None).await; assert!(res.is_ok()); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("message text".to_string()); + let mut msg = Message::new_text("message text".to_string()); let msg_id = add_device_msg(&t, Some("some-label"), Some(&mut msg)).await; assert!(msg_id.is_ok()); @@ -5647,8 +5629,7 @@ mod tests { add_device_msg(&t, Some("some-label"), None).await.ok(); assert!(was_device_msg_ever_added(&t, "some-label").await.unwrap()); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("message text".to_string()); + let mut msg = Message::new_text("message text".to_string()); add_device_msg(&t, Some("another-label"), Some(&mut msg)) .await .ok(); @@ -5665,8 +5646,7 @@ mod tests { async fn test_delete_device_chat() { let t = TestContext::new().await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("message text".to_string()); + let mut msg = Message::new_text("message text".to_string()); add_device_msg(&t, Some("some-label"), Some(&mut msg)) .await .ok(); @@ -5689,8 +5669,7 @@ mod tests { .await .unwrap(); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("message text".to_string()); + let mut msg = Message::new_text("message text".to_string()); assert!(send_msg(&t, device_chat_id, &mut msg).await.is_err()); assert!(prepare_msg(&t, device_chat_id, &mut msg).await.is_err()); @@ -5701,8 +5680,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_and_reset_all_device_msgs() { let t = TestContext::new().await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("message text".to_string()); + let mut msg = Message::new_text("message text".to_string()); let msg_id1 = add_device_msg(&t, Some("some-label"), Some(&mut msg)) .await .unwrap(); @@ -5734,8 +5712,7 @@ mod tests { async fn test_archive() { // create two chats let t = TestContext::new().await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("foo".to_string()); + let mut msg = Message::new_text("foo".to_string()); let msg_id = add_device_msg(&t, None, Some(&mut msg)).await.unwrap(); let chat_id1 = message::Message::load_from_db(&t, msg_id) .await @@ -6035,8 +6012,7 @@ mod tests { let t = TestContext::new().await; // create 3 chats, wait 1 second in between to get a reliable order (we order by time) - let mut msg = Message::new(Viewtype::Text); - msg.set_text("foo".to_string()); + let mut msg = Message::new_text("foo".to_string()); let msg_id = add_device_msg(&t, None, Some(&mut msg)).await.unwrap(); let chat_id1 = message::Message::load_from_db(&t, msg_id) .await @@ -6113,8 +6089,7 @@ mod tests { ChatVisibility::Pinned, ); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hi!".into()); + let mut msg = Message::new_text("hi!".into()); let sent_msg = bob.send_msg(bob_chat_id, &mut msg).await; let msg = alice.recv_msg(&sent_msg).await; assert_eq!(msg.chat_id, alice_chat_id); @@ -6753,8 +6728,7 @@ mod tests { let alice_chat = alice.create_chat(&bob).await; let bob_chat = bob.create_chat(&alice).await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("Hi Bob".to_owned()); + let mut msg = Message::new_text("Hi Bob".to_owned()); let sent_msg = alice.send_msg(alice_chat.get_id(), &mut msg).await; let msg = bob.recv_msg(&sent_msg).await; @@ -6805,8 +6779,7 @@ mod tests { let received_msg = bob.recv_msg(&sent_msg).await; // Bob quotes received message and sends a reply to Alice. - let mut reply = Message::new(Viewtype::Text); - reply.set_text("Reply".to_owned()); + let mut reply = Message::new_text("Reply".to_owned()); reply.set_quote(&bob, Some(&received_msg)).await?; let sent_reply = bob.send_msg(bob_chat.id, &mut reply).await; let received_reply = alice.recv_msg(&sent_reply).await; @@ -6889,8 +6862,7 @@ mod tests { let group_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "secretgrpname").await?; add_contact_to_chat(&alice, group_id, bob_id).await?; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("bla foo".to_owned()); + let mut msg = Message::new_text("bla foo".to_owned()); let sent_msg = alice.send_msg(group_id, &mut msg).await; assert!(sent_msg.payload().contains("secretgrpname")); assert!(sent_msg.payload().contains("secretname")); diff --git a/src/chatlist.rs b/src/chatlist.rs index f1ad18d90a..5505c1d96d 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -476,7 +476,6 @@ mod tests { add_contact_to_chat, create_group_chat, get_chat_contacts, remove_contact_from_chat, send_text_msg, ProtectionStatus, }; - use crate::message::Viewtype; use crate::receive_imf::receive_imf; use crate::stock_str::StockMessage; use crate::test_utils::TestContext; @@ -510,8 +509,7 @@ mod tests { // Instead of setting drafts for chat_id1 and chat_id3, we could also sleep // 2s here. for chat_id in &[chat_id1, chat_id3, chat_id2] { - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hello".to_string()); + let mut msg = Message::new_text("hello".to_string()); chat_id.set_draft(&t, Some(&mut msg)).await.unwrap(); } @@ -755,8 +753,7 @@ mod tests { .await .unwrap(); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("foo:\nbar \r\n test".to_string()); + let mut msg = Message::new_text("foo:\nbar \r\n test".to_string()); chat_id1.set_draft(&t, Some(&mut msg)).await.unwrap(); let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); diff --git a/src/configure.rs b/src/configure.rs index 58f5aab5b9..990501468e 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -19,11 +19,12 @@ use auto_outlook::outlk_autodiscover; use deltachat_contact_tools::EmailAddress; use futures::FutureExt; use futures_lite::FutureExt as _; -use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; +use percent_encoding::utf8_percent_encode; use server_params::{expand_param_vector, ServerParams}; use tokio::task; use crate::config::{self, Config}; +use crate::constants::NON_ALPHANUMERIC_WITHOUT_DOT; use crate::context::Context; use crate::imap::Imap; use crate::log::LogExt; @@ -31,7 +32,7 @@ use crate::login_param::{ ConfiguredCertificateChecks, ConfiguredLoginParam, ConfiguredServerLoginParam, ConnectionCandidate, EnteredCertificateChecks, EnteredLoginParam, }; -use crate::message::{Message, Viewtype}; +use crate::message::Message; use crate::oauth2::get_oauth2_addr; use crate::provider::{Protocol, Socket, UsernamePattern}; use crate::smtp::Smtp; @@ -142,8 +143,7 @@ async fn on_configure_completed( } if !provider.after_login_hint.is_empty() { - let mut msg = Message::new(Viewtype::Text); - msg.text = provider.after_login_hint.to_string(); + let mut msg = Message::new_text(provider.after_login_hint.to_string()); if chat::add_device_msg(context, Some("core-provider-info"), Some(&mut msg)) .await .is_err() @@ -156,9 +156,9 @@ async fn on_configure_completed( if let Some(new_addr) = context.get_config(Config::ConfiguredAddr).await? { if let Some(old_addr) = old_addr { if !addr_cmp(&new_addr, &old_addr) { - let mut msg = Message::new(Viewtype::Text); - msg.text = - stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await; + let mut msg = Message::new_text( + stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await, + ); chat::add_device_msg(context, None, Some(&mut msg)) .await .context("Cannot add AEAP explanation") @@ -499,7 +499,15 @@ async fn get_autoconfig( param: &EnteredLoginParam, param_domain: &str, ) -> Option> { - let param_addr_urlencoded = utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string(); + // Make sure to not encode `.` as `%2E` here. + // Some servers like murena.io on 2024-11-01 produce incorrect autoconfig XML + // when address is encoded. + // E.g. + // + // produced XML file with `foobar@example%2Eorg` + // resulting in failure to log in. + let param_addr_urlencoded = + utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC_WITHOUT_DOT).to_string(); if let Ok(res) = moz_autoconfigure( ctx, diff --git a/src/contact.rs b/src/contact.rs index cf13669bf6..6f511bde8b 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -143,6 +143,43 @@ impl ContactId { .await?; Ok(()) } + + /// Returns contact adress. + pub async fn addr(&self, context: &Context) -> Result { + let addr = context + .sql + .query_row("SELECT addr FROM contacts WHERE id=?", (self,), |row| { + let addr: String = row.get(0)?; + Ok(addr) + }) + .await?; + Ok(addr) + } + + /// Resets encryption with the contact. + /// + /// Effect is similar to receiving a message without Autocrypt header + /// from the contact, but this action is triggered manually by the user. + /// + /// For example, this will result in sending the next message + /// to 1:1 chat unencrypted, but will not remove existing verified keys. + pub async fn reset_encryption(self, context: &Context) -> Result<()> { + let now = time(); + + let addr = self.addr(context).await?; + if let Some(mut peerstate) = Peerstate::from_addr(context, &addr).await? { + peerstate.degrade_encryption(now); + peerstate.save_to_db(&context.sql).await?; + } + + // Reset 1:1 chat protection. + if let Some(chat_id) = ChatId::lookup_by_contact(context, self).await? { + chat_id + .set_protection(context, ProtectionStatus::Unprotected, now, Some(self)) + .await?; + } + Ok(()) + } } impl fmt::Display for ContactId { @@ -425,9 +462,12 @@ pub enum Origin { /// To: of incoming messages of unknown sender IncomingUnknownTo = 0x40, - /// address scanned but not verified + /// Address scanned but not verified. UnhandledQrScan = 0x80, + /// Address scanned from a SecureJoin QR code, but not verified yet. + UnhandledSecurejoinQrScan = 0x81, + /// Reply-To: of incoming message of known sender /// Contacts with at least this origin value are shown in the contact list. IncomingReplyTo = 0x100, @@ -3153,4 +3193,59 @@ Until the false-positive is fixed: Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_reset_encryption() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + + let msg = tcm.send_recv_accept(alice, bob, "Hello!").await; + assert_eq!(msg.get_showpadlock(), false); + + let msg = tcm.send_recv(bob, alice, "Hi!").await; + assert_eq!(msg.get_showpadlock(), true); + let alice_bob_contact_id = msg.from_id; + + alice_bob_contact_id.reset_encryption(alice).await?; + + let msg = tcm.send_recv(alice, bob, "Unencrypted").await; + assert_eq!(msg.get_showpadlock(), false); + + Ok(()) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_reset_verified_encryption() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + + tcm.execute_securejoin(bob, alice).await; + + let msg = tcm.send_recv(bob, alice, "Encrypted").await; + assert_eq!(msg.get_showpadlock(), true); + + let alice_bob_chat_id = msg.chat_id; + let alice_bob_contact_id = msg.from_id; + alice_bob_contact_id.reset_encryption(alice).await?; + + // Check that the contact is still verified after resetting encryption. + let alice_bob_contact = Contact::get_by_id(alice, alice_bob_contact_id).await?; + assert_eq!(alice_bob_contact.is_verified(alice).await?, true); + + // 1:1 chat and profile is no longer verified. + assert_eq!(alice_bob_contact.is_profile_verified(alice).await?, false); + + let info_msg = alice.get_last_msg_in(alice_bob_chat_id).await; + assert_eq!( + info_msg.text, + "bob@example.net sent a message from another device." + ); + + let msg = tcm.send_recv(alice, bob, "Unencrypted").await; + assert_eq!(msg.get_showpadlock(), false); + + Ok(()) + } } diff --git a/src/context.rs b/src/context.rs index 40a1ce6ee5..965810e190 100644 --- a/src/context.rs +++ b/src/context.rs @@ -29,7 +29,7 @@ use crate::events::{Event, EventEmitter, EventType, Events}; use crate::imap::{FolderMeaning, Imap, ServerMetadata}; use crate::key::{load_self_public_key, load_self_secret_key, DcKey as _}; use crate::login_param::{ConfiguredLoginParam, EnteredLoginParam}; -use crate::message::{self, Message, MessageState, MsgId, Viewtype}; +use crate::message::{self, Message, MessageState, MsgId}; use crate::param::{Param, Params}; use crate::peer_channels::Iroh; use crate::peerstate::Peerstate; @@ -1189,8 +1189,7 @@ impl Context { .set_protection(self, ProtectionStatus::Protected, time(), Some(contact_id)) .await?; - let mut msg = Message::new(Viewtype::Text); - msg.text = self.get_self_report().await?; + let mut msg = Message::new_text(self.get_self_report().await?); chat_id.set_draft(self, Some(&mut msg)).await?; @@ -1789,12 +1788,10 @@ mod tests { assert!(res.is_empty()); // Add messages to chat with Bob. - let mut msg1 = Message::new(Viewtype::Text); - msg1.set_text("foobar".to_string()); + let mut msg1 = Message::new_text("foobar".to_string()); send_msg(&alice, chat.id, &mut msg1).await?; - let mut msg2 = Message::new(Viewtype::Text); - msg2.set_text("barbaz".to_string()); + let mut msg2 = Message::new_text("barbaz".to_string()); send_msg(&alice, chat.id, &mut msg2).await?; alice.send_text(chat.id, "Δ-Chat").await; @@ -1897,8 +1894,7 @@ mod tests { .await; // Add 999 messages - let mut msg = Message::new(Viewtype::Text); - msg.set_text("foobar".to_string()); + let mut msg = Message::new_text("foobar".to_string()); for _ in 0..999 { send_msg(&alice, chat.id, &mut msg).await?; } diff --git a/src/decrypt.rs b/src/decrypt.rs index f3120926c8..7c33fe096f 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -31,11 +31,11 @@ pub fn try_decrypt( return Ok(None); }; - decrypt_part( - encrypted_data_part, - private_keyring, - public_keyring_for_validate, - ) + let data = encrypted_data_part.get_body_raw()?; + + let (plain, ret_valid_signatures) = + pgp::pk_decrypt(data, private_keyring, public_keyring_for_validate)?; + Ok(Some((plain, ret_valid_signatures))) } pub(crate) async fn prepare_decryption( @@ -204,37 +204,6 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Option<&'a ParsedMail } } -/// Returns Ok(None) if nothing encrypted was found. -fn decrypt_part( - mail: &ParsedMail<'_>, - private_keyring: &[SignedSecretKey], - public_keyring_for_validate: &[SignedPublicKey], -) -> Result, HashSet)>> { - let data = mail.get_body_raw()?; - - if has_decrypted_pgp_armor(&data) { - let (plain, ret_valid_signatures) = - pgp::pk_decrypt(data, private_keyring, public_keyring_for_validate)?; - return Ok(Some((plain, ret_valid_signatures))); - } - - Ok(None) -} - -#[allow(clippy::indexing_slicing)] -fn has_decrypted_pgp_armor(input: &[u8]) -> bool { - if let Some(index) = input.iter().position(|b| *b > b' ') { - if input.len() - index > 26 { - let start = index; - let end = start + 27; - - return &input[start..end] == b"-----BEGIN PGP MESSAGE-----"; - } - } - - false -} - /// Validates signatures of Multipart/Signed message part, as defined in RFC 1847. /// /// Returns the signed part and the set of key @@ -346,24 +315,6 @@ mod tests { use crate::receive_imf::receive_imf; use crate::test_utils::TestContext; - #[test] - fn test_has_decrypted_pgp_armor() { - let data = b" -----BEGIN PGP MESSAGE-----"; - assert_eq!(has_decrypted_pgp_armor(data), true); - - let data = b" \n-----BEGIN PGP MESSAGE-----"; - assert_eq!(has_decrypted_pgp_armor(data), true); - - let data = b" -----BEGIN PGP MESSAGE---"; - assert_eq!(has_decrypted_pgp_armor(data), false); - - let data = b" -----BEGIN PGP MESSAGE-----"; - assert_eq!(has_decrypted_pgp_armor(data), true); - - let data = b"blas"; - assert_eq!(has_decrypted_pgp_armor(data), false); - } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mixed_up_mime() -> Result<()> { // "Mixed Up" mail as received when sending an encrypted diff --git a/src/download.rs b/src/download.rs index 7fa657f906..243c451183 100644 --- a/src/download.rs +++ b/src/download.rs @@ -318,8 +318,7 @@ mod tests { let t = TestContext::new_alice().await; let chat = t.create_chat_with_contact("Bob", "bob@example.org").await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("Hi Bob".to_owned()); + let mut msg = Message::new_text("Hi Bob".to_owned()); let msg_id = send_msg(&t, chat.id, &mut msg).await?; let msg = Message::load_from_db(&t, msg_id).await?; assert_eq!(msg.download_state(), DownloadState::Done); diff --git a/src/ephemeral.rs b/src/ephemeral.rs index d1d40a8ace..276119028f 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -223,8 +223,9 @@ impl ChatId { self.inner_set_ephemeral_timer(context, timer).await?; if self.is_promoted(context).await? { - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_ephemeral_timer_changed(context, timer, ContactId::SELF).await; + let mut msg = Message::new_text( + stock_ephemeral_timer_changed(context, timer, ContactId::SELF).await, + ); msg.param.set_cmd(SystemMessage::EphemeralTimerChanged); if let Err(err) = send_msg(context, self, &mut msg).await { error!( @@ -1362,8 +1363,7 @@ mod tests { chat.id .set_ephemeral_timer(&alice, Timer::Enabled { duration }) .await?; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hi".to_string()); + let mut msg = Message::new_text("hi".to_string()); assert!(chat::send_msg_sync(&alice, chat.id, &mut msg) .await .is_err()); @@ -1393,8 +1393,7 @@ mod tests { let sent = alice.pop_sent_msg().await; bob.recv_msg(&sent).await; - let mut poi_msg = Message::new(Viewtype::Text); - poi_msg.text = "Here".to_string(); + let mut poi_msg = Message::new_text("Here".to_string()); poi_msg.set_location(10.0, 20.0); let alice_sent_message = alice.send_msg(chat.id, &mut poi_msg).await; diff --git a/src/html.rs b/src/html.rs index ee6b469b66..380cfc65b8 100644 --- a/src/html.rs +++ b/src/html.rs @@ -525,8 +525,7 @@ test some special html-characters as < > and & but also " and &#x // alice sends a message with html-part to bob let chat_id = alice.create_chat(&bob).await.id; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("plain text".to_string()); + let mut msg = Message::new_text("plain text".to_string()); msg.set_html(Some("html text".to_string())); assert!(msg.mime_modified); chat::send_msg(&alice, chat_id, &mut msg).await.unwrap(); diff --git a/src/imap.rs b/src/imap.rs index 8246fdd6a7..303dbd6d41 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -36,7 +36,7 @@ use crate::log::LogExt; use crate::login_param::{ prioritize_server_login_params, ConfiguredLoginParam, ConfiguredServerLoginParam, }; -use crate::message::{self, Message, MessageState, MessengerMessage, MsgId, Viewtype}; +use crate::message::{self, Message, MessageState, MessengerMessage, MsgId}; use crate::mimeparser; use crate::net::proxy::ProxyConfig; use crate::net::session::SessionStream; @@ -426,8 +426,7 @@ impl Imap { && err_str.to_lowercase().contains("authentication") && context.get_config_bool(Config::NotifyAboutWrongPw).await? { - let mut msg = Message::new(Viewtype::Text); - msg.text.clone_from(&message); + let mut msg = Message::new_text(message); if let Err(e) = chat::add_device_msg_with_importance( context, None, @@ -1203,6 +1202,8 @@ impl Session { .await .context("failed to fetch flags")?; + let mut got_unsolicited_fetch = false; + while let Some(fetch) = list .try_next() .await @@ -1212,6 +1213,7 @@ impl Session { uid } else { info!(context, "FETCH result contains no UID, skipping"); + got_unsolicited_fetch = true; continue; }; let is_seen = fetch.flags().any(|flag| flag == Flag::Seen); @@ -1234,6 +1236,15 @@ impl Session { warn!(context, "FETCH result contains no MODSEQ"); } } + drop(list); + + if got_unsolicited_fetch { + // We got unsolicited FETCH, which means some flags + // have been modified while our request was in progress. + // We may or may not have these new flags as a part of the response, + // so better skip next IDLE and do another round of flag synchronization. + self.new_mail = true; + } set_modseq(context, folder, highest_modseq) .await @@ -1719,17 +1730,21 @@ impl Imap { } impl Session { - /// Return whether the server sent an unsolicited EXISTS response. + /// Return whether the server sent an unsolicited EXISTS or FETCH response. + /// /// Drains all responses from `session.unsolicited_responses` in the process. - /// If this returns `true`, this means that new emails arrived and you should - /// fetch again, even if you just fetched. - fn server_sent_unsolicited_exists(&self, context: &Context) -> Result { + /// + /// If this returns `true`, this means that new emails arrived + /// or flags have been changed. + /// In this case we may want to skip next IDLE and do a round + /// of fetching new messages and synchronizing seen flags. + fn drain_unsolicited_responses(&self, context: &Context) -> Result { use async_imap::imap_proto::Response; use async_imap::imap_proto::ResponseCode; use UnsolicitedResponse::*; let folder = self.selected_folder.as_deref().unwrap_or_default(); - let mut unsolicited_exists = false; + let mut should_refetch = false; while let Ok(response) = self.unsolicited_responses.try_recv() { match response { Exists(_) => { @@ -1737,28 +1752,38 @@ impl Session { context, "Need to refetch {folder:?}, got unsolicited EXISTS {response:?}" ); - unsolicited_exists = true; + should_refetch = true; } - // We are not interested in the following responses and they are are - // sent quite frequently, so, we ignore them without logging them Expunge(_) | Recent(_) => {} - Other(response_data) - if matches!( - response_data.parsed(), - Response::Fetch { .. } - | Response::Done { - code: Some(ResponseCode::CopyUid(_, _, _)), - .. - } - ) => {} + Other(ref response_data) => { + match response_data.parsed() { + Response::Fetch { .. } => { + info!( + context, + "Need to refetch {folder:?}, got unsolicited FETCH {response:?}" + ); + should_refetch = true; + } + + // We are not interested in the following responses and they are are + // sent quite frequently, so, we ignore them without logging them. + Response::Done { + code: Some(ResponseCode::CopyUid(_, _, _)), + .. + } => {} + _ => { + info!(context, "{folder:?}: got unsolicited response {response:?}") + } + } + } _ => { info!(context, "{folder:?}: got unsolicited response {response:?}") } } } - Ok(unsolicited_exists) + Ok(should_refetch) } } diff --git a/src/imap/idle.rs b/src/imap/idle.rs index 892e8757b8..3680b0c9a7 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -9,7 +9,6 @@ use tokio::time::timeout; use super::session::Session; use super::Imap; use crate::context::Context; -use crate::imap::FolderMeaning; use crate::net::TIMEOUT; use crate::tools::{self, time_elapsed}; @@ -32,7 +31,7 @@ impl Session { self.select_with_uidvalidity(context, folder).await?; - if self.server_sent_unsolicited_exists(context)? { + if self.drain_unsolicited_responses(context)? { self.new_mail = true; } @@ -109,37 +108,16 @@ impl Imap { pub(crate) async fn fake_idle( &mut self, context: &Context, - session: &mut Session, watch_folder: String, - folder_meaning: FolderMeaning, ) -> Result<()> { let fake_idle_start_time = tools::Time::now(); info!(context, "IMAP-fake-IDLEing folder={:?}", watch_folder); - // Loop until we are interrupted or until we fetch something. - loop { - match timeout(Duration::from_secs(60), self.idle_interrupt_receiver.recv()).await { - Err(_) => { - // Let's see if fetching messages results - // in anything. If so, we behave as if IDLE had data but - // will have already fetched the messages so perform_*_fetch - // will not find any new. - let res = self - .fetch_new_messages(context, session, &watch_folder, folder_meaning, false) - .await?; - - info!(context, "fetch_new_messages returned {:?}", res); - - if res { - break; - } - } - Ok(_) => { - info!(context, "Fake IDLE interrupted."); - break; - } - } + // Wait for 60 seconds or until we are interrupted. + match timeout(Duration::from_secs(60), self.idle_interrupt_receiver.recv()).await { + Err(_) => info!(context, "Fake IDLE finished."), + Ok(_) => info!(context, "Fake IDLE interrupted."), } info!( diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index a4e17d04d6..d102684d54 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -66,21 +66,11 @@ impl Imap { && folder_meaning != FolderMeaning::Drafts && folder_meaning != FolderMeaning::Trash { - // Drain leftover unsolicited EXISTS messages - session.server_sent_unsolicited_exists(context)?; - - loop { - self.fetch_move_delete(context, session, folder.name(), folder_meaning) - .await - .context("Can't fetch new msgs in scanned folder") - .log_err(context) - .ok(); - - // If the server sent an unsocicited EXISTS during the fetch, we need to fetch again - if !session.server_sent_unsolicited_exists(context)? { - break; - } - } + self.fetch_move_delete(context, session, folder.name(), folder_meaning) + .await + .context("Can't fetch new msgs in scanned folder") + .log_err(context) + .ok(); } } diff --git a/src/imex/transfer.rs b/src/imex/transfer.rs index d280dd8f88..7298834a2b 100644 --- a/src/imex/transfer.rs +++ b/src/imex/transfer.rs @@ -42,7 +42,7 @@ use tokio_util::sync::CancellationToken; use crate::chat::add_device_msg; use crate::context::Context; use crate::imex::BlobDirContents; -use crate::message::{Message, Viewtype}; +use crate::message::Message; use crate::qr::Qr; use crate::stock_str::backup_transfer_msg_body; use crate::tools::{create_id, time, TempPathGuard}; @@ -200,8 +200,7 @@ impl BackupProvider { info!(context, "Received backup reception acknowledgement."); context.emit_event(EventType::ImexProgress(1000)); - let mut msg = Message::new(Viewtype::Text); - msg.text = backup_transfer_msg_body(&context).await; + let mut msg = Message::new_text(backup_transfer_msg_body(&context).await); add_device_msg(&context, None, Some(&mut msg)).await?; Ok(()) @@ -369,6 +368,7 @@ mod tests { use std::time::Duration; use crate::chat::{get_chat_msgs, send_msg, ChatItem}; + use crate::message::Viewtype; use crate::test_utils::TestContextManager; use super::*; @@ -382,8 +382,7 @@ mod tests { // Write a message in the self chat let self_chat = ctx0.get_self_chat().await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hi there".to_string()); + let mut msg = Message::new_text("hi there".to_string()); send_msg(&ctx0, self_chat.id, &mut msg).await.unwrap(); // Send an attachment in the self chat diff --git a/src/location.rs b/src/location.rs index 289761f1d2..f2fa919b83 100644 --- a/src/location.rs +++ b/src/location.rs @@ -290,8 +290,7 @@ pub async fn send_locations_to_chat( ) .await?; if 0 != seconds && !is_sending_locations_before { - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_str::msg_location_enabled(context).await; + let mut msg = Message::new_text(stock_str::msg_location_enabled(context).await); msg.param.set_cmd(SystemMessage::LocationStreamingEnabled); chat::send_msg(context, chat_id, &mut msg) .await diff --git a/src/message.rs b/src/message.rs index 609d2bd39d..b4cb3d825f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -150,16 +150,17 @@ impl MsgId { pub(crate) async fn set_delivered(self, context: &Context) -> Result<()> { update_msg_state(context, self, MessageState::OutDelivered).await?; - let chat_id: ChatId = context + let chat_id: Option = context .sql .query_get_value("SELECT chat_id FROM msgs WHERE id=?", (self,)) - .await? - .unwrap_or_default(); + .await?; context.emit_event(EventType::MsgDelivered { - chat_id, + chat_id: chat_id.unwrap_or_default(), msg_id: self, }); - chatlist_events::emit_chatlist_item_changed(context, chat_id); + if let Some(chat_id) = chat_id { + chatlist_events::emit_chatlist_item_changed(context, chat_id); + } Ok(()) } @@ -491,6 +492,15 @@ impl Message { } } + /// Creates a new message with Viewtype::Text. + pub fn new_text(text: String) -> Self { + Message { + viewtype: Viewtype::Text, + text, + ..Default::default() + } + } + /// Loads message with given ID from the database. /// /// Returns an error if the message does not exist. @@ -1841,20 +1851,21 @@ pub(crate) async fn set_msg_failed( } msg.error = Some(error.to_string()); - context + let exists = context .sql .execute( "UPDATE msgs SET state=?, error=? WHERE id=?;", (msg.state, error, msg.id), ) - .await?; - + .await? + > 0; context.emit_event(EventType::MsgFailed { chat_id: msg.chat_id, msg_id: msg.id, }); - chatlist_events::emit_chatlist_item_changed(context, msg.chat_id); - + if exists { + chatlist_events::emit_chatlist_item_changed(context, msg.chat_id); + } Ok(()) } @@ -2333,8 +2344,7 @@ mod tests { let chat = d.create_chat_with_contact("", "dest@example.com").await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("Quoted message".to_string()); + let mut msg = Message::new_text("Quoted message".to_string()); // Prepare message for sending, so it gets a Message-Id. assert!(msg.rfc724_mid.is_empty()); @@ -2400,9 +2410,8 @@ mod tests { add_contact_to_chat(alice, alice_group, alice_flubby_contact_id).await?; // Alice quotes encrypted message in unencrypted chat. - let mut msg = Message::new(Viewtype::Text); + let mut msg = Message::new_text("unencrypted".to_string()); msg.set_quote(alice, Some(&alice_received_message)).await?; - msg.set_text("unencrypted".to_string()); chat::send_msg(alice, alice_group, &mut msg).await?; let bob_received_message = bob.recv_msg(&alice.pop_sent_msg().await).await; @@ -2460,8 +2469,7 @@ mod tests { .unwrap(); let contact = Contact::get_by_id(&alice, contact_id).await.unwrap(); - let mut msg = Message::new(Viewtype::Text); - msg.set_text("bla blubb".to_string()); + let mut msg = Message::new_text("bla blubb".to_string()); msg.set_override_sender_name(Some("over ride".to_string())); assert_eq!( msg.get_override_sender_name(), @@ -2508,8 +2516,7 @@ mod tests { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; let alice_chat = alice.create_chat(&bob).await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("this is the text!".to_string()); + let mut msg = Message::new_text("this is the text!".to_string()); // alice sends to bob, assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 0); @@ -2594,8 +2601,7 @@ mod tests { } // check outgoing messages states on sender side - let mut alice_msg = Message::new(Viewtype::Text); - alice_msg.set_text("hi!".to_string()); + let mut alice_msg = Message::new_text("hi!".to_string()); assert_eq!(alice_msg.get_state(), MessageState::Undefined); // message not yet in db, assert_state() won't work alice_chat @@ -2778,8 +2784,7 @@ def hello(): let chat = alice .create_chat_with_contact("Bob", "bob@example.org") .await; - let mut msg = Message::new(Viewtype::Text); - msg.set_text("hi".to_string()); + let mut msg = Message::new_text("hi".to_string()); assert!(chat::send_msg_sync(&alice, chat.id, &mut msg) .await .is_err()); diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 5983a1f935..4cafd4f385 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1982,8 +1982,7 @@ mod tests { group_id: ChatId, quote: Option<&Message>, ) -> Result { - let mut new_msg = Message::new(Viewtype::Text); - new_msg.set_text("Hi".to_string()); + let mut new_msg = Message::new_text("Hi".to_string()); if let Some(q) = quote { new_msg.set_quote(t, Some(q)).await?; } @@ -2069,8 +2068,7 @@ mod tests { let chat_id = ChatId::create_for_contact(&t, contact_id).await.unwrap(); - let mut new_msg = Message::new(Viewtype::Text); - new_msg.set_text("Hi".to_string()); + let mut new_msg = Message::new_text("Hi".to_string()); new_msg.chat_id = chat_id; chat::prepare_msg(&t, chat_id, &mut new_msg).await.unwrap(); @@ -2177,8 +2175,7 @@ mod tests { let chat_id = chats.get_chat_id(0).unwrap(); chat_id.accept(context).await.unwrap(); - let mut new_msg = Message::new(Viewtype::Text); - new_msg.set_text("Hi".to_string()); + let mut new_msg = Message::new_text("Hi".to_string()); new_msg.chat_id = chat_id; chat::prepare_msg(context, chat_id, &mut new_msg) .await @@ -2295,8 +2292,7 @@ mod tests { // send message to bob: that should get multipart/mixed because of the avatar moved to inner header; // make sure, `Subject:` stays in the outer header (imf header) - let mut msg = Message::new(Viewtype::Text); - msg.set_text("this is the text!".to_string()); + let mut msg = Message::new_text("this is the text!".to_string()); let sent_msg = t.send_msg(chat.id, &mut msg).await; let mut payload = sent_msg.payload().splitn(3, "\r\n\r\n"); @@ -2362,8 +2358,7 @@ mod tests { // send message to bob: that should get multipart/signed. // `Subject:` is protected by copying it. // make sure, `Subject:` stays in the outer header (imf header) - let mut msg = Message::new(Viewtype::Text); - msg.set_text("this is the text!".to_string()); + let mut msg = Message::new_text("this is the text!".to_string()); let sent_msg = t.send_msg(chat.id, &mut msg).await; let mut payload = sent_msg.payload().splitn(4, "\r\n\r\n"); @@ -2496,8 +2491,7 @@ mod tests { // send message to bob: that should get multipart/mixed because of the avatar moved to inner header; // make sure, `Subject:` stays in the outer header (imf header) - let mut msg = Message::new(Viewtype::Text); - msg.set_text("this is the text!".to_string()); + let mut msg = Message::new_text("this is the text!".to_string()); let sent_msg = t.send_msg(chat.id, &mut msg).await; let payload = sent_msg.payload(); diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 3c3e5bb24c..ee52147b0f 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -2237,12 +2237,22 @@ async fn handle_ndn( } else { "Delivery to at least one recipient failed.".to_string() }; + let err_msg = &error; let mut first = true; for msg in msgs { let (msg_id, chat_id, chat_type) = msg?; let mut message = Message::load_from_db(context, msg_id).await?; - set_msg_failed(context, &mut message, &error).await?; + let aggregated_error = message + .error + .as_ref() + .map(|err| format!("{}\n\n{}", err, err_msg)); + set_msg_failed( + context, + &mut message, + aggregated_error.as_ref().unwrap_or(err_msg), + ) + .await?; if first { // Add only one info msg for all failed messages ndn_maybe_add_info_msg(context, failed, chat_id, chat_type).await?; @@ -3595,11 +3605,24 @@ On 2020-10-25, Bob wrote: assert!(mimemsg.parts[0].msg.len() <= DC_DESIRED_TEXT_LEN + DC_ELLIPSIS.len()); } - { + for draft in [false, true] { let chat = t.get_self_chat().await; - t.send_text(chat.id, &long_txt).await; + let mut msg = Message::new_text(long_txt.clone()); + if draft { + chat.id.set_draft(&t, Some(&mut msg)).await?; + } + t.send_msg(chat.id, &mut msg).await; let msg = t.get_last_msg_in(chat.id).await; assert!(msg.has_html()); + assert_eq!( + msg.id + .get_html(&t) + .await? + .unwrap() + .matches("just repeated") + .count(), + REPEAT_CNT + ); assert!( msg.text.matches("just repeated").count() <= DC_DESIRED_TEXT_LEN / REPEAT_TXT.len() ); @@ -3607,7 +3630,6 @@ On 2020-10-25, Bob wrote: } t.set_config(Config::Bot, Some("1")).await?; - { let mimemsg = MimeMessage::from_bytes(&t, long_txt.as_ref(), None).await?; assert!(!mimemsg.is_mime_modified); diff --git a/src/peer_channels.rs b/src/peer_channels.rs index 504f3b3874..254c7dd3b6 100644 --- a/src/peer_channels.rs +++ b/src/peer_channels.rs @@ -590,17 +590,6 @@ mod tests { let alice = &mut tcm.alice().await; let bob = &mut tcm.bob().await; - bob.ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - - alice - .ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - // Alice sends webxdc to bob let alice_chat = alice.create_chat(bob).await; let mut instance = Message::new(Viewtype::File); @@ -739,17 +728,6 @@ mod tests { let alice = &mut tcm.alice().await; let bob = &mut tcm.bob().await; - bob.ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - - alice - .ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - assert!(alice .get_config_bool(Config::WebxdcRealtimeEnabled) .await @@ -907,17 +885,6 @@ mod tests { let alice = &mut tcm.alice().await; let bob = &mut tcm.bob().await; - bob.ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - - alice - .ctx - .set_config_bool(Config::WebxdcRealtimeEnabled, true) - .await - .unwrap(); - // Alice sends webxdc to bob let alice_chat = alice.create_chat(bob).await; let mut instance = Message::new(Viewtype::File); @@ -986,6 +953,11 @@ mod tests { let mut tcm = TestContextManager::new(); let alice = &mut tcm.alice().await; + alice + .set_config_bool(Config::WebxdcRealtimeEnabled, false) + .await + .unwrap(); + // creates iroh endpoint as side effect send_webxdc_realtime_advertisement(alice, MsgId::new(1)) .await diff --git a/src/qr.rs b/src/qr.rs index 22cfa2b958..dee84d5329 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -446,7 +446,7 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Result { if let (Some(addr), Some(invitenumber), Some(authcode)) = (&addr, invitenumber, authcode) { let addr = ContactAddress::new(addr)?; let (contact_id, _) = - Contact::add_or_lookup(context, &name, &addr, Origin::UnhandledQrScan) + Contact::add_or_lookup(context, &name, &addr, Origin::UnhandledSecurejoinQrScan) .await .with_context(|| format!("failed to add or lookup contact for address {addr:?}"))?; @@ -1270,7 +1270,8 @@ mod tests { if let Qr::AskVerifyContact { contact_id, .. } = qr { let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?; assert_eq!(contact.get_addr(), "cli@deltachat.de"); - assert_eq!(contact.get_name(), "Jörn P. P."); + assert_eq!(contact.get_authname(), "Jörn P. P."); + assert_eq!(contact.get_name(), ""); } else { bail!("Wrong QR code type"); } @@ -1285,6 +1286,7 @@ mod tests { if let Qr::AskVerifyContact { contact_id, .. } = qr { let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?; assert_eq!(contact.get_addr(), "cli@deltachat.de"); + assert_eq!(contact.get_authname(), ""); assert_eq!(contact.get_name(), ""); } else { bail!("Wrong QR code type"); diff --git a/src/quota.rs b/src/quota.rs index 9680a20464..0070a76ca3 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -11,7 +11,7 @@ use crate::config::Config; use crate::context::Context; use crate::imap::scan_folders::get_watched_folders; use crate::imap::session::Session as ImapSession; -use crate::message::{Message, Viewtype}; +use crate::message::Message; use crate::tools::{self, time_elapsed}; use crate::{stock_str, EventType}; @@ -142,8 +142,8 @@ impl Context { Some(&highest.to_string()), ) .await?; - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_str::quota_exceeding(self, highest).await; + let mut msg = + Message::new_text(stock_str::quota_exceeding(self, highest).await); add_device_msg_with_importance(self, None, Some(&mut msg), true).await?; } else if highest <= QUOTA_ALLCLEAR_PERCENTAGE { self.set_config_internal(Config::QuotaExceeding, None) diff --git a/src/reaction.rs b/src/reaction.rs index b621e914a7..6bb71f2a49 100644 --- a/src/reaction.rs +++ b/src/reaction.rs @@ -26,7 +26,7 @@ use crate::chatlist_events; use crate::contact::ContactId; use crate::context::Context; use crate::events::EventType; -use crate::message::{rfc724_mid_exists, Message, MsgId, Viewtype}; +use crate::message::{rfc724_mid_exists, Message, MsgId}; use crate::param::Param; /// A single reaction consisting of multiple emoji sequences. @@ -229,8 +229,7 @@ pub async fn send_reaction(context: &Context, msg_id: MsgId, reaction: &str) -> let chat_id = msg.chat_id; let reaction: Reaction = reaction.into(); - let mut reaction_msg = Message::new(Viewtype::Text); - reaction_msg.text = reaction.as_str().to_string(); + let mut reaction_msg = Message::new_text(reaction.as_str().to_string()); reaction_msg.set_reaction(); reaction_msg.in_reply_to = Some(msg.rfc724_mid); reaction_msg.hidden = true; diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 021c8bc52c..d057306b70 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -1093,8 +1093,8 @@ async fn add_parts( .await?; let now = tools::time(); let update_config = if last_time.saturating_add(24 * 60 * 60) <= now { - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_str::cant_decrypt_outgoing_msgs(context).await; + let mut msg = + Message::new_text(stock_str::cant_decrypt_outgoing_msgs(context).await); chat::add_device_msg(context, None, Some(&mut msg)) .await .log_err(context) diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index 9053306290..b9dd661cf6 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -883,6 +883,54 @@ async fn test_parse_ndn_group_msg() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_concat_multiple_ndns() -> Result<()> { + let t = TestContext::new().await; + t.configure_addr("alice@posteo.org").await; + let mid = "1234@mail.gmail.com"; + receive_imf( + &t, + b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\ + From: alice@posteo.org\n\ + To: hanerthaertidiuea@gmx.de\n\ + Subject: foo\n\ + Message-ID: <1234@mail.gmail.com>\n\ + Chat-Version: 1.0\n\ + Chat-Disposition-Notification-To: alice@example.org\n\ + Date: Sun, 22 Mar 2020 22:37:57 +0000\n\ + \n\ + hello\n", + false, + ) + .await?; + + let chats = Chatlist::try_load(&t, 0, None, None).await?; + let msg_id = chats.get_msg_id(0)?.unwrap(); + + let raw = include_str!("../../test-data/message/posteo_ndn.eml"); + let raw = raw.replace( + "Message-ID: <04422840-f884-3e37-5778-8192fe22d8e1@posteo.de>", + &format!("Message-ID: <{}>", mid), + ); + receive_imf(&t, raw.as_bytes(), false).await?; + + let msg = Message::load_from_db(&t, msg_id).await?; + + let err = "Undelivered Mail Returned to Sender – This is the mail system at host mout01.posteo.de.\n\nI'm sorry to have to inform you that your message could not\nbe delivered to one or more recipients. It's attached below.\n\nFor further assistance, please send mail to postmaster.\n\nIf you do so, please include this problem report. You can\ndelete your own text from the attached returned message.\n\n The mail system\n\n: host mx01.emig.gmx.net[212.227.17.5] said: 550\n Requested action not taken: mailbox unavailable (in reply to RCPT TO\n command)".to_string(); + assert_eq!(msg.error(), Some(err.clone())); + assert_eq!(msg.state, MessageState::OutFailed); + + let raw = raw.replace( + "Message-Id: <20200609184422.DCB6B1200DD@mout01.posteo.de>", + "Message-Id: ", + ); + receive_imf(&t, raw.as_bytes(), false).await?; + let msg = Message::load_from_db(&t, msg_id).await?; + + assert_eq!(msg.error(), Some([err.clone(), err].join("\n\n"))); + Ok(()) +} + async fn load_imf_email(context: &Context, imf_raw: &[u8]) -> Message { context .set_config(Config::ShowEmails, Some("2")) @@ -2178,8 +2226,7 @@ async fn test_no_smtp_job_for_self_chat() -> Result<()> { let bob = &tcm.bob().await; bob.set_config_bool(Config::BccSelf, false).await?; let chat_id = bob.get_self_chat().await.id; - let mut msg = Message::new(Viewtype::Text); - msg.text = "Happy birthday to me".to_string(); + let mut msg = Message::new_text("Happy birthday to me".to_string()); chat::send_msg(bob, chat_id, &mut msg).await?; assert!(bob.pop_sent_msg_opt(Duration::ZERO).await.is_none()); Ok(()) @@ -3298,8 +3345,7 @@ async fn test_outgoing_private_reply_multidevice() -> Result<()> { assert_eq!(received_group.name, "Group"); assert_eq!(received_group.can_send(&alice1).await?, false); // Can't send because it's Blocked::Request - let mut msg_out = Message::new(Viewtype::Text); - msg_out.set_text("Private reply".to_string()); + let mut msg_out = Message::new_text("Private reply".to_string()); assert_eq!(received_group.blocked, Blocked::Request); msg_out.set_quote(&alice1, Some(&received)).await?; @@ -3506,8 +3552,7 @@ async fn test_no_private_reply_to_blocked_account() -> Result<()> { let received_group = Chat::load_from_db(&alice, received.chat_id).await?; assert_eq!(received_group.typ, Chattype::Group); - let mut msg_out = Message::new(Viewtype::Text); - msg_out.set_text("Private reply".to_string()); + let mut msg_out = Message::new_text("Private reply".to_string()); msg_out.set_quote(&alice, Some(&received)).await?; let alice_bob_chat = alice.create_chat(&bob).await; diff --git a/src/scheduler.rs b/src/scheduler.rs index a901c7c971..fd987c0f01 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -655,9 +655,7 @@ async fn fetch_idle( ctx, "IMAP session does not support IDLE, going to fake idle." ); - connection - .fake_idle(ctx, &mut session, watch_folder, folder_meaning) - .await?; + connection.fake_idle(ctx, watch_folder).await?; return Ok(session); } @@ -669,9 +667,7 @@ async fn fetch_idle( .unwrap_or_default() { info!(ctx, "IMAP IDLE is disabled, going to fake idle."); - connection - .fake_idle(ctx, &mut session, watch_folder, folder_meaning) - .await?; + connection.fake_idle(ctx, watch_folder).await?; return Ok(session); } diff --git a/src/securejoin.rs b/src/securejoin.rs index 3b2a7ecb4d..9106e0cdd7 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -765,6 +765,7 @@ mod tests { WrongAliceGossip, SecurejoinWaitTimeout, AliceIsBot, + AliceHasName, } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -792,10 +793,21 @@ mod tests { test_setup_contact_ex(SetupContactCase::AliceIsBot).await } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_setup_contact_alice_has_name() { + test_setup_contact_ex(SetupContactCase::AliceHasName).await + } + async fn test_setup_contact_ex(case: SetupContactCase) { let mut tcm = TestContextManager::new(); let alice = tcm.alice().await; let alice_addr = &alice.get_config(Config::Addr).await.unwrap().unwrap(); + if case == SetupContactCase::AliceHasName { + alice + .set_config(Config::Displayname, Some("Alice")) + .await + .unwrap(); + } let bob = tcm.bob().await; bob.set_config(Config::Displayname, Some("Bob Examplenet")) .await @@ -840,7 +852,10 @@ mod tests { Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(), 1 ); - + let contact_alice_id = Contact::lookup_id_by_addr(&bob.ctx, alice_addr, Origin::Unknown) + .await + .expect("Error looking up contact") + .expect("Contact not found"); let sent = bob.pop_sent_msg().await; assert!(!sent.payload.contains("Bob Examplenet")); assert_eq!(sent.recipient(), EmailAddress::new(alice_addr).unwrap()); @@ -974,6 +989,7 @@ mod tests { .await .unwrap(); assert_eq!(contact_bob.get_authname(), "Bob Examplenet"); + assert!(contact_bob.get_name().is_empty()); assert_eq!(contact_bob.is_bot(), false); // exactly one one-to-one chat should be visible for both now @@ -1003,14 +1019,13 @@ mod tests { } // Make sure Alice hasn't yet sent their name to Bob. - let contact_alice_id = Contact::lookup_id_by_addr(&bob.ctx, alice_addr, Origin::Unknown) - .await - .expect("Error looking up contact") - .expect("Contact not found"); let contact_alice = Contact::get_by_id(&bob.ctx, contact_alice_id) .await .unwrap(); - assert_eq!(contact_alice.get_authname(), ""); + match case { + SetupContactCase::AliceHasName => assert_eq!(contact_alice.get_authname(), "Alice"), + _ => assert_eq!(contact_alice.get_authname(), ""), + }; // Check Alice sent the right message to Bob. let sent = alice.pop_sent_msg().await; @@ -1033,6 +1048,7 @@ mod tests { .await .unwrap(); assert_eq!(contact_alice.get_authname(), "Alice Exampleorg"); + assert!(contact_alice.get_name().is_empty()); assert_eq!(contact_alice.is_bot(), case == SetupContactCase::AliceIsBot); if case != SetupContactCase::SecurejoinWaitTimeout { diff --git a/src/smtp.rs b/src/smtp.rs index 9d73501ccd..0c1bd33d76 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -126,6 +126,7 @@ impl Smtp { let login_params = prioritize_server_login_params(&context.sql, login_params, "smtp").await?; + let mut first_error = None; for lp in login_params { info!(context, "SMTP trying to connect to {}.", &lp.connection); let transport = match connect::connect_and_auth( @@ -143,6 +144,7 @@ impl Smtp { Ok(transport) => transport, Err(err) => { warn!(context, "SMTP failed to connect and authenticate: {err:#}."); + first_error.get_or_insert(err); continue; } }; @@ -157,7 +159,7 @@ impl Smtp { return Ok(()); } - Err(format_err!("SMTP failed to connect")) + Err(first_error.unwrap_or_else(|| format_err!("No SMTP connection candidates provided"))) } } @@ -370,8 +372,10 @@ pub(crate) async fn send_msg_to_smtp( ) .await?; if retries > 6 { - let mut msg = Message::load_from_db(context, msg_id).await?; - message::set_msg_failed(context, &mut msg, "Number of retries exceeded the limit.").await?; + if let Some(mut msg) = Message::load_from_db_optional(context, msg_id).await? { + message::set_msg_failed(context, &mut msg, "Number of retries exceeded the limit.") + .await?; + } context .sql .execute("DELETE FROM smtp WHERE id=?", (rowid,)) diff --git a/src/sql.rs b/src/sql.rs index 827626481b..0356f851c6 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -17,7 +17,7 @@ use crate::ephemeral::start_ephemeral_timers; use crate::imex::BLOBS_BACKUP_NAME; use crate::location::delete_orphaned_poi_locations; use crate::log::LogExt; -use crate::message::{Message, MsgId, Viewtype}; +use crate::message::{Message, MsgId}; use crate::net::dns::prune_dns_cache; use crate::net::prune_connection_history; use crate::param::{Param, Params}; @@ -154,29 +154,28 @@ impl Sql { // don't have main database passphrase at this point. // See for documentation. // Without resetting import may fail due to existing tables. - let res = res.and_then(|_| { + res.and_then(|_| { conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, true) .context("failed to set SQLITE_DBCONFIG_RESET_DATABASE") - }); - let res = res.and_then(|_| { + }) + .and_then(|_| { conn.execute("VACUUM", []) .context("failed to vacuum the database") - }); - let res = res.and( + }) + .and( conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, false) .context("failed to unset SQLITE_DBCONFIG_RESET_DATABASE"), - ); - let res = res.and_then(|_| { + ) + .and_then(|_| { conn.query_row("SELECT sqlcipher_export('main', 'backup')", [], |_row| { Ok(()) }) .context("failed to import from attached backup database") - }); - let res = res.and( + }) + .and( conn.execute("DETACH DATABASE backup", []) .context("failed to detach backup database"), - ); - res?; + )?; Ok(()) }) .await @@ -247,8 +246,7 @@ impl Sql { // We now always watch all folders and delete messages there if delete_server is enabled. // So, for people who have delete_server enabled, disable it and add a hint to the devicechat: if context.get_config_delete_server_after().await?.is_some() { - let mut msg = Message::new(Viewtype::Text); - msg.set_text(stock_str::delete_server_turned_off(context).await); + let mut msg = Message::new_text(stock_str::delete_server_turned_off(context).await); add_device_msg(context, None, Some(&mut msg)).await?; context .set_config_internal(Config::DeleteServerAfter, Some("0")) @@ -1129,8 +1127,7 @@ mod tests { let t = TestContext::new_alice().await; let chat = t.create_chat_with_contact("bob", "bob@example.com").await; - let mut new_draft = Message::new(Viewtype::Text); - new_draft.set_text("This is my draft".to_string()); + let mut new_draft = Message::new_text("This is my draft".to_string()); chat.id.set_draft(&t, Some(&mut new_draft)).await.unwrap(); housekeeping(&t).await.unwrap(); diff --git a/src/stock_str.rs b/src/stock_str.rs index a9785f7dae..d03cc193d7 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -1419,8 +1419,7 @@ impl Context { msg.param.set(Param::File, blob.as_name()); chat::add_device_msg(self, Some("core-welcome-image"), Some(&mut msg)).await?; - let mut msg = Message::new(Viewtype::Text); - msg.text = welcome_message(self).await; + let mut msg = Message::new_text(welcome_message(self).await); chat::add_device_msg(self, Some("core-welcome"), Some(&mut msg)).await?; Ok(()) } diff --git a/src/summary.rs b/src/summary.rs index 3c68b7b72f..b0b81a281f 100644 --- a/src/summary.rs +++ b/src/summary.rs @@ -306,8 +306,7 @@ mod tests { .unwrap(); let some_text = " bla \t\n\tbla\n\t".to_string(); - let mut msg = Message::new(Viewtype::Text); - msg.set_text(some_text.to_string()); + let msg = Message::new_text(some_text.to_string()); assert_summary_texts(&msg, ctx, "bla bla").await; // for simple text, the type is not added to the summary let mut msg = Message::new(Viewtype::Image); @@ -416,8 +415,7 @@ mod tests { } // Forwarded - let mut msg = Message::new(Viewtype::Text); - msg.set_text(some_text.clone()); + let mut msg = Message::new_text(some_text.clone()); msg.param.set_int(Param::Forwarded, 1); assert_eq!(msg.get_summary_text(ctx).await, "Forwarded: bla bla"); // for simple text, the type is not added to the summary assert_eq!(msg.get_summary_text_without_prefix(ctx).await, "bla bla"); // skipping prefix used for reactions summaries diff --git a/src/test_utils.rs b/src/test_utils.rs index 5075298899..4a8473bc05 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -730,8 +730,7 @@ impl TestContext { /// [`TestContext::recv_msg`] with the returned [`SentMessage`] if it wants to receive /// the message. pub async fn send_text(&self, chat_id: ChatId, txt: &str) -> SentMessage<'_> { - let mut msg = Message::new(Viewtype::Text); - msg.text = txt.to_string(); + let mut msg = Message::new_text(txt.to_string()); self.send_msg(chat_id, &mut msg).await } diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 564cc231de..c8531c5844 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -6,7 +6,7 @@ use crate::chatlist::Chatlist; use crate::config::Config; use crate::constants::{Chattype, DC_GCL_FOR_FORWARDING}; use crate::contact::{Contact, ContactId, Origin}; -use crate::message::{Message, Viewtype}; +use crate::message::Message; use crate::mimefactory::MimeFactory; use crate::mimeparser::SystemMessage; use crate::receive_imf::receive_imf; @@ -716,8 +716,7 @@ async fn test_break_protection_then_verify_again() -> Result<()> { assert!(!alice_bob_chat.can_send(&alice).await?); // Alice's UI should still be able to save a draft, which Alice started to type right when she got Bob's message: - let mut msg = Message::new(Viewtype::Text); - msg.set_text("Draftttt".to_string()); + let mut msg = Message::new_text("Draftttt".to_string()); alice_bob_chat.id.set_draft(&alice, Some(&mut msg)).await?; assert_eq!( alice_bob_chat.id.get_draft(&alice).await?.unwrap().text, diff --git a/src/tools.rs b/src/tools.rs index 2b0f6618c1..89c50759d1 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -250,8 +250,7 @@ async fn maybe_warn_on_bad_time(context: &Context, now: i64, known_past_timestam async fn maybe_warn_on_outdated(context: &Context, now: i64, approx_compile_time: i64) { if now > approx_compile_time + DC_OUTDATED_WARNING_DAYS * 24 * 60 * 60 { - let mut msg = Message::new(Viewtype::Text); - msg.text = stock_str::update_reminder_msg_body(context).await; + let mut msg = Message::new_text(stock_str::update_reminder_msg_body(context).await); if let Some(timestamp) = chrono::DateTime::::from_timestamp(now, 0) { add_device_msg( context, diff --git a/src/webxdc/maps_integration.rs b/src/webxdc/maps_integration.rs index 38d3f5c0b1..4209d8710d 100644 --- a/src/webxdc/maps_integration.rs +++ b/src/webxdc/maps_integration.rs @@ -36,7 +36,7 @@ use crate::{chat, location}; use std::collections::{hash_map, HashMap}; use crate::context::Context; -use crate::message::{Message, MsgId, Viewtype}; +use crate::message::{Message, MsgId}; use crate::chat::ChatId; use crate::color::color_int_to_hex_string; @@ -85,8 +85,7 @@ pub(crate) async fn intercept_send_update( ChatId::create_for_contact(context, ContactId::SELF).await? }; - let mut poi_msg = Message::new(Viewtype::Text); - poi_msg.text = label; + let mut poi_msg = Message::new_text(label); poi_msg.set_location(lat, lng); chat::send_msg(context, chat_id, &mut poi_msg).await?; } else {