From 8b8dcf61efabfd5589998aa7df79c7aade618146 Mon Sep 17 00:00:00 2001 From: adbenitez Date: Sat, 4 Mar 2023 23:14:45 -0500 Subject: [PATCH 01/31] add new golang bindings lib to README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e9f6b1eb..1dd938b65 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,9 @@ Language bindings are available for: - over cffi (legacy): \[[πŸ“‚ source](./node) | [πŸ“¦ npm](https://www.npmjs.com/package/deltachat-node) | [πŸ“š docs](https://js.delta.chat)\] - over jsonrpc built with napi.rs: \[[πŸ“‚ source](https://github.com/deltachat/napi-jsonrpc) | [πŸ“¦ npm](https://www.npmjs.com/package/@deltachat/napi-jsonrpc)\] - **Python** \[[πŸ“‚ source](./python) | [πŸ“¦ pypi](https://pypi.org/project/deltachat) | [πŸ“š docs](https://py.delta.chat)\] -- **Go**[^1] \[[πŸ“‚ source](https://github.com/deltachat/go-deltachat/)\] +- **Go** + - over jsonrpc: \[[πŸ“‚ source](https://github.com/deltachat/deltachat-rpc-client-go/)\] + - over cffi[^1]: \[[πŸ“‚ source](https://github.com/deltachat/go-deltachat/)\] - **Free Pascal**[^1] \[[πŸ“‚ source](https://github.com/deltachat/deltachat-fp/)\] - **Java** and **Swift** (contained in the Android/iOS repos) From ef1970b742f7d8ffc66953bfc4a9a2ca16d63797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kl=C3=A4hn?= <39526136+Septias@users.noreply.github.com> Date: Wed, 8 Mar 2023 14:13:07 +0100 Subject: [PATCH 02/31] Also document private items for rust docs (#4137) also document private items for rust docs --- .github/workflows/upload-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upload-docs.yml b/.github/workflows/upload-docs.yml index 8f0ceb3c0..1e813855a 100644 --- a/.github/workflows/upload-docs.yml +++ b/.github/workflows/upload-docs.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v3 - name: Build the documentation with cargo run: | - cargo doc --package deltachat --no-deps + cargo doc --package deltachat --no-deps --document-private-items - name: Upload to rs.delta.chat uses: up9cloud/action-rsync@v1.3 env: From d71bf1c4be81d784c31f1c60cb97282d32162e7d Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 8 Mar 2023 14:03:02 +0000 Subject: [PATCH 03/31] Fix documentation on enabling REPL logs As `repl` example was moved into `deltachat_repl` crate, the name of the log target has changed. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1dd938b65..937967a1c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ $ curl https://sh.rustup.rs -sSf | sh Compile and run Delta Chat Core command line utility, using `cargo`: ``` -$ RUST_LOG=repl=info cargo run -p deltachat-repl -- ~/deltachat-db +$ RUST_LOG=deltachat_repl=info cargo run -p deltachat-repl -- ~/deltachat-db ``` where ~/deltachat-db is the database file. Delta Chat will create it if it does not exist. @@ -113,7 +113,7 @@ $ cargo build -p deltachat_ffi --release - `DCC_MIME_DEBUG`: if set outgoing and incoming message will be printed -- `RUST_LOG=repl=info,async_imap=trace,async_smtp=trace`: enable IMAP and +- `RUST_LOG=deltachat_repl=info,async_imap=trace,async_smtp=trace`: enable IMAP and SMTP tracing in addition to info messages. ### Expensive tests From db28c1bdc4c49c8571dbf4107b6ce7a66644c36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kl=C3=A4hn?= <39526136+Septias@users.noreply.github.com> Date: Wed, 8 Mar 2023 21:35:15 +0100 Subject: [PATCH 04/31] Update doxygen for cffi docs (#4136) fix styling --- deltachat-ffi/Doxyfile.css | 14 ++++++++++++-- deltachat-ffi/deltachat.h | 2 +- deltachat-ffi/doxygen-dark-theme | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) create mode 160000 deltachat-ffi/doxygen-dark-theme diff --git a/deltachat-ffi/Doxyfile.css b/deltachat-ffi/Doxyfile.css index 9ff6816ed..2bf87be0c 100644 --- a/deltachat-ffi/Doxyfile.css +++ b/deltachat-ffi/Doxyfile.css @@ -1,14 +1,24 @@ +:root { + --accent: hsl(0 0% 70%); +} + +@media (prefers-color-scheme: dark) { + :root { + --accent: hsl(0 0% 30%); + } +} + /* the code snippet frame, defaults to white which tends to get badly readable in combination with explaining text around */ div.fragment { - background-color: #e0e0e0; + background-color: var(--accent); border: 0; padding: 1em; border-radius: 6px; } code { - background-color: #e0e0e0; + background-color: var(--accent); padding-left: .5em; padding-right: .5em; border-radius: 6px; diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 298664c8e..9208579c1 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -6623,7 +6623,7 @@ void dc_event_unref(dc_event_t* event); /// "You changed your email address from %1$s to %2$s. /// If you now send a message to a group, contacts there will automatically -/// replace the old with your new address.\n\nIt's highly advised to set up +/// replace the old with your new address.\n\n It's highly advised to set up /// your old email provider to forward all emails to your new email address. /// Otherwise you might miss messages of contacts who did not get your new /// address yet." + the link to the AEAP blog post diff --git a/deltachat-ffi/doxygen-dark-theme b/deltachat-ffi/doxygen-dark-theme new file mode 160000 index 000000000..101c1f915 --- /dev/null +++ b/deltachat-ffi/doxygen-dark-theme @@ -0,0 +1 @@ +Subproject commit 101c1f91523b9f2ea6932b1d7b727e67a4cd7171 From de391155b1bad90080310b7d58ca32ab909a009d Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 8 Mar 2023 17:45:05 +0000 Subject: [PATCH 05/31] Do not prepare the message explicitly in the test context Explicit `prepare_msg` corresponding to `dc_prepare_msg` is intended only for the case where the message is prepared before the file is ready. It is not indented for calling right before send_msg and requires that file path in the blobdir. With explicit `prepare_msg` removed all the tests still pass but there is no requirement that the file is put into blobdir beforehand. --- src/test_utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index 7a8028b0f..3b57724be 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -599,7 +599,6 @@ impl TestContext { /// [`TestContext::recv_msg`] with the returned [`SentMessage`] if it wants to receive /// the message. pub async fn send_msg(&self, chat_id: ChatId, msg: &mut Message) -> SentMessage<'_> { - chat::prepare_msg(self, chat_id, msg).await.unwrap(); let msg_id = chat::send_msg(self, chat_id, msg).await.unwrap(); let res = self.pop_sent_msg().await; assert_eq!( From 9e03f2699255b9ba0129a575a9bef5403c2af1f7 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 8 Mar 2023 08:09:55 +0000 Subject: [PATCH 06/31] deltachat-ffi: print causes for all errors --- deltachat-ffi/src/lib.rs | 47 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 8d92da18c..0e5ac85e3 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -292,12 +292,12 @@ pub unsafe extern "C" fn dc_set_stock_translation( Some(id) => match ctx.set_stock_translation(id, msg).await { Ok(()) => 1, Err(err) => { - warn!(ctx, "set_stock_translation failed: {}", err); + warn!(ctx, "set_stock_translation failed: {err:#}"); 0 } }, None => { - warn!(ctx, "invalid stock message id {}", stock_id); + warn!(ctx, "invalid stock message id {stock_id}"); 0 } } @@ -320,7 +320,7 @@ pub unsafe extern "C" fn dc_set_config_from_qr( match qr::set_config_from_qr(ctx, &qr).await { Ok(()) => 1, Err(err) => { - error!(ctx, "Failed to create account from QR code: {}", err); + error!(ctx, "Failed to create account from QR code: {err:#}"); 0 } } @@ -338,7 +338,7 @@ pub unsafe extern "C" fn dc_get_info(context: *const dc_context_t) -> *mut libc: match ctx.get_info().await { Ok(info) => render_info(info).unwrap_or_default().strdup(), Err(err) => { - warn!(ctx, "failed to get info: {}", err); + warn!(ctx, "failed to get info: {err:#}"); "".strdup() } } @@ -379,7 +379,7 @@ pub unsafe extern "C" fn dc_get_connectivity_html( match ctx.get_connectivity_html().await { Ok(html) => html.strdup(), Err(err) => { - error!(ctx, "Failed to get connectivity html: {}", err); + error!(ctx, "Failed to get connectivity html: {err:#}"); "".strdup() } } @@ -1137,7 +1137,7 @@ pub unsafe extern "C" fn dc_get_draft(context: *mut dc_context_t, chat_id: u32) } Ok(None) => ptr::null_mut(), Err(err) => { - error!(ctx, "Failed to get draft for chat #{}: {}", chat_id, err); + error!(ctx, "Failed to get draft for chat #{chat_id}: {err:#}"); ptr::null_mut() } } @@ -1727,7 +1727,7 @@ pub unsafe extern "C" fn dc_get_chat_encrinfo( .await .map(|s| s.strdup()) .unwrap_or_else(|e| { - error!(ctx, "{}", e); + error!(ctx, "{e:#}"); ptr::null_mut() }) }) @@ -1890,7 +1890,7 @@ pub unsafe extern "C" fn dc_resend_msgs( let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt); if let Err(err) = block_on(chat::resend_msgs(ctx, &msg_ids)) { - error!(ctx, "Resending failed: {}", err); + error!(ctx, "Resending failed: {err:#}"); 0 } else { 1 @@ -1931,14 +1931,11 @@ pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) -> // C-core API returns empty messages, do the same warn!( ctx, - "dc_get_msg called with special msg_id={}, returning empty msg", msg_id + "dc_get_msg called with special msg_id={msg_id}, returning empty msg" ); message::Message::default() } else { - error!( - ctx, - "dc_get_msg could not retrieve msg_id {}: {}", msg_id, e - ); + error!(ctx, "dc_get_msg could not retrieve msg_id {msg_id}: {e:#}"); return ptr::null_mut(); } } @@ -2131,7 +2128,7 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo( .await .map(|s| s.strdup()) .unwrap_or_else(|e| { - error!(ctx, "{}", e); + error!(ctx, "{e:#}"); ptr::null_mut() }) }) @@ -2153,7 +2150,7 @@ pub unsafe extern "C" fn dc_delete_contact( match Contact::delete(ctx, contact_id).await { Ok(_) => 1, Err(err) => { - error!(ctx, "cannot delete contact: {}", err); + error!(ctx, "cannot delete contact: {err:#}"); 0 } } @@ -2229,7 +2226,7 @@ pub unsafe extern "C" fn dc_imex_has_backup( Err(err) => { // do not bubble up error to the user, // the ui will expect that the file does not exist or cannot be accessed - warn!(ctx, "dc_imex_has_backup: {}", err); + warn!(ctx, "dc_imex_has_backup: {err:#}"); ptr::null_mut() } } @@ -2248,7 +2245,7 @@ pub unsafe extern "C" fn dc_initiate_key_transfer(context: *mut dc_context_t) -> match imex::initiate_key_transfer(ctx).await { Ok(res) => res.strdup(), Err(err) => { - error!(ctx, "dc_initiate_key_transfer(): {}", err); + error!(ctx, "dc_initiate_key_transfer(): {err:#}"); ptr::null_mut() } } @@ -2273,7 +2270,7 @@ pub unsafe extern "C" fn dc_continue_key_transfer( { Ok(()) => 1, Err(err) => { - warn!(ctx, "dc_continue_key_transfer: {}", err); + warn!(ctx, "dc_continue_key_transfer: {err:#}"); 0 } } @@ -2704,7 +2701,7 @@ pub unsafe extern "C" fn dc_chatlist_get_chat_id( match ffi_list.list.get_chat_id(index) { Ok(chat_id) => chat_id.to_u32(), Err(err) => { - warn!(ctx, "get_chat_id failed: {}", err); + warn!(ctx, "get_chat_id failed: {err:#}"); 0 } } @@ -2724,7 +2721,7 @@ pub unsafe extern "C" fn dc_chatlist_get_msg_id( match ffi_list.list.get_msg_id(index) { Ok(msg_id) => msg_id.map_or(0, |msg_id| msg_id.to_u32()), Err(err) => { - warn!(ctx, "get_msg_id failed: {}", err); + warn!(ctx, "get_msg_id failed: {err:#}"); 0 } } @@ -2883,7 +2880,7 @@ pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut Ok(Some(p)) => p.to_string_lossy().strdup(), Ok(None) => ptr::null_mut(), Err(err) => { - error!(ctx, "failed to get profile image: {:?}", err); + error!(ctx, "failed to get profile image: {err:#}"); ptr::null_mut() } } @@ -3035,7 +3032,7 @@ pub unsafe extern "C" fn dc_chat_get_info_json( let chat = match chat::Chat::load_from_db(ctx, ChatId::new(chat_id)).await { Ok(chat) => chat, Err(err) => { - error!(ctx, "dc_get_chat_info_json() failed to load chat: {}", err); + error!(ctx, "dc_get_chat_info_json() failed to load chat: {err:#}"); return "".strdup(); } }; @@ -3044,7 +3041,7 @@ pub unsafe extern "C" fn dc_chat_get_info_json( Err(err) => { error!( ctx, - "dc_get_chat_info_json() failed to get chat info: {}", err + "dc_get_chat_info_json() failed to get chat info: {err:#}" ); return "".strdup(); } @@ -3283,7 +3280,7 @@ pub unsafe extern "C" fn dc_msg_get_webxdc_info(msg: *mut dc_msg_t) -> *mut libc let info = match ffi_msg.message.get_webxdc_info(ctx).await { Ok(info) => info, Err(err) => { - error!(ctx, "dc_msg_get_webxdc_info() failed to get info: {}", err); + error!(ctx, "dc_msg_get_webxdc_info() failed to get info: {err:#}"); return "".strdup(); } }; @@ -4151,7 +4148,7 @@ impl ResultExt for Result { match self { Ok(t) => t, Err(err) => { - error!(context, "{}: {}", message, err); + error!(context, "{message}: {err:#}"); Default::default() } } From 00791157e2d383dabb8e6b60bdd1530f4c2cca0c Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 9 Mar 2023 11:31:34 +0000 Subject: [PATCH 07/31] Drop unused columns We are currently using libsqlite3-sys 0.25.2, corresponding to SQLcipher 4.5.2 and SQLite 3.39.2. SQLite supports ALTER TABLE DROP COLUMN since version 3.35.0, and it has received critical database corruption bugfixes in 3.35.5. There have been no fixes to it between SQLite 3.36.0 and 3.41.0, so it appears stable now. --- CHANGELOG.md | 1 + src/sql/migrations.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e80e3874..46de6640d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Run `cargo-deny` in CI. #4101 - Check provider database with CI. #4099 - Switch to DEFERRED transactions #4100 +- Drop unused SQL columns #4141 ### Fixes - Do not block async task executor while decrypting the messages. #4079 diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 02f13ecf3..0cdae4c44 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -690,6 +690,17 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid); } sql.set_db_version(98).await?; } + if dbversion < 99 { + sql.execute_migration( + "ALTER TABLE msgs DROP COLUMN server_folder; + ALTER TABLE msgs DROP COLUMN server_uid; + ALTER TABLE msgs DROP COLUMN move_state; + ALTER TABLE chats DROP COLUMN draft_timestamp; + ALTER TABLE chats DROP COLUMN draft_txt", + 99, + ) + .await?; + } let new_version = sql .get_raw_config_int(VERSION_CFG) From 6a394a0dc8c39eee53823682ee408f74c35683aa Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 9 Mar 2023 16:42:47 +0000 Subject: [PATCH 08/31] fixup: move changelog to unreleased section --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46de6640d..82f97334b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Changes +- Drop unused SQL columns #4141 + + ## 1.111.0 ### Changes @@ -8,7 +14,6 @@ - Run `cargo-deny` in CI. #4101 - Check provider database with CI. #4099 - Switch to DEFERRED transactions #4100 -- Drop unused SQL columns #4141 ### Fixes - Do not block async task executor while decrypting the messages. #4079 @@ -18,6 +23,7 @@ - jsonrpc: add more advanced API to send a message. #4097 - jsonrpc: add get webxdc blob API `getWebxdcBlob` #4070 + ## 1.110.0 ### Changes From a853b8283a789e944f7bb3ce6270679e93b52153 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 10 Mar 2023 01:30:57 +0000 Subject: [PATCH 09/31] Upgrade to Rust 1.68.0 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 286ba3757..59e7810d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: name: Rustfmt and Clippy runs-on: ubuntu-latest env: - RUSTUP_TOOLCHAIN: 1.67.1 + RUSTUP_TOOLCHAIN: 1.68.0 steps: - uses: actions/checkout@v3 - name: Install rustfmt and clippy @@ -72,10 +72,10 @@ jobs: include: # Currently used Rust version. - os: ubuntu-latest - rust: 1.64.0 + rust: 1.68.0 python: 3.9 - os: windows-latest - rust: 1.64.0 + rust: 1.68.0 python: false # Python bindings compilation on Windows is not supported. # Minimum Supported Rust Version = 1.63.0 From 0ac61690cf09da170de11cb8e0a84b78a19349e3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 11 Mar 2023 10:17:19 +0000 Subject: [PATCH 10/31] Enable all features when running clippy --- scripts/clippy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/clippy.sh b/scripts/clippy.sh index f462c4651..986d03325 100755 --- a/scripts/clippy.sh +++ b/scripts/clippy.sh @@ -1,3 +1,3 @@ #!/bin/sh # Run clippy for all Rust code in the project. -cargo clippy --workspace --all-targets -- -D warnings +cargo clippy --workspace --all-targets --all-features -- -D warnings From 7d3fcd9a3c7602a14fa68a747f951b866cf1df50 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 11 Mar 2023 13:58:50 +0100 Subject: [PATCH 11/31] restore original Doxygen contrasts the contrast was decreased at https://github.com/deltachat/deltachat-core-rust/pull/4136 , there were also suggestions to fix it there, but it was probably just forgotten :) this pr increases the contrast between code background and code font again to the level it was before and also to what similar themes are doing. --- deltachat-ffi/Doxyfile.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deltachat-ffi/Doxyfile.css b/deltachat-ffi/Doxyfile.css index 2bf87be0c..fbd8a4354 100644 --- a/deltachat-ffi/Doxyfile.css +++ b/deltachat-ffi/Doxyfile.css @@ -1,11 +1,11 @@ :root { - --accent: hsl(0 0% 70%); + --accent: hsl(0 0% 85%); } @media (prefers-color-scheme: dark) { :root { - --accent: hsl(0 0% 30%); + --accent: hsl(0 0% 25%); } } From 4411b883d75f00c77ef39add56ccedfe65bd28b5 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 11 Mar 2023 22:15:09 +0000 Subject: [PATCH 12/31] Remove doxygen-dark-theme --- deltachat-ffi/doxygen-dark-theme | 1 - 1 file changed, 1 deletion(-) delete mode 160000 deltachat-ffi/doxygen-dark-theme diff --git a/deltachat-ffi/doxygen-dark-theme b/deltachat-ffi/doxygen-dark-theme deleted file mode 160000 index 101c1f915..000000000 --- a/deltachat-ffi/doxygen-dark-theme +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 101c1f91523b9f2ea6932b1d7b727e67a4cd7171 From 2151a24b7f4779f9a0fef49f5c46f2bac6851d01 Mon Sep 17 00:00:00 2001 From: adbenitez Date: Sun, 5 Mar 2023 09:34:12 -0500 Subject: [PATCH 13/31] update deltachat-rpc-server/README.md --- deltachat-rpc-server/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/deltachat-rpc-server/README.md b/deltachat-rpc-server/README.md index f64ec1cae..2027072a5 100644 --- a/deltachat-rpc-server/README.md +++ b/deltachat-rpc-server/README.md @@ -5,10 +5,13 @@ over standard I/O. ## Install -To install run: +To download binary pre-builds check the [releases page](https://github.com/deltachat/deltachat-core-rust/releases). +Rename the downloaded binary to `deltachat-rpc-server` and add it to your `PATH`. + +To install from source run: ```sh -cargo install --path ../deltachat-rpc-server +cargo install --git https://github.com/deltachat/deltachat-core-rust/ deltachat-rpc-server ``` The `deltachat-rpc-server` executable will be installed into `$HOME/.cargo/bin` that should be available From a4323035764da368afb4529216526318f2593554 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Mar 2023 14:06:42 +0000 Subject: [PATCH 14/31] Remove explicit .iter() and .iter_mut() calls in for loops --- src/html.rs | 4 ++-- src/imap.rs | 2 +- src/lib.rs | 3 ++- src/mimefactory.rs | 2 +- src/mimeparser.rs | 6 +++--- src/net.rs | 2 +- src/receive_imf.rs | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/html.rs b/src/html.rs index d74a5bbac..b4dbd32e7 100644 --- a/src/html.rs +++ b/src/html.rs @@ -124,7 +124,7 @@ impl HtmlMsgParser { async move { match get_mime_multipart_type(&mail.ctype) { MimeMultipartType::Multiple => { - for cur_data in mail.subparts.iter() { + for cur_data in &mail.subparts { self.collect_texts_recursive(cur_data).await? } Ok(()) @@ -180,7 +180,7 @@ impl HtmlMsgParser { async move { match get_mime_multipart_type(&mail.ctype) { MimeMultipartType::Multiple => { - for cur_data in mail.subparts.iter() { + for cur_data in &mail.subparts { self.cid_to_data_recursive(context, cur_data).await?; } Ok(()) diff --git a/src/imap.rs b/src/imap.rs index 2ee391d3e..91f6ae9cc 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1390,7 +1390,7 @@ impl Imap { let mut uid_msgs = HashMap::with_capacity(request_uids.len()); let mut count = 0; - for &request_uid in request_uids.iter() { + for &request_uid in &request_uids { // Check if FETCH response is already in `uid_msgs`. let mut fetch_response = uid_msgs.remove(&request_uid); diff --git a/src/lib.rs b/src/lib.rs index c224ab09d..976d122b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,8 @@ clippy::wildcard_imports, clippy::needless_borrow, clippy::cast_lossless, - clippy::unused_async + clippy::unused_async, + clippy::explicit_iter_loop )] #![allow( clippy::match_bool, diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 0de80907c..6d291ae23 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -485,7 +485,7 @@ impl<'a> MimeFactory<'a> { None }; - for (name, addr) in self.recipients.iter() { + for (name, addr) in &self.recipients { if let Some(email_to_remove) = email_to_remove { if email_to_remove == addr { continue; diff --git a/src/mimeparser.rs b/src/mimeparser.rs index e05e46ad6..000cdac0c 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -640,7 +640,7 @@ impl MimeMessage { } if self.is_forwarded { - for part in self.parts.iter_mut() { + for part in &mut self.parts { part.param.set_int(Param::Forwarded, 1); } } @@ -943,7 +943,7 @@ impl MimeMessage { } // Add all parts (we need another part, preferably text/plain, to show as an error message) - for cur_data in mail.subparts.iter() { + for cur_data in &mail.subparts { if self .parse_mime_recursive(context, cur_data, is_related) .await? @@ -977,7 +977,7 @@ impl MimeMessage { _ => { // Add all parts (in fact, AddSinglePartIfKnown() later check if // the parts are really supported) - for cur_data in mail.subparts.iter() { + for cur_data in &mail.subparts { if self .parse_mime_recursive(context, cur_data, is_related) .await? diff --git a/src/net.rs b/src/net.rs index 2d36e90aa..a0f3a3313 100644 --- a/src/net.rs +++ b/src/net.rs @@ -57,7 +57,7 @@ async fn lookup_host_with_cache( } }; - for addr in resolved_addrs.iter() { + for addr in &resolved_addrs { let ip_string = addr.ip().to_string(); if ip_string == hostname { // IP address resolved into itself, not interesting to cache. diff --git a/src/receive_imf.rs b/src/receive_imf.rs index d30880bf6..f52f0838a 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -604,7 +604,7 @@ async fn add_parts( // to the sender's name, indicating to the user that he/she is not part of the group. let from = &mime_parser.from; let name: &str = from.display_name.as_ref().unwrap_or(&from.addr); - for part in mime_parser.parts.iter_mut() { + for part in &mut mime_parser.parts { part.param.set(Param::OverrideSenderDisplayname, name); } } @@ -668,7 +668,7 @@ async fn add_parts( // we use name from From:-header as override name if prevent_rename { if let Some(name) = &mime_parser.from.display_name { - for part in mime_parser.parts.iter_mut() { + for part in &mut mime_parser.parts { part.param.set(Param::OverrideSenderDisplayname, name); } } From 2bd7781276ed98ed7050364843177bf82d7b1246 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Mar 2023 14:45:46 +0000 Subject: [PATCH 15/31] Enable cloned_instead_of_copied clippy lint --- src/lib.rs | 3 ++- src/receive_imf.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 976d122b4..b15f5dcf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,8 @@ clippy::needless_borrow, clippy::cast_lossless, clippy::unused_async, - clippy::explicit_iter_loop + clippy::explicit_iter_loop, + clippy::cloned_instead_of_copied )] #![allow( clippy::match_bool, diff --git a/src/receive_imf.rs b/src/receive_imf.rs index f52f0838a..9a8504d43 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -737,7 +737,7 @@ async fn add_parts( // the mail is on the IMAP server, probably it is also delivered. // We cannot recreate other states (read, error). state = MessageState::OutDelivered; - to_id = to_ids.get(0).cloned().unwrap_or_default(); + to_id = to_ids.get(0).copied().unwrap_or_default(); let self_sent = from_id == ContactId::SELF && to_ids.len() == 1 && to_ids.contains(&ContactId::SELF); From 4d620afdb89714a07890843b56803b014c006624 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Mar 2023 14:51:44 +0000 Subject: [PATCH 16/31] Enable clippy::explicit_into_iter_loop --- src/chat.rs | 2 +- src/contact.rs | 2 +- src/imex.rs | 2 +- src/lib.rs | 1 + src/message.rs | 4 ++-- src/receive_imf.rs | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 06b029dd8..edffef4ba 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -418,7 +418,7 @@ impl ChatId { ProtectionStatus::Protected => match chat.typ { Chattype::Single | Chattype::Group | Chattype::Broadcast => { let contact_ids = get_chat_contacts(context, self).await?; - for contact_id in contact_ids.into_iter() { + for contact_id in contact_ids { let contact = Contact::get_by_id(context, contact_id).await?; if contact.is_verified(context).await? != VerifiedStatus::BidirectVerified { bail!("{} is not verified.", contact.get_display_name()); diff --git a/src/contact.rs b/src/contact.rs index 2ae958603..4b8c4c3ab 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -727,7 +727,7 @@ impl Contact { pub async fn add_address_book(context: &Context, addr_book: &str) -> Result { let mut modify_cnt = 0; - for (name, addr) in split_address_book(addr_book).into_iter() { + for (name, addr) in split_address_book(addr_book) { let (name, addr) = sanitize_name_and_addr(name, addr); let name = normalize_name(&name); match ContactAddress::new(&addr) { diff --git a/src/imex.rs b/src/imex.rs index d26a0a613..bd7091800 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -602,7 +602,7 @@ async fn export_backup_inner( let mut written_files = 0; let mut last_progress = 0; - for entry in read_dir.into_iter() { + for entry in read_dir { let name = entry.file_name(); if !entry.file_type().await?.is_file() { warn!( diff --git a/src/lib.rs b/src/lib.rs index b15f5dcf7..51a72a1d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ clippy::cast_lossless, clippy::unused_async, clippy::explicit_iter_loop, + clippy::explicit_into_iter_loop, clippy::cloned_instead_of_copied )] #![allow( diff --git a/src/message.rs b/src/message.rs index fd88cf628..258a8624a 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1502,7 +1502,7 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> curr_rfc724_mid, curr_blocked, _curr_ephemeral_timer, - ) in msgs.into_iter() + ) in msgs { if curr_blocked == Blocked::Not && (curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed) @@ -1741,7 +1741,7 @@ pub(crate) async fn handle_ndn( }; let mut first = true; - for msg in msgs.into_iter() { + for msg in msgs { let (msg_id, chat_id, chat_type) = msg?; set_msg_failed(context, msg_id, &error).await; if first { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 9a8504d43..c37eb3633 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -2162,7 +2162,7 @@ async fn check_verified_properties( ) .await?; - for (to_addr, mut is_verified) in rows.into_iter() { + for (to_addr, mut is_verified) in rows { info!( context, "check_verified_properties: {:?} self={:?}", From b14e59c5f30eb93e0cec1440a948e506c11338b5 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sun, 12 Mar 2023 21:46:07 +0100 Subject: [PATCH 17/31] "full message view" not needed because of footers standard footers meanwhile go the "contact status", so they are no longer a reason to trigger "full message view". this was already discussed when the HTML view was introduced at #2125 however, forgotten to change when the "contact status" was added at #2218 this pr will result in a cleaner chat view with less "Show Full Message..." buttons and will also save some storage (in fact, i came over that when reviewing #4129 ) --- CHANGELOG.md | 1 + src/receive_imf/tests.rs | 4 +++- src/simplify.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82f97334b..50731518e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Changes - Drop unused SQL columns #4141 +- "full message view" not needed because of footers that go to contact status #4151 ## 1.111.0 diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index 9cdcc2c20..ed3791fe7 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -2085,9 +2085,11 @@ Original signature", false, ) .await?; - let one2one_chat_id = t.get_last_msg().await.chat_id; + let msg = t.get_last_msg().await; + let one2one_chat_id = msg.chat_id; let bob = Contact::load_from_db(&t, bob_id).await?; assert_eq!(bob.get_status(), "Original signature"); + assert!(!msg.has_html()); receive_imf( &t, diff --git a/src/simplify.rs b/src/simplify.rs index 7709dbf37..623c9ab63 100644 --- a/src/simplify.rs +++ b/src/simplify.rs @@ -80,7 +80,8 @@ pub(crate) struct SimplifiedText { /// True if the message is forwarded. pub is_forwarded: bool, - /// True if nonstandard footer was removed. + /// True if nonstandard footer was removed + /// or if the message contains quotes other than `top_quote`. pub is_cut: bool, /// Top quote, if any. @@ -103,7 +104,6 @@ pub(crate) fn simplify(mut input: String, is_chat_message: bool) -> SimplifiedTe let original_lines = &lines; let (lines, footer_lines) = remove_message_footer(lines); let footer = footer_lines.map(|footer_lines| render_message(footer_lines, false)); - is_cut = is_cut || footer.is_some(); let text = if is_chat_message { render_message(lines, false) @@ -330,7 +330,7 @@ mod tests { } = simplify(input, true); assert_eq!(text, "Hi! How are you?\n\n---\n\nI am good."); assert!(!is_forwarded); - assert!(is_cut); + assert!(!is_cut); assert_eq!( footer.unwrap(), "Sent with my Delta Chat Messenger: https://delta.chat" @@ -365,7 +365,7 @@ mod tests { assert_eq!(text, "Forwarded message"); assert!(is_forwarded); - assert!(is_cut); + assert!(!is_cut); assert_eq!(footer.unwrap(), "Signature goes here"); } @@ -442,7 +442,7 @@ mod tests { .. } = simplify(input, true); assert_eq!(text, "text\n\n--\nno footer"); - assert!(is_cut); + assert!(!is_cut); assert_eq!(footer.unwrap(), "footer"); let input = "text\n\n--\ntreated as footer when unescaped".to_string(); @@ -453,7 +453,7 @@ mod tests { .. } = simplify(input.clone(), true); assert_eq!(text, "text"); // see remove_message_footer() for some explanations - assert!(is_cut); + assert!(!is_cut); assert_eq!(footer.unwrap(), "treated as footer when unescaped"); let escaped = escape_message_footer_marks(&input); let SimplifiedText { @@ -495,7 +495,7 @@ mod tests { .. } = simplify(input.clone(), true); assert_eq!(text, ""); // see remove_message_footer() for some explanations - assert!(is_cut); + assert!(!is_cut); assert_eq!(footer.unwrap(), "treated as footer when unescaped"); let escaped = escape_message_footer_marks(&input); From 11ca698139e046fa350cedaf688e7f34d7df405d Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sun, 12 Mar 2023 19:40:37 +0100 Subject: [PATCH 18/31] allow generated html being rendered in dark mode `` is a hint to the browsers that the page can be rendered in light as well as in dark mode and that the browser can apply corresponding defaults. as we do not add css colors on our own, this is sufficient for letting generated html messasge being rendered in dark mode. cmp. https://drafts.csswg.org/css-color-adjust/#color-scheme-prop closes #4146 --- CHANGELOG.md | 1 + src/html.rs | 20 ++++++++++++++++---- src/plaintext.rs | 44 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50731518e..750db29b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Changes - Drop unused SQL columns #4141 - "full message view" not needed because of footers that go to contact status #4151 +- Pick up system's light/dark mode in generated message HTML #4150 ## 1.111.0 diff --git a/src/html.rs b/src/html.rs index b4dbd32e7..a76214bc6 100644 --- a/src/html.rs +++ b/src/html.rs @@ -292,7 +292,10 @@ mod tests { assert_eq!( parser.html, r##" - + + + + This message does not have Content-Type nor Subject.

@@ -308,7 +311,10 @@ This message does not have Content-Type nor Subject.
assert_eq!( parser.html, r##" - + + + + message with a non-UTF-8 encoding: Γ€ΓΆΓΌΓŸΓ„Γ–Γœ

@@ -325,7 +331,10 @@ message with a non-UTF-8 encoding: Γ€ΓΆΓΌΓŸΓ„Γ–Γœ
assert_eq!( parser.html, r##" - + + + + This line ends with a space and will be merged with the next one due to format=flowed.

This line does not end with a space
@@ -344,7 +353,10 @@ and will be wrapped as usual.
assert_eq!( parser.html, r##" - + + + + mime-modified should not be set set as there is no html and no special stuff;
although not being a delta-message.
test some special html-characters as < > and & but also " and ' :)
diff --git a/src/plaintext.rs b/src/plaintext.rs index e50311677..2808e68a8 100644 --- a/src/plaintext.rs +++ b/src/plaintext.rs @@ -34,8 +34,13 @@ impl PlainText { let lines = split_lines(&self.text); - let mut ret = - "\n\n".to_string(); + let mut ret = r#" + + + + +"# + .to_string(); for line in lines { let is_quote = line.starts_with('>'); @@ -118,7 +123,10 @@ http://link-at-start-of-line.org assert_eq!( html, r##" - + + + + line 1
line 2
line with https://link-mid-of-line.org and http://link-end-of-line.com/file?foo=bar%20
@@ -140,7 +148,10 @@ line with https://link-mid-of-line.org - + + + + line with <http://encapsulated.link/?foo=_bar> here!
"# @@ -158,7 +169,10 @@ line with <http://encapsulated.l assert_eq!( html, r#" - + + + + line with nohttp://no.link here
"# @@ -176,7 +190,10 @@ line with nohttp://no.link here
assert_eq!( html, r#" - + + + + just an address:
foo@bar.org another@one.de
"# @@ -194,7 +211,10 @@ just an address: foo@bar.org - + + + + line still line
>quote
>still quote
@@ -215,7 +235,10 @@ line still line
assert_eq!( html, r#" - + + + + linestill line
>quote
>still quote
@@ -236,7 +259,10 @@ linestill line
assert_eq!( html, r#" - + + + + line
still line
>quote
From 5805f99acd0154ac41425d524ad862881d7b350c Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 12 Mar 2023 23:13:22 +0000 Subject: [PATCH 19/31] Test calling dc_context_unref() during dc_configure() dc_configure() spawns a background configuration process. It should increase the number of context references so even if we unref the context, it is not dropped until the end of the configuration process. Currently running the test with `pytest tests/test_1_online.py::test_configure_unref` results in segmentation fault. --- python/tests/test_1_online.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 7f62dcefd..d1761f02e 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -72,6 +72,19 @@ def test_configure_canceled(acfactory): pass +def test_configure_unref(tmpdir): + """Test that removing the last reference to the context during ongoing configuration + does not result in use-after-free.""" + from deltachat.capi import ffi, lib + + path = tmpdir.mkdir("test_configure_unref").join("dc.db").strpath + dc_context = lib.dc_context_new(ffi.NULL, path.encode("utf8"), ffi.NULL) + lib.dc_set_config(dc_context, "addr".encode("utf8"), "foo@x.testrun.org".encode("utf8")) + lib.dc_set_config(dc_context, "mail_pw".encode("utf8"), "abc".encode("utf8")) + lib.dc_configure(dc_context) + lib.dc_context_unref(dc_context) + + def test_export_import_self_keys(acfactory, tmpdir, lp): ac1, ac2 = acfactory.get_online_accounts(2) From 30fef395b45b82b4f7cdf8b5018f8c81628b2ef1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 12:14:55 +0000 Subject: [PATCH 20/31] Increase dc_context_t reference count during dc_configure() This fixes use-after-free in case dc_context_unref() is called while the background process spawned by dc_configure() is still running. Corresponding regression test in Python can be run with `pytest tests/test_1_online.py::test_configure_unref`. --- deltachat-ffi/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 0e5ac85e3..630a66f33 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -428,9 +428,10 @@ pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) { return; } - let ctx = &*context; + // Clone the context Arc so we do not use the reference after dc_configure() returns. + let ctx = (*context).clone(); - spawn(async move { ctx.configure().await.log_err(ctx, "Configure failed") }); + spawn(async move { ctx.configure().await.log_err(&ctx, "Configure failed") }); } #[no_mangle] From 474faefca8bf94b13303b41b8e51302475e12920 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 12:36:26 +0000 Subject: [PATCH 21/31] Increase dc_context_t reference count during dc_imex() --- deltachat-ffi/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 630a66f33..e4467fa17 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -2197,13 +2197,14 @@ pub unsafe extern "C" fn dc_imex( }; let passphrase = to_opt_string_lossy(param2); - let ctx = &*context; + // Clone the context Arc so we do not use the reference after dc_imex() returns. + let ctx = (*context).clone(); if let Some(param1) = to_opt_string_lossy(param1) { spawn(async move { - imex::imex(ctx, what, param1.as_ref(), passphrase) + imex::imex(&ctx, what, param1.as_ref(), passphrase) .await - .log_err(ctx, "IMEX failed") + .log_err(&ctx, "IMEX failed") }); } else { eprintln!("dc_imex called without a valid directory"); From 0afd3d595f5a9846a9e24d89eeaa09188851f0bc Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 13:07:26 +0000 Subject: [PATCH 22/31] Fix potential use-after-free in dc_jsonrpc_request() --- deltachat-ffi/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index e4467fa17..20592108e 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -4653,8 +4653,12 @@ mod jsonrpc { return; } - let api = &*jsonrpc_instance; - let handle = &api.handle; + let handle = &(*jsonrpc_instance).handle; + + // Clone the handle so we do not use the reference + // in spawned task after return from dc_jsonrpc_request(). + let handle = handle.clone(); + let request = to_string_lossy(request); spawn(async move { handle.handle_incoming(&request).await; From 8936e9a416c78b70023bdc4255907d48e9d763e1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 12:38:57 +0000 Subject: [PATCH 23/31] Add `dc_configure`, `dc_imex` and `dc_jsonrpc_request()` fixes to changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 750db29b4..68d6667d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ - "full message view" not needed because of footers that go to contact status #4151 - Pick up system's light/dark mode in generated message HTML #4150 +### Fixes +- Fix segmentation fault if `dc_context_unref()` is called during + background process spawned by `dc_configure()` or `dc_imex()` + or `dc_jsonrpc_instance_t` is unreferenced + during handling the JSON-RPC request. #4153 + ## 1.111.0 From 8d80aea5c8d8fd7c7ec9713084d00b76c4ab8ed5 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 15:56:00 +0000 Subject: [PATCH 24/31] Reduce the scope of unsafe blocks in FFI Spawn tasks from safe functions to ensure there is no use-after-free. --- deltachat-ffi/src/lib.rs | 42 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 20592108e..a3eae996c 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -421,6 +421,10 @@ pub unsafe extern "C" fn dc_get_oauth2_url( }) } +fn spawn_configure(ctx: Context) { + spawn(async move { ctx.configure().await.log_err(&ctx, "Configure failed") }); +} + #[no_mangle] pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) { if context.is_null() { @@ -428,10 +432,8 @@ pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) { return; } - // Clone the context Arc so we do not use the reference after dc_configure() returns. - let ctx = (*context).clone(); - - spawn(async move { ctx.configure().await.log_err(&ctx, "Configure failed") }); + let ctx = &*context; + spawn_configure(ctx.clone()); } #[no_mangle] @@ -2177,6 +2179,14 @@ pub unsafe extern "C" fn dc_get_contact( }) } +fn spawn_imex(ctx: Context, what: imex::ImexMode, param1: String, passphrase: Option) { + spawn(async move { + imex::imex(&ctx, what, param1.as_ref(), passphrase) + .await + .log_err(&ctx, "IMEX failed") + }); +} + #[no_mangle] pub unsafe extern "C" fn dc_imex( context: *mut dc_context_t, @@ -2197,15 +2207,10 @@ pub unsafe extern "C" fn dc_imex( }; let passphrase = to_opt_string_lossy(param2); - // Clone the context Arc so we do not use the reference after dc_imex() returns. - let ctx = (*context).clone(); + let ctx = &*context; if let Some(param1) = to_opt_string_lossy(param1) { - spawn(async move { - imex::imex(&ctx, what, param1.as_ref(), passphrase) - .await - .log_err(&ctx, "IMEX failed") - }); + spawn_imex(ctx.clone(), what, param1, passphrase); } else { eprintln!("dc_imex called without a valid directory"); } @@ -4643,6 +4648,12 @@ mod jsonrpc { drop(Box::from_raw(jsonrpc_instance)); } + fn spawn_handle_jsonrpc_request(handle: RpcSession, request: String) { + spawn(async move { + handle.handle_incoming(&request).await; + }); + } + #[no_mangle] pub unsafe extern "C" fn dc_jsonrpc_request( jsonrpc_instance: *mut dc_jsonrpc_instance_t, @@ -4654,15 +4665,8 @@ mod jsonrpc { } let handle = &(*jsonrpc_instance).handle; - - // Clone the handle so we do not use the reference - // in spawned task after return from dc_jsonrpc_request(). - let handle = handle.clone(); - let request = to_string_lossy(request); - spawn(async move { - handle.handle_incoming(&request).await; - }); + spawn_handle_jsonrpc_request(handle.clone(), request); } #[no_mangle] From 90d233381885e9718c62fec56d93e26c751964ea Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 22:31:36 +0000 Subject: [PATCH 25/31] python: update for latest ruff 0.0.255 --- python/pyproject.toml | 2 +- python/tests/test_1_online.py | 6 +++--- python/tests/test_3_offline.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index fb846cc8f..1cd94c48e 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -51,7 +51,7 @@ git_describe_command = "git describe --dirty --tags --long --match v*.*" line-length = 120 [tool.ruff] -select = ["E", "F", "W", "YTT", "C4", "ISC", "ICN", "TID", "DTZ", "PLC", "PLE", "PLW", "PIE", "COM", "UP004", "UP010", "UP031", "UP032", "ANN204"] +select = ["E", "F", "W", "YTT", "C40", "ISC", "ICN", "TID", "DTZ", "PLC", "PLE", "PLW", "PIE", "COM", "UP004", "UP010", "UP031", "UP032", "ANN204"] line-length = 120 [tool.isort] diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index d1761f02e..412247cbb 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -217,13 +217,13 @@ def test_html_message(acfactory, lp): lp.sec("ac1: prepare and send text message to ac2") msg1 = chat.send_text("message0") assert not msg1.has_html() - assert msg1.html == "" + assert not msg1.html lp.sec("wait for ac2 to receive message") msg2 = ac2._evtracker.wait_next_incoming_message() assert msg2.text == "message0" assert not msg2.has_html() - assert msg2.html == "" + assert not msg2.html lp.sec("ac1: prepare and send HTML+text message to ac2") msg1 = Message.new_empty(ac1, "text") @@ -2150,7 +2150,7 @@ def test_status(acfactory): chat12.send_text("hello") msg = ac2._evtracker.wait_next_incoming_message() assert msg.text == "hello" - assert msg.get_sender_contact().status == "" + assert not msg.get_sender_contact().status def test_group_quote(acfactory, lp): diff --git a/python/tests/test_3_offline.py b/python/tests/test_3_offline.py index e7a1a6231..e9a297681 100644 --- a/python/tests/test_3_offline.py +++ b/python/tests/test_3_offline.py @@ -295,8 +295,8 @@ class TestOfflineChat: assert d["archived"] == chat.is_archived() # assert d["param"] == chat.param assert d["color"] == chat.get_color() - assert d["profile_image"] == "" if chat.get_profile_image() is None else chat.get_profile_image() - assert d["draft"] == "" if chat.get_draft() is None else chat.get_draft() + assert not d["profile_image"] if chat.get_profile_image() is None else chat.get_profile_image() + assert not d["draft"] if chat.get_draft() is None else chat.get_draft() def test_group_chat_creation_with_translation(self, ac1): ac1.set_stock_translation(const.DC_STR_GROUP_NAME_CHANGED_BY_YOU, "abc %1$s xyz %2$s") From 73e7ee5c13ef2cb8c88050388c3543aa2f121a4e Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 13 Mar 2023 21:24:47 +0000 Subject: [PATCH 26/31] Build armv7 deltachat-rpc-server binaries without NDK --- .github/workflows/deltachat-rpc-server.yml | 15 ++++++++++---- scripts/README.md | 4 +++- scripts/aarch64-unknown-linux-musl.sh | 18 ----------------- scripts/zig-rpc-server.sh | 23 ++++++++++++++++++++++ 4 files changed, 37 insertions(+), 23 deletions(-) delete mode 100755 scripts/aarch64-unknown-linux-musl.sh create mode 100755 scripts/zig-rpc-server.sh diff --git a/.github/workflows/deltachat-rpc-server.yml b/.github/workflows/deltachat-rpc-server.yml index f073474f6..194b67ddc 100644 --- a/.github/workflows/deltachat-rpc-server.yml +++ b/.github/workflows/deltachat-rpc-server.yml @@ -35,22 +35,29 @@ jobs: path: target/x86_64-unknown-linux-musl/release/deltachat-rpc-server if-no-files-found: error - build_aarch64_linux: - name: Cross-compile deltachat-rpc-server for aarch64 Linux + build_linux: + name: Cross-compile deltachat-rpc-server for aarch64 and armv7 Linux runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - name: Build - run: sh scripts/aarch64-unknown-linux-musl.sh + run: sh scripts/zig-rpc-server.sh - - name: Upload binary + - name: Upload aarch64 binary uses: actions/upload-artifact@v3 with: name: deltachat-rpc-server-aarch64 path: target/aarch64-unknown-linux-musl/release/deltachat-rpc-server if-no-files-found: error + - name: Upload armv7 binary + uses: actions/upload-artifact@v3 + with: + name: deltachat-rpc-server-armv7 + path: target/armv7-unknown-linux-musleabihf/release/deltachat-rpc-server + if-no-files-found: error + build_android: name: Cross-compile deltachat-rpc-server for Android (armeabi-v7a, arm64-v8a, x86 and x86_64) runs-on: ubuntu-22.04 diff --git a/scripts/README.md b/scripts/README.md index af6a6addd..d8fdf0360 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -20,7 +20,9 @@ and an own build machine. - `run_all.sh` builds Python wheels -- `aarch64-unknown-linux-musl.sh` cross-compiles static `deltachat-rpc-server` for aarch64 +- `zig-rpc-server.sh` compiles binaries of `deltachat-rpc-server` using Zig toolchain statically linked against musl libc. + +- `android-rpc-server.sh` compiles binaries of `deltachat-rpc-server` using Android NDK. ## Triggering runs on the build machine locally (fast!) diff --git a/scripts/aarch64-unknown-linux-musl.sh b/scripts/aarch64-unknown-linux-musl.sh deleted file mode 100755 index 272574fce..000000000 --- a/scripts/aarch64-unknown-linux-musl.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -# -# Build statically linked deltachat-rpc-server for aarch64-unknown-linux-musl. - -set -x -set -e - -# Download Zig -rm -fr zig-linux-x86_64-0.10.1 zig-linux-x86_64-0.10.1.tar.xz -wget https://ziglang.org/download/0.10.1/zig-linux-x86_64-0.10.1.tar.xz -tar xf zig-linux-x86_64-0.10.1.tar.xz -export PATH="$PATH:$PWD/zig-linux-x86_64-0.10.1" - -cargo install cargo-zigbuild - -rustup target add aarch64-unknown-linux-musl - -cargo zigbuild --release --target aarch64-unknown-linux-musl -p deltachat-rpc-server --features vendored diff --git a/scripts/zig-rpc-server.sh b/scripts/zig-rpc-server.sh new file mode 100755 index 000000000..f18f301ca --- /dev/null +++ b/scripts/zig-rpc-server.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Build statically linked deltachat-rpc-server using cargo-zigbuild. + +set -x +set -e + +unset RUSTFLAGS + +ZIG_VERSION=0.11.0-dev.1935+1d96a17af + +# Download Zig +rm -fr "$ZIG_VERSION" "ZIG_VERSION.tar.xz" +wget "https://ziglang.org/builds/zig-linux-x86_64-$ZIG_VERSION.tar.xz" +tar xf "zig-linux-x86_64-$ZIG_VERSION.tar.xz" +export PATH="$PWD/zig-linux-x86_64-$ZIG_VERSION:$PATH" + +cargo install cargo-zigbuild + +for TARGET in aarch64-unknown-linux-musl armv7-unknown-linux-musleabihf; do + rustup target add "$TARGET" + cargo zigbuild --release --target "$TARGET" -p deltachat-rpc-server --features vendored +done From 6fbcf67190867a2cf4fbfa6d7fba2a8b2feff5c3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 14 Mar 2023 09:37:03 +0000 Subject: [PATCH 27/31] python: revert ruff C4 -> C40 change It is an error in ruff 0.0.255, will be fixed in the next version: https://github.com/charliermarsh/ruff/commit/a8c1915e2efbcd0a4bd798ed3e81cdc18f8e1890 --- python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 1cd94c48e..fb846cc8f 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -51,7 +51,7 @@ git_describe_command = "git describe --dirty --tags --long --match v*.*" line-length = 120 [tool.ruff] -select = ["E", "F", "W", "YTT", "C40", "ISC", "ICN", "TID", "DTZ", "PLC", "PLE", "PLW", "PIE", "COM", "UP004", "UP010", "UP031", "UP032", "ANN204"] +select = ["E", "F", "W", "YTT", "C4", "ISC", "ICN", "TID", "DTZ", "PLC", "PLE", "PLW", "PIE", "COM", "UP004", "UP010", "UP031", "UP032", "ANN204"] line-length = 120 [tool.isort] From 6b67f8bcfd9e80a1f98ae2bce1342068526a4b35 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 13 Mar 2023 16:48:46 -0300 Subject: [PATCH 28/31] Support non-persistent configuration with DELTACHAT_* env #3986 This way we can test some recently added config options that we don't want to expose in UI like DeleteToTrash or SignUnencrypted. Note that persistent config options like DeleteToTrash should remain anyway because they allow fine-grained (per-account) control. Having them matters for tests also. --- CHANGELOG.md | 1 + src/config.rs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d6667d3..76b768dc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Drop unused SQL columns #4141 - "full message view" not needed because of footers that go to contact status #4151 - Pick up system's light/dark mode in generated message HTML #4150 +- Support non-persistent configuration with DELTACHAT_* env ### Fixes - Fix segmentation fault if `dc_context_unref()` is called during diff --git a/src/config.rs b/src/config.rs index 2fa64ae96..39cd00877 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ //! # Key-value configuration management. +use std::env; use std::str::FromStr; use anyhow::{ensure, Context as _, Result}; @@ -317,6 +318,11 @@ impl Context { /// Get a configuration key. Returns `None` if no value is set, and no default value found. pub async fn get_config(&self, key: Config) -> Result> { + let env_key = format!("DELTACHAT_{}", key.as_ref().to_uppercase()); + if let Ok(value) = env::var(env_key) { + return Ok(Some(value)); + } + let value = match key { Config::Selfavatar => { let rel_path = self.sql.get_raw_config(key.as_ref()).await?; From cdd696db955b872355655d3c553b3508ed7570cc Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 15 Mar 2023 11:00:20 +0000 Subject: [PATCH 29/31] Delete expired messages using multiple SQL requests With existing approach of constructing the SQL query dynamically I get errors like this: ephemeral.rs:575: update failed: too many SQL variables: Error code 1: SQL error or missing database In my case it is trying to delete 143658 messages. This is the result of importing a Desktop backup and enabling device auto-deletion on the phone. Current SQLite limit is 32766 variables as stated in . --- CHANGELOG.md | 1 + src/ephemeral.rs | 55 +++++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76b768dc1..1e1612431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ background process spawned by `dc_configure()` or `dc_imex()` or `dc_jsonrpc_instance_t` is unreferenced during handling the JSON-RPC request. #4153 +- Delete expired messages using multiple SQL requests. #4158 ## 1.111.0 diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 507c65e57..306f3d7c5 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -68,7 +68,7 @@ use std::num::ParseIntError; use std::str::FromStr; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use anyhow::{ensure, Context as _, Result}; +use anyhow::{ensure, Result}; use async_channel::Receiver; use serde::{Deserialize, Serialize}; use tokio::time::timeout; @@ -433,37 +433,40 @@ pub(crate) async fn delete_expired_messages(context: &Context, now: i64) -> Resu let rows = select_expired_messages(context, now).await?; if !rows.is_empty() { - context + info!(context, "Attempting to delete {} messages.", rows.len()); + + let (msgs_changed, webxdc_deleted) = context .sql - .execute( + .transaction(|transaction| { + let mut msgs_changed = Vec::with_capacity(rows.len()); + let mut webxdc_deleted = Vec::new(); + // If you change which information is removed here, also change MsgId::trash() and // which information receive_imf::add_parts() still adds to the db if the chat_id is TRASH - &format!( - r#" -UPDATE msgs -SET - chat_id=?, txt='', subject='', txt_raw='', - mime_headers='', from_id=0, to_id=0, param='' -WHERE id IN ({}) -"#, - sql::repeat_vars(rows.len()) - ), - rusqlite::params_from_iter( - std::iter::once(&DC_CHAT_ID_TRASH as &dyn crate::ToSql).chain( - rows.iter() - .map(|(msg_id, _chat_id, _viewtype)| msg_id as &dyn crate::ToSql), - ), - ), - ) - .await - .context("update failed")?; + for (msg_id, chat_id, viewtype) in rows { + transaction.execute( + "UPDATE msgs + 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], + )?; - for (msg_id, chat_id, viewtype) in rows { + msgs_changed.push((chat_id, msg_id)); + if viewtype == Viewtype::Webxdc { + webxdc_deleted.push(msg_id) + } + } + Ok((msgs_changed, webxdc_deleted)) + }) + .await?; + + for (chat_id, msg_id) in msgs_changed { context.emit_msgs_changed(chat_id, msg_id); + } - if viewtype == Viewtype::Webxdc { - context.emit_event(EventType::WebxdcInstanceDeleted { msg_id }); - } + for msg_id in webxdc_deleted { + context.emit_event(EventType::WebxdcInstanceDeleted { msg_id }); } } From 8db64726eace1eaab371b1389da583fd42aed51a Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 15 Mar 2023 21:08:06 +0000 Subject: [PATCH 30/31] sql: expect zero-column results from `PRAGMA incremental_vacuum` The fact that `PRAGMA incremental_vacuum` may return a zero-column SQLITE_ROW result is documented in `sqlite3_data_count()` documentation: Previously successful auto_vacuum worked, but resulted in a "Failed to run incremental vacuum" log. --- CHANGELOG.md | 1 + src/sql.rs | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e1612431..544a6ccf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ or `dc_jsonrpc_instance_t` is unreferenced during handling the JSON-RPC request. #4153 - Delete expired messages using multiple SQL requests. #4158 +- Do not emit "Failed to run incremental vacuum" warnings on success. #4160 ## 1.111.0 diff --git a/src/sql.rs b/src/sql.rs index aec50171a..86f3bb4fa 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -713,12 +713,22 @@ pub async fn housekeeping(context: &Context) -> Result<()> { // Try to clear the freelist to free some space on the disk. This // only works if auto_vacuum is enabled. - if let Err(err) = context + match context .sql - .execute("PRAGMA incremental_vacuum", paramsv![]) + .query_row_optional("PRAGMA incremental_vacuum", (), |_row| Ok(())) .await { - warn!(context, "Failed to run incremental vacuum: {}", err); + Err(err) => { + warn!(context, "Failed to run incremental vacuum: {err:#}"); + } + Ok(Some(())) => { + // Incremental vacuum returns a zero-column result if it did anything. + info!(context, "Successfully ran incremental vacuum."); + } + Ok(None) => { + // Incremental vacuum returned `SQLITE_DONE` immediately, + // there were no pages to remove. + } } if let Err(e) = context From f0249096119ad56c2f3751560dc9341f904956c9 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 15 Mar 2023 22:01:22 +0000 Subject: [PATCH 31/31] sql: replace empty paramsv![] with empty tuples --- deltachat-repl/src/cmdline.rs | 18 +++++++++--------- src/authres.rs | 2 +- src/chat.rs | 16 +++++----------- src/config.rs | 2 +- src/context.rs | 9 +++------ src/ephemeral.rs | 14 ++++---------- src/imex.rs | 2 +- src/key.rs | 6 +++--- src/location.rs | 5 +---- src/message.rs | 4 ++-- src/peerstate.rs | 2 +- src/securejoin/bobstate.rs | 2 +- src/sql.rs | 8 ++++---- src/sql/migrations.rs | 2 +- src/sync.rs | 4 ++-- src/test_utils.rs | 2 +- src/webxdc.rs | 18 +++++++++--------- 17 files changed, 49 insertions(+), 67 deletions(-) diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index 60f6dc750..e659ea7e8 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -35,7 +35,7 @@ async fn reset_tables(context: &Context, bits: i32) { if 0 != bits & 1 { context .sql() - .execute("DELETE FROM jobs;", paramsv![]) + .execute("DELETE FROM jobs;", ()) .await .unwrap(); println!("(1) Jobs reset."); @@ -43,7 +43,7 @@ async fn reset_tables(context: &Context, bits: i32) { if 0 != bits & 2 { context .sql() - .execute("DELETE FROM acpeerstates;", paramsv![]) + .execute("DELETE FROM acpeerstates;", ()) .await .unwrap(); println!("(2) Peerstates reset."); @@ -51,7 +51,7 @@ async fn reset_tables(context: &Context, bits: i32) { if 0 != bits & 4 { context .sql() - .execute("DELETE FROM keypairs;", paramsv![]) + .execute("DELETE FROM keypairs;", ()) .await .unwrap(); println!("(4) Private keypairs reset."); @@ -59,36 +59,36 @@ async fn reset_tables(context: &Context, bits: i32) { if 0 != bits & 8 { context .sql() - .execute("DELETE FROM contacts WHERE id>9;", paramsv![]) + .execute("DELETE FROM contacts WHERE id>9;", ()) .await .unwrap(); context .sql() - .execute("DELETE FROM chats WHERE id>9;", paramsv![]) + .execute("DELETE FROM chats WHERE id>9;", ()) .await .unwrap(); context .sql() - .execute("DELETE FROM chats_contacts;", paramsv![]) + .execute("DELETE FROM chats_contacts;", ()) .await .unwrap(); context .sql() - .execute("DELETE FROM msgs WHERE id>9;", paramsv![]) + .execute("DELETE FROM msgs WHERE id>9;", ()) .await .unwrap(); context .sql() .execute( "DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';", - paramsv![], + (), ) .await .unwrap(); context.sql().config_cache().write().await.clear(); context .sql() - .execute("DELETE FROM leftgrps;", paramsv![]) + .execute("DELETE FROM leftgrps;", ()) .await .unwrap(); println!("(8) Rest but server config reset."); diff --git a/src/authres.rs b/src/authres.rs index eb267ddc9..41e45e8cd 100644 --- a/src/authres.rs +++ b/src/authres.rs @@ -334,7 +334,7 @@ async fn set_dkim_works_timestamp( async fn clear_dkim_works(context: &Context) -> Result<()> { context .sql - .execute("DELETE FROM sending_domains", paramsv![]) + .execute("DELETE FROM sending_domains", ()) .await?; Ok(()) } diff --git a/src/chat.rs b/src/chat.rs index edffef4ba..0442dea3c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -853,7 +853,7 @@ impl ChatId { AND c.blocked=0 AND c.archived=1 ", - paramsv![], + (), ) .await? } else { @@ -2578,7 +2578,7 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()> "SELECT DISTINCT(m.chat_id) FROM msgs m LEFT JOIN chats c ON m.chat_id=c.id WHERE m.state=10 AND m.hidden=0 AND m.chat_id>9 AND c.blocked=0 AND c.archived=1", - paramsv![], + (), |row| row.get::<_, ChatId>(0), |ids| ids.collect::, _>>().map_err(Into::into) ) @@ -3500,10 +3500,7 @@ pub(crate) async fn get_chat_cnt(context: &Context) -> Result { // no database, no chats - this is no error (needed eg. for information) let count = context .sql - .count( - "SELECT COUNT(*) FROM chats WHERE id>9 AND blocked=0;", - paramsv![], - ) + .count("SELECT COUNT(*) FROM chats WHERE id>9 AND blocked=0;", ()) .await?; Ok(count) } else { @@ -3676,17 +3673,14 @@ pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Resul paramsv![ContactId::DEVICE], ) .await?; - context - .sql - .execute("DELETE FROM devmsglabels;", paramsv![]) - .await?; + context.sql.execute("DELETE FROM devmsglabels;", ()).await?; // Insert labels for welcome messages to avoid them being readded on reconfiguration. context .sql .execute( r#"INSERT INTO devmsglabels (label) VALUES ("core-welcome-image"), ("core-welcome")"#, - paramsv![], + (), ) .await?; context.set_config(Config::QuotaExceeding, None).await?; diff --git a/src/config.rs b/src/config.rs index 39cd00877..76dca83a2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -424,7 +424,7 @@ impl Context { match key { Config::Selfavatar => { self.sql - .execute("UPDATE contacts SET selfavatar_sent=0;", paramsv![]) + .execute("UPDATE contacts SET selfavatar_sent=0;", ()) .await?; match value { Some(value) => { diff --git a/src/context.rs b/src/context.rs index 667f41d8e..13479a7ea 100644 --- a/src/context.rs +++ b/src/context.rs @@ -590,7 +590,7 @@ impl Context { .unwrap_or_default(); let journal_mode = self .sql - .query_get_value("PRAGMA journal_mode;", paramsv![]) + .query_get_value("PRAGMA journal_mode;", ()) .await? .unwrap_or_else(|| "unknown".to_string()); let e2ee_enabled = self.get_config_int(Config::E2eeEnabled).await?; @@ -598,14 +598,11 @@ impl Context { let bcc_self = self.get_config_int(Config::BccSelf).await?; let send_sync_msgs = self.get_config_int(Config::SendSyncMsgs).await?; - let prv_key_cnt = self - .sql - .count("SELECT COUNT(*) FROM keypairs;", paramsv![]) - .await?; + let prv_key_cnt = self.sql.count("SELECT COUNT(*) FROM keypairs;", ()).await?; let pub_key_cnt = self .sql - .count("SELECT COUNT(*) FROM acpeerstates;", paramsv![]) + .count("SELECT COUNT(*) FROM acpeerstates;", ()) .await?; let fingerprint_str = match SignedPublicKey::load_self(self).await { Ok(key) => key.fingerprint().hex(), diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 306f3d7c5..f7dadf5d8 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -1173,7 +1173,7 @@ mod tests { // No other messages are marked for deletion. assert_eq!( t.sql - .count("SELECT COUNT(*) FROM imap WHERE target=''", paramsv![],) + .count("SELECT COUNT(*) FROM imap WHERE target=''", ()) .await?, 0 ); @@ -1187,10 +1187,7 @@ mod tests { .update_download_state(&t, DownloadState::Available) .await?; t.sql - .execute( - "UPDATE imap SET target=folder WHERE rfc724_mid='1000'", - paramsv![], - ) + .execute("UPDATE imap SET target=folder WHERE rfc724_mid='1000'", ()) .await?; delete_expired_imap_messages(&t).await?; test_marked_for_deletion(&t, 1000).await?; // Delete downloadable anyway. @@ -1201,10 +1198,7 @@ mod tests { delete_expired_imap_messages(&t).await?; test_marked_for_deletion(&t, 1010).await?; t.sql - .execute( - "UPDATE imap SET target=folder WHERE rfc724_mid='1010'", - paramsv![], - ) + .execute("UPDATE imap SET target=folder WHERE rfc724_mid='1010'", ()) .await?; MsgId::new(1010) @@ -1214,7 +1208,7 @@ mod tests { // Keep downloadable for now. assert_eq!( t.sql - .count("SELECT COUNT(*) FROM imap WHERE target=''", paramsv![],) + .count("SELECT COUNT(*) FROM imap WHERE target=''", ()) .await?, 0 ); diff --git a/src/imex.rs b/src/imex.rs index bd7091800..7ca3bb15c 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -697,7 +697,7 @@ async fn export_self_keys(context: &Context, dir: &Path) -> Result<()> { .sql .query_map( "SELECT id, public_key, private_key, is_default FROM keypairs;", - paramsv![], + (), |row| { let id = row.get(0)?; let public_key_blob: Vec = row.get(1)?; diff --git a/src/key.rs b/src/key.rs index 3b48fe19e..74fb997cf 100644 --- a/src/key.rs +++ b/src/key.rs @@ -148,7 +148,7 @@ impl DcKey for SignedSecretKey { WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr") AND is_default=1; "#, - paramsv![], + (), |row| { let bytes: Vec = row.get(0)?; Ok(bytes) @@ -302,7 +302,7 @@ pub async fn store_self_keypair( .context("failed to remove old use of key")?; if default == KeyPairUse::Default { transaction - .execute("UPDATE keypairs SET is_default=0;", paramsv![]) + .execute("UPDATE keypairs SET is_default=0;", ()) .context("failed to clear default")?; } let is_default = match default { @@ -592,7 +592,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD let nrows = || async { ctx.sql - .count("SELECT COUNT(*) FROM keypairs;", paramsv![]) + .count("SELECT COUNT(*) FROM keypairs;", ()) .await .unwrap() }; diff --git a/src/location.rs b/src/location.rs index 7bb381497..52315585b 100644 --- a/src/location.rs +++ b/src/location.rs @@ -434,10 +434,7 @@ fn is_marker(txt: &str) -> bool { /// Deletes all locations from the database. pub async fn delete_all(context: &Context) -> Result<()> { - context - .sql - .execute("DELETE FROM locations;", paramsv![]) - .await?; + context.sql.execute("DELETE FROM locations;", ()).await?; context.emit_event(EventType::LocationChanged(None)); Ok(()) } diff --git a/src/message.rs b/src/message.rs index 258a8624a..b287e6c57 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1794,7 +1794,7 @@ pub async fn get_unblocked_msg_cnt(context: &Context) -> usize { "SELECT COUNT(*) \ FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \ WHERE m.id>9 AND m.chat_id>9 AND c.blocked=0;", - paramsv![], + (), ) .await { @@ -1814,7 +1814,7 @@ pub async fn get_request_msg_cnt(context: &Context) -> usize { "SELECT COUNT(*) \ FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \ WHERE c.blocked=2;", - paramsv![], + (), ) .await { diff --git a/src/peerstate.rs b/src/peerstate.rs index 2913326fe..16378c918 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -718,7 +718,7 @@ pub(crate) async fn deduplicate_peerstates(sql: &Sql) -> Result<()> { FROM acpeerstates GROUP BY addr )", - paramsv![], + (), ) .await?; diff --git a/src/securejoin/bobstate.rs b/src/securejoin/bobstate.rs index 9640e5d1c..b6584f6e1 100644 --- a/src/securejoin/bobstate.rs +++ b/src/securejoin/bobstate.rs @@ -163,7 +163,7 @@ impl BobState { // guaranteed to only have one row. sql.query_row_optional( "SELECT id, invite, next_step, chat_id FROM bobstate;", - paramsv![], + (), |row| { let s = BobState { id: row.get(0)?, diff --git a/src/sql.rs b/src/sql.rs index 86f3bb4fa..eff04a157 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -220,7 +220,7 @@ impl Sql { let addrs = self .query_map( "SELECT addr FROM acpeerstates;", - paramsv![], + (), |row| row.get::<_, String>(0), |addrs| { addrs @@ -742,7 +742,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> { .sql .execute( "DELETE FROM msgs_mdns WHERE msg_id NOT IN (SELECT id FROM msgs)", - paramsv![], + (), ) .await .ok_or_log_msg(context, "failed to remove old MDNs"); @@ -790,7 +790,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { .sql .query_map( "SELECT value FROM config;", - paramsv![], + (), |row| row.get::<_, String>(0), |rows| { for row in rows { @@ -925,7 +925,7 @@ async fn maybe_add_from_param( ) -> Result<()> { sql.query_map( query, - paramsv![], + (), |row| row.get::<_, String>(0), |rows| { for row in rows { diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 0cdae4c44..d23261862 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -391,7 +391,7 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#, sql.execute( r#" CREATE TABLE imap_sync (folder TEXT PRIMARY KEY, uidvalidity INTEGER DEFAULT 0, uid_next INTEGER DEFAULT 0);"#, -paramsv![] +() ) .await?; for c in &[ diff --git a/src/sync.rs b/src/sync.rs index a977d1c57..2976a07fc 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -155,7 +155,7 @@ impl Context { .sql .query_map( "SELECT id, item FROM multi_device_sync ORDER BY id;", - paramsv![], + (), |row| Ok((row.get::<_, u32>(0)?, row.get::<_, String>(1)?)), |rows| { let mut ids = vec![]; @@ -201,7 +201,7 @@ impl Context { self.sql .execute( &format!("DELETE FROM multi_device_sync WHERE id IN ({ids});"), - paramsv![], + (), ) .await?; Ok(()) diff --git a/src/test_utils.rs b/src/test_utils.rs index 3b57724be..5006f31c6 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -398,7 +398,7 @@ impl TestContext { SELECT id, msg_id, mime, recipients FROM smtp ORDER BY id DESC"#, - paramsv![], + (), |row| { let rowid: i64 = row.get(0)?; let msg_id: MsgId = row.get(1)?; diff --git a/src/webxdc.rs b/src/webxdc.rs index 1c9a8095b..bfaaa8741 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -438,7 +438,7 @@ impl Context { "DELETE FROM smtp_status_updates WHERE msg_id IN (SELECT msg_id FROM smtp_status_updates LIMIT 1) RETURNING msg_id, first_serial, last_serial, descr", - paramsv![], + (), |row| { let instance_id: MsgId = row.get(0)?; let first_serial: StatusUpdateSerial = row.get(1)?; @@ -1195,7 +1195,7 @@ mod tests { ); assert_eq!( t.sql - .count("SELECT COUNT(*) FROM msgs_status_updates;", paramsv![],) + .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) .await?, 0 ); @@ -1543,14 +1543,14 @@ mod tests { assert_eq!( t.sql - .count("SELECT COUNT(*) FROM smtp_status_updates", paramsv![],) + .count("SELECT COUNT(*) FROM smtp_status_updates", ()) .await?, 1 ); t.flush_status_updates().await?; assert_eq!( t.sql - .count("SELECT COUNT(*) FROM smtp_status_updates", paramsv![],) + .count("SELECT COUNT(*) FROM smtp_status_updates", ()) .await?, 0 ); @@ -1580,7 +1580,7 @@ mod tests { .await?; assert_eq!( t.sql - .count("SELECT COUNT(*) FROM smtp_status_updates", paramsv![],) + .count("SELECT COUNT(*) FROM smtp_status_updates", ()) .await?, 3 ); @@ -1606,7 +1606,7 @@ mod tests { } assert_eq!( t.sql - .count("SELECT COUNT(*) FROM smtp_status_updates", paramsv![],) + .count("SELECT COUNT(*) FROM smtp_status_updates", ()) .await?, 2 - i ); @@ -1648,7 +1648,7 @@ mod tests { assert_eq!( alice .sql - .count("SELECT COUNT(*) FROM smtp_status_updates", paramsv![],) + .count("SELECT COUNT(*) FROM smtp_status_updates", ()) .await?, 0 ); @@ -2438,7 +2438,7 @@ sth_for_the = "future""# assert_eq!( alice .sql - .count("SELECT COUNT(*) FROM msgs_status_updates;", paramsv![],) + .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) .await?, 0 ); @@ -2461,7 +2461,7 @@ sth_for_the = "future""# assert!( alice .sql - .count("SELECT COUNT(*) FROM msgs_status_updates;", paramsv![],) + .count("SELECT COUNT(*) FROM msgs_status_updates;", ()) .await? > 0 );