From 4b933ed2efb30b7dec201b43f3817e30be0f1d6c Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 4 Apr 2023 09:00:19 +0000 Subject: [PATCH 01/24] Update to iroh 0.4.1 --- CHANGELOG.md | 6 ++++++ Cargo.lock | 4 ++-- Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4073efa8b..ce8849900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.112.6 - unreleased + +### Fixed + +- Updated `iroh` from 0.4.0 to 0.4.1 to fix transfer of large accounts with many blob files. + ## [1.112.5] - 2023-04-02 ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 2aeaff170..e1e6f2f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2325,9 +2325,9 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "iroh" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c019223f5af15f978ff44ae02b8b83d21d53df4c42d4475aa80670819c3ecdce" +checksum = "e4fb9858c8cd3dd924a5da5bc511363845a9bcfdfac066bb2ef8454eb6111546" dependencies = [ "abao", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 9ff90b60f..d0546f1f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ futures-lite = "1.12.0" hex = "0.4.0" humansize = "2" image = { version = "0.24.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } -iroh = { version = "0.4.0", default-features = false } +iroh = { version = "0.4.1", default-features = false } kamadak-exif = "0.5" lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" } libc = "0.2" From a1f112470e0c1fe018cfb9c0564459bd2147005a Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 27 Mar 2023 14:21:43 +0200 Subject: [PATCH 02/24] add a device message when backup transfer ends that way, UI can just close the transfer dialog, so that, at the end, both devices end in the chatlist. we can also use this for troubleshooting - if the device message is not present, transfer did not succeed completely. (a separate device message may be nice in that case - but that is another effort, same for making the device message reappear after deletion or after some time) --- CHANGELOG.md | 4 ++++ deltachat-ffi/deltachat.h | 5 +++++ src/imex/transfer.rs | 11 +++++++++-- src/stock_str.rs | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce8849900..17b910756 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.112.6 - unreleased +### Changes + +- Add a device message after backup transfer #4301 + ### Fixed - Updated `iroh` from 0.4.0 to 0.4.1 to fix transfer of large accounts with many blob files. diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 3203d865d..c901ab738 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -7069,6 +7069,11 @@ void dc_event_unref(dc_event_t* event); /// `%1$s` will be replaced by name and address of the account. #define DC_STR_BACKUP_TRANSFER_QR 162 +/// "Account transferred to your second device." +/// +/// Used as a device message after a successful backup transfer. +#define DC_STR_BACKUP_TRANSFER_MSG_BODY 163 + /** * @} */ diff --git a/src/imex/transfer.rs b/src/imex/transfer.rs index e2a257511..f4d693922 100644 --- a/src/imex/transfer.rs +++ b/src/imex/transfer.rs @@ -47,9 +47,11 @@ use tokio_stream::wrappers::ReadDirStream; use tokio_util::sync::CancellationToken; use crate::blob::BlobDirContents; -use crate::chat::delete_and_reset_all_device_msgs; +use crate::chat::{add_device_msg, delete_and_reset_all_device_msgs}; use crate::context::Context; +use crate::message::{Message, Viewtype}; use crate::qr::Qr; +use crate::stock_str::backup_transfer_msg_body; use crate::{e2ee, EventType}; use super::{export_database, DBFILE_BACKUP_NAME}; @@ -270,7 +272,12 @@ impl BackupProvider { } }; match &res { - Ok(_) => context.emit_event(SendProgress::Completed.into()), + Ok(_) => { + context.emit_event(SendProgress::Completed.into()); + let mut msg = Message::new(Viewtype::Text); + msg.text = Some(backup_transfer_msg_body(context).await); + add_device_msg(context, None, Some(&mut msg)).await?; + } Err(err) => { error!(context, "Backup transfer failure: {err:#}"); context.emit_event(SendProgress::Failed.into()) diff --git a/src/stock_str.rs b/src/stock_str.rs index 6a1f3ccf6..d41e43057 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -407,6 +407,9 @@ pub enum StockMessage { #[strum(props(fallback = "Scan to set up second device for %1$s"))] BackupTransferQr = 162, + + #[strum(props(fallback = "ℹ️ Account transferred to your second device."))] + BackupTransferMsgBody = 163, } impl StockMessage { @@ -1261,6 +1264,10 @@ pub(crate) async fn backup_transfer_qr(context: &Context) -> Result { .replace1(&full_name)) } +pub(crate) async fn backup_transfer_msg_body(context: &Context) -> String { + translated(context, StockMessage::BackupTransferMsgBody).await +} + impl Context { /// Set the stock string for the [StockMessage]. /// From 26403a15996ba977bccf4fdcfcf3a75d3233d91a Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 4 Apr 2023 12:54:23 +0000 Subject: [PATCH 03/24] Update `spin` from 0.9.7 to 0.9.8 `spin` 0.9.7 is yanked: https://rustsec.org/advisories/RUSTSEC-2023-0031 --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1e6f2f15..c657c66d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1781,7 +1781,7 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin 0.9.7", + "spin 0.9.8", ] [[package]] @@ -4147,9 +4147,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ "lock_api", ] From 78d1aa46a11a0040747a36a0f602bc845f74c818 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 4 Apr 2023 14:21:02 +0200 Subject: [PATCH 04/24] update changelog for 1.112.6 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17b910756..86f676d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 1.112.6 - unreleased +## [1.112.6] - 2023-04-04 ### Changes From 0eb2f5bf52f11776a52a12f87b5389e4f9b4daf3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 4 Apr 2023 14:23:21 +0200 Subject: [PATCH 05/24] fix some CHANGELOG typos --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86f676d08..e3d6775d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,8 +30,8 @@ ### Changes - Update iroh, remove `default-net` from `[patch.crates-io]` section. -- transfer backup: Connect to mutliple provider addresses concurrently. This should speed up connection time significantly on the getter side. #4240 -- Make sure BackupProvider is cancelled on drop (or dc_backup_provider_unref). The BackupProvider will now alaway finish with an IMEX event of 1000 or 0, previoulsy it would sometimes finishe with 1000 (success) when it really was 0 (failure). #4242 +- transfer backup: Connect to multiple provider addresses concurrently. This should speed up connection time significantly on the getter side. #4240 +- Make sure BackupProvider is cancelled on drop (or `dc_backup_provider_unref`). The BackupProvider will now always finish with an IMEX event of 1000 or 0, previously it would sometimes finished with 1000 (success) when it really was 0 (failure). #4242 ### Fixes - Do not return media from trashed messages in the "All media" view. #4247 From 1b00334281b6db16a0628488e6908efcfdbbd3f8 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 4 Apr 2023 14:24:39 +0200 Subject: [PATCH 06/24] bump version to 1.112.6 --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- deltachat-ffi/Cargo.toml | 2 +- deltachat-jsonrpc/Cargo.toml | 2 +- deltachat-jsonrpc/typescript/package.json | 4 ++-- deltachat-repl/Cargo.toml | 2 +- deltachat-rpc-server/Cargo.toml | 2 +- package.json | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c657c66d0..5d9f4fa9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1061,7 +1061,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.112.5" +version = "1.112.6" dependencies = [ "ansi_term", "anyhow", @@ -1135,7 +1135,7 @@ dependencies = [ [[package]] name = "deltachat-jsonrpc" -version = "1.112.5" +version = "1.112.6" dependencies = [ "anyhow", "async-channel", @@ -1158,7 +1158,7 @@ dependencies = [ [[package]] name = "deltachat-repl" -version = "1.112.5" +version = "1.112.6" dependencies = [ "ansi_term", "anyhow", @@ -1173,7 +1173,7 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.112.5" +version = "1.112.6" dependencies = [ "anyhow", "deltachat", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.112.5" +version = "1.112.6" dependencies = [ "anyhow", "deltachat", diff --git a/Cargo.toml b/Cargo.toml index d0546f1f3..5deca72b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.112.5" +version = "1.112.6" edition = "2021" license = "MPL-2.0" rust-version = "1.64" diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index bdac367da..f6ed211e4 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.112.5" +version = "1.112.6" description = "Deltachat FFI" edition = "2018" readme = "README.md" diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 5a4504924..3360e7368 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.112.5" +version = "1.112.6" description = "DeltaChat JSON-RPC API" edition = "2021" default-run = "deltachat-jsonrpc-server" diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index 5121a87e2..16bf3ae20 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -55,5 +55,5 @@ }, "type": "module", "types": "dist/deltachat.d.ts", - "version": "1.112.5" -} + "version": "1.112.6" +} \ No newline at end of file diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index 91a72738e..c6cee05cf 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-repl" -version = "1.112.5" +version = "1.112.6" license = "MPL-2.0" edition = "2021" diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index c06856bbe..5edba509b 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-rpc-server" -version = "1.112.5" +version = "1.112.6" description = "DeltaChat JSON-RPC server" edition = "2021" readme = "README.md" diff --git a/package.json b/package.json index a06a0c3f5..9c07314bd 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,5 @@ "test:mocha": "mocha -r esm node/test/test.js --growl --reporter=spec --bail --exit" }, "types": "node/dist/index.d.ts", - "version": "1.112.5" -} + "version": "1.112.6" +} \ No newline at end of file From 185a0193cce60fd472a41e20205652176f7e552c Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 4 Apr 2023 12:56:13 +0000 Subject: [PATCH 07/24] Fix newline at the end of package.json --- deltachat-jsonrpc/typescript/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index 16bf3ae20..e2743bba7 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -56,4 +56,4 @@ "type": "module", "types": "dist/deltachat.d.ts", "version": "1.112.6" -} \ No newline at end of file +} diff --git a/package.json b/package.json index 9c07314bd..6716b8c01 100644 --- a/package.json +++ b/package.json @@ -61,4 +61,4 @@ }, "types": "node/dist/index.d.ts", "version": "1.112.6" -} \ No newline at end of file +} From c8988f5a55e52b350843cdf9f54d808b8761738d Mon Sep 17 00:00:00 2001 From: iequidoo Date: Fri, 31 Mar 2023 17:31:07 -0300 Subject: [PATCH 08/24] maybe_add_time_based_warnings(): Use release date instead of the provider DB update one (#4213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bjoern wrote: > maybe_add_time_based_warnings() requires some date guaranteed to be in the near past. based on this known date we check if the system clock is wrong (if earlier than known date) and if the used Delta Chat version may be outdated (1 year passed since known date). while this does not catch all situations, it catches quite some errors with comparable few effort. > > figuring out the date guaranteed to be in the near past is a bit tricky. that time, we added get_provider_update_timestamp() for exactly that purpose - it is checked manually by some dev and updated from time to time, usually before a release. > > however, meanwhile, the provider-db gets updated less frequently - things might be settled a bit more - and, get_provider_update_timestamp() was also changed to return the date of the last commit, instead of last run. while that seem to be more on-purpose, we cannot even do an “empty” database update to update the known date. > > as get_provider_update_timestamp() is not used for anything else, maybe we should completely remove that function and replace it by get_last_release_timestamp that is then updated by ./scripts/set_core_version.py - the result of that is reviewed manually anyway, so that seems to be a good place (i prefer manual review here and mistrust further automation as also dev or ci clocks may be wrong :) --- CHANGELOG.md | 1 + release-date.in | 1 + scripts/create-provider-data-rs.py | 2 +- scripts/set_core_version.py | 24 +++++++++--- src/lib.rs | 1 + src/provider.rs | 25 +----------- src/provider/data.rs | 2 +- src/release.rs | 10 +++++ src/tools.rs | 62 ++++++++++++++++++------------ 9 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 release-date.in create mode 100644 src/release.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f12fa4cf..470bd4af5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Remove upper limit on the attachment size. #4253 - Update rPGP to 0.10.1. #4236 - Compress `mime_headers` column with HTML emails stored in database +- maybe_add_time_based_warnings(): Use release date instead of the provider DB update one ### Fixes - Fix python bindings README documentation on installing the bindings from source. diff --git a/release-date.in b/release-date.in new file mode 100644 index 000000000..5dc1be6ba --- /dev/null +++ b/release-date.in @@ -0,0 +1 @@ +2023-04-04 \ No newline at end of file diff --git a/scripts/create-provider-data-rs.py b/scripts/create-provider-data-rs.py index 57f92428e..824e3354d 100755 --- a/scripts/create-provider-data-rs.py +++ b/scripts/create-provider-data-rs.py @@ -233,7 +233,7 @@ if __name__ == "__main__": else: now = datetime.datetime.fromisoformat(sys.argv[2]) out_all += ( - "pub static PROVIDER_UPDATED: Lazy = " + "pub static _PROVIDER_UPDATED: Lazy = " "Lazy::new(|| chrono::NaiveDate::from_ymd_opt(" + str(now.year) + ", " diff --git a/scripts/set_core_version.py b/scripts/set_core_version.py index 63e3ec205..cd6303cc9 100755 --- a/scripts/set_core_version.py +++ b/scripts/set_core_version.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import datetime import json import os import pathlib @@ -91,15 +92,25 @@ def main(): ffi_toml = read_toml_version("deltachat-ffi/Cargo.toml") assert core_toml == ffi_toml, (core_toml, ffi_toml) + today = datetime.date.today().isoformat() + if "alpha" not in newversion: - for line in open("CHANGELOG.md"): + changelog_name = "CHANGELOG.md" + changelog_tmpname = changelog_name + ".tmp" + changelog_tmp = open(changelog_tmpname, "w") + found = False + for line in open(changelog_name): ## 1.25.0 - if line.startswith("## [") and line[4:].strip().startswith(newversion): - break - else: + if line == f"## [{newversion}]\n": + line = f"## [{newversion}] - {today}\n" + found = True + changelog_tmp.write(line) + if not found: raise SystemExit( - f"CHANGELOG.md contains no entry for version: {newversion}" + f"{changelog_name} contains no entry for version: {newversion}" ) + changelog_tmp.close() + os.rename(changelog_tmpname, changelog_name) for toml_filename in toml_list: replace_toml_version(toml_filename, newversion) @@ -107,6 +118,9 @@ def main(): for json_filename in json_list: update_package_json(json_filename, newversion) + with open("release-date.in", "w") as f: + f.write(today) + print("running cargo check") subprocess.call(["cargo", "check"]) diff --git a/src/lib.rs b/src/lib.rs index 51a72a1d5..0e25cdd51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,7 @@ pub mod ephemeral; mod http; mod imap; pub mod imex; +pub mod release; mod scheduler; #[macro_use] mod job; diff --git a/src/provider.rs b/src/provider.rs index 2d37b1347..58e1cd517 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -3,12 +3,11 @@ mod data; use anyhow::Result; -use chrono::{NaiveDateTime, NaiveTime}; use trust_dns_resolver::{config, AsyncResolver, TokioAsyncResolver}; use crate::config::Config; use crate::context::Context; -use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS, PROVIDER_UPDATED}; +use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS}; /// Provider status according to manual testing. #[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] @@ -258,22 +257,12 @@ pub fn get_provider_by_id(id: &str) -> Option<&'static Provider> { } } -/// Returns update timestamp as a unix timestamp compatible for comparison with time() and database times. -pub fn get_provider_update_timestamp() -> i64 { - NaiveDateTime::new(*PROVIDER_UPDATED, NaiveTime::from_hms_opt(0, 0, 0).unwrap()) - .timestamp_millis() - / 1_000 -} - #[cfg(test)] mod tests { #![allow(clippy::indexing_slicing)] - use chrono::NaiveDate; - use super::*; use crate::test_utils::TestContext; - use crate::tools::time; #[test] fn test_get_provider_by_domain_unexistant() { @@ -336,18 +325,6 @@ mod tests { ); } - #[test] - fn test_get_provider_update_timestamp() { - let timestamp_past = NaiveDateTime::new( - NaiveDate::from_ymd_opt(2020, 9, 9).unwrap(), - NaiveTime::from_hms_opt(0, 0, 0).unwrap(), - ) - .timestamp_millis() - / 1_000; - assert!(get_provider_update_timestamp() <= time()); - assert!(get_provider_update_timestamp() > timestamp_past); - } - #[test] fn test_get_resolver() -> Result<()> { assert!(get_resolver().is_ok()); diff --git a/src/provider/data.rs b/src/provider/data.rs index 8ca9d91e9..32b1ff465 100644 --- a/src/provider/data.rs +++ b/src/provider/data.rs @@ -1945,5 +1945,5 @@ pub(crate) static PROVIDER_IDS: Lazy> = ]) }); -pub static PROVIDER_UPDATED: Lazy = +pub static _PROVIDER_UPDATED: Lazy = Lazy::new(|| chrono::NaiveDate::from_ymd_opt(2023, 2, 20).unwrap()); diff --git a/src/release.rs b/src/release.rs new file mode 100644 index 000000000..0545079ec --- /dev/null +++ b/src/release.rs @@ -0,0 +1,10 @@ +//! DC release info. + +use chrono::NaiveDate; +use once_cell::sync::Lazy; + +const DATE_STR: &str = include_str!("../release-date.in"); + +/// Last release date. +pub static DATE: Lazy = + Lazy::new(|| NaiveDate::parse_from_str(DATE_STR, "%Y-%m-%d").unwrap()); diff --git a/src/tools.rs b/src/tools.rs index 7ce5eacde..71874cf83 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -13,7 +13,7 @@ use std::time::{Duration, SystemTime}; use anyhow::{bail, Context as _, Result}; use base64::Engine as _; -use chrono::{Local, TimeZone}; +use chrono::{Local, NaiveDateTime, NaiveTime, TimeZone}; use futures::{StreamExt, TryStreamExt}; use mailparse::dateparse; use mailparse::headers::Headers; @@ -26,7 +26,6 @@ use crate::constants::{DC_ELLIPSIS, DC_OUTDATED_WARNING_DAYS}; use crate::context::Context; use crate::events::EventType; use crate::message::{Message, Viewtype}; -use crate::provider::get_provider_update_timestamp; use crate::stock_str; /// Shortens a string to a specified length and adds "[...]" to the @@ -163,12 +162,23 @@ pub(crate) fn create_smeared_timestamps(context: &Context, count: usize) -> i64 context.smeared_timestamp.create_n(now, count as i64) } +/// Returns the last release timestamp as a unix timestamp compatible for comparison with time() and +/// database times. +pub fn get_release_timestamp() -> i64 { + NaiveDateTime::new( + *crate::release::DATE, + NaiveTime::from_hms_opt(0, 0, 0).unwrap(), + ) + .timestamp_millis() + / 1_000 +} + // if the system time is not plausible, once a day, add a device message. // for testing we're using time() as that is also used for message timestamps. // moreover, add a warning if the app is outdated. pub(crate) async fn maybe_add_time_based_warnings(context: &Context) { - if !maybe_warn_on_bad_time(context, time(), get_provider_update_timestamp()).await { - maybe_warn_on_outdated(context, time(), get_provider_update_timestamp()).await; + if !maybe_warn_on_bad_time(context, time(), get_release_timestamp()).await { + maybe_warn_on_outdated(context, time(), get_release_timestamp()).await; } } @@ -1140,17 +1150,17 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; / 1_000; // a correct time must not add a device message - maybe_warn_on_bad_time(&t, timestamp_now, get_provider_update_timestamp()).await; + maybe_warn_on_bad_time(&t, timestamp_now, get_release_timestamp()).await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); assert_eq!(chats.len(), 0); // we cannot find out if a date in the future is wrong - a device message is not added - maybe_warn_on_bad_time(&t, timestamp_future, get_provider_update_timestamp()).await; + maybe_warn_on_bad_time(&t, timestamp_future, get_release_timestamp()).await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); assert_eq!(chats.len(), 0); // a date in the past must add a device message - maybe_warn_on_bad_time(&t, timestamp_past, get_provider_update_timestamp()).await; + maybe_warn_on_bad_time(&t, timestamp_past, get_release_timestamp()).await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); assert_eq!(chats.len(), 1); let device_chat_id = chats.get_chat_id(0).unwrap(); @@ -1158,31 +1168,21 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; assert_eq!(msgs.len(), 1); // the message should be added only once a day - test that an hour later and nearly a day later - maybe_warn_on_bad_time( - &t, - timestamp_past + 60 * 60, - get_provider_update_timestamp(), - ) - .await; + maybe_warn_on_bad_time(&t, timestamp_past + 60 * 60, get_release_timestamp()).await; let msgs = chat::get_chat_msgs(&t, device_chat_id).await.unwrap(); assert_eq!(msgs.len(), 1); maybe_warn_on_bad_time( &t, timestamp_past + 60 * 60 * 24 - 1, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; let msgs = chat::get_chat_msgs(&t, device_chat_id).await.unwrap(); assert_eq!(msgs.len(), 1); // next day, there should be another device message - maybe_warn_on_bad_time( - &t, - timestamp_past + 60 * 60 * 24, - get_provider_update_timestamp(), - ) - .await; + maybe_warn_on_bad_time(&t, timestamp_past + 60 * 60 * 24, get_release_timestamp()).await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); assert_eq!(chats.len(), 1); assert_eq!(device_chat_id, chats.get_chat_id(0).unwrap()); @@ -1200,7 +1200,7 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; maybe_warn_on_outdated( &t, timestamp_now + 180 * 24 * 60 * 60, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); @@ -1210,7 +1210,7 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; maybe_warn_on_outdated( &t, timestamp_now + 365 * 24 * 60 * 60, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); @@ -1224,13 +1224,13 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; maybe_warn_on_outdated( &t, timestamp_now + (365 + 1) * 24 * 60 * 60, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; maybe_warn_on_outdated( &t, timestamp_now + (365 + 2) * 24 * 60 * 60, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); @@ -1245,7 +1245,7 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; maybe_warn_on_outdated( &t, timestamp_now + (365 + 33) * 24 * 60 * 60, - get_provider_update_timestamp(), + get_release_timestamp(), ) .await; let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap(); @@ -1255,6 +1255,18 @@ DKIM Results: Passed=true, Works=true, Allow_Keychange=true"; assert_eq!(msgs.len(), test_len + 1); } + #[test] + fn test_get_release_timestamp() { + let timestamp_past = NaiveDateTime::new( + NaiveDate::from_ymd_opt(2020, 9, 9).unwrap(), + NaiveTime::from_hms_opt(0, 0, 0).unwrap(), + ) + .timestamp_millis() + / 1_000; + assert!(get_release_timestamp() <= time()); + assert!(get_release_timestamp() > timestamp_past); + } + #[test] fn test_remove_subject_prefix() { assert_eq!(remove_subject_prefix("Subject"), "Subject"); From 36bec9c295639c2c2bc627439b4b44e13c4483d7 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 4 Apr 2023 16:09:30 -0400 Subject: [PATCH 09/24] Update "accounts.toml" atomically (#4295) --- CHANGELOG.md | 1 + src/accounts.rs | 51 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 470bd4af5..2ba5fd561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### Fixes - Fix python bindings README documentation on installing the bindings from source. - Show a warning if quota list is empty #4261 +- Update "accounts.toml" atomically ## [1.112.6] - 2023-04-04 diff --git a/src/accounts.rs b/src/accounts.rs index f81c9a7ca..082057595 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use anyhow::{ensure, Context as _, Result}; use serde::{Deserialize, Serialize}; use tokio::fs; +use tokio::io::AsyncWriteExt; use uuid::Uuid; use crate::context::Context; @@ -301,7 +302,7 @@ pub const DB_NAME: &str = "dc.db"; /// Account manager configuration file. #[derive(Debug, Clone, PartialEq)] -pub struct Config { +struct Config { file: PathBuf, inner: InnerConfig, } @@ -325,10 +326,8 @@ impl Config { selected_account: 0, next_id: 1, }; - let cfg = Config { - file: dir.join(CONFIG_NAME), - inner, - }; + let file = dir.join(CONFIG_NAME); + let mut cfg = Self { file, inner }; cfg.sync().await?; @@ -336,10 +335,24 @@ impl Config { } /// Sync the inmemory representation to disk. - async fn sync(&self) -> Result<()> { - fs::write(&self.file, toml::to_string_pretty(&self.inner)?) + /// Takes a mutable reference because the saved file is a part of the `Config` state. This + /// protects from parallel calls resulting to a wrong file contents. + async fn sync(&mut self) -> Result<()> { + let tmp_path = self.file.with_extension("toml.tmp"); + let mut file = fs::File::create(&tmp_path) .await - .context("failed to write config") + .context("failed to create a tmp config")?; + file.write_all(toml::to_string_pretty(&self.inner)?.as_bytes()) + .await + .context("failed to write a tmp config")?; + file.sync_data() + .await + .context("failed to sync a tmp config")?; + drop(file); + fs::rename(&tmp_path, &self.file) + .await + .context("failed to rename config")?; + Ok(()) } /// Read a configuration from the given file into memory. @@ -359,7 +372,7 @@ impl Config { } } - let config = Self { file, inner }; + let mut config = Self { file, inner }; if modified { config.sync().await?; } @@ -503,17 +516,19 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts1"); - let mut accounts1 = Accounts::new(p.clone()).await.unwrap(); - accounts1.add_account().await.unwrap(); + { + let mut accounts = Accounts::new(p.clone()).await.unwrap(); + accounts.add_account().await.unwrap(); - let accounts2 = Accounts::open(p).await.unwrap(); + assert_eq!(accounts.accounts.len(), 1); + assert_eq!(accounts.config.get_selected_account(), 1); + } + { + let accounts = Accounts::open(p).await.unwrap(); - assert_eq!(accounts1.accounts.len(), 1); - assert_eq!(accounts1.config.get_selected_account(), 1); - - assert_eq!(accounts1.dir, accounts2.dir); - assert_eq!(accounts1.config, accounts2.config,); - assert_eq!(accounts1.accounts.len(), accounts2.accounts.len()); + assert_eq!(accounts.accounts.len(), 1); + assert_eq!(accounts.config.get_selected_account(), 1); + } } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] From eed8e081459a76047e8639dc225c9aaa567d1a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kl=C3=A4hn?= <39526136+Septias@users.noreply.github.com> Date: Fri, 7 Apr 2023 10:36:37 +0200 Subject: [PATCH 10/24] Protect against RTLO attacks (#3609) Protect against RTLO attackts --- CHANGELOG.md | 4 ++-- src/chat.rs | 39 +++++++++++++++++++++++++++++++++++++-- src/contact.rs | 23 ++++++++++++++--------- src/mimeparser.rs | 4 +++- src/receive_imf.rs | 9 ++++++--- src/tools.rs | 13 +++++++++++-- src/webxdc.rs | 9 ++++++--- 7 files changed, 79 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ba5fd561..b5d78e1c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,10 @@ - Remove upper limit on the attachment size. #4253 - Update rPGP to 0.10.1. #4236 - Compress `mime_headers` column with HTML emails stored in database +- Strip BIDI characters in system messages, files, group names and contact names #3479 - maybe_add_time_based_warnings(): Use release date instead of the provider DB update one + ### Fixes - Fix python bindings README documentation on installing the bindings from source. - Show a warning if quota list is empty #4261 @@ -219,7 +221,6 @@ - Do not treat invalid email addresses as an exception #3942 - Add timeouts to HTTP requests #3948 - ## 1.105.0 ### Changes @@ -305,7 +306,6 @@ - Disable read timeout during IMAP IDLE #3826 - Bots automatically accept mailing lists #3831 - ## 1.102.0 ### Changes diff --git a/src/chat.rs b/src/chat.rs index 8e505d32d..ef7c3b024 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -36,8 +36,8 @@ use crate::smtp::send_msg_to_smtp; use crate::stock_str; use crate::tools::{ buf_compress, create_id, create_outgoing_rfc724_mid, create_smeared_timestamp, - create_smeared_timestamps, get_abs_path, gm2local_offset, improve_single_line_input, time, - IsNoneOrEmpty, + create_smeared_timestamps, get_abs_path, gm2local_offset, improve_single_line_input, + strip_rtlo_characters, time, IsNoneOrEmpty, }; use crate::webxdc::WEBXDC_SUFFIX; use crate::{location, sql}; @@ -269,6 +269,7 @@ impl ChatId { create_protected: ProtectionStatus, param: Option, ) -> Result { + let grpname = strip_rtlo_characters(grpname); let row_id = context.sql.insert( "INSERT INTO chats (type, name, grpid, blocked, created_timestamp, protected, param) VALUES(?, ?, ?, ?, ?, ?, ?);", @@ -2208,6 +2209,13 @@ pub async fn send_msg_sync(context: &Context, chat_id: ChatId, msg: &mut Message } async fn send_msg_inner(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result { + // protect all system messages againts RTLO attacks + if msg.is_system_message() { + if let Some(text) = &msg.text { + msg.text = Some(strip_rtlo_characters(text.as_ref())); + } + } + if prepare_send_msg(context, chat_id, msg).await?.is_some() { context.emit_msgs_changed(msg.chat_id, msg.id); @@ -3808,6 +3816,7 @@ mod tests { use crate::message::delete_msgs; use crate::receive_imf::receive_imf; use crate::test_utils::TestContext; + use tokio::fs; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_info() { @@ -6107,4 +6116,30 @@ mod tests { Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_blob_renaming() -> Result<()> { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + let chat_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "Group").await?; + add_contact_to_chat( + &alice, + chat_id, + Contact::create(&alice, "bob", "bob@example.net").await?, + ) + .await?; + let dir = tempfile::tempdir()?; + let file = dir.path().join("harmless_file.\u{202e}txt.exe"); + fs::write(&file, "aaa").await?; + let mut msg = Message::new(Viewtype::File); + msg.set_file(file.to_str().unwrap(), None); + let msg = bob.recv_msg(&alice.send_msg(chat_id, &mut msg).await).await; + + // the file bob receives should not contain BIDI-control characters + assert_eq!( + Some("$BLOBDIR/harmless_file.txt.exe"), + msg.param.get(Param::File), + ); + Ok(()) + } } diff --git a/src/contact.rs b/src/contact.rs index 07430d308..c3ef90283 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -32,7 +32,10 @@ use crate::mimeparser::AvatarAction; use crate::param::{Param, Params}; use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::sql::{self, params_iter}; -use crate::tools::{duration_to_str, get_abs_path, improve_single_line_input, time, EmailAddress}; +use crate::tools::{ + duration_to_str, get_abs_path, improve_single_line_input, strip_rtlo_characters, time, + EmailAddress, +}; use crate::{chat, stock_str}; /// Time during which a contact is considered as seen recently. @@ -536,7 +539,7 @@ impl Contact { return Ok((ContactId::SELF, sth_modified)); } - let mut name = name; + let mut name = strip_rtlo_characters(name); #[allow(clippy::collapsible_if)] if origin <= Origin::OutgoingTo { // The user may accidentally have written to a "noreply" address with another MUA: @@ -551,7 +554,7 @@ impl Contact { // For these kind of email addresses, sender and address often don't belong together // (like hocuri ). In this example, hocuri shouldn't // be saved as the displayname for notifications@github.com. - name = ""; + name = "".to_string(); } } @@ -1291,18 +1294,20 @@ fn sanitize_name_and_addr(name: &str, addr: &str) -> (String, String) { if let Some(captures) = ADDR_WITH_NAME_REGEX.captures(addr.as_ref()) { ( if name.is_empty() { - captures - .get(1) - .map_or("".to_string(), |m| normalize_name(m.as_str())) + strip_rtlo_characters( + &captures + .get(1) + .map_or("".to_string(), |m| normalize_name(m.as_str())), + ) } else { - name.to_string() + strip_rtlo_characters(name) }, captures .get(2) .map_or("".to_string(), |m| m.as_str().to_string()), ) } else { - (name.to_string(), addr.to_string()) + (strip_rtlo_characters(name), addr.to_string()) } } @@ -1489,7 +1494,7 @@ pub fn normalize_name(full_name: &str) -> String { match full_name.as_bytes() { [b'\'', .., b'\''] | [b'\"', .., b'\"'] | [b'<', .., b'>'] => full_name .get(1..full_name.len() - 1) - .map_or("".to_string(), |s| s.trim().into()), + .map_or("".to_string(), |s| s.trim().to_string()), _ => full_name.to_string(), } } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index de5009ce4..f19e3af57 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -33,7 +33,7 @@ use crate::peerstate::Peerstate; use crate::simplify::{simplify, SimplifiedText}; use crate::stock_str; use crate::sync::SyncItems; -use crate::tools::{get_filemeta, parse_receive_headers, truncate_by_lines}; +use crate::tools::{get_filemeta, parse_receive_headers, strip_rtlo_characters, truncate_by_lines}; use crate::{location, tools}; /// A parsed MIME message. @@ -1952,6 +1952,8 @@ fn get_attachment_filename( }; } + let desired_filename = desired_filename.map(|filename| strip_rtlo_characters(&filename)); + Ok(desired_filename) } diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 01aaa4faa..8ee1b324c 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -37,7 +37,9 @@ use crate::reaction::{set_msg_reaction, Reaction}; use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device}; use crate::sql; use crate::stock_str; -use crate::tools::{buf_compress, extract_grpid_from_rfc724_mid, smeared_time}; +use crate::tools::{ + buf_compress, extract_grpid_from_rfc724_mid, smeared_time, strip_rtlo_characters, +}; use crate::{contact, imap}; /// This is the struct that is returned after receiving one email (aka MIME message). @@ -1077,7 +1079,7 @@ async fn add_parts( let mut created_db_entries = Vec::with_capacity(mime_parser.parts.len()); - for part in &mime_parser.parts { + for part in &mut mime_parser.parts { if part.is_reaction { set_msg_reaction( context, @@ -1093,6 +1095,7 @@ async fn add_parts( if is_system_message != SystemMessage::Unknown { param.set_int(Param::Cmd, is_system_message as i32); } + if let Some(replace_msg_id) = replace_msg_id { let placeholder = Message::load_from_db(context, replace_msg_id).await?; for key in [ @@ -1681,7 +1684,7 @@ async fn apply_group_changes( .sql .execute( "UPDATE chats SET name=? WHERE id=?;", - paramsv![grpname.to_string(), chat_id], + paramsv![strip_rtlo_characters(grpname), chat_id], ) .await?; send_event_chat_modified = true; diff --git a/src/tools.rs b/src/tools.rs index 71874cf83..23b66c934 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -560,9 +560,11 @@ impl rusqlite::types::ToSql for EmailAddress { } } -/// Makes sure that a user input that is not supposed to contain newlines does not contain newlines. +/// Sanitizes user input +/// - strip newlines +/// - strip malicious bidi characters pub(crate) fn improve_single_line_input(input: &str) -> String { - input.replace(['\n', '\r'], " ").trim().to_string() + strip_rtlo_characters(input.replace(['\n', '\r'], " ").trim()) } pub(crate) trait IsNoneOrEmpty { @@ -701,6 +703,13 @@ pub(crate) fn buf_decompress(buf: &[u8]) -> Result> { Ok(mem::take(decompressor.get_mut())) } +const RTLO_CHARACTERS: [char; 5] = ['\u{202A}', '\u{202B}', '\u{202C}', '\u{202D}', '\u{202E}']; +/// This method strips all occurances of the RTLO Unicode character. +/// [Why is this needed](https://github.com/deltachat/deltachat-core-rust/issues/3479)? +pub(crate) fn strip_rtlo_characters(input_str: &str) -> String { + input_str.replace(|char| RTLO_CHARACTERS.contains(&char), "") +} + #[cfg(test)] mod tests { #![allow(clippy::indexing_slicing)] diff --git a/src/webxdc.rs b/src/webxdc.rs index 07d7da54a..d1c92b350 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -20,6 +20,7 @@ use crate::mimeparser::SystemMessage; use crate::param::Param; use crate::param::Params; use crate::scheduler::InterruptInfo; +use crate::tools::strip_rtlo_characters; use crate::tools::{create_smeared_timestamp, get_abs_path}; use crate::{chat, EventType}; @@ -293,13 +294,13 @@ impl Context { can_info_msg: bool, from_id: ContactId, ) -> Result { - let update_str = update_str.trim(); + let update_str = strip_rtlo_characters(update_str.trim()); if update_str.is_empty() { bail!("create_status_update_record: empty update."); } let status_update_item: StatusUpdateItem = - if let Ok(item) = serde_json::from_str::(update_str) { + if let Ok(item) = serde_json::from_str::(&update_str) { item } else { bail!("create_status_update_record: no valid update item."); @@ -351,7 +352,9 @@ impl Context { .param .update_timestamp(Param::WebxdcSummaryTimestamp, timestamp)? { - instance.param.set(Param::WebxdcSummary, summary); + instance + .param + .set(Param::WebxdcSummary, strip_rtlo_characters(summary)); param_changed = true; } } From 11e6a325a2e50026d77863c14fdf0ede8fa71fcd Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 8 Apr 2023 18:27:35 +0000 Subject: [PATCH 11/24] ci: remove references to nonexistent matrix.rust --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4455ec2c6..f0659c359 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,7 @@ jobs: - name: Upload C library uses: actions/upload-artifact@v3 with: - name: ${{ matrix.os }}-${{matrix.rust}}-libdeltachat.a + name: ${{ matrix.os }}-libdeltachat.a path: target/debug/libdeltachat.a retention-days: 1 @@ -142,7 +142,7 @@ jobs: - name: Upload deltachat-rpc-server uses: actions/upload-artifact@v3 with: - name: ${{ matrix.os }}-${{matrix.rust}}-deltachat-rpc-server + name: ${{ matrix.os }}-deltachat-rpc-server path: target/debug/deltachat-rpc-server retention-days: 1 @@ -196,7 +196,7 @@ jobs: - name: Download libdeltachat.a uses: actions/download-artifact@v3 with: - name: ${{ matrix.os }}-${{matrix.rust}}-libdeltachat.a + name: ${{ matrix.os }}-libdeltachat.a path: target/debug - name: Install python @@ -255,7 +255,7 @@ jobs: - name: Download deltachat-rpc-server uses: actions/download-artifact@v3 with: - name: ${{ matrix.os }}-${{matrix.rust}}-deltachat-rpc-server + name: ${{ matrix.os }}-deltachat-rpc-server path: target/debug - name: Make deltachat-rpc-server executable From cecc080931f7915dee968ab18e09c625fd2ebbe4 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 11 Apr 2023 18:45:37 +0000 Subject: [PATCH 12/24] Update crossbeam-channel to 0.5.8 0.5.7 is yanked --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcde18ee5..2bebe7620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,9 +905,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", From f1eeb1df8cdaee9448bb1aabce05c724598e2cce Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 4 Apr 2023 11:33:48 -0400 Subject: [PATCH 13/24] Cleanly terminate deltachat-rpc-server (#4234) Do it as per "Thread safety" section in deltachat-ffi/deltachat.h. Also terminate on ctrl-c. --- CHANGELOG.md | 3 +- Cargo.lock | 1 + deltachat-rpc-server/Cargo.toml | 1 + deltachat-rpc-server/src/main.rs | 59 +++++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d78e1c3..07b14f765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ - Compress `mime_headers` column with HTML emails stored in database - Strip BIDI characters in system messages, files, group names and contact names #3479 - maybe_add_time_based_warnings(): Use release date instead of the provider DB update one - +- Cleanly terminate deltachat-rpc-server. + Also terminate on ctrl-c. ### Fixes - Fix python bindings README documentation on installing the bindings from source. diff --git a/Cargo.lock b/Cargo.lock index 2bebe7620..a2748fc7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1280,6 +1280,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "tokio-util", "yerpc", ] diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index d808da059..f66223ade 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -20,6 +20,7 @@ log = "0.4" serde_json = "1.0.95" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.27.0", features = ["io-std"] } +tokio-util = "0.7.7" yerpc = { version = "0.4.0", features = ["anyhow_expose"] } [features] diff --git a/deltachat-rpc-server/src/main.rs b/deltachat-rpc-server/src/main.rs index 1e957a38b..87df5fdf4 100644 --- a/deltachat-rpc-server/src/main.rs +++ b/deltachat-rpc-server/src/main.rs @@ -3,6 +3,7 @@ use std::env; ///! ///! It speaks JSON Lines over stdio. use std::path::PathBuf; +use std::sync::Arc; use anyhow::{anyhow, Context as _, Result}; use deltachat::constants::DC_VERSION_STR; @@ -10,7 +11,9 @@ use deltachat_jsonrpc::api::events::event_to_json_rpc_notification; use deltachat_jsonrpc::api::{Accounts, CommandApi}; use futures_lite::stream::StreamExt; use tokio::io::{self, AsyncBufReadExt, BufReader}; +use tokio::sync::RwLock; use tokio::task::JoinHandle; +use tokio_util::sync::CancellationToken; use yerpc::{RpcClient, RpcSession}; #[tokio::main(flavor = "multi_thread")] @@ -40,24 +43,38 @@ async fn main() -> Result<()> { let events = accounts.get_event_emitter(); log::info!("Creating JSON-RPC API."); - let state = CommandApi::new(accounts); + let accounts = Arc::new(RwLock::new(accounts)); + let state = CommandApi::from_arc(accounts.clone()); let (client, mut out_receiver) = RpcClient::new(); - let session = RpcSession::new(client.clone(), state); + let session = RpcSession::new(client.clone(), state.clone()); + let canceler = CancellationToken::new(); // Events task converts core events to JSON-RPC notifications. let events_task: JoinHandle> = tokio::spawn(async move { + let mut r = Ok(()); while let Some(event) = events.recv().await { + if r.is_err() { + continue; + } let event = event_to_json_rpc_notification(event); - client.send_notification("event", Some(event)).await?; + r = client.send_notification("event", Some(event)).await; } + r?; Ok(()) }); // Send task prints JSON responses to stdout. + let cancelable = canceler.clone(); let send_task: JoinHandle> = tokio::spawn(async move { - while let Some(message) = out_receiver.next().await { - let message = serde_json::to_string(&message)?; + loop { + let message = tokio::select! { + _ = cancelable.cancelled() => break, + message = out_receiver.next() => match message { + None => break, + Some(message) => serde_json::to_string(&message)?, + } + }; log::trace!("RPC send {}", message); println!("{message}"); } @@ -68,23 +85,41 @@ async fn main() -> Result<()> { let recv_task: JoinHandle> = tokio::spawn(async move { let stdin = io::stdin(); let mut lines = BufReader::new(stdin).lines(); - while let Some(message) = lines.next_line().await? { + loop { + let message = tokio::select! { + _ = tokio::signal::ctrl_c() => { + log::info!("got ctrl-c event"); + break; + } + message = lines.next_line() => match message? { + None => { + log::info!("EOF reached on stdin"); + break; + } + Some(message) => message, + } + }; log::trace!("RPC recv {}", message); let session = session.clone(); tokio::spawn(async move { session.handle_incoming(&message).await; }); } - log::info!("EOF reached on stdin"); Ok(()) }); - // Wait for the end of stdin. - recv_task.await??; + // Wait for the end of stdin / ctrl-c. + recv_task.await?.ok(); - // Shutdown the server. - send_task.abort(); - events_task.abort(); + // See "Thread safety" section in deltachat-ffi/deltachat.h for explanation. + // NB: Events are drained by events_task. + canceler.cancel(); + accounts.read().await.stop_io().await; + drop(state); + let (r0, r1) = tokio::join!(events_task, send_task); + for r in [r0, r1] { + r??; + } Ok(()) } From 619b849ce7a1c316ec85d6d3de700cd5ff5cc3fb Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 12 Apr 2023 22:12:46 +0000 Subject: [PATCH 14/24] sql: cleanup usage of ToSql Moved custom ToSql trait including Send + Sync from lib.rs to sql.rs. Replaced most params! and paramsv! macro usage with tuples. Replaced paramsv! and params_iterv! with params_slice!, because there is no need to construct a vector. --- src/authres.rs | 4 +- src/chat.rs | 181 ++++++++++++++++--------------------- src/chatlist.rs | 10 +- src/contact.rs | 59 ++++++------ src/context.rs | 62 ++++++------- src/download.rs | 4 +- src/ephemeral.rs | 57 +++++------- src/imap.rs | 38 ++++---- src/imex.rs | 9 +- src/job.rs | 28 +++--- src/key.rs | 8 +- src/lib.rs | 5 - src/location.rs | 38 ++++---- src/message.rs | 68 +++++++------- src/mimefactory.rs | 4 +- src/mimeparser.rs | 7 +- src/net.rs | 6 +- src/peerstate.rs | 18 ++-- src/reaction.rs | 8 +- src/receive_imf.rs | 13 +-- src/receive_imf/tests.rs | 2 +- src/securejoin/bobstate.rs | 14 +-- src/smtp.rs | 21 ++--- src/sql.rs | 66 ++++++-------- src/sql/migrations.rs | 4 +- src/sync.rs | 5 +- src/test_utils.rs | 2 +- src/token.rs | 12 +-- src/update_helper.rs | 4 +- src/webxdc.rs | 12 +-- 30 files changed, 349 insertions(+), 420 deletions(-) diff --git a/src/authres.rs b/src/authres.rs index 41e45e8cd..cc684e544 100644 --- a/src/authres.rs +++ b/src/authres.rs @@ -308,7 +308,7 @@ async fn dkim_works_timestamp(context: &Context, from_domain: &str) -> Result 0) @@ -435,10 +435,7 @@ impl ChatId { context .sql - .execute( - "UPDATE chats SET protected=? WHERE id=?;", - paramsv![protect, self], - ) + .execute("UPDATE chats SET protected=? WHERE id=?;", (protect, self)) .await?; context.emit_event(EventType::ChatModified(self)); @@ -524,12 +521,12 @@ impl ChatId { if visibility == ChatVisibility::Archived { transaction.execute( "UPDATE msgs SET state=? WHERE chat_id=? AND state=?;", - paramsv![MessageState::InNoticed, self, MessageState::InFresh], + (MessageState::InNoticed, self, MessageState::InFresh), )?; } transaction.execute( "UPDATE chats SET archived=? WHERE id=?;", - paramsv![visibility, self], + (visibility, self), )?; Ok(()) }) @@ -558,7 +555,7 @@ impl ChatId { .execute( "UPDATE chats SET archived=0 WHERE id=? AND archived=1 \ AND NOT(muted_until=-1 OR muted_until>?)", - paramsv![self, time()], + (self, time()), ) .await?; return Ok(()); @@ -576,7 +573,7 @@ impl ChatId { WHERE state=? AND hidden=0 AND chat_id=?", - paramsv![MessageState::InFresh, self], + (MessageState::InFresh, self), ) .await?; if unread_cnt == 1 { @@ -587,7 +584,7 @@ impl ChatId { } context .sql - .execute("UPDATE chats SET archived=0 WHERE id=?", paramsv![self]) + .execute("UPDATE chats SET archived=0 WHERE id=?", (self,)) .await?; Ok(()) } @@ -616,26 +613,23 @@ impl ChatId { .sql .execute( "DELETE FROM msgs_mdns WHERE msg_id IN (SELECT id FROM msgs WHERE chat_id=?);", - paramsv![self], + (self,), ) .await?; context .sql - .execute("DELETE FROM msgs WHERE chat_id=?;", paramsv![self]) + .execute("DELETE FROM msgs WHERE chat_id=?;", (self,)) .await?; context .sql - .execute( - "DELETE FROM chats_contacts WHERE chat_id=?;", - paramsv![self], - ) + .execute("DELETE FROM chats_contacts WHERE chat_id=?;", (self,)) .await?; context .sql - .execute("DELETE FROM chats WHERE id=?;", paramsv![self]) + .execute("DELETE FROM chats WHERE id=?;", (self,)) .await?; context.emit_msgs_changed_without_ids(); @@ -691,7 +685,7 @@ impl ChatId { .sql .query_get_value( "SELECT id FROM msgs WHERE chat_id=? AND state=?;", - paramsv![self, MessageState::OutDraft], + (self, MessageState::OutDraft), ) .await?; Ok(msg_id) @@ -773,14 +767,14 @@ impl ChatId { "UPDATE msgs SET timestamp=?,type=?,txt=?, param=?,mime_in_reply_to=? WHERE id=?;", - paramsv![ + ( time(), msg.viewtype, msg.text.as_deref().unwrap_or(""), msg.param.to_string(), msg.in_reply_to.as_deref().unwrap_or_default(), - msg.id - ], + msg.id, + ), ) .await?; return Ok(true); @@ -804,7 +798,7 @@ impl ChatId { hidden, mime_in_reply_to) VALUES (?,?,?, ?,?,?,?,?,?);", - paramsv![ + ( self, ContactId::SELF, time(), @@ -814,7 +808,7 @@ impl ChatId { msg.param.to_string(), 1, msg.in_reply_to.as_deref().unwrap_or_default(), - ], + ), ) .await?; msg.id = MsgId::new(row_id.try_into()?); @@ -827,7 +821,7 @@ impl ChatId { .sql .count( "SELECT COUNT(*) FROM msgs WHERE hidden=0 AND chat_id=?", - paramsv![self], + (self,), ) .await?; Ok(count) @@ -870,7 +864,7 @@ impl ChatId { WHERE state=? AND hidden=0 AND chat_id=?;", - paramsv![MessageState::InFresh, self], + (MessageState::InFresh, self), ) .await? }; @@ -880,7 +874,7 @@ impl ChatId { pub(crate) async fn get_param(self, context: &Context) -> Result { let res: Option = context .sql - .query_get_value("SELECT param FROM chats WHERE id=?", paramsv![self]) + .query_get_value("SELECT param FROM chats WHERE id=?", (self,)) .await?; Ok(res .map(|s| s.parse().unwrap_or_default()) @@ -925,13 +919,13 @@ impl ChatId { let row = sql .query_row_optional( &query, - paramsv![ + ( self, MessageState::OutPreparing, MessageState::OutDraft, MessageState::OutPending, - MessageState::OutFailed - ], + MessageState::OutFailed, + ), f, ) .await?; @@ -1053,10 +1047,7 @@ impl ChatId { pub async fn get_gossiped_timestamp(self, context: &Context) -> Result { let timestamp: Option = context .sql - .query_get_value( - "SELECT gossiped_timestamp FROM chats WHERE id=?;", - paramsv![self], - ) + .query_get_value("SELECT gossiped_timestamp FROM chats WHERE id=?;", (self,)) .await?; Ok(timestamp.unwrap_or_default()) } @@ -1079,7 +1070,7 @@ impl ChatId { .sql .execute( "UPDATE chats SET gossiped_timestamp=? WHERE id=?;", - paramsv![timestamp, self], + (timestamp, self), ) .await?; @@ -1175,7 +1166,7 @@ impl Chat { c.blocked, c.locations_send_until, c.muted_until, c.protected FROM chats c WHERE c.id=?;", - paramsv![chat_id], + (chat_id,), |row| { let c = Chat { id: chat_id, @@ -1289,7 +1280,7 @@ impl Chat { .sql .execute( "UPDATE chats SET param=? WHERE id=?", - paramsv![self.param.to_string(), self.id], + (self.param.to_string(), self.id), ) .await?; Ok(()) @@ -1471,7 +1462,7 @@ impl Chat { .sql .query_get_value( "SELECT contact_id FROM chats_contacts WHERE chat_id=?;", - paramsv![self.id], + (self.id,), ) .await? { @@ -1552,13 +1543,13 @@ impl Chat { "INSERT INTO locations \ (timestamp,from_id,chat_id, latitude,longitude,independent)\ VALUES (?,?,?, ?,?,1);", - paramsv![ + ( timestamp, ContactId::SELF, self.id, msg.param.get_float(Param::SetLatitude).unwrap_or_default(), msg.param.get_float(Param::SetLongitude).unwrap_or_default(), - ], + ), ) .await { @@ -1604,7 +1595,7 @@ impl Chat { mime_headers=?, mime_compressed=1, location_id=?, ephemeral_timer=?, ephemeral_timestamp=? WHERE id=?;", - paramsv![ + params_slice![ new_rfc724_mid, self.id, ContactId::SELF, @@ -1653,7 +1644,7 @@ impl Chat { ephemeral_timer, ephemeral_timestamp) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,?,?,?);", - paramsv![ + params_slice![ new_rfc724_mid, self.id, ContactId::SELF, @@ -1864,7 +1855,7 @@ async fn update_special_chat_name( .sql .execute( "UPDATE chats SET name=? WHERE id=? AND name!=?", - paramsv![name, chat_id, name], + (&name, chat_id, &name), ) .await?; } @@ -1927,7 +1918,7 @@ impl ChatIdBlocked { WHERE c.type=100 -- 100 = Chattype::Single AND c.id>9 -- 9 = DC_CHAT_ID_LAST_SPECIAL AND j.contact_id=?;", - paramsv![contact_id], + (contact_id,), |row| { let id: ChatId = row.get(0)?; let blocked: Blocked = row.get(1)?; @@ -1978,13 +1969,13 @@ impl ChatIdBlocked { "INSERT INTO chats (type, name, param, blocked, created_timestamp) VALUES(?, ?, ?, ?, ?)", - params![ + ( Chattype::Single, chat_name, params.to_string(), create_blocked as u8, - create_smeared_timestamp(context) - ], + create_smeared_timestamp(context), + ), )?; let chat_id = ChatId::new( transaction @@ -1997,7 +1988,7 @@ impl ChatIdBlocked { "INSERT INTO chats_contacts (chat_id, contact_id) VALUES((SELECT last_insert_rowid()), ?)", - params![contact_id], + (contact_id,), )?; Ok(chat_id) @@ -2157,7 +2148,7 @@ pub async fn is_contact_in_chat( .sql .exists( "SELECT COUNT(*) FROM chats_contacts WHERE chat_id=? AND contact_id=?;", - paramsv![chat_id, contact_id], + (chat_id, contact_id), ) .await?; Ok(exists) @@ -2378,12 +2369,12 @@ async fn create_send_msg_job(context: &Context, msg_id: MsgId) -> Result Result<()> .sql .exists( "SELECT COUNT(*) FROM msgs WHERE state=? AND hidden=0 AND chat_id=?;", - paramsv![MessageState::InFresh, chat_id], + (MessageState::InFresh, chat_id), ) .await?; if !exists { @@ -2645,7 +2636,7 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()> WHERE state=? AND hidden=0 AND chat_id=?;", - paramsv![MessageState::InNoticed, MessageState::InFresh, chat_id], + (MessageState::InNoticed, MessageState::InFresh, chat_id), ) .await?; } @@ -2694,12 +2685,12 @@ pub(crate) async fn mark_old_messages_as_noticed( AND hidden=0 AND chat_id=? AND timestamp<=?;", - paramsv![ + ( MessageState::InNoticed, MessageState::InFresh, msg.chat_id, - msg.sort_timestamp - ], + msg.sort_timestamp, + ), )?; if changed_rows > 0 { changed_chats.push(msg.chat_id); @@ -2747,7 +2738,7 @@ pub async fn get_chat_media( AND (type=? OR type=? OR type=?) AND hidden=0 ORDER BY timestamp, id;", - paramsv![ + ( chat_id.is_none(), chat_id.unwrap_or_else(|| ChatId::new(0)), DC_CHAT_ID_TRASH, @@ -2762,7 +2753,7 @@ pub async fn get_chat_media( } else { msg_type }, - ], + ), |row| row.get::<_, MsgId>(0), |ids| Ok(ids.flatten().collect()), ) @@ -2840,7 +2831,7 @@ pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result(0), |ids| ids.collect::, _>>().map_err(Into::into), ) @@ -2866,12 +2857,12 @@ pub async fn create_group_chat( "INSERT INTO chats (type, name, grpid, param, created_timestamp) VALUES(?, ?, ?, \'U=1\', ?);", - paramsv![ + ( Chattype::Group, chat_name, grpid, create_smeared_timestamp(context), - ], + ), ) .await?; @@ -2904,7 +2895,7 @@ async fn find_unused_broadcast_list_name(context: &Context) -> Result { .sql .exists( "SELECT COUNT(*) FROM chats WHERE type=? AND name=?;", - paramsv![Chattype::Broadcast, better_name], + (Chattype::Broadcast, &better_name), ) .await? { @@ -2924,12 +2915,12 @@ pub async fn create_broadcast_list(context: &Context) -> Result { "INSERT INTO chats (type, name, grpid, param, created_timestamp) VALUES(?, ?, ?, \'U=1\', ?);", - paramsv![ + ( Chattype::Broadcast, chat_name, grpid, create_smeared_timestamp(context), - ], + ), ) .await?; let chat_id = ChatId::new(u32::try_from(row_id)?); @@ -2950,7 +2941,7 @@ pub(crate) async fn add_to_chat_contacts_table( for contact_id in contact_ids { transaction.execute( "INSERT OR IGNORE INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)", - paramsv![chat_id, contact_id], + (chat_id, contact_id), )?; } Ok(()) @@ -2970,7 +2961,7 @@ pub(crate) async fn remove_from_chat_contacts_table( .sql .execute( "DELETE FROM chats_contacts WHERE chat_id=? AND contact_id=?", - paramsv![chat_id, contact_id], + (chat_id, contact_id), ) .await?; Ok(()) @@ -3088,7 +3079,7 @@ pub(crate) async fn shall_attach_selfavatar(context: &Context, chat_id: ChatId) FROM chats_contacts cc LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? AND cc.contact_id!=?;", - paramsv![chat_id, ContactId::SELF], + (chat_id, ContactId::SELF), |row| Ok(row.get::<_, i64>(0)), |rows| { let mut needs_attach = false; @@ -3161,7 +3152,7 @@ pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuratio .sql .execute( "UPDATE chats SET muted_until=? WHERE id=?;", - paramsv![duration, chat_id], + (duration, chat_id), ) .await .context(format!("Failed to set mute duration for {chat_id}"))?; @@ -3248,10 +3239,7 @@ async fn set_group_explicitly_left(context: &Context, grpid: &str) -> Result<()> if !is_group_explicitly_left(context, grpid).await? { context .sql - .execute( - "INSERT INTO leftgrps (grpid) VALUES(?);", - paramsv![grpid.to_string()], - ) + .execute("INSERT INTO leftgrps (grpid) VALUES(?);", (grpid,)) .await?; } @@ -3261,10 +3249,7 @@ async fn set_group_explicitly_left(context: &Context, grpid: &str) -> Result<()> pub(crate) async fn is_group_explicitly_left(context: &Context, grpid: &str) -> Result { let exists = context .sql - .exists( - "SELECT COUNT(*) FROM leftgrps WHERE grpid=?;", - paramsv![grpid], - ) + .exists("SELECT COUNT(*) FROM leftgrps WHERE grpid=?;", (grpid,)) .await?; Ok(exists) } @@ -3296,7 +3281,7 @@ pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) - .sql .execute( "UPDATE chats SET name=? WHERE id=?;", - paramsv![new_name.to_string(), chat_id], + (new_name.to_string(), chat_id), ) .await?; if chat.is_promoted() @@ -3549,7 +3534,7 @@ pub(crate) async fn get_chat_id_by_grpid( .sql .query_row_optional( "SELECT id, blocked, protected FROM chats WHERE grpid=?;", - paramsv![grpid], + (grpid,), |row| { let chat_id = row.get::<_, ChatId>(0)?; @@ -3603,7 +3588,7 @@ pub async fn add_device_msg_with_importance( .sql .query_get_value( "SELECT MAX(timestamp) FROM msgs WHERE chat_id=?", - paramsv![chat_id], + (chat_id,), ) .await? { @@ -3628,7 +3613,7 @@ pub async fn add_device_msg_with_importance( param, rfc724_mid) VALUES (?,?,?,?,?,?,?,?,?,?,?);", - paramsv![ + ( chat_id, ContactId::DEVICE, ContactId::SELF, @@ -3640,7 +3625,7 @@ pub async fn add_device_msg_with_importance( msg.text.as_ref().cloned().unwrap_or_default(), msg.param.to_string(), rfc724_mid, - ], + ), ) .await?; @@ -3653,10 +3638,7 @@ pub async fn add_device_msg_with_importance( if let Some(label) = label { context .sql - .execute( - "INSERT INTO devmsglabels (label) VALUES (?);", - paramsv![label.to_string()], - ) + .execute("INSERT INTO devmsglabels (label) VALUES (?);", (label,)) .await?; } @@ -3683,7 +3665,7 @@ pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result .sql .exists( "SELECT COUNT(label) FROM devmsglabels WHERE label=?", - paramsv![label], + (label,), ) .await?; @@ -3700,10 +3682,7 @@ pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Result<()> { context .sql - .execute( - "DELETE FROM msgs WHERE from_id=?;", - paramsv![ContactId::DEVICE], - ) + .execute("DELETE FROM msgs WHERE from_id=?;", (ContactId::DEVICE,)) .await?; context.sql.execute("DELETE FROM devmsglabels;", ()).await?; @@ -3746,7 +3725,7 @@ pub(crate) async fn add_info_msg_with_cmd( context.sql.insert( "INSERT INTO msgs (chat_id,from_id,to_id,timestamp,timestamp_sent,timestamp_rcvd,type,state,txt,rfc724_mid,ephemeral_timer, param,mime_in_reply_to) VALUES (?,?,?, ?,?,?,?,?, ?,?,?, ?,?);", - paramsv![ + ( chat_id, from_id.unwrap_or(ContactId::INFO), ContactId::INFO, @@ -3760,7 +3739,7 @@ pub(crate) async fn add_info_msg_with_cmd( ephemeral_timer, param.to_string(), parent.map(|msg|msg.rfc724_mid.clone()).unwrap_or_default() - ] + ) ).await?; let msg_id = MsgId::new(row_id.try_into()?); @@ -3800,7 +3779,7 @@ pub(crate) async fn update_msg_text_and_timestamp( .sql .execute( "UPDATE msgs SET txt=?, timestamp=? WHERE id=?;", - paramsv![text, timestamp, msg_id], + (text, timestamp, msg_id), ) .await?; context.emit_msgs_changed(chat_id, msg_id); diff --git a/src/chatlist.rs b/src/chatlist.rs index 038c061a6..ddd60c072 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -137,7 +137,7 @@ impl Chatlist { AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?2) GROUP BY c.id ORDER BY c.archived=?3 DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - paramsv![MessageState::OutDraft, query_contact_id, ChatVisibility::Pinned], + (MessageState::OutDraft, query_contact_id, ChatVisibility::Pinned), process_row, process_rows, ).await? @@ -164,7 +164,7 @@ impl Chatlist { AND c.archived=1 GROUP BY c.id ORDER BY IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - paramsv![MessageState::OutDraft], + (MessageState::OutDraft,), process_row, process_rows, ) @@ -198,7 +198,7 @@ impl Chatlist { AND c.name LIKE ?3 GROUP BY c.id ORDER BY IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - paramsv![MessageState::OutDraft, skip_id, str_like_cmd], + (MessageState::OutDraft, skip_id, str_like_cmd), process_row, process_rows, ) @@ -228,7 +228,7 @@ impl Chatlist { AND NOT c.archived=?4 GROUP BY c.id ORDER BY c.id=?5 DESC, c.archived=?6 DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - paramsv![MessageState::OutDraft, skip_id, flag_for_forwarding, ChatVisibility::Archived, sort_id_up, ChatVisibility::Pinned], + (MessageState::OutDraft, skip_id, flag_for_forwarding, ChatVisibility::Archived, sort_id_up, ChatVisibility::Pinned), process_row, process_rows, ).await?; @@ -356,7 +356,7 @@ pub async fn get_archived_cnt(context: &Context) -> Result { .sql .count( "SELECT COUNT(*) FROM chats WHERE blocked!=? AND archived=?;", - paramsv![Blocked::Yes, ChatVisibility::Archived], + (Blocked::Yes, ChatVisibility::Archived), ) .await?; Ok(count) diff --git a/src/contact.rs b/src/contact.rs index c3ef90283..a9f48009c 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -347,7 +347,7 @@ impl Contact { c.authname, c.param, c.status FROM contacts c WHERE c.id=?;", - paramsv![contact_id], + (contact_id,), |row| { let name: String = row.get(0)?; let addr: String = row.get(1)?; @@ -460,7 +460,7 @@ impl Contact { .sql .execute( "UPDATE msgs SET state=? WHERE from_id=? AND state=?;", - paramsv![MessageState::InNoticed, id, MessageState::InFresh], + (MessageState::InNoticed, id, MessageState::InFresh), ) .await?; Ok(()) @@ -493,7 +493,7 @@ impl Contact { "SELECT id FROM contacts \ WHERE addr=?1 COLLATE NOCASE \ AND id>?2 AND origin>=?3 AND blocked=0;", - paramsv![addr_normalized, ContactId::LAST_SPECIAL, min_origin as u32,], + (&addr_normalized, ContactId::LAST_SPECIAL, min_origin as u32), ) .await?; Ok(id) @@ -608,7 +608,7 @@ impl Contact { transaction .execute( "UPDATE contacts SET name=?, addr=?, origin=?, authname=? WHERE id=?;", - paramsv![ + ( new_name, if update_addr { addr.to_string() @@ -626,7 +626,7 @@ impl Contact { row_authname }, row_id - ], + ), )?; if update_name || update_authname { @@ -634,7 +634,7 @@ impl Contact { // This is one of the few duplicated data, however, getting the chat list is easier this way. let chat_id: Option = transaction.query_row( "SELECT id FROM chats WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)", - params![Chattype::Single, isize::try_from(row_id)?], + (Chattype::Single, isize::try_from(row_id)?), |row| { let chat_id: ChatId = row.get(0)?; Ok(chat_id) @@ -648,7 +648,7 @@ impl Contact { "SELECT addr, name, authname FROM contacts WHERE id=?", - params![contact_id], + (contact_id,), |row| { let addr: String = row.get(0)?; let name: String = row.get(1)?; @@ -666,7 +666,7 @@ impl Contact { let count = transaction.execute( "UPDATE chats SET name=?1 WHERE id=?2 AND name!=?1", - params![chat_name, chat_id])?; + (chat_name, chat_id))?; if count > 0 { // Chat name updated @@ -684,7 +684,7 @@ impl Contact { .execute( "INSERT INTO contacts (name, addr, origin, authname) VALUES (?, ?, ?, ?);", - params![ + ( if update_name { name.to_string() } else { @@ -697,7 +697,7 @@ impl Contact { } else { "".to_string() } - ], + ), )?; sth_modified = Modifier::Created; @@ -798,12 +798,12 @@ impl Contact { ORDER BY c.last_seen DESC, c.id DESC;", sql::repeat_vars(self_addrs.len()) ), - rusqlite::params_from_iter(params_iter(&self_addrs).chain(params_iterv![ + rusqlite::params_from_iter(params_iter(&self_addrs).chain(params_slice![ ContactId::LAST_SPECIAL, Origin::IncomingReplyTo, s3str_like_cmd, s3str_like_cmd, - if flag_verified_only { 0i32 } else { 1i32 }, + if flag_verified_only { 0i32 } else { 1i32 } ])), |row| row.get::<_, ContactId>(0), |ids| { @@ -850,7 +850,7 @@ impl Contact { ORDER BY last_seen DESC, id DESC;", sql::repeat_vars(self_addrs.len()) ), - rusqlite::params_from_iter(params_iter(&self_addrs).chain(params_iterv![ + rusqlite::params_from_iter(params_iter(&self_addrs).chain(params_slice![ ContactId::LAST_SPECIAL, Origin::IncomingReplyTo ])), @@ -883,7 +883,7 @@ impl Contact { .transaction(move |transaction| { let mut stmt = transaction .prepare("SELECT name, grpid FROM chats WHERE type=? AND blocked=?")?; - let rows = stmt.query_map(params![Chattype::Mailinglist, Blocked::Yes], |row| { + let rows = stmt.query_map((Chattype::Mailinglist, Blocked::Yes), |row| { let name: String = row.get(0)?; let grpid: String = row.get(1)?; Ok((name, grpid)) @@ -905,7 +905,7 @@ impl Contact { // Always do an update in case the blocking is reset or name is changed. transaction.execute( "UPDATE contacts SET name=?, origin=?, blocked=1 WHERE addr=?", - params![&name, Origin::MailinglistAddress, &grpid], + (&name, Origin::MailinglistAddress, &grpid), )?; } Ok(()) @@ -920,7 +920,7 @@ impl Contact { .sql .count( "SELECT COUNT(*) FROM contacts WHERE id>? AND blocked!=0", - paramsv![ContactId::LAST_SPECIAL], + (ContactId::LAST_SPECIAL,), ) .await?; Ok(count) @@ -936,7 +936,7 @@ impl Contact { .sql .query_map( "SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY last_seen DESC, id DESC;", - paramsv![ContactId::LAST_SPECIAL], + (ContactId::LAST_SPECIAL,), |row| row.get::<_, ContactId>(0), |ids| { ids.collect::, _>>() @@ -1030,12 +1030,12 @@ impl Contact { let deleted_contacts = transaction.execute( "DELETE FROM contacts WHERE id=? AND (SELECT COUNT(*) FROM chats_contacts WHERE contact_id=?)=0;", - paramsv![contact_id, contact_id], + (contact_id, contact_id), )?; if deleted_contacts == 0 { transaction.execute( "UPDATE contacts SET origin=? WHERE id=?;", - paramsv![Origin::Hidden, contact_id], + (Origin::Hidden, contact_id), )?; } Ok(()) @@ -1063,7 +1063,7 @@ impl Contact { .sql .execute( "UPDATE contacts SET param=? WHERE id=?", - paramsv![self.param.to_string(), self.id], + (self.param.to_string(), self.id), ) .await?; Ok(()) @@ -1075,7 +1075,7 @@ impl Contact { .sql .execute( "UPDATE contacts SET status=? WHERE id=?", - paramsv![self.status, self.id], + (&self.status, self.id), ) .await?; Ok(()) @@ -1233,7 +1233,7 @@ impl Contact { .sql .count( "SELECT COUNT(*) FROM contacts WHERE id>?;", - paramsv![ContactId::LAST_SPECIAL], + (ContactId::LAST_SPECIAL,), ) .await?; Ok(count) @@ -1247,10 +1247,7 @@ impl Contact { let exists = context .sql - .exists( - "SELECT COUNT(*) FROM contacts WHERE id=?;", - paramsv![contact_id], - ) + .exists("SELECT COUNT(*) FROM contacts WHERE id=?;", (contact_id,)) .await?; Ok(exists) } @@ -1265,7 +1262,7 @@ impl Contact { .sql .execute( "UPDATE contacts SET origin=? WHERE id=? AND origin 0 @@ -1580,7 +1577,7 @@ impl RecentlySeenLoop { .query_map( "SELECT id, last_seen FROM contacts WHERE last_seen > ?", - paramsv![time() - SEEN_RECENTLY_SECONDS], + (time() - SEEN_RECENTLY_SECONDS,), |row| { let contact_id: ContactId = row.get("id")?; let last_seen: i64 = row.get("last_seen")?; diff --git a/src/context.rs b/src/context.rs index a9bbd01ad..2161d0855 100644 --- a/src/context.rs +++ b/src/context.rs @@ -799,7 +799,7 @@ impl Context { " AND NOT(c.muted_until=-1 OR c.muted_until>?)", " ORDER BY m.timestamp DESC,m.id DESC;" ), - paramsv![MessageState::InFresh, time()], + (MessageState::InFresh, time()), |row| row.get::<_, MsgId>(0), |rows| { let mut list = Vec::new(); @@ -824,24 +824,10 @@ impl Context { } let str_like_in_text = format!("%{real_query}%"); - let do_query = |query, params| { - self.sql.query_map( - query, - params, - |row| row.get::<_, MsgId>("id"), - |rows| { - let mut ret = Vec::new(); - for id in rows { - ret.push(id?); - } - Ok(ret) - }, - ) - }; - let list = if let Some(chat_id) = chat_id { - do_query( - "SELECT m.id AS id + self.sql + .query_map( + "SELECT m.id AS id FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id @@ -850,9 +836,17 @@ impl Context { AND ct.blocked=0 AND txt LIKE ? ORDER BY m.timestamp,m.id;", - paramsv![chat_id, str_like_in_text], - ) - .await? + (chat_id, str_like_in_text), + |row| row.get::<_, MsgId>("id"), + |rows| { + let mut ret = Vec::new(); + for id in rows { + ret.push(id?); + } + Ok(ret) + }, + ) + .await? } else { // For performance reasons results are sorted only by `id`, that is in the order of // message reception. @@ -864,8 +858,9 @@ impl Context { // of unwanted results that are discarded moments later, we added `LIMIT 1000`. // According to some tests, this limit speeds up eg. 2 character searches by factor 10. // The limit is documented and UI may add a hint when getting 1000 results. - do_query( - "SELECT m.id AS id + self.sql + .query_map( + "SELECT m.id AS id FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id @@ -877,9 +872,17 @@ impl Context { AND ct.blocked=0 AND m.txt LIKE ? ORDER BY m.id DESC LIMIT 1000", - paramsv![str_like_in_text], - ) - .await? + (str_like_in_text,), + |row| row.get::<_, MsgId>("id"), + |rows| { + let mut ret = Vec::new(); + for id in rows { + ret.push(id?); + } + Ok(ret) + }, + ) + .await? }; Ok(list) @@ -1089,7 +1092,7 @@ mod tests { t.sql .execute( "UPDATE chats SET muted_until=? WHERE id=?;", - paramsv![time() - 3600, bob.id], + (time() - 3600, bob.id), ) .await .unwrap(); @@ -1106,10 +1109,7 @@ mod tests { // to test get_fresh_msgs() with invalid mute_until (everything < -1), // that results in "muted forever" by definition. t.sql - .execute( - "UPDATE chats SET muted_until=-2 WHERE id=?;", - paramsv![bob.id], - ) + .execute("UPDATE chats SET muted_until=-2 WHERE id=?;", (bob.id,)) .await .unwrap(); let bob = Chat::load_from_db(&t, bob.id).await.unwrap(); diff --git a/src/download.rs b/src/download.rs index 89c99f011..cc60e873d 100644 --- a/src/download.rs +++ b/src/download.rs @@ -101,7 +101,7 @@ impl MsgId { .sql .execute( "UPDATE msgs SET download_state=? WHERE id=?;", - paramsv![download_state, self], + (download_state, self), ) .await?; context.emit_event(EventType::MsgsChanged { @@ -134,7 +134,7 @@ impl Job { .sql .query_row_optional( "SELECT uid, folder FROM imap WHERE rfc724_mid=? AND target=folder", - paramsv![msg.rfc724_mid], + (&msg.rfc724_mid,), |row| { let server_uid: u32 = row.get(0)?; let server_folder: String = row.get(1)?; diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 55bc6b76d..22c3b6303 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -174,10 +174,7 @@ impl ChatId { pub async fn get_ephemeral_timer(self, context: &Context) -> Result { let timer = context .sql - .query_get_value( - "SELECT ephemeral_timer FROM chats WHERE id=?;", - paramsv![self], - ) + .query_get_value("SELECT ephemeral_timer FROM chats WHERE id=?;", (self,)) .await?; Ok(timer.unwrap_or_default()) } @@ -199,7 +196,7 @@ impl ChatId { "UPDATE chats SET ephemeral_timer=? WHERE id=?;", - paramsv![timer, self], + (timer, self), ) .await?; @@ -291,10 +288,7 @@ impl MsgId { pub(crate) async fn ephemeral_timer(self, context: &Context) -> Result { let res = match context .sql - .query_get_value( - "SELECT ephemeral_timer FROM msgs WHERE id=?", - paramsv![self], - ) + .query_get_value("SELECT ephemeral_timer FROM msgs WHERE id=?", (self,)) .await? { None | Some(0) => Timer::Disabled, @@ -314,7 +308,7 @@ impl MsgId { "UPDATE msgs SET ephemeral_timestamp = ? \ WHERE (ephemeral_timestamp == 0 OR ephemeral_timestamp > ?) \ AND id = ?", - paramsv![ephemeral_timestamp, ephemeral_timestamp, self], + (ephemeral_timestamp, ephemeral_timestamp, self), ) .await?; context.scheduler.interrupt_ephemeral_task().await; @@ -338,8 +332,8 @@ pub(crate) async fn start_ephemeral_timers_msgids( sql::repeat_vars(msg_ids.len()) ), rusqlite::params_from_iter( - std::iter::once(&now as &dyn crate::ToSql) - .chain(std::iter::once(&now as &dyn crate::ToSql)) + std::iter::once(&now as &dyn crate::sql::ToSql) + .chain(std::iter::once(&now as &dyn crate::sql::ToSql)) .chain(params_iter(msg_ids)), ), ) @@ -369,7 +363,7 @@ WHERE AND ephemeral_timestamp <= ? AND chat_id != ? "#, - paramsv![now, DC_CHAT_ID_TRASH], + (now, DC_CHAT_ID_TRASH), |row| { let id: MsgId = row.get("id")?; let chat_id: ChatId = row.get("chat_id")?; @@ -402,12 +396,12 @@ WHERE AND chat_id != ? AND chat_id != ? "#, - paramsv![ + ( threshold_timestamp, DC_CHAT_ID_LAST_SPECIAL, self_chat_id, - device_chat_id - ], + device_chat_id, + ), |row| { let id: MsgId = row.get("id")?; let chat_id: ChatId = row.get("chat_id")?; @@ -449,7 +443,7 @@ pub(crate) async fn delete_expired_messages(context: &Context, now: i64) -> Resu SET chat_id=?, txt='', subject='', txt_raw='', mime_headers='', from_id=0, to_id=0, param='' WHERE id=?", - params![DC_CHAT_ID_TRASH, msg_id], + (DC_CHAT_ID_TRASH, msg_id), )?; msgs_changed.push((chat_id, msg_id)); @@ -494,7 +488,7 @@ async fn next_delete_device_after_timestamp(context: &Context) -> Result Option { WHERE ephemeral_timestamp != 0 AND chat_id != ?; "#, - paramsv![DC_CHAT_ID_TRASH], // Trash contains already deleted messages, skip them + (DC_CHAT_ID_TRASH,), // Trash contains already deleted messages, skip them ) .await { @@ -605,12 +599,12 @@ pub(crate) async fn delete_expired_imap_messages(context: &Context) -> Result<() (download_state != 0 AND timestamp < ?) OR (ephemeral_timestamp != 0 AND ephemeral_timestamp <= ?)) )", - paramsv![ - target, + ( + &target, threshold_timestamp, threshold_timestamp_extended, now, - ], + ), ) .await?; @@ -635,12 +629,12 @@ pub(crate) async fn start_ephemeral_timers(context: &Context) -> Result<()> { WHERE ephemeral_timer > 0 \ AND ephemeral_timestamp = 0 \ AND state NOT IN (?, ?, ?)", - paramsv![ + ( time(), MessageState::InFresh, MessageState::InNoticed, - MessageState::OutDraft - ], + MessageState::OutDraft, + ), ) .await?; @@ -1106,7 +1100,7 @@ mod tests { assert!(msg.text.is_none_or_empty(), "{:?}", msg.text); let rawtxt: Option = t .sql - .query_get_value("SELECT txt_raw FROM msgs WHERE id=?;", paramsv![msg_id]) + .query_get_value("SELECT txt_raw FROM msgs WHERE id=?;", (msg_id,)) .await .unwrap(); assert!(rawtxt.is_none_or_empty(), "{rawtxt:?}"); @@ -1131,13 +1125,13 @@ mod tests { t.sql .execute( "INSERT INTO msgs (id, rfc724_mid, timestamp, ephemeral_timestamp) VALUES (?,?,?,?);", - paramsv![id, message_id, timestamp, ephemeral_timestamp], + (id, &message_id, timestamp, ephemeral_timestamp), ) .await?; t.sql .execute( "INSERT INTO imap (rfc724_mid, folder, uid, target) VALUES (?,'INBOX',?, 'INBOX');", - paramsv![message_id, id], + (&message_id, id), ) .await?; } @@ -1148,7 +1142,7 @@ mod tests { .sql .count( "SELECT COUNT(*) FROM imap WHERE target='' AND rfc724_mid=?", - paramsv![id.to_string()], + (id.to_string(),), ) .await?, 1 @@ -1159,10 +1153,7 @@ mod tests { async fn remove_uid(context: &Context, id: u32) -> Result<()> { context .sql - .execute( - "DELETE FROM imap WHERE rfc724_mid=?", - paramsv![id.to_string()], - ) + .execute("DELETE FROM imap WHERE rfc724_mid=?", (id.to_string(),)) .await?; Ok(()) } diff --git a/src/imap.rs b/src/imap.rs index 0e5b15492..2de7b666d 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -550,7 +550,7 @@ impl Imap { context .sql .transaction(move |transaction| { - transaction.execute("DELETE FROM imap WHERE folder=?", params![folder])?; + transaction.execute("DELETE FROM imap WHERE folder=?", (folder,))?; for (uid, (rfc724_mid, target)) in &msgs { // This may detect previously undetected moved // messages, so we update server_folder too. @@ -560,7 +560,7 @@ impl Imap { ON CONFLICT(folder, uid, uidvalidity) DO UPDATE SET rfc724_mid=excluded.rfc724_mid, target=excluded.target", - params![rfc724_mid, folder, uid, uid_validity, target], + (rfc724_mid, folder, uid, uid_validity, target), )?; } Ok(()) @@ -676,7 +676,7 @@ impl Imap { .sql .execute( "DELETE FROM imap WHERE folder=? AND uidvalidity!=?", - paramsv![folder, new_uid_validity], + (&folder, new_uid_validity), ) .await?; @@ -759,7 +759,7 @@ impl Imap { ON CONFLICT(folder, uid, uidvalidity) DO UPDATE SET rfc724_mid=excluded.rfc724_mid, target=excluded.target", - paramsv![message_id, folder, uid, uid_validity, &target], + (&message_id, &folder, uid, uid_validity, &target), ) .await?; @@ -1050,7 +1050,7 @@ impl Session { WHERE folder = ? AND target != folder ORDER BY target, uid", - paramsv![folder], + (folder,), |row| { let rowid: i64 = row.get(0)?; let uid: u32 = row.get(1)?; @@ -2168,7 +2168,7 @@ async fn mark_seen_by_uid( AND uid=?3 LIMIT 1 )", - paramsv![&folder, uid_validity, uid], + (&folder, uid_validity, uid), |row| { let msg_id: MsgId = row.get(0)?; let chat_id: ChatId = row.get(1)?; @@ -2184,12 +2184,12 @@ async fn mark_seen_by_uid( "UPDATE msgs SET state=?1 WHERE (state=?2 OR state=?3) AND id=?4", - paramsv![ + ( MessageState::InSeen, MessageState::InFresh, MessageState::InNoticed, - msg_id - ], + msg_id, + ), ) .await .with_context(|| format!("failed to update msg {msg_id} state"))? @@ -2219,7 +2219,7 @@ pub(crate) async fn markseen_on_imap_table(context: &Context, message_id: &str) .execute( "INSERT OR IGNORE INTO imap_markseen (id) SELECT id FROM imap WHERE rfc724_mid=?", - paramsv![message_id], + (message_id,), ) .await?; context @@ -2239,7 +2239,7 @@ pub(crate) async fn set_uid_next(context: &Context, folder: &str, uid_next: u32) .execute( "INSERT INTO imap_sync (folder, uid_next) VALUES (?,?) ON CONFLICT(folder) DO UPDATE SET uid_next=excluded.uid_next", - paramsv![folder, uid_next], + (folder, uid_next), ) .await?; Ok(()) @@ -2253,10 +2253,7 @@ pub(crate) async fn set_uid_next(context: &Context, folder: &str, uid_next: u32) async fn get_uid_next(context: &Context, folder: &str) -> Result { Ok(context .sql - .query_get_value( - "SELECT uid_next FROM imap_sync WHERE folder=?;", - paramsv![folder], - ) + .query_get_value("SELECT uid_next FROM imap_sync WHERE folder=?;", (folder,)) .await? .unwrap_or(0)) } @@ -2271,7 +2268,7 @@ pub(crate) async fn set_uidvalidity( .execute( "INSERT INTO imap_sync (folder, uidvalidity) VALUES (?,?) ON CONFLICT(folder) DO UPDATE SET uidvalidity=excluded.uidvalidity", - paramsv![folder, uidvalidity], + (folder, uidvalidity), ) .await?; Ok(()) @@ -2282,7 +2279,7 @@ async fn get_uidvalidity(context: &Context, folder: &str) -> Result { .sql .query_get_value( "SELECT uidvalidity FROM imap_sync WHERE folder=?;", - paramsv![folder], + (folder,), ) .await? .unwrap_or(0)) @@ -2294,7 +2291,7 @@ pub(crate) async fn set_modseq(context: &Context, folder: &str, modseq: u64) -> .execute( "INSERT INTO imap_sync (folder, modseq) VALUES (?,?) ON CONFLICT(folder) DO UPDATE SET modseq=excluded.modseq", - paramsv![folder, modseq], + (folder, modseq), ) .await?; Ok(()) @@ -2303,10 +2300,7 @@ pub(crate) async fn set_modseq(context: &Context, folder: &str, modseq: u64) -> async fn get_modseq(context: &Context, folder: &str) -> Result { Ok(context .sql - .query_get_value( - "SELECT modseq FROM imap_sync WHERE folder=?;", - paramsv![folder], - ) + .query_get_value("SELECT modseq FROM imap_sync WHERE folder=?;", (folder,)) .await? .unwrap_or(0)) } diff --git a/src/imex.rs b/src/imex.rs index cc6a59dc9..cfb6d76cf 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -763,14 +763,11 @@ async fn export_database(context: &Context, dest: &Path, passphrase: String) -> context .sql .call_write(|conn| { - conn.execute("VACUUM;", params![]) + conn.execute("VACUUM;", ()) .map_err(|err| warn!(context, "Vacuum failed, exporting anyway {err}")) .ok(); - conn.execute( - "ATTACH DATABASE ? AS backup KEY ?", - paramsv![dest, passphrase], - ) - .context("failed to attach backup database")?; + conn.execute("ATTACH DATABASE ? AS backup KEY ?", (dest, passphrase)) + .context("failed to attach backup database")?; let res = conn .query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(())) .context("failed to export to attached backup database"); diff --git a/src/job.rs b/src/job.rs index f6fc19809..f739f4f63 100644 --- a/src/job.rs +++ b/src/job.rs @@ -99,7 +99,7 @@ impl Job { if self.job_id != 0 { context .sql - .execute("DELETE FROM jobs WHERE id=?;", paramsv![self.job_id as i32]) + .execute("DELETE FROM jobs WHERE id=?;", (self.job_id as i32,)) .await?; } @@ -117,22 +117,22 @@ impl Job { .sql .execute( "UPDATE jobs SET desired_timestamp=?, tries=? WHERE id=?;", - paramsv![ + ( self.desired_timestamp, i64::from(self.tries), self.job_id as i32, - ], + ), ) .await?; } else { context.sql.execute( "INSERT INTO jobs (added_timestamp, action, foreign_id, desired_timestamp) VALUES (?,?,?,?);", - paramsv![ + ( self.added_timestamp, self.action, self.foreign_id, self.desired_timestamp - ] + ) ).await?; } @@ -277,7 +277,7 @@ WHERE desired_timestamp<=? ORDER BY action DESC, added_timestamp LIMIT 1; "#; - params = paramsv![t]; + params = vec![t]; } else { // processing after call to dc_maybe_network(): // process _all_ pending jobs that failed before @@ -289,13 +289,13 @@ WHERE tries>0 ORDER BY desired_timestamp, action DESC LIMIT 1; "#; - params = paramsv![]; + params = vec![]; }; loop { let job_res = context .sql - .query_row_optional(query, params.clone(), |row| { + .query_row_optional(query, rusqlite::params_from_iter(params.clone()), |row| { let job = Job { job_id: row.get("id")?, action: row.get("action")?, @@ -318,12 +318,14 @@ LIMIT 1; // TODO: improve by only doing a single query let id = context .sql - .query_row(query, params.clone(), |row| row.get::<_, i32>(0)) + .query_row(query, rusqlite::params_from_iter(params.clone()), |row| { + row.get::<_, i32>(0) + }) .await .context("failed to retrieve invalid job ID from the database")?; context .sql - .execute("DELETE FROM jobs WHERE id=?;", paramsv![id]) + .execute("DELETE FROM jobs WHERE id=?;", (id,)) .await .with_context(|| format!("failed to delete invalid job {id}"))?; } @@ -344,7 +346,7 @@ mod tests { "INSERT INTO jobs (added_timestamp, action, foreign_id, desired_timestamp) VALUES (?, ?, ?, ?);", - paramsv![ + ( now, if valid { Action::DownloadMsg as i32 @@ -352,8 +354,8 @@ mod tests { -1 }, foreign_id, - now - ], + now, + ), ) .await .unwrap(); diff --git a/src/key.rs b/src/key.rs index 74fb997cf..2965cfb55 100644 --- a/src/key.rs +++ b/src/key.rs @@ -100,7 +100,7 @@ impl DcKey for SignedPublicKey { WHERE addr=? AND is_default=1; "#, - paramsv![addr], + (addr,), |row| { let bytes: Vec = row.get(0)?; Ok(bytes) @@ -240,7 +240,7 @@ pub(crate) async fn load_keypair( WHERE addr=?1 AND is_default=1; "#, - paramsv![addr], + (addr,), |row| { let pub_bytes: Vec = row.get(0)?; let sec_bytes: Vec = row.get(1)?; @@ -297,7 +297,7 @@ pub async fn store_self_keypair( transaction .execute( "DELETE FROM keypairs WHERE public_key=? OR private_key=?;", - paramsv![public_key, secret_key], + (&public_key, &secret_key), ) .context("failed to remove old use of key")?; if default == KeyPairUse::Default { @@ -317,7 +317,7 @@ pub async fn store_self_keypair( .execute( "INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);", - paramsv![addr, is_default, public_key, secret_key, t], + (addr, is_default, &public_key, &secret_key, t), ) .context("failed to insert keypair")?; diff --git a/src/lib.rs b/src/lib.rs index 0e25cdd51..38c8d0d47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,11 +35,6 @@ extern crate rusqlite; #[macro_use] extern crate strum_macros; -#[allow(missing_docs)] -pub trait ToSql: rusqlite::ToSql + Send + Sync {} - -impl ToSql for T {} - #[macro_use] pub mod log; diff --git a/src/location.rs b/src/location.rs index 28864263d..cae938cf8 100644 --- a/src/location.rs +++ b/src/location.rs @@ -271,11 +271,11 @@ pub async fn send_locations_to_chat( SET locations_send_begin=?, \ locations_send_until=? \ WHERE id=?", - paramsv![ + ( if 0 != seconds { now } else { 0 }, if 0 != seconds { now + seconds } else { 0 }, chat_id, - ], + ), ) .await?; if 0 != seconds && !is_sending_locations_before { @@ -310,7 +310,7 @@ pub async fn is_sending_locations_to_chat( .sql .exists( "SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;", - paramsv![chat_id, time()], + (chat_id, time()), ) .await? } @@ -319,7 +319,7 @@ pub async fn is_sending_locations_to_chat( .sql .exists( "SELECT COUNT(id) FROM chats WHERE locations_send_until>?;", - paramsv![time()], + (time(),), ) .await? } @@ -338,7 +338,7 @@ pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64 .sql .query_map( "SELECT id FROM chats WHERE locations_send_until>?;", - paramsv![time()], + (time(),), |row| row.get::<_, i32>(0), |chats| { chats @@ -352,14 +352,14 @@ pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64 if let Err(err) = context.sql.execute( "INSERT INTO locations \ (latitude, longitude, accuracy, timestamp, chat_id, from_id) VALUES (?,?,?,?,?,?);", - paramsv![ + ( latitude, longitude, accuracy, time(), chat_id, ContactId::SELF, - ] + ) ).await { warn!(context, "failed to store location {:#}", err); } else { @@ -404,14 +404,14 @@ pub async fn get_range( AND (? OR l.from_id=?) \ AND (l.independent=1 OR (l.timestamp>=? AND l.timestamp<=?)) \ ORDER BY l.timestamp DESC, l.id DESC, msg_id DESC;", - paramsv![ + ( disable_chat_id, chat_id, disable_contact_id, contact_id as i32, timestamp_from, timestamp_to, - ], + ), |row| { let msg_id = row.get(6)?; let txt: String = row.get(9)?; @@ -471,7 +471,7 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32) let (locations_send_begin, locations_send_until, locations_last_sent) = context.sql.query_row( "SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;", - paramsv![chat_id], |row| { + (chat_id,), |row| { let send_begin: i64 = row.get(0)?; let send_until: i64 = row.get(1)?; let last_sent: i64 = row.get(2)?; @@ -500,12 +500,12 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32) AND independent=0 \ GROUP BY timestamp \ ORDER BY timestamp;", - paramsv![ + ( ContactId::SELF, locations_send_begin, locations_last_sent, ContactId::SELF - ], + ), |row| { let location_id: i32 = row.get(0)?; let latitude: f64 = row.get(1)?; @@ -575,7 +575,7 @@ pub async fn set_kml_sent_timestamp( .sql .execute( "UPDATE chats SET locations_last_sent=? WHERE id=?;", - paramsv![timestamp, chat_id], + (timestamp, chat_id), ) .await?; Ok(()) @@ -587,7 +587,7 @@ pub async fn set_msg_location_id(context: &Context, msg_id: MsgId, location_id: .sql .execute( "UPDATE msgs SET location_id=? WHERE id=?;", - paramsv![location_id, msg_id], + (location_id, msg_id), ) .await?; @@ -629,10 +629,10 @@ pub(crate) async fn save( .prepare_cached("SELECT id FROM locations WHERE timestamp=? AND from_id=?")?; let mut stmt_insert = conn.prepare_cached(stmt_insert)?; - let exists = stmt_test.exists(paramsv![timestamp, contact_id])?; + let exists = stmt_test.exists((timestamp, contact_id))?; if independent || !exists { - stmt_insert.execute(paramsv![ + stmt_insert.execute(( timestamp, contact_id, chat_id, @@ -640,7 +640,7 @@ pub(crate) async fn save( longitude, accuracy, independent, - ])?; + ))?; if timestamp > newest_timestamp { // okay to drop, as we use cached prepared statements @@ -729,7 +729,7 @@ async fn maybe_send_locations(context: &Context) -> Result> { AND timestamp>=? \ AND timestamp>? \ AND independent=0", - paramsv![ContactId::SELF, locations_send_begin, locations_last_sent,], + (ContactId::SELF, locations_send_begin, locations_last_sent), ) .await?; @@ -781,7 +781,7 @@ async fn maybe_send_locations(context: &Context) -> Result> { "UPDATE chats \ SET locations_send_begin=0, locations_send_until=0 \ WHERE id=?", - paramsv![chat_id], + (chat_id,), ) .await .context("failed to disable location streaming")?; diff --git a/src/message.rs b/src/message.rs index 3ec5a99ae..563020b7c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -77,7 +77,7 @@ impl MsgId { pub async fn get_state(self, context: &Context) -> Result { let result = context .sql - .query_get_value("SELECT state FROM msgs WHERE id=?", paramsv![self]) + .query_get_value("SELECT state FROM msgs WHERE id=?", (self,)) .await? .unwrap_or_default(); Ok(result) @@ -106,7 +106,7 @@ SET param='' WHERE id=?; "#, - paramsv![chat_id, self], + (chat_id, self), ) .await?; @@ -119,22 +119,19 @@ WHERE id=?; // sure they are not left while the message is deleted. context .sql - .execute("DELETE FROM smtp WHERE msg_id=?", paramsv![self]) + .execute("DELETE FROM smtp WHERE msg_id=?", (self,)) .await?; context .sql - .execute("DELETE FROM msgs_mdns WHERE msg_id=?;", paramsv![self]) + .execute("DELETE FROM msgs_mdns WHERE msg_id=?;", (self,)) .await?; context .sql - .execute( - "DELETE FROM msgs_status_updates WHERE msg_id=?;", - paramsv![self], - ) + .execute("DELETE FROM msgs_status_updates WHERE msg_id=?;", (self,)) .await?; context .sql - .execute("DELETE FROM msgs WHERE id=?;", paramsv![self]) + .execute("DELETE FROM msgs WHERE id=?;", (self,)) .await?; Ok(()) } @@ -143,7 +140,7 @@ WHERE id=?; update_msg_state(context, self, MessageState::OutDelivered).await?; let chat_id: ChatId = context .sql - .query_get_value("SELECT chat_id FROM msgs WHERE id=?", paramsv![self]) + .query_get_value("SELECT chat_id FROM msgs WHERE id=?", (self,)) .await? .unwrap_or_default(); context.emit_event(EventType::MsgDelivered { @@ -328,7 +325,7 @@ impl Message { " FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id", " WHERE m.id=?;" ), - paramsv![id], + (id,), |row| { let text = match row.get_ref("txt")? { rusqlite::types::ValueRef::Text(buf) => { @@ -949,7 +946,7 @@ impl Message { .sql .execute( "UPDATE msgs SET param=? WHERE id=?;", - paramsv![self.param.to_string(), self.id], + (self.param.to_string(), self.id), ) .await?; Ok(()) @@ -960,7 +957,7 @@ impl Message { .sql .execute( "UPDATE msgs SET subject=? WHERE id=?;", - paramsv![self.subject, self.id], + (&self.subject, self.id), ) .await?; Ok(()) @@ -1094,7 +1091,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { let msg = Message::load_from_db(context, msg_id).await?; let rawtxt: Option = context .sql - .query_get_value("SELECT txt_raw FROM msgs WHERE id=?;", paramsv![msg_id]) + .query_get_value("SELECT txt_raw FROM msgs WHERE id=?;", (msg_id,)) .await?; let mut ret = String::new(); @@ -1144,7 +1141,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { .sql .query_map( "SELECT contact_id, timestamp_sent FROM msgs_mdns WHERE msg_id=?;", - paramsv![msg_id], + (msg_id,), |row| { let contact_id: ContactId = row.get(0)?; let ts: i64 = row.get(1)?; @@ -1225,7 +1222,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { .sql .query_map( "SELECT folder, uid FROM imap WHERE rfc724_mid=?", - paramsv![msg.rfc724_mid], + (msg.rfc724_mid,), |row| { let folder: String = row.get("folder")?; let uid: u32 = row.get("uid")?; @@ -1245,7 +1242,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { } let hop_info: Option = context .sql - .query_get_value("SELECT hop_info FROM msgs WHERE id=?;", paramsv![msg_id]) + .query_get_value("SELECT hop_info FROM msgs WHERE id=?;", (msg_id,)) .await?; ret += "\n\n"; @@ -1353,7 +1350,7 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result Result ensure!(rows_updated <= 1), Err(e) => { @@ -1421,7 +1418,7 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { .sql .execute( "UPDATE imap SET target=? WHERE rfc724_mid=?", - paramsv![target, msg.rfc724_mid], + (target, msg.rfc724_mid), ) .await?; @@ -1459,7 +1456,7 @@ async fn delete_poi_location(context: &Context, location_id: u32) -> Result<()> .sql .execute( "DELETE FROM locations WHERE independent = 1 AND id=?;", - paramsv![location_id as i32], + (location_id as i32,), ) .await?; Ok(()) @@ -1558,7 +1555,7 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> .sql .execute( "INSERT INTO smtp_mdns (msg_id, from_id, rfc724_mid) VALUES(?, ?, ?)", - paramsv![id, curr_from_id, curr_rfc724_mid], + (id, curr_from_id, curr_rfc724_mid), ) .await .context("failed to insert into smtp_mdns")?; @@ -1586,10 +1583,7 @@ pub(crate) async fn update_msg_state( ) -> Result<()> { context .sql - .execute( - "UPDATE msgs SET state=? WHERE id=?;", - paramsv![state, msg_id], - ) + .execute("UPDATE msgs SET state=? WHERE id=?;", (state, msg_id)) .await?; Ok(()) } @@ -1609,7 +1603,7 @@ pub(crate) async fn exists(context: &Context, msg_id: MsgId) -> Result { let chat_id: Option = context .sql - .query_get_value("SELECT chat_id FROM msgs WHERE id=?;", paramsv![msg_id]) + .query_get_value("SELECT chat_id FROM msgs WHERE id=?;", (msg_id,)) .await?; if let Some(chat_id) = chat_id { @@ -1635,7 +1629,7 @@ pub(crate) async fn set_msg_failed(context: &Context, msg_id: MsgId, error: &str .sql .execute( "UPDATE msgs SET state=?, error=? WHERE id=?;", - paramsv![msg.state, error, msg_id], + (msg.state, error, msg_id), ) .await { @@ -1680,7 +1674,7 @@ pub async fn handle_mdn( " WHERE rfc724_mid=? AND from_id=1", " ORDER BY m.id;" ), - paramsv![rfc724_mid], + (&rfc724_mid,), |row| { Ok(( row.get::<_, MsgId>("msg_id")?, @@ -1706,7 +1700,7 @@ pub async fn handle_mdn( .sql .exists( "SELECT COUNT(*) FROM msgs_mdns WHERE msg_id=? AND contact_id=?;", - paramsv![msg_id, from_id], + (msg_id, from_id), ) .await? { @@ -1714,7 +1708,7 @@ pub async fn handle_mdn( .sql .execute( "INSERT INTO msgs_mdns (msg_id, contact_id, timestamp_sent) VALUES (?, ?, ?);", - paramsv![msg_id, from_id, timestamp_sent], + (msg_id, from_id, timestamp_sent), ) .await?; } @@ -1754,7 +1748,7 @@ pub(crate) async fn handle_ndn( " FROM msgs m LEFT JOIN chats c ON m.chat_id=c.id", " WHERE rfc724_mid=? AND from_id=1", ), - paramsv![failed.rfc724_mid], + (&failed.rfc724_mid,), |row| { Ok(( row.get::<_, MsgId>("msg_id")?, @@ -1894,7 +1888,7 @@ pub async fn estimate_deletion_cnt( AND timestamp < ? AND chat_id != ? AND EXISTS (SELECT * FROM imap WHERE rfc724_mid=m.rfc724_mid);", - paramsv![DC_MSG_ID_LAST_SPECIAL, threshold_timestamp, self_chat_id], + (DC_MSG_ID_LAST_SPECIAL, threshold_timestamp, self_chat_id), ) .await? } else { @@ -1907,12 +1901,12 @@ pub async fn estimate_deletion_cnt( AND timestamp < ? AND chat_id != ? AND chat_id != ? AND hidden = 0;", - paramsv![ + ( DC_MSG_ID_LAST_SPECIAL, threshold_timestamp, self_chat_id, - DC_CHAT_ID_TRASH - ], + DC_CHAT_ID_TRASH, + ), ) .await? }; @@ -1933,7 +1927,7 @@ pub(crate) async fn rfc724_mid_exists( .sql .query_row_optional( "SELECT id FROM msgs WHERE rfc724_mid=?", - paramsv![rfc724_mid], + (rfc724_mid,), |row| { let msg_id: MsgId = row.get(0)?; diff --git a/src/mimefactory.rs b/src/mimefactory.rs index ce4bac4c1..24a22de0e 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -166,7 +166,7 @@ impl<'a> MimeFactory<'a> { FROM chats_contacts cc \ LEFT JOIN contacts c ON cc.contact_id=c.id \ WHERE cc.chat_id=? AND cc.contact_id>9;", - paramsv![msg.chat_id], + (msg.chat_id,), |row| { let authname: String = row.get(0)?; let addr: String = row.get(1)?; @@ -195,7 +195,7 @@ impl<'a> MimeFactory<'a> { .sql .query_row( "SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?", - paramsv![msg.id], + (msg.id,), |row| { let in_reply_to: String = row.get(0)?; let references: String = row.get(1)?; diff --git a/src/mimeparser.rs b/src/mimeparser.rs index f19e3af57..455c5733f 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -1668,10 +1668,7 @@ impl MimeMessage { { context .sql - .query_get_value( - "SELECT timestamp FROM msgs WHERE rfc724_mid=?", - paramsv![field], - ) + .query_get_value("SELECT timestamp FROM msgs WHERE rfc724_mid=?", (field,)) .await? } else { None @@ -2352,7 +2349,7 @@ mod tests { .sql .execute( "INSERT INTO msgs (rfc724_mid, timestamp) VALUES(?,?)", - paramsv!["Gr.beZgAF2Nn0-.oyaJOpeuT70@example.org", timestamp], + ("Gr.beZgAF2Nn0-.oyaJOpeuT70@example.org", timestamp), ) .await .expect("Failed to write to the database"); diff --git a/src/net.rs b/src/net.rs index a0f3a3313..c6cc6f539 100644 --- a/src/net.rs +++ b/src/net.rs @@ -75,7 +75,7 @@ async fn lookup_host_with_cache( VALUES (?, ?, ?) ON CONFLICT (hostname, address) DO UPDATE SET timestamp=excluded.timestamp", - paramsv![hostname, ip_string, now], + (hostname, ip_string, now), ) .await?; } @@ -89,7 +89,7 @@ async fn lookup_host_with_cache( WHERE hostname = ? AND ? < timestamp + 30 * 24 * 3600 ORDER BY timestamp DESC", - paramsv![hostname, now], + (hostname, now), |row| { let address: String = row.get(0)?; Ok(address) @@ -157,7 +157,7 @@ pub(crate) async fn connect_tcp( "UPDATE dns_cache SET timestamp = ? WHERE address = ?", - paramsv![time(), resolved_addr.ip().to_string()], + (time(), resolved_addr.ip().to_string()), ) .await?; break; diff --git a/src/peerstate.rs b/src/peerstate.rs index 16378c918..47b9cda13 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -144,7 +144,7 @@ impl Peerstate { verified_key, verified_key_fingerprint, verifier \ FROM acpeerstates \ WHERE addr=? COLLATE NOCASE LIMIT 1;"; - Self::from_stmt(context, query, paramsv![addr]).await + Self::from_stmt(context, query, (addr,)).await } /// Loads peerstate corresponding to the given fingerprint from the database. @@ -160,7 +160,7 @@ impl Peerstate { OR gossip_key_fingerprint=? \ ORDER BY public_key_fingerprint=? DESC LIMIT 1;"; let fp = fingerprint.hex(); - Self::from_stmt(context, query, paramsv![fp, fp, fp]).await + Self::from_stmt(context, query, (&fp, &fp, &fp)).await } /// Loads peerstate by address or verified fingerprint. @@ -180,7 +180,7 @@ impl Peerstate { OR addr=? COLLATE NOCASE \ ORDER BY verified_key_fingerprint=? DESC, last_seen DESC LIMIT 1;"; let fp = fingerprint.hex(); - Self::from_stmt(context, query, paramsv![fp, addr, fp]).await + Self::from_stmt(context, query, (&fp, &addr, &fp)).await } async fn from_stmt( @@ -471,7 +471,7 @@ impl Peerstate { verified_key = excluded.verified_key, verified_key_fingerprint = excluded.verified_key_fingerprint, verifier = excluded.verifier", - paramsv![ + ( self.last_seen, self.last_seen_autocrypt, self.prefer_encrypt as i64, @@ -482,9 +482,9 @@ impl Peerstate { self.gossip_key_fingerprint.as_ref().map(|fp| fp.hex()), self.verified_key.as_ref().map(|k| k.to_bytes()), self.verified_key_fingerprint.as_ref().map(|fp| fp.hex()), - self.addr, + &self.addr, self.verifier.as_deref().unwrap_or(""), - ], + ), ) .await?; Ok(()) @@ -524,7 +524,7 @@ impl Peerstate { .sql .query_get_value( "SELECT id FROM contacts WHERE addr=? COLLATE NOCASE;", - paramsv![self.addr], + (&self.addr,), ) .await? .with_context(|| format!("contact with peerstate.addr {:?} not found", &self.addr))?; @@ -554,7 +554,7 @@ impl Peerstate { .sql .query_get_value( "SELECT created_timestamp FROM chats WHERE id=?;", - paramsv![chat_id], + (chat_id,), ) .await? .unwrap_or(0) @@ -851,7 +851,7 @@ mod tests { // can be loaded without errors. ctx.ctx .sql - .execute("INSERT INTO acpeerstates (addr) VALUES(?)", paramsv![addr]) + .execute("INSERT INTO acpeerstates (addr) VALUES(?)", (addr,)) .await .expect("Failed to write to the database"); diff --git a/src/reaction.rs b/src/reaction.rs index 832304b87..d8ad4b5bb 100644 --- a/src/reaction.rs +++ b/src/reaction.rs @@ -156,7 +156,7 @@ async fn set_msg_id_reaction( "DELETE FROM reactions WHERE msg_id = ?1 AND contact_id = ?2", - paramsv![msg_id, contact_id], + (msg_id, contact_id), ) .await?; } else { @@ -167,7 +167,7 @@ async fn set_msg_id_reaction( VALUES (?1, ?2, ?3) ON CONFLICT(msg_id, contact_id) DO UPDATE SET reaction=excluded.reaction", - paramsv![msg_id, contact_id, reaction.as_str()], + (msg_id, contact_id, reaction.as_str()), ) .await?; } @@ -247,7 +247,7 @@ async fn get_self_reaction(context: &Context, msg_id: MsgId) -> Result "SELECT reaction FROM reactions WHERE msg_id=? AND contact_id=?", - paramsv![msg_id, ContactId::SELF], + (msg_id, ContactId::SELF), ) .await?; Ok(reaction_str @@ -262,7 +262,7 @@ pub async fn get_msg_reactions(context: &Context, msg_id: MsgId) -> Result?", - paramsv![chat_id, MessageState::InFresh], + (chat_id, MessageState::InFresh), ) .await?; @@ -1684,7 +1684,7 @@ async fn apply_group_changes( .sql .execute( "UPDATE chats SET name=? WHERE id=?;", - paramsv![strip_rtlo_characters(grpname), chat_id], + (strip_rtlo_characters(grpname), chat_id), ) .await?; send_event_chat_modified = true; @@ -1754,10 +1754,7 @@ async fn apply_group_changes( // start from scratch. context .sql - .execute( - "DELETE FROM chats_contacts WHERE chat_id=?;", - paramsv![chat_id], - ) + .execute("DELETE FROM chats_contacts WHERE chat_id=?;", (chat_id,)) .await?; members_to_add.push(ContactId::SELF); diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index ed3791fe7..aee277e5d 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -374,7 +374,7 @@ async fn test_no_message_id_header() { .sql .exists( "SELECT COUNT(*) FROM msgs WHERE chat_id=?;", - paramsv![DC_CHAT_ID_TRASH], + (DC_CHAT_ID_TRASH,), ) .await .unwrap()); diff --git a/src/securejoin/bobstate.rs b/src/securejoin/bobstate.rs index b6584f6e1..04b1edd33 100644 --- a/src/securejoin/bobstate.rs +++ b/src/securejoin/bobstate.rs @@ -135,21 +135,21 @@ impl BobState { // rows that we will delete. So start with a dummy UPDATE. transaction.execute( r#"UPDATE bobstate SET next_step=?;"#, - params![SecureJoinStep::Terminated], + (SecureJoinStep::Terminated,), )?; let mut stmt = transaction.prepare("SELECT id FROM bobstate;")?; let mut aborted = Vec::new(); - for id in stmt.query_map(params![], |row| row.get::<_, i64>(0))? { + for id in stmt.query_map((), |row| row.get::<_, i64>(0))? { let id = id?; let state = BobState::from_db_id(transaction, id)?; aborted.push(state); } // Finally delete everything and insert new row. - transaction.execute("DELETE FROM bobstate;", params![])?; + transaction.execute("DELETE FROM bobstate;", ())?; transaction.execute( "INSERT INTO bobstate (invite, next_step, chat_id) VALUES (?, ?, ?);", - params![invite, next, chat_id], + (invite, next, chat_id), )?; let id = transaction.last_insert_rowid(); Ok((id, aborted)) @@ -180,7 +180,7 @@ impl BobState { fn from_db_id(connection: &Connection, id: i64) -> rusqlite::Result { connection.query_row( "SELECT invite, next_step, chat_id FROM bobstate WHERE id=?;", - params![id], + (id,), |row| { let s = BobState { id, @@ -217,12 +217,12 @@ impl BobState { SecureJoinStep::AuthRequired | SecureJoinStep::ContactConfirm => { sql.execute( "UPDATE bobstate SET next_step=? WHERE id=?;", - paramsv![next, self.id], + (next, self.id), ) .await?; } SecureJoinStep::Terminated | SecureJoinStep::Completed => { - sql.execute("DELETE FROM bobstate WHERE id=?;", paramsv!(self.id)) + sql.execute("DELETE FROM bobstate WHERE id=?;", (self.id,)) .await?; } } diff --git a/src/smtp.rs b/src/smtp.rs index 26402b325..bc6e29e90 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -520,10 +520,7 @@ pub(crate) async fn send_msg_to_smtp( // database. context .sql - .execute( - "UPDATE smtp SET retries=retries+1 WHERE id=?", - paramsv![rowid], - ) + .execute("UPDATE smtp SET retries=retries+1 WHERE id=?", (rowid,)) .await .context("failed to update retries count")?; @@ -531,7 +528,7 @@ pub(crate) async fn send_msg_to_smtp( .sql .query_row( "SELECT mime, recipients, msg_id, retries FROM smtp WHERE id=?", - paramsv![rowid], + (rowid,), |row| { let mime: String = row.get(0)?; let recipients: String = row.get(1)?; @@ -545,7 +542,7 @@ pub(crate) async fn send_msg_to_smtp( message::set_msg_failed(context, msg_id, "Number of retries exceeded the limit.").await; context .sql - .execute("DELETE FROM smtp WHERE id=?", paramsv![rowid]) + .execute("DELETE FROM smtp WHERE id=?", (rowid,)) .await .context("failed to remove message with exceeded retry limit from smtp table")?; bail!("Number of retries exceeded the limit"); @@ -588,7 +585,7 @@ pub(crate) async fn send_msg_to_smtp( SendResult::Success | SendResult::Failure(_) => { context .sql - .execute("DELETE FROM smtp WHERE id=?", paramsv![rowid]) + .execute("DELETE FROM smtp WHERE id=?", (rowid,)) .await?; } }; @@ -637,7 +634,7 @@ pub(crate) async fn send_smtp_messages(context: &Context, connection: &mut Smtp) .sql .query_map( "SELECT id FROM smtp ORDER BY id ASC", - paramsv![], + (), |row| { let rowid: i64 = row.get(0)?; Ok(rowid) @@ -691,7 +688,7 @@ async fn send_mdn_msg_id( "SELECT msg_id, rfc724_mid FROM smtp_mdns WHERE from_id=? AND msg_id!=?", - paramsv![contact_id, msg_id], + (contact_id, msg_id), |row| { let msg_id: MsgId = row.get(0)?; let rfc724_mid: String = row.get(1)?; @@ -718,7 +715,7 @@ async fn send_mdn_msg_id( info!(context, "Successfully sent MDN for {}", msg_id); context .sql - .execute("DELETE FROM smtp_mdns WHERE msg_id = ?", paramsv![msg_id]) + .execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,)) .await?; if !additional_msg_ids.is_empty() { let q = format!( @@ -779,7 +776,7 @@ async fn send_mdn(context: &Context, smtp: &mut Smtp) -> Result { .sql .execute( "UPDATE smtp_mdns SET retries=retries+1 WHERE msg_id=?", - paramsv![msg_id], + (msg_id,), ) .await .context("failed to update MDN retries count")?; @@ -789,7 +786,7 @@ async fn send_mdn(context: &Context, smtp: &mut Smtp) -> Result { // database, do not try to send this MDN again. context .sql - .execute("DELETE FROM smtp_mdns WHERE msg_id = ?", paramsv![msg_id]) + .execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,)) .await?; Err(err) } else { diff --git a/src/sql.rs b/src/sql.rs index 641b352ec..eab857af4 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -23,27 +23,28 @@ use crate::peerstate::{deduplicate_peerstates, Peerstate}; use crate::stock_str; use crate::tools::{delete_file, time}; -#[allow(missing_docs)] +/// Extension to [`rusqlite::ToSql`] trait +/// which also includes [`Send`] and [`Sync`]. +pub trait ToSql: rusqlite::ToSql + Send + Sync {} + +impl ToSql for T {} + +/// Constructs a slice of trait object references `&dyn ToSql`. +/// +/// One of the uses is passing more than 16 parameters +/// to a query, because [`rusqlite::Params`] is only implemented +/// for tuples of up to 16 elements. #[macro_export] -macro_rules! paramsv { - () => { - rusqlite::params_from_iter(Vec::<&dyn $crate::ToSql>::new()) - }; - ($($param:expr),+ $(,)?) => { - rusqlite::params_from_iter(vec![$(&$param as &dyn $crate::ToSql),+]) +macro_rules! params_slice { + ($($param:expr),+) => { + [$(&$param as &dyn $crate::sql::ToSql),+] }; } -#[allow(missing_docs)] -#[macro_export] -macro_rules! params_iterv { - ($($param:expr),+ $(,)?) => { - vec![$(&$param as &dyn $crate::ToSql),+] - }; -} - -pub(crate) fn params_iter(iter: &[impl crate::ToSql]) -> impl Iterator { - iter.iter().map(|item| item as &dyn crate::ToSql) +pub(crate) fn params_iter( + iter: &[impl crate::sql::ToSql], +) -> impl Iterator { + iter.iter().map(|item| item as &dyn crate::sql::ToSql) } mod migrations; @@ -139,11 +140,8 @@ impl Sql { let res = self .call_write(move |conn| { // Check that backup passphrase is correct before resetting our database. - conn.execute( - "ATTACH DATABASE ? AS backup KEY ?", - paramsv![path_str, passphrase], - ) - .context("failed to attach backup database")?; + conn.execute("ATTACH DATABASE ? AS backup KEY ?", (path_str, passphrase)) + .context("failed to attach backup database")?; if let Err(err) = conn .query_row("SELECT count(*) FROM sqlite_master", [], |_row| Ok(())) .context("backup passphrase is not correct") @@ -556,27 +554,21 @@ impl Sql { let mut lock = self.config_cache.write().await; if let Some(value) = value { let exists = self - .exists( - "SELECT COUNT(*) FROM config WHERE keyname=?;", - paramsv![key], - ) + .exists("SELECT COUNT(*) FROM config WHERE keyname=?;", (key,)) .await?; if exists { - self.execute( - "UPDATE config SET value=? WHERE keyname=?;", - paramsv![value, key], - ) - .await?; + self.execute("UPDATE config SET value=? WHERE keyname=?;", (value, key)) + .await?; } else { self.execute( "INSERT INTO config (keyname, value) VALUES (?, ?);", - paramsv![key, value], + (key, value), ) .await?; } } else { - self.execute("DELETE FROM config WHERE keyname=?;", paramsv![key]) + self.execute("DELETE FROM config WHERE keyname=?;", (key,)) .await?; } lock.insert(key.to_string(), value.map(|s| s.to_string())); @@ -597,7 +589,7 @@ impl Sql { let mut lock = self.config_cache.write().await; let value = self - .query_get_value("SELECT value FROM config WHERE keyname=?;", paramsv![key]) + .query_get_value("SELECT value FROM config WHERE keyname=?;", (key,)) .await .context(format!("failed to fetch raw config: {key}"))?; lock.insert(key.to_string(), value.clone()); @@ -980,7 +972,7 @@ async fn prune_tombstones(sql: &Sql) -> Result<()> { AND NOT EXISTS ( SELECT * FROM imap WHERE msgs.rfc724_mid=rfc724_mid AND target!='' )", - paramsv![DC_CHAT_ID_TRASH], + (DC_CHAT_ID_TRASH,), ) .await?; Ok(()) @@ -1163,12 +1155,12 @@ mod tests { sql.open(&t, "".to_string()).await?; sql.execute( "INSERT INTO config (keyname, value) VALUES (?, ?);", - paramsv!("foo", "bar"), + ("foo", "bar"), ) .await?; let value: Option = sql - .query_get_value("SELECT value FROM config WHERE keyname=?;", paramsv!("foo")) + .query_get_value("SELECT value FROM config WHERE keyname=?;", ("foo",)) .await?; assert_eq!(value.unwrap(), "bar"); diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 55c979a87..9493164ea 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -30,7 +30,7 @@ pub async fn run(context: &Context, sql: &Sql) -> Result<(bool, bool, bool, bool // set raw config inside the transaction transaction.execute( "INSERT INTO config (keyname, value) VALUES (?, ?);", - paramsv![VERSION_CFG, format!("{dbversion_before_update}")], + (VERSION_CFG, format!("{dbversion_before_update}")), )?; Ok(()) }) @@ -746,7 +746,7 @@ impl Sql { fn set_db_version_trans(transaction: &mut rusqlite::Transaction, version: i32) -> Result<()> { transaction.execute( "UPDATE config SET value=? WHERE keyname=?;", - params![format!("{version}"), VERSION_CFG], + (format!("{version}"), VERSION_CFG), )?; Ok(()) } diff --git a/src/sync.rs b/src/sync.rs index ea10cbce9..008c450fd 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -65,10 +65,7 @@ impl Context { let item = SyncItem { timestamp, data }; let item = serde_json::to_string(&item)?; self.sql - .execute( - "INSERT INTO multi_device_sync (item) VALUES(?);", - paramsv![item], - ) + .execute("INSERT INTO multi_device_sync (item) VALUES(?);", (item,)) .await?; Ok(()) diff --git a/src/test_utils.rs b/src/test_utils.rs index 07fbef649..0332df566 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -425,7 +425,7 @@ impl TestContext { }; self.ctx .sql - .execute("DELETE FROM smtp WHERE id=?;", paramsv![rowid]) + .execute("DELETE FROM smtp WHERE id=?;", (rowid,)) .await .expect("failed to remove job"); update_msg_state(&self.ctx, msg_id, MessageState::OutDelivered) diff --git a/src/token.rs b/src/token.rs index 30acb81a0..2db815864 100644 --- a/src/token.rs +++ b/src/token.rs @@ -35,7 +35,7 @@ pub async fn save( .sql .execute( "INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);", - paramsv![namespace, foreign_id, token, time()], + (namespace, foreign_id, token, time()), ) .await?, None => { @@ -43,7 +43,7 @@ pub async fn save( .sql .execute( "INSERT INTO tokens (namespc, token, timestamp) VALUES (?, ?, ?);", - paramsv![namespace, token, time()], + (namespace, token, time()), ) .await? } @@ -71,7 +71,7 @@ pub async fn lookup( .sql .query_get_value( "SELECT token FROM tokens WHERE namespc=? AND foreign_id=? ORDER BY timestamp DESC LIMIT 1;", - paramsv![namespace, chat_id], + (namespace, chat_id), ) .await? } @@ -81,7 +81,7 @@ pub async fn lookup( .sql .query_get_value( "SELECT token FROM tokens WHERE namespc=? AND foreign_id=0 ORDER BY timestamp DESC LIMIT 1;", - paramsv![namespace], + (namespace,), ) .await? } @@ -108,7 +108,7 @@ pub async fn exists(context: &Context, namespace: Namespace, token: &str) -> boo .sql .exists( "SELECT COUNT(*) FROM tokens WHERE namespc=? AND token=?;", - paramsv![namespace, token], + (namespace, token), ) .await .unwrap_or_default() @@ -119,7 +119,7 @@ pub async fn delete(context: &Context, namespace: Namespace, token: &str) -> Res .sql .execute( "DELETE FROM tokens WHERE namespc=? AND token=?;", - paramsv![namespace, token], + (namespace, token), ) .await?; Ok(()) diff --git a/src/update_helper.rs b/src/update_helper.rs index ed140dfdd..539ad85c2 100644 --- a/src/update_helper.rs +++ b/src/update_helper.rs @@ -31,7 +31,7 @@ impl Context { if update { transaction.execute( "UPDATE contacts SET param=? WHERE id=?", - params![param.to_string(), contact_id], + (param.to_string(), contact_id), )?; } Ok(update) @@ -61,7 +61,7 @@ impl ChatId { if update { transaction.execute( "UPDATE chats SET param=? WHERE id=?", - params![param.to_string(), self], + (param.to_string(), self), )?; } Ok(update) diff --git a/src/webxdc.rs b/src/webxdc.rs index d1c92b350..cf143da12 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -263,7 +263,7 @@ impl Context { FROM msgs WHERE chat_id=?1 AND hidden=0 ORDER BY timestamp DESC, id DESC LIMIT 1"#, - paramsv![instance.chat_id], + (instance.chat_id,), |row| { let last_msg_id: MsgId = row.get(0)?; let last_from_id: ContactId = row.get(1)?; @@ -387,7 +387,7 @@ impl Context { .sql .insert( "INSERT INTO msgs_status_updates (msg_id, update_item) VALUES(?, ?);", - paramsv![instance_id, serde_json::to_string(&status_update_item)?], + (instance_id, serde_json::to_string(&status_update_item)?), ) .await?; let status_update_serial = StatusUpdateSerial(u32::try_from(rowid)?); @@ -435,7 +435,7 @@ impl Context { "INSERT INTO smtp_status_updates (msg_id, first_serial, last_serial, descr) VALUES(?, ?, ?, ?) ON CONFLICT(msg_id) DO UPDATE SET last_serial=excluded.last_serial, descr=excluded.descr", - paramsv![instance.id, status_update_serial, status_update_serial, descr], + (instance.id, status_update_serial, status_update_serial, descr), ).await?; self.scheduler .interrupt_smtp(InterruptInfo::new(false)) @@ -579,7 +579,7 @@ impl Context { .sql .query_map( "SELECT update_item, id FROM msgs_status_updates WHERE msg_id=? AND id>? ORDER BY id", - paramsv![instance_msg_id, last_known_serial], + (instance_msg_id, last_known_serial), |row| { let update_item_str = row.get::<_, String>(0)?; let serial = row.get::<_, StatusUpdateSerial>(1)?; @@ -631,11 +631,11 @@ impl Context { .sql .query_map( "SELECT update_item FROM msgs_status_updates WHERE msg_id=? AND id>=? AND id<=? ORDER BY id", - paramsv![ + ( instance_msg_id, range.map(|r|r.0).unwrap_or(StatusUpdateSerial(0)), range.map(|r|r.1).unwrap_or(StatusUpdateSerial(u32::MAX)), - ], + ), |row| row.get::<_, String>(0), |rows| { let mut json = String::default(); From 28fd27476f3e068faf1f5c2550f3abda01c0223f Mon Sep 17 00:00:00 2001 From: Hocuri Date: Thu, 13 Apr 2023 18:14:23 +0200 Subject: [PATCH 15/24] Small verification fixes (#4317) * Small performance improvement by not unnecessarily loading the peerstate * Remove wrong info message "{contact} verified" when scanning a QR code with just an email I think that this was a bug in the original C code and then slipped through two refactorings. --- CHANGELOG.md | 2 ++ src/contact.rs | 4 +--- src/qr.rs | 12 ++---------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07b14f765..11cb919e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ - maybe_add_time_based_warnings(): Use release date instead of the provider DB update one - Cleanly terminate deltachat-rpc-server. Also terminate on ctrl-c. +- Refactorings #4317 + ### Fixes - Fix python bindings README documentation on installing the bindings from source. diff --git a/src/contact.rs b/src/contact.rs index a9f48009c..78269f003 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1195,9 +1195,7 @@ impl Contact { if peerstate.verified_key.is_some() { return Ok(VerifiedStatus::BidirectVerified); } - } - - if let Some(peerstate) = Peerstate::from_addr(context, &self.addr).await? { + } else if let Some(peerstate) = Peerstate::from_addr(context, &self.addr).await? { if peerstate.verified_key.is_some() { return Ok(VerifiedStatus::BidirectVerified); } diff --git a/src/qr.rs b/src/qr.rs index 920776b5e..f40b3786e 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -10,7 +10,7 @@ use percent_encoding::percent_decode_str; use serde::Deserialize; use self::dclogin_scheme::configure_from_login_qr; -use crate::chat::{self, get_chat_id_by_grpid, ChatIdBlocked}; +use crate::chat::{get_chat_id_by_grpid, ChatIdBlocked}; use crate::config::Config; use crate::constants::Blocked; use crate::contact::{ @@ -21,7 +21,6 @@ use crate::key::Fingerprint; use crate::message::Message; use crate::peerstate::Peerstate; use crate::socks::Socks5Config; -use crate::tools::time; use crate::{token, EventType}; const OPENPGP4FPR_SCHEME: &str = "OPENPGP4FPR:"; // yes: uppercase @@ -435,16 +434,9 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Result { Contact::add_or_lookup(context, &name, peerstate_addr, Origin::UnhandledQrScan) .await .context("add_or_lookup")?; - let chat = ChatIdBlocked::get_for_contact(context, contact_id, Blocked::Request) + ChatIdBlocked::get_for_contact(context, contact_id, Blocked::Request) .await .context("Failed to create (new) chat for contact")?; - chat::add_info_msg( - context, - chat.id, - &format!("{} verified.", peerstate.addr), - time(), - ) - .await?; Ok(Qr::FprOk { contact_id }) } else { let contact_id = Contact::lookup_id_by_addr(context, &addr, Origin::Unknown) From d4f2507288d2f885371a59ff97eafb807855296f Mon Sep 17 00:00:00 2001 From: Hocuri Date: Thu, 13 Apr 2023 18:27:25 +0200 Subject: [PATCH 16/24] =?UTF-8?q?Remove=20confusing=20log=20"ignoring=20un?= =?UTF-8?q?solicited=20response=20Recent(=E2=80=A6)"=20(#3934)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't seem to add value and gives the impression that something went wrong. --- CHANGELOG.md | 1 + src/imap.rs | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11cb919e1..4a72189f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Compress `mime_headers` column with HTML emails stored in database - Strip BIDI characters in system messages, files, group names and contact names #3479 - maybe_add_time_based_warnings(): Use release date instead of the provider DB update one +- Remove confusing log line "ignoring unsolicited response Recent(…)" #3934 - Cleanly terminate deltachat-rpc-server. Also terminate on ctrl-c. - Refactorings #4317 diff --git a/src/imap.rs b/src/imap.rs index 2de7b666d..a82b45a0a 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1740,17 +1740,37 @@ impl Session { /// 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 { + use async_imap::imap_proto::Response; + use async_imap::imap_proto::ResponseCode; + use UnsolicitedResponse::*; + let mut unsolicited_exists = false; while let Ok(response) = self.unsolicited_responses.try_recv() { match response { - UnsolicitedResponse::Exists(_) => { + Exists(_) => { info!( context, "Need to fetch again, got unsolicited EXISTS {:?}", response ); unsolicited_exists = true; } - _ => info!(context, "ignoring unsolicited response {:?}", response), + + // 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(_, _, _)), + .. + } + ) => {} + + _ => { + info!(context, "got unsolicited response {:?}", response) + } } } Ok(unsolicited_exists) From 436766f0023b3a2d53dc55f7cdf7599f0403d379 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:04:54 +0000 Subject: [PATCH 17/24] build(deps): bump h2 from 0.3.15 to 0.3.17 in /fuzz Bumps [h2](https://github.com/hyperium/h2) from 0.3.15 to 0.3.17. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.15...v0.3.17) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- fuzz/Cargo.lock | 900 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 600 insertions(+), 300 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 0fff96832..e9033c1cf 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -55,7 +55,7 @@ checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom 0.2.8", "once_cell", - "version_check 0.9.4", + "version_check", ] [[package]] @@ -73,6 +73,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -118,7 +133,7 @@ dependencies = [ "asn1-rs-derive", "asn1-rs-impl", "displaydoc", - "nom 7.1.1", + "nom", "num-traits", "rusticata-macros", "thiserror", @@ -133,7 +148,7 @@ checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "synstructure", ] @@ -145,7 +160,7 @@ checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -174,18 +189,19 @@ dependencies = [ [[package]] name = "async-imap" -version = "0.6.0" -source = "git+https://github.com/async-email/async-imap?branch=master#85ff7a3d9d71a3715354fabf2fc1a8d047b5710e" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8379e2f1cdeb79afd2006932d7e8f64993fc0f7386d0ebc37231c90b05968c25" dependencies = [ "async-channel", "async-native-tls 0.4.0", - "base64 0.13.1", + "base64 0.21.0", "byte-pool", "chrono", "futures", "imap-proto", "log", - "nom 7.1.1", + "nom", "once_cell", "ouroboros", "pin-utils", @@ -229,7 +245,7 @@ dependencies = [ "futures", "hostname", "log", - "nom 7.1.1", + "nom", "pin-project", "thiserror", "tokio", @@ -243,14 +259,14 @@ checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] name = "async_zip" -version = "0.0.11" +version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50d29ab7e2f9e808cca1a69ea56a36f4ff216f54a41a23aae1fd4afc05cc020" +checksum = "b2105142db9c6203b9dadc83b0553394589a6cb31b1449a3b46b42f47c3434d0" dependencies = [ "async-compression", "crc32fast", @@ -281,18 +297,18 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base16ct" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.11.0" @@ -460,7 +476,7 @@ checksum = "3b3c57c2a0967ad1a09ba4c2bf8f1c6b6db2f71e8c0db4fa280c65a0f6c249c3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -492,10 +508,41 @@ dependencies = [ ] [[package]] -name = "buf_redux" -version = "0.8.4" +name = "brotli" +version = "3.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "buffer-redux" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2886ea01509598caac116942abd33ab5a88fa32acdf7e4abfa0fc489ca520c9" dependencies = [ "memchr", "safemem", @@ -531,9 +578,19 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] [[package]] name = "cast5" @@ -600,43 +657,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "4.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" -dependencies = [ - "bitflags 2.0.2", - "clap_derive", - "clap_lex", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "cobs" version = "0.2.3" @@ -668,24 +688,11 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "console" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.42.0", -] - [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "const_format" @@ -790,6 +797,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -813,6 +832,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" +dependencies = [ + "cfg-if", + "digest 0.10.6", + "fiat-crypto", + "packed_simd_2", + "platforms", + "subtle", + "zeroize", +] + [[package]] name = "cxx" version = "1.0.85" @@ -837,7 +871,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.107", ] [[package]] @@ -854,7 +888,7 @@ checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -878,7 +912,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.107", ] [[package]] @@ -889,7 +923,7 @@ checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -898,41 +932,26 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" -[[package]] -name = "data-encoding-macro" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" -dependencies = [ - "data-encoding", - "data-encoding-macro-internal", -] - -[[package]] -name = "data-encoding-macro-internal" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" -dependencies = [ - "data-encoding", - "syn", -] - [[package]] name = "default-net" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cdeb2fba22cc965edfe42933910a84d8202417302f734ac98d34a7ee5ead51" +checksum = "a4898b43aed56499fad6b294d15b3e76a51df68079bf492e5daae38ca084e003" dependencies = [ + "dlopen2", "libc", "memalloc", + "netlink-packet-core", + "netlink-packet-route", + "netlink-sys", + "once_cell", "system-configuration", "windows", ] [[package]] name = "deltachat" -version = "1.112.0" +version = "1.112.6" dependencies = [ "anyhow", "async-channel", @@ -942,7 +961,7 @@ dependencies = [ "async_zip", "backtrace", "base64 0.21.0", - "bitflags 1.3.2", + "brotli", "chrono", "deltachat_derive", "email", @@ -990,6 +1009,7 @@ dependencies = [ "tokio-io-timeout", "tokio-stream", "tokio-tar", + "tokio-util", "toml", "trust-dns-resolver", "url", @@ -1011,7 +1031,7 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -1022,7 +1042,18 @@ checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", "der_derive", - "pem-rfc7468", + "pem-rfc7468 0.6.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed" +dependencies = [ + "const-oid", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -1034,7 +1065,7 @@ checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ "asn1-rs", "displaydoc", - "nom 7.1.1", + "nom", "num-bigint", "num-traits", "rusticata-macros", @@ -1049,38 +1080,38 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] name = "derive_builder" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] name = "derive_builder_macro" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" dependencies = [ "derive_builder_core", - "syn", + "syn 1.0.107", ] [[package]] @@ -1093,7 +1124,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.107", ] [[package]] @@ -1155,7 +1186,30 @@ checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", +] + +[[package]] +name = "dlopen2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b121caccfc363e4d9a4589528f3bef7c71b83c6ed01c8dc68cbeeb7fd29ec698" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a09ac8bb8c16a282264c379dffba707b9c998afc7506009137f3c6136888078" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] @@ -1164,10 +1218,23 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +dependencies = [ + "der 0.7.3", + "digest 0.10.6", + "elliptic-curve 0.13.4", + "rfc6979 0.4.0", + "signature 2.1.0", ] [[package]] @@ -1177,7 +1244,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" dependencies = [ "serde", - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.1.0", ] [[package]] @@ -1186,8 +1263,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 3.2.0", + "ed25519 1.5.2", "rand 0.7.3", "serde", "serde_bytes", @@ -1195,6 +1272,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798f704d128510932661a3489b08e3f4c934a01d61c5def59ae7b8e48f19665a" +dependencies = [ + "curve25519-dalek 4.0.0-rc.2", + "ed25519 2.2.1", + "serde", + "sha2 0.10.6", + "zeroize", +] + [[package]] name = "educe" version = "0.4.20" @@ -1204,7 +1294,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1219,15 +1309,36 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", "digest 0.10.6", - "ff", + "ff 0.12.1", "generic-array", - "group", + "group 0.12.1", "rand_core 0.6.4", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.1", + "digest 0.10.6", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "hkdf", + "pem-rfc7468 0.7.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.1", "subtle", "zeroize", ] @@ -1244,15 +1355,9 @@ dependencies = [ "lazy_static", "rand 0.7.3", "time 0.1.45", - "version_check 0.9.4", + "version_check", ] -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - [[package]] name = "encoded-words" version = "0.2.0" @@ -1355,7 +1460,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1369,7 +1474,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.107", ] [[package]] @@ -1461,6 +1566,22 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "filetime" version = "0.2.19" @@ -1601,7 +1722,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1641,7 +1762,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", - "version_check 0.9.4", + "version_check", + "zeroize", ] [[package]] @@ -1670,9 +1792,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.11.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" dependencies = [ "color_quant", "weezl", @@ -1690,16 +1812,27 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", @@ -1753,6 +1886,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1813,7 +1955,7 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e682e2bd70ecbcce5209f11a992a4ba001fea8e60acf7860ce007629e6d2756" dependencies = [ - "libm", + "libm 0.2.6", ] [[package]] @@ -1877,6 +2019,15 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1906,9 +2057,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.5" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" dependencies = [ "bytemuck", "byteorder", @@ -1926,7 +2077,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f73b1b63179418b20aa81002d616c5f21b4ba257da9bca6989ea64dc573933e0" dependencies = [ - "nom 7.1.1", + "nom", ] [[package]] @@ -1939,19 +2090,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "indicatif" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" -dependencies = [ - "console", - "number_prefix", - "portable-atomic 0.3.19", - "tokio", - "unicode-width", -] - [[package]] name = "inout" version = "0.1.3" @@ -2000,28 +2138,24 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" [[package]] name = "iroh" -version = "0.3.0" -source = "git+https://github.com/n0-computer/iroh?branch=main#bf22ee2c311cf2a845bd7ef9425dc773d05502a2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4fb9858c8cd3dd924a5da5bc511363845a9bcfdfac066bb2ef8454eb6111546" dependencies = [ "abao", "anyhow", "base64 0.21.0", "blake3", "bytes", - "clap", - "console", - "data-encoding", "default-net", - "der", + "der 0.6.1", "derive_more", "dirs-next", - "ed25519-dalek", + "ed25519-dalek 1.0.1", "futures", "hex", - "indicatif", - "multibase", "num_cpus", - "portable-atomic 1.1.0", + "portable-atomic", "postcard", "quic-rpc", "quinn", @@ -2046,18 +2180,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys 0.42.0", -] - [[package]] name = "itoa" version = "1.0.5" @@ -2136,6 +2258,12 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + [[package]] name = "libm" version = "0.2.6" @@ -2144,9 +2272,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libsqlite3-sys" -version = "0.25.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" dependencies = [ "cc", "openssl-sys", @@ -2300,17 +2428,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "multibase" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" -dependencies = [ - "base-x", - "data-encoding", - "data-encoding-macro", -] - [[package]] name = "mutate_once" version = "0.1.1" @@ -2345,13 +2462,52 @@ dependencies = [ ] [[package]] -name = "nom" -version = "4.2.3" +name = "netlink-packet-core" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +checksum = "7e5cf0b54effda4b91615c40ff0fd12d0d4c9a6e0f5116874f03941792ff535a" dependencies = [ - "memchr", - "version_check 0.1.5", + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea993e32c77d87f01236c38f572ecb6c311d592e56a06262a007fd2a6e31253c" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-sys" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +dependencies = [ + "bytes", + "libc", + "log", ] [[package]] @@ -2402,7 +2558,7 @@ checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" dependencies = [ "byteorder", "lazy_static", - "libm", + "libm 0.2.6", "num-integer", "num-iter", "num-traits", @@ -2420,7 +2576,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -2462,7 +2618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm", + "libm 0.2.6", ] [[package]] @@ -2475,12 +2631,6 @@ dependencies = [ "libc", ] -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "object" version = "0.30.0" @@ -2534,7 +2684,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -2566,12 +2716,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "ouroboros" version = "0.15.5" @@ -2592,7 +2736,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -2607,8 +2751,20 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", +] + +[[package]] +name = "p256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc7304b8213f8597952b2f4c3d7f09947d46bb677801df8f287ffd2c4e26f9da" +dependencies = [ + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", + "primeorder", "sha2 0.10.6", ] @@ -2618,11 +2774,33 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", "sha2 0.10.6", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", + "primeorder", + "sha2 0.10.6", +] + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", +] + [[package]] name = "parking" version = "2.0.0" @@ -2652,6 +2830,12 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + [[package]] name = "pem" version = "1.1.1" @@ -2670,6 +2854,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -2678,17 +2871,19 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pgp" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991e3f098483f52c454c7cb16720adc010c2966a8845d3c34aad589cb86d3196" +checksum = "37a79d6411154d1a9908e7a2c4bac60a5742f6125823c2c30780c7039aef02f0" dependencies = [ "aes", - "base64 0.13.1", + "base64 0.21.0", "bitfield", "block-padding", "blowfish", - "buf_redux", + "bstr", + "buffer-redux", "byteorder", + "camellia", "cast5", "cfb-mode", "chrono", @@ -2697,23 +2892,27 @@ dependencies = [ "derive_builder", "des", "digest 0.10.6", - "ed25519-dalek", + "ed25519-dalek 2.0.0-rc.2", + "elliptic-curve 0.13.4", "flate2", "generic-array", "hex", + "idea", "log", "md-5", - "nom 4.2.3", + "nom", "num-bigint-dig", "num-derive", "num-traits", + "p256 0.13.1", + "p384 0.13.0", "rand 0.8.5", "ripemd", - "rsa", + "rsa 0.9.0-pre.1", "sha1", "sha2 0.10.6", "sha3", - "signature", + "signature 2.1.0", "smallvec", "thiserror", "twofish", @@ -2738,7 +2937,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -2759,9 +2958,21 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.6.1", + "pkcs8 0.9.0", + "spki 0.6.0", + "zeroize", +] + +[[package]] +name = "pkcs1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575fd6eebed721a2929faa1ee1383a49788378083bbbd7f299af75dd84195cee" +dependencies = [ + "der 0.7.3", + "pkcs8 0.10.2", + "spki 0.7.1", "zeroize", ] @@ -2771,8 +2982,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.3", + "spki 0.7.1", ] [[package]] @@ -2781,6 +3002,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "png" version = "0.17.7" @@ -2793,12 +3020,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "portable-atomic" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" - [[package]] name = "portable-atomic" version = "1.1.0" @@ -2825,7 +3046,7 @@ checksum = "fc4b01218787dd4420daf63875163a787a78294ad48a24e9f6fa8c6507759a79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -2840,6 +3061,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" +[[package]] +name = "primeorder" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5" +dependencies = [ + "elliptic-curve 0.13.4", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2849,8 +3079,8 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", - "version_check 0.9.4", + "syn 1.0.107", + "version_check", ] [[package]] @@ -2861,14 +3091,14 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check 0.9.4", + "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -2905,9 +3135,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.27.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" dependencies = [ "memchr", ] @@ -2964,9 +3194,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -3112,9 +3342,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "reqwest" -version = "0.11.14" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" dependencies = [ "base64 0.21.0", "bytes", @@ -3163,11 +3393,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -3204,22 +3444,43 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "pkcs1", - "pkcs8", + "pkcs1 0.4.1", + "pkcs8 0.9.0", "rand_core 0.6.4", - "signature", + "signature 1.6.4", "smallvec", "subtle", "zeroize", ] [[package]] -name = "rusqlite" -version = "0.28.0" +name = "rsa" +version = "0.9.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +checksum = "f16504cc31b04d2a5ec729f0c7e1b62e76634a9537f089df0ca1981dc8208a89" dependencies = [ - "bitflags 1.3.2", + "byteorder", + "const-oid", + "digest 0.10.6", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1 0.7.2", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.1.0", + "subtle", + "zeroize", +] + +[[package]] +name = "rusqlite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" +dependencies = [ + "bitflags 2.0.2", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -3260,7 +3521,7 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "nom 7.1.1", + "nom", ] [[package]] @@ -3384,10 +3645,24 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array", - "pkcs8", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.3", + "generic-array", + "pkcs8 0.10.2", "subtle", "zeroize", ] @@ -3456,7 +3731,7 @@ checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -3575,6 +3850,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.7" @@ -3628,7 +3913,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +dependencies = [ + "base64ct", + "der 0.7.3", ] [[package]] @@ -3638,7 +3933,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19cfdc32e0199062113edf41f344fbf784b8205a94600233c84eb838f45191e1" dependencies = [ "base64ct", - "pem-rfc7468", + "pem-rfc7468 0.6.0", "sha2 0.10.6", ] @@ -3648,14 +3943,14 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "288d8f5562af5a3be4bda308dd374b2c807b940ac370b5efa1c99311da91d9a1" dependencies = [ - "ed25519-dalek", - "p256", - "p384", + "ed25519-dalek 1.0.1", + "p256 0.11.1", + "p384 0.11.2", "rand_core 0.6.4", - "rsa", - "sec1", + "rsa 0.7.2", + "sec1 0.3.0", "sha2 0.10.6", - "signature", + "signature 1.6.4", "ssh-encoding", "zeroize", ] @@ -3700,7 +3995,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.107", ] [[package]] @@ -3720,6 +4015,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -3728,7 +4034,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "unicode-xid", ] @@ -3809,7 +4115,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -3913,7 +4219,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -3969,9 +4275,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -4041,7 +4347,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -4250,12 +4556,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - [[package]] name = "version_check" version = "0.9.4" @@ -4327,7 +4627,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-shared", ] @@ -4361,7 +4661,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4589,12 +4889,12 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "1.1.1" +version = "2.0.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" dependencies = [ - "curve25519-dalek", - "rand_core 0.5.1", + "curve25519-dalek 3.2.0", + "rand_core 0.6.4", "zeroize", ] @@ -4609,7 +4909,7 @@ dependencies = [ "data-encoding", "der-parser", "lazy_static", - "nom 7.1.1", + "nom", "oid-registry", "rusticata-macros", "thiserror", @@ -4651,6 +4951,6 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "synstructure", ] From 4da0e9ac6411c4bac301b0499cb568870a8fd997 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:07:57 +0000 Subject: [PATCH 18/24] cargo: bump h2 from 0.3.16 to 0.3.17 Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2748fc7a..89b75936b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2177,9 +2177,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", From c6a64e8d932986f4a6b32774e796a32915b33d75 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Thu, 13 Apr 2023 22:45:47 +0200 Subject: [PATCH 19/24] Don't let blocking be bypassed using groups (#4316) * Don't let blocking be bypassed using groups Fix #4313 * Fix another bug: A blocked group was sometimes not unblocked when an unblocked contact sent a message into it. --- CHANGELOG.md | 1 + src/receive_imf.rs | 32 ++++++++++++++------------- src/receive_imf/tests.rs | 48 ++++++++++++++++++++++++++++++++++++++++ src/test_utils.rs | 24 +++++++++++++++++++- 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a72189f2..422f47b8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Fix python bindings README documentation on installing the bindings from source. - Show a warning if quota list is empty #4261 - Update "accounts.toml" atomically +- Don't let blocking be bypassed using groups #4316 ## [1.112.6] - 2023-04-04 diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 12e16800b..9418a228f 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -553,18 +553,18 @@ async fn add_parts( // signals whether the current user is a bot let is_bot = context.get_config_bool(Config::Bot).await?; + let create_blocked = match test_normal_chat { + Some(ChatIdBlocked { + id: _, + blocked: Blocked::Request, + }) if is_bot => Blocked::Not, + Some(ChatIdBlocked { id: _, blocked }) => blocked, + None => Blocked::Request, + }; + if chat_id.is_none() { // try to create a group - let create_blocked = match test_normal_chat { - Some(ChatIdBlocked { - id: _, - blocked: Blocked::Not, - }) => Blocked::Not, - _ if is_bot => Blocked::Not, - _ => Blocked::Request, - }; - if let Some((new_chat_id, new_chat_id_blocked)) = create_or_lookup_group( context, mime_parser, @@ -581,13 +581,15 @@ async fn add_parts( { chat_id = Some(new_chat_id); chat_id_blocked = new_chat_id_blocked; + } + } - // if the chat is somehow blocked but we want to create a non-blocked chat, - // unblock the chat - if chat_id_blocked != Blocked::Not && create_blocked == Blocked::Not { - new_chat_id.unblock(context).await?; - chat_id_blocked = Blocked::Not; - } + // if the chat is somehow blocked but we want to create a non-blocked chat, + // unblock the chat + if chat_id_blocked != Blocked::Not && create_blocked != Blocked::Yes { + if let Some(chat_id) = chat_id { + chat_id.set_blocked(context, create_blocked).await?; + chat_id_blocked = create_blocked; } } diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index aee277e5d..cf64ee3b5 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -3046,6 +3046,54 @@ async fn test_no_private_reply_to_blocked_account() -> Result<()> { Ok(()) } +/// Regression test for two bugs: +/// +/// 1. If you blocked some spammer using DC, the 1:1 messages with that contact +/// are not received, but they could easily bypass this restriction creating +/// a new group with only you two as member. +/// 2. A blocked group was sometimes not unblocked when when an unblocked +/// contact sent a message into it. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_blocked_contact_creates_group() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + let fiona = tcm.fiona().await; + + let chat = alice.create_chat(&bob).await; + chat.id.block(&alice).await?; + + let group_id = bob + .create_group_with_members( + ProtectionStatus::Unprotected, + "group name", + &[&alice, &fiona], + ) + .await; + + let sent = bob.send_text(group_id, "Heyho, I'm a spammer!").await; + let rcvd = alice.recv_msg(&sent).await; + // Alice blocked Bob, so she shouldn't get the message + assert_eq!(rcvd.chat_blocked, Blocked::Yes); + + // Fiona didn't block Bob, though, so she gets the message + let rcvd = fiona.recv_msg(&sent).await; + assert_eq!(rcvd.chat_blocked, Blocked::Request); + + // Fiona writes to the group + rcvd.chat_id.accept(&fiona).await?; + let sent = fiona.send_text(rcvd.chat_id, "Hello from Fiona").await; + + // The group is unblocked now that Fiona sent a message to it + let rcvd = alice.recv_msg(&sent).await; + assert_eq!(rcvd.chat_blocked, Blocked::Request); + // In order not to lose context, Bob's message should also be shown in the group + let msgs = chat::get_chat_msgs(&alice, rcvd.chat_id).await?; + assert_eq!(msgs.len(), 2); + + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_thunderbird_autocrypt() -> Result<()> { let t = TestContext::new_bob().await; diff --git a/src/test_utils.rs b/src/test_utils.rs index 0332df566..003b3578c 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -18,7 +18,10 @@ use tokio::runtime::Handle; use tokio::sync::RwLock; use tokio::task; -use crate::chat::{self, Chat, ChatId, MessageListOptions}; +use crate::chat::{ + self, add_to_chat_contacts_table, create_group_chat, Chat, ChatId, MessageListOptions, + ProtectionStatus, +}; use crate::chatlist::Chatlist; use crate::config::Config; use crate::constants::Chattype; @@ -702,6 +705,25 @@ impl TestContext { ); } } + + pub async fn create_group_with_members( + &self, + protect: ProtectionStatus, + chat_name: &str, + members: &[&TestContext], + ) -> ChatId { + let chat_id = create_group_chat(self, protect, chat_name).await.unwrap(); + let mut to_add = vec![]; + for member in members { + let contact = self.add_or_lookup_contact(member).await; + to_add.push(contact.id); + } + add_to_chat_contacts_table(self, chat_id, &to_add) + .await + .unwrap(); + + chat_id + } } impl Deref for TestContext { From 318ed4e6e1ea11e3fe61f03bda567b00858a53b5 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 14 Apr 2023 16:23:34 +0000 Subject: [PATCH 20/24] Fix `pip install` argument in python README Attempt to run `pip install python` will fail trying to install package from PyPI. --- python/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/README.rst b/python/README.rst index c2b4d87e2..da1b25c7e 100644 --- a/python/README.rst +++ b/python/README.rst @@ -122,7 +122,7 @@ Build and install the bindings: export DCC_RS_DEV="$PWD" export DCC_RS_TARGET=release - python -m pip install python + python -m pip install ./python `DCC_RS_DEV` environment variable specifies the location of the core development tree. If this variable is not set, From b369a3054454f58070d7ed02f779eba3153e30d1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 14 Apr 2023 16:24:08 +0000 Subject: [PATCH 21/24] Pass scripts/run-python-test.sh arguments to pytest --- scripts/run-python-test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/run-python-test.sh b/scripts/run-python-test.sh index 93acd07cc..544e1e278 100755 --- a/scripts/run-python-test.sh +++ b/scripts/run-python-test.sh @@ -22,4 +22,5 @@ export PYTHONDONTWRITEBYTECODE=1 # run python tests (tox invokes pytest to run tests in python/tests) #TOX_PARALLEL_NO_SPINNER=1 tox -e lint,doc tox -e lint -tox -e doc,py +tox -e doc +tox -e py -- "$@" From 28a13e98a66deda5da31f2b455e2fe6220dd75a3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 14 Apr 2023 20:10:18 +0000 Subject: [PATCH 22/24] Add JSON-RPC API can_send() --- CHANGELOG.md | 2 +- deltachat-jsonrpc/src/api/mod.rs | 9 +++++++++ deltachat-rpc-client/src/deltachat_rpc_client/chat.py | 4 ++++ deltachat-rpc-client/tests/test_something.py | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 422f47b8d..714cd3d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - Cleanly terminate deltachat-rpc-server. Also terminate on ctrl-c. - Refactorings #4317 - +- Add JSON-RPC API `can_send()`. ### Fixes - Fix python bindings README documentation on installing the bindings from source. diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index e821a5b68..eac81c312 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1701,6 +1701,15 @@ impl CommandApi { Ok(msg_id) } + /// Checks if messages can be sent to a given chat. + async fn can_send(&self, account_id: u32, chat_id: u32) -> Result { + let ctx = self.get_context(account_id).await?; + let chat_id = ChatId::new(chat_id); + let chat = Chat::load_from_db(&ctx, chat_id).await?; + let can_send = chat.can_send(&ctx).await?; + Ok(can_send) + } + // --------------------------------------------- // functions for the composer // the composer is the message input field diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py index 65063a6f3..a9cfad8ab 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py @@ -105,6 +105,10 @@ class Chat: info = await self._rpc.get_full_chat_by_id(self.account.id, self.id) return AttrDict(chat=self, **info) + async def can_send(self) -> bool: + """Return true if messages can be sent to the chat.""" + return await self._rpc.can_send(self.account.id, self.id) + async def send_message( self, text: Optional[str] = None, diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index fc05854d6..ee08791fe 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -147,7 +147,9 @@ async def test_chat(acfactory) -> None: assert alice_chat_bob != bob_chat_alice assert repr(alice_chat_bob) await alice_chat_bob.delete() + assert not await bob_chat_alice.can_send() await bob_chat_alice.accept() + assert await bob_chat_alice.can_send() await bob_chat_alice.block() bob_chat_alice = await snapshot.sender.create_chat() await bob_chat_alice.mute() From fa87d2e22577a4e7e821ee054a63d42a91820e79 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 12 Apr 2023 21:48:14 +0000 Subject: [PATCH 23/24] New APIs for message processing loops This patch adds new C APIs dc_get_next_msgs() and dc_wait_next_msgs(), and their JSON-RPC counterparts get_next_msgs() and wait_next_msgs(). New configuration "last_msg_id" tracks the last message ID processed by the bot. get_next_msgs() returns message IDs above the "last_msg_id". wait_next_msgs() waits for new message notification and calls get_next_msgs(). wait_next_msgs() can be used to build a separate message processing loop independent of the event loop. Async Python API get_fresh_messages_in_arrival_order() is deprecated in favor of get_next_messages(). Introduced Python APIs: - Account.wait_next_incoming_message() - Message.is_from_self() - Message.is_from_device() Introduced Rust APIs: - Context.set_config_u32() - Context.get_config_u32() --- CHANGELOG.md | 8 ++ deltachat-ffi/deltachat.h | 74 +++++++++++- deltachat-ffi/src/lib.rs | 44 +++++++ deltachat-jsonrpc/src/api/mod.rs | 48 ++++++++ .../examples/echobot_no_hooks.py | 6 +- .../src/deltachat_rpc_client/__init__.py | 3 +- .../src/deltachat_rpc_client/account.py | 16 +++ .../src/deltachat_rpc_client/client.py | 7 +- deltachat-rpc-client/tests/test_something.py | 30 ++++- python/src/deltachat/account.py | 16 +++ python/src/deltachat/message.py | 10 ++ python/tests/test_1_online.py | 6 +- src/chat.rs | 3 + src/config.rs | 14 +++ src/context.rs | 111 +++++++++++++++++- src/message.rs | 6 + src/receive_imf.rs | 1 + src/scheduler.rs | 10 ++ 18 files changed, 398 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 714cd3d22..21a540326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ Also terminate on ctrl-c. - Refactorings #4317 - Add JSON-RPC API `can_send()`. +- New `dc_get_next_msgs()` and `dc_wait_next_msgs()` C APIs. + New `get_next_msgs()` and `wait_next_msgs()` JSON-RPC API. + These APIs can be used by bots to get all unprocessed messages + in the order of their arrival and wait for them without relying on events. +- Async Python API `get_fresh_messages_in_arrival_order()` is deprecated + in favor of `get_next_msgs()` and `wait_next_msgs()`. +- New Python bindings API `Account.wait_next_incoming_message()`. +- New Python bindings APIs `Message.is_from_self()` and `Message.is_from_device()`. ### Fixes - Fix python bindings README documentation on installing the bindings from source. diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index c901ab738..c76a5891a 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -181,12 +181,17 @@ typedef struct _dc_event_emitter dc_accounts_event_emitter_t; * and check it in the event loop thread * every time before calling dc_get_next_event(). * To terminate the event loop, main thread should: - * 1. Notify event loop that it should terminate by atomically setting the - * boolean flag in the memory shared between the main thread and event loop. + * 1. Notify background threads, + * such as event loop (blocking in dc_get_next_event()) + * and message processing loop (blocking in dc_wait_next_msgs()), + * that they should terminate by atomically setting the + * boolean flag in the memory + * shared between the main thread and background loop threads. * 2. Call dc_stop_io() or dc_accounts_stop_io(), depending * on whether a single account or account manager is used. * Stopping I/O is guaranteed to emit at least one event * and interrupt the event loop even if it was blocked on dc_get_next_event(). + * Stopping I/O is guaranteed to interrupt a single dc_wait_next_msgs(). * 3. Wait until the event loop thread notices the flag, * exits the event loop and terminates. * 4. Call dc_context_unref() or dc_accounts_unref(). @@ -457,6 +462,16 @@ char* dc_get_blobdir (const dc_context_t* context); * Prevents adding the "Device messages" and "Saved messages" chats, * adds Auto-Submitted header to outgoing messages * and accepts contact requests automatically (calling dc_accept_chat() is not needed for bots). + * - `last_msg_id` = database ID of the last message processed by the bot. + * This ID and IDs below it are guaranteed not to be returned + * by dc_get_next_msgs() and dc_wait_next_msgs(). + * The value is updated automatically + * when dc_markseen_msgs() is called, + * but the bot can also set it manually if it processed + * the message but does not want to mark it as seen. + * For most bots calling `dc_markseen_msgs()` is the + * recommended way to update this value + * even for self-sent messages. * - `fetch_existing_msgs` = 1=fetch most recent existing messages on configure (default), * 0=do not fetch existing messages on configure. * In both cases, existing recipients are added to the contact database. @@ -1343,6 +1358,56 @@ int dc_estimate_deletion_cnt (dc_context_t* context, int from_ser dc_array_t* dc_get_fresh_msgs (dc_context_t* context); +/** + * Returns the message IDs of all messages of any chat + * with a database ID higher than `last_msg_id` config value. + * + * This function is intended for use by bots. + * Self-sent messages, device messages, + * messages from contact requests + * and muted chats are included, + * but messages from explicitly blocked contacts + * and chats are ignored. + * + * This function may be called as a part of event loop + * triggered by DC_EVENT_INCOMING_MSG if you are only interested + * in the incoming messages. + * Otherwise use a separate message processing loop + * calling dc_wait_next_msgs() in a separate thread. + * + * @memberof dc_context_t + * @param context The context object as returned from dc_context_new(). + * @return An array of message IDs, must be dc_array_unref()'d when no longer used. + * On errors, the list is empty. NULL is never returned. + */ +dc_array_t* dc_get_next_msgs (dc_context_t* context); + + +/** + * Waits for notification of new messages + * and returns an array of new message IDs. + * See the documentation for dc_get_next_msgs() + * for the details of return value. + * + * This function waits for internal notification of + * a new message in the database and returns afterwards. + * Notification is also sent when I/O is started + * to allow processing new messages + * and when I/O is stopped using dc_stop_io() or dc_accounts_stop_io() + * to allow for manual interruption of the message processing loop. + * The function may return an empty array if there are + * no messages after notification, + * which may happen on start or if the message is quickly deleted + * after adding it to the database. + * + * @memberof dc_context_t + * @param context The context object as returned from dc_context_new(). + * @return An array of message IDs, must be dc_array_unref()'d when no longer used. + * On errors, the list is empty. NULL is never returned. + */ +dc_array_t* dc_wait_next_msgs (dc_context_t* context); + + /** * Mark all messages in a chat as _noticed_. * _Noticed_ messages are no longer _fresh_ and do not count as being unseen @@ -1942,6 +2007,11 @@ int dc_resend_msgs (dc_context_t* context, const uint3 * Moreover, timer is started for incoming ephemeral messages. * This also happens for contact requests chats. * + * This function updates last_msg_id configuration value + * to the maximum of the current value and IDs passed to this function. + * Bots which mark messages as seen can rely on this side effect + * to avoid updating last_msg_id value manually. + * * One #DC_EVENT_MSGS_NOTICED event is emitted per modified chat. * * @memberof dc_context_t diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 7daa9d195..6872c6d38 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1280,6 +1280,50 @@ pub unsafe extern "C" fn dc_get_fresh_msgs( }) } +#[no_mangle] +pub unsafe extern "C" fn dc_get_next_msgs(context: *mut dc_context_t) -> *mut dc_array::dc_array_t { + if context.is_null() { + eprintln!("ignoring careless call to dc_get_next_msgs()"); + return ptr::null_mut(); + } + let ctx = &*context; + + let msg_ids = block_on(ctx.get_next_msgs()) + .context("failed to get next messages") + .log_err(ctx) + .unwrap_or_default(); + let arr = dc_array_t::from( + msg_ids + .iter() + .map(|msg_id| msg_id.to_u32()) + .collect::>(), + ); + Box::into_raw(Box::new(arr)) +} + +#[no_mangle] +pub unsafe extern "C" fn dc_wait_next_msgs( + context: *mut dc_context_t, +) -> *mut dc_array::dc_array_t { + if context.is_null() { + eprintln!("ignoring careless call to dc_wait_next_msgs()"); + return ptr::null_mut(); + } + let ctx = &*context; + + let msg_ids = block_on(ctx.wait_next_msgs()) + .context("failed to wait for next messages") + .log_err(ctx) + .unwrap_or_default(); + let arr = dc_array_t::from( + msg_ids + .iter() + .map(|msg_id| msg_id.to_u32()) + .collect::>(), + ); + Box::into_raw(Box::new(arr)) +} + #[no_mangle] pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id: u32) { if context.is_null() { diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index eac81c312..cc994ed63 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -453,6 +453,49 @@ impl CommandApi { ChatId::new(chat_id).get_fresh_msg_cnt(&ctx).await } + /// Gets messages to be processed by the bot and returns their IDs. + /// + /// Only messages with database ID higher than `last_msg_id` config value + /// are returned. After processing the messages, the bot should + /// update `last_msg_id` by calling [`markseen_msgs`] + /// or manually updating the value to avoid getting already + /// processed messages. + /// + /// [`markseen_msgs`]: Self::markseen_msgs + async fn get_next_msgs(&self, account_id: u32) -> Result> { + let ctx = self.get_context(account_id).await?; + let msg_ids = ctx + .get_next_msgs() + .await? + .iter() + .map(|msg_id| msg_id.to_u32()) + .collect(); + Ok(msg_ids) + } + + /// Waits for messages to be processed by the bot and returns their IDs. + /// + /// This function is similar to [`get_next_msgs`], + /// but waits for internal new message notification before returning. + /// New message notification is sent when new message is added to the database, + /// on initialization, when I/O is started and when I/O is stopped. + /// This allows bots to use `wait_next_msgs` in a loop to process + /// old messages after initialization and during the bot runtime. + /// To shutdown the bot, stopping I/O can be used to interrupt + /// pending or next `wait_next_msgs` call. + /// + /// [`get_next_msgs`]: Self::get_next_msgs + async fn wait_next_msgs(&self, account_id: u32) -> Result> { + let ctx = self.get_context(account_id).await?; + let msg_ids = ctx + .wait_next_msgs() + .await? + .iter() + .map(|msg_id| msg_id.to_u32()) + .collect(); + Ok(msg_ids) + } + /// Estimate the number of messages that will be deleted /// by the set_config()-options `delete_device_after` or `delete_server_after`. /// This is typically used to show the estimated impact to the user @@ -944,6 +987,11 @@ impl CommandApi { /// Moreover, timer is started for incoming ephemeral messages. /// This also happens for contact requests chats. /// + /// This function updates `last_msg_id` configuration value + /// to the maximum of the current value and IDs passed to this function. + /// Bots which mark messages as seen can rely on this side effect + /// to avoid updating `last_msg_id` value manually. + /// /// One #DC_EVENT_MSGS_NOTICED event is emitted per modified chat. async fn markseen_msgs(&self, account_id: u32, msg_ids: Vec) -> Result<()> { let ctx = self.get_context(account_id).await?; diff --git a/deltachat-rpc-client/examples/echobot_no_hooks.py b/deltachat-rpc-client/examples/echobot_no_hooks.py index fadf2e560..77fda86e7 100644 --- a/deltachat-rpc-client/examples/echobot_no_hooks.py +++ b/deltachat-rpc-client/examples/echobot_no_hooks.py @@ -6,7 +6,7 @@ import asyncio import logging import sys -from deltachat_rpc_client import DeltaChat, EventType, Rpc +from deltachat_rpc_client import DeltaChat, EventType, Rpc, SpecialContactId async def main(): @@ -30,9 +30,9 @@ async def main(): await deltachat.start_io() async def process_messages(): - for message in await account.get_fresh_messages_in_arrival_order(): + for message in await account.get_next_messages(): snapshot = await message.get_snapshot() - if not snapshot.is_bot and not snapshot.is_info: + if snapshot.from_id != SpecialContactId.SELF and not snapshot.is_bot and not snapshot.is_info: await snapshot.chat.send_text(snapshot.text) await snapshot.message.mark_seen() diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/__init__.py b/deltachat-rpc-client/src/deltachat_rpc_client/__init__.py index 94edad50e..727c51c80 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/__init__.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/__init__.py @@ -3,7 +3,7 @@ from ._utils import AttrDict, run_bot_cli, run_client_cli from .account import Account from .chat import Chat from .client import Bot, Client -from .const import EventType +from .const import EventType, SpecialContactId from .contact import Contact from .deltachat import DeltaChat from .message import Message @@ -19,6 +19,7 @@ __all__ = [ "DeltaChat", "EventType", "Message", + "SpecialContactId", "Rpc", "run_bot_cli", "run_client_cli", diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/account.py b/deltachat-rpc-client/src/deltachat_rpc_client/account.py index 6434ee966..4c44079f7 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/account.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/account.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, List, Optional, Tuple, Union +from warnings import warn from ._utils import AttrDict from .chat import Chat @@ -239,7 +240,22 @@ class Account: fresh_msg_ids = await self._rpc.get_fresh_msgs(self.id) return [Message(self, msg_id) for msg_id in fresh_msg_ids] + async def get_next_messages(self) -> List[Message]: + """Return a list of next messages.""" + next_msg_ids = await self._rpc.get_next_msgs(self.id) + return [Message(self, msg_id) for msg_id in next_msg_ids] + + async def wait_next_messages(self) -> List[Message]: + """Wait for new messages and return a list of them.""" + next_msg_ids = await self._rpc.wait_next_msgs(self.id) + return [Message(self, msg_id) for msg_id in next_msg_ids] + async def get_fresh_messages_in_arrival_order(self) -> List[Message]: """Return fresh messages list sorted in the order of their arrival, with ascending IDs.""" + warn( + "get_fresh_messages_in_arrival_order is deprecated, use get_next_messages instead.", + DeprecationWarning, + stacklevel=2, + ) fresh_msg_ids = sorted(await self._rpc.get_fresh_msgs(self.id)) return [Message(self, msg_id) for msg_id in fresh_msg_ids] diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/client.py b/deltachat-rpc-client/src/deltachat_rpc_client/client.py index 6f816e5de..5205a1ed9 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/client.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/client.py @@ -20,7 +20,7 @@ from ._utils import ( parse_system_image_changed, parse_system_title_changed, ) -from .const import COMMAND_PREFIX, EventType, SystemMessageType +from .const import COMMAND_PREFIX, EventType, SpecialContactId, SystemMessageType from .events import ( EventFilter, GroupImageChanged, @@ -189,9 +189,10 @@ class Client: async def _process_messages(self) -> None: if self._should_process_messages: - for message in await self.account.get_fresh_messages_in_arrival_order(): + for message in await self.account.get_next_messages(): snapshot = await message.get_snapshot() - await self._on_new_msg(snapshot) + if snapshot.from_id not in [SpecialContactId.SELF, SpecialContactId.DEVICE]: + await self._on_new_msg(snapshot) if snapshot.is_info and snapshot.system_message_type != SystemMessageType.WEBXDC_INFO_MESSAGE: await self._handle_info_msg(snapshot) await snapshot.message.mark_seen() diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index ee08791fe..d17c28a16 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -98,8 +98,8 @@ async def test_account(acfactory) -> None: assert await alice.get_chatlist() assert await alice.get_chatlist(snapshot=True) assert await alice.get_qr_code() - await alice.get_fresh_messages() - await alice.get_fresh_messages_in_arrival_order() + assert await alice.get_fresh_messages() + assert await alice.get_next_messages() group = await alice.create_group("test group") await group.add_contact(alice_contact_bob) @@ -305,3 +305,29 @@ async def test_bot(acfactory) -> None: await acfactory.process_message(from_account=user, to_client=bot, text="hello") event = await acfactory.process_message(from_account=user, to_client=bot, text="/help") mock.hook.assert_called_once_with(event.msg_id) + + +@pytest.mark.asyncio() +async def test_wait_next_messages(acfactory) -> None: + alice = await acfactory.new_configured_account() + + # Create a bot account so it does not receive device messages in the beginning. + bot = await acfactory.new_preconfigured_account() + await bot.set_config("bot", "1") + await bot.configure() + + # There are no old messages and the call returns immediately. + assert not await bot.wait_next_messages() + + # Bot starts waiting for messages. + next_messages_task = asyncio.create_task(bot.wait_next_messages()) + + bot_addr = await bot.get_config("addr") + alice_contact_bot = await alice.create_contact(bot_addr, "Bob") + alice_chat_bot = await alice_contact_bot.create_chat() + await alice_chat_bot.send_text("Hello!") + + next_messages = await next_messages_task + assert len(next_messages) == 1 + snapshot = await next_messages[0].get_snapshot() + assert snapshot.text == "Hello!" diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index 9d80e35f7..6d067f4fb 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -376,6 +376,22 @@ class Account: dc_array = ffi.gc(lib.dc_get_fresh_msgs(self._dc_context), lib.dc_array_unref) return (x for x in iter_array(dc_array, lambda x: Message.from_db(self, x)) if x is not None) + def _wait_next_message_ids(self) -> List[int]: + """Return IDs of all next messages from all chats.""" + dc_array = ffi.gc(lib.dc_wait_next_msgs(self._dc_context), lib.dc_array_unref) + return [lib.dc_array_get_id(dc_array, i) for i in range(lib.dc_array_get_cnt(dc_array))] + + def wait_next_incoming_message(self) -> Message: + """Waits until the next incoming message + with ID higher than given is received and returns it.""" + while True: + message_ids = self._wait_next_message_ids() + for msg_id in message_ids: + message = Message.from_db(self, msg_id) + if message and not message.is_from_self() and not message.is_from_device(): + self.set_config("last_msg_id", str(msg_id)) + return message + def create_chat(self, obj) -> Chat: """Create a 1:1 chat with Account, Contact or e-mail address.""" return self.create_contact(obj).create_chat() diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index 1c2986728..e58d97d05 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -344,6 +344,16 @@ class Message: contact_id = lib.dc_msg_get_from_id(self._dc_msg) return Contact(self.account, contact_id) + def is_from_self(self): + """Return true if the message is sent by self.""" + contact_id = lib.dc_msg_get_from_id(self._dc_msg) + return contact_id == const.DC_CONTACT_ID_SELF + + def is_from_device(self): + """Return true if the message is sent by the device.""" + contact_id = lib.dc_msg_get_from_id(self._dc_msg) + return contact_id == const.DC_CONTACT_ID_DEVICE + # # Message State query methods # diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index cfa5655a1..85e1774bd 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -44,21 +44,21 @@ def test_configure_generate_key(acfactory, lp): lp.sec("ac1: send unencrypted message to ac2") chat.send_text("message1") lp.sec("ac2: waiting for message from ac1") - msg_in = ac2._evtracker.wait_next_incoming_message() + msg_in = ac2.wait_next_incoming_message() assert msg_in.text == "message1" assert not msg_in.is_encrypted() lp.sec("ac2: send encrypted message to ac1") msg_in.chat.send_text("message2") lp.sec("ac1: waiting for message from ac2") - msg2_in = ac1._evtracker.wait_next_incoming_message() + msg2_in = ac1.wait_next_incoming_message() assert msg2_in.text == "message2" assert msg2_in.is_encrypted() lp.sec("ac1: send encrypted message to ac2") msg2_in.chat.send_text("message3") lp.sec("ac2: waiting for message from ac1") - msg3_in = ac2._evtracker.wait_next_incoming_message() + msg3_in = ac2.wait_next_incoming_message() assert msg3_in.text == "message3" assert msg3_in.is_encrypted() diff --git a/src/chat.rs b/src/chat.rs index d61f93bfd..7561c511f 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1666,6 +1666,7 @@ impl Chat { ], ) .await?; + context.new_msgs_notify.notify_one(); msg.id = MsgId::new(u32::try_from(raw_id)?); maybe_set_logging_xdc(context, msg, self.id).await?; @@ -3628,6 +3629,7 @@ pub async fn add_device_msg_with_importance( ), ) .await?; + context.new_msgs_notify.notify_one(); msg_id = MsgId::new(u32::try_from(row_id)?); if !msg.hidden { @@ -3741,6 +3743,7 @@ pub(crate) async fn add_info_msg_with_cmd( parent.map(|msg|msg.rfc724_mid.clone()).unwrap_or_default() ) ).await?; + context.new_msgs_notify.notify_one(); let msg_id = MsgId::new(row_id.try_into()?); context.emit_msgs_changed(chat_id, msg_id); diff --git a/src/config.rs b/src/config.rs index 035caf314..3527e0096 100644 --- a/src/config.rs +++ b/src/config.rs @@ -308,6 +308,9 @@ pub enum Config { /// This value is used internally to remember the MsgId of the logging xdc #[strum(props(default = "0"))] DebugLogging, + + /// Last message processed by the bot. + LastMsgId, } impl Context { @@ -358,6 +361,11 @@ impl Context { Ok(self.get_config_parsed(key).await?.unwrap_or_default()) } + /// Returns 32-bit unsigned integer configuration value for the given key. + pub async fn get_config_u32(&self, key: Config) -> Result { + Ok(self.get_config_parsed(key).await?.unwrap_or_default()) + } + /// Returns 64-bit signed integer configuration value for the given key. pub async fn get_config_i64(&self, key: Config) -> Result { Ok(self.get_config_parsed(key).await?.unwrap_or_default()) @@ -459,6 +467,12 @@ impl Context { Ok(()) } + /// Set the given config to an unsigned 32-bit integer value. + pub async fn set_config_u32(&self, key: Config, value: u32) -> Result<()> { + self.set_config(key, Some(&value.to_string())).await?; + Ok(()) + } + /// Set the given config to a boolean value. pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> { self.set_config(key, if value { Some("1") } else { Some("0") }) diff --git a/src/context.rs b/src/context.rs index 2161d0855..3245a6ff7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -11,7 +11,7 @@ use std::time::{Duration, Instant, SystemTime}; use anyhow::{bail, ensure, Context as _, Result}; use async_channel::{self as channel, Receiver, Sender}; use ratelimit::Ratelimit; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::{Mutex, Notify, RwLock}; use tokio::task; use crate::chat::{get_chat_cnt, ChatId}; @@ -218,6 +218,11 @@ pub struct InnerContext { /// IMAP UID resync request. pub(crate) resync_request: AtomicBool, + /// Notify about new messages. + /// + /// This causes [`Context::wait_next_msgs`] to wake up. + pub(crate) new_msgs_notify: Notify, + /// Server ID response if ID capability is supported /// and the server returned non-NIL on the inbox connection. /// @@ -363,6 +368,11 @@ impl Context { blobdir.display() ); + let new_msgs_notify = Notify::new(); + // Notify once immediately to allow processing old messages + // without starting I/O. + new_msgs_notify.notify_one(); + let inner = InnerContext { id, blobdir, @@ -379,6 +389,7 @@ impl Context { quota: RwLock::new(None), quota_update_request: AtomicBool::new(false), resync_request: AtomicBool::new(false), + new_msgs_notify, server_id: RwLock::new(None), creation_time: std::time::SystemTime::now(), last_full_folder_scan: Mutex::new(None), @@ -767,6 +778,10 @@ impl Context { "debug_logging", self.get_config_int(Config::DebugLogging).await?.to_string(), ); + res.insert( + "last_msg_id", + self.get_config_int(Config::LastMsgId).await?.to_string(), + ); let elapsed = self.creation_time.elapsed(); res.insert("uptime", duration_to_str(elapsed.unwrap_or_default())); @@ -813,6 +828,66 @@ impl Context { Ok(list) } + /// Returns a list of messages with database ID higher than requested. + /// + /// Blocked contacts and chats are excluded, + /// but self-sent messages and contact requests are included in the results. + pub async fn get_next_msgs(&self) -> Result> { + let last_msg_id = match self.get_config(Config::LastMsgId).await? { + Some(s) => MsgId::new(s.parse()?), + None => MsgId::new_unset(), + }; + + let list = self + .sql + .query_map( + "SELECT m.id + FROM msgs m + LEFT JOIN contacts ct + ON m.from_id=ct.id + LEFT JOIN chats c + ON m.chat_id=c.id + WHERE m.id>? + AND m.hidden=0 + AND m.chat_id>9 + AND ct.blocked=0 + AND c.blocked!=1 + ORDER BY m.id ASC", + ( + last_msg_id.to_u32(), // Explicitly convert to u32 because 0 is allowed. + ), + |row| { + let msg_id: MsgId = row.get(0)?; + Ok(msg_id) + }, + |rows| { + let mut list = Vec::new(); + for row in rows { + list.push(row?); + } + Ok(list) + }, + ) + .await?; + Ok(list) + } + + /// Returns a list of messages with database ID higher than last marked as seen. + /// + /// This function is supposed to be used by bot to request messages + /// that are not processed yet. + /// + /// Waits for notification and returns a result. + /// Note that the result may be empty if the message is deleted + /// shortly after notification or notification is manually triggered + /// to interrupt waiting. + /// Notification may be manually triggered by calling [`Self::stop_io`]. + pub async fn wait_next_msgs(&self) -> Result> { + self.new_msgs_notify.notified().await; + let list = self.get_next_msgs().await?; + Ok(list) + } + /// Searches for messages containing the query string. /// /// If `chat_id` is provided this searches only for messages in this chat, if `chat_id` @@ -1444,4 +1519,38 @@ mod tests { Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_get_next_msgs() -> Result<()> { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + + let alice_chat = alice.create_chat(&bob).await; + + assert!(alice.get_next_msgs().await?.is_empty()); + assert!(bob.get_next_msgs().await?.is_empty()); + + let sent_msg = alice.send_text(alice_chat.id, "Hi Bob").await; + let received_msg = bob.recv_msg(&sent_msg).await; + + let bob_next_msg_ids = bob.get_next_msgs().await?; + assert_eq!(bob_next_msg_ids.len(), 1); + assert_eq!(bob_next_msg_ids.get(0), Some(&received_msg.id)); + + bob.set_config_u32(Config::LastMsgId, received_msg.id.to_u32()) + .await?; + assert!(bob.get_next_msgs().await?.is_empty()); + + // Next messages include self-sent messages. + let alice_next_msg_ids = alice.get_next_msgs().await?; + assert_eq!(alice_next_msg_ids.len(), 1); + assert_eq!(alice_next_msg_ids.get(0), Some(&sent_msg.sender_msg_id)); + + alice + .set_config_u32(Config::LastMsgId, sent_msg.sender_msg_id.to_u32()) + .await?; + assert!(alice.get_next_msgs().await?.is_empty()); + + Ok(()) + } } diff --git a/src/message.rs b/src/message.rs index 563020b7c..ea72a8c99 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1468,6 +1468,12 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> return Ok(()); } + let old_last_msg_id = MsgId::new(context.get_config_u32(Config::LastMsgId).await?); + let last_msg_id = msg_ids.iter().fold(&old_last_msg_id, std::cmp::max); + context + .set_config_u32(Config::LastMsgId, last_msg_id.to_u32()) + .await?; + let msgs = context .sql .query_map( diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 9418a228f..c3b2712bf 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -363,6 +363,7 @@ pub(crate) async fn receive_imf_inner( chat_id.emit_msg_event(context, *msg_id, incoming && fresh); } } + context.new_msgs_notify.notify_one(); mime_parser .handle_reports(context, from_id, sent_timestamp, &mime_parser.parts) diff --git a/src/scheduler.rs b/src/scheduler.rs index 2404d7e22..840824f09 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -62,6 +62,11 @@ impl SchedulerState { /// Starts the scheduler if it is not yet started. async fn do_start(mut inner: RwLockWriteGuard<'_, InnerSchedulerState>, context: Context) { info!(context, "starting IO"); + + // Notify message processing loop + // to allow processing old messages after restart. + context.new_msgs_notify.notify_one(); + let ctx = context.clone(); match Scheduler::start(context).await { Ok(scheduler) => *inner = InnerSchedulerState::Started(scheduler), @@ -95,6 +100,11 @@ impl SchedulerState { // to terminate on receiving the next event and then call stop_io() // which will emit the below event(s) info!(context, "stopping IO"); + + // Wake up message processing loop even if there are no messages + // to allow for clean shutdown. + context.new_msgs_notify.notify_one(); + if let Some(debug_logging) = context.debug_logging.read().await.as_ref() { debug_logging.loop_handle.abort(); } From 5403fd849cfb0f6f93e4008705ac4a993c2cd923 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 16 Apr 2023 00:20:37 +0000 Subject: [PATCH 24/24] Comment fixes --- src/context.rs | 4 ++-- src/events.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/context.rs b/src/context.rs index 3245a6ff7..833e68e9f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -253,8 +253,8 @@ pub(crate) struct DebugLogging { pub(crate) msg_id: MsgId, /// Handle to the background task responsible for sending pub(crate) loop_handle: task::JoinHandle<()>, - /// Channel that log events should be send to - /// A background loop will receive and handle them + /// Channel that log events should be sent to. + /// A background loop will receive and handle them. pub(crate) sender: Sender, } diff --git a/src/events.rs b/src/events.rs index ebb1d299f..ade9fe8db 100644 --- a/src/events.rs +++ b/src/events.rs @@ -32,7 +32,9 @@ impl Events { Self { receiver, sender } } - /// Emits an event. + /// Emits an event into event channel. + /// + /// If the channel is full, deletes the oldest event first. pub fn emit(&self, event: Event) { match self.sender.try_send(event) { Ok(()) => {} @@ -49,7 +51,7 @@ impl Events { } } - /// Retrieve the event emitter. + /// Creates an event emitter. pub fn get_emitter(&self) -> EventEmitter { EventEmitter(self.receiver.clone()) }