diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42441489d..4455ec2c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,11 @@ env: RUSTFLAGS: -Dwarnings jobs: - lint: - name: Rustfmt and Clippy + lint_rust: + name: Lint Rust runs-on: ubuntu-latest env: - RUSTUP_TOOLCHAIN: 1.68.0 + RUSTUP_TOOLCHAIN: 1.68.2 steps: - uses: actions/checkout@v3 - name: Install rustfmt and clippy @@ -31,6 +31,8 @@ jobs: run: cargo fmt --all -- --check - name: Run clippy run: scripts/clippy.sh + - name: Check + run: cargo check --workspace --all-targets --all-features cargo_deny: name: cargo deny @@ -64,34 +66,28 @@ jobs: - name: Rustdoc run: cargo doc --document-private-items --no-deps - build_and_test: - name: Build and test + rust_tests: + name: Rust tests strategy: - fail-fast: false matrix: include: - # Currently used Rust version. - os: ubuntu-latest - rust: 1.68.0 - python: 3.9 + rust: 1.68.2 - os: windows-latest - rust: 1.68.0 - python: false # Python bindings compilation on Windows is not supported. + rust: 1.68.2 - os: macos-latest - rust: 1.68.0 - python: 3.9 + rust: 1.68.2 - # Minimum Supported Rust Version = 1.64.0 + # Minimum Supported Rust Version = 1.65.0 # # Minimum Supported Python Version = 3.7 # This is the minimum version for which manylinux Python wheels are # built. - os: ubuntu-latest - rust: 1.64.0 - python: 3.7 + rust: 1.65.0 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 - name: Install Rust ${{ matrix.rust }} run: rustup toolchain install --profile minimal ${{ matrix.rust }} @@ -100,64 +96,176 @@ jobs: - name: Cache rust cargo artifacts uses: swatinem/rust-cache@v2 - - name: Check - run: cargo check --workspace --bins --examples --tests --benches - - name: Tests run: cargo test --workspace - name: Test cargo vendor run: cargo vendor + c_library: + name: Build C library + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Cache rust cargo artifacts + uses: swatinem/rust-cache@v2 + + - name: Build C library + run: cargo build -p deltachat_ffi --features jsonrpc + + - name: Upload C library + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.rust}}-libdeltachat.a + path: target/debug/libdeltachat.a + retention-days: 1 + + rpc_server: + name: Build deltachat-rpc-server + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Cache rust cargo artifacts + uses: swatinem/rust-cache@v2 + + - name: Build deltachat-rpc-server + run: cargo build -p deltachat-rpc-server + + - name: Upload deltachat-rpc-server + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.rust}}-deltachat-rpc-server + path: target/debug/deltachat-rpc-server + retention-days: 1 + + python_lint: + name: Python lint + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Install tox + run: pip install tox + + - name: Lint Python bindings + working-directory: python + run: tox -e lint + + - name: Lint deltachat-rpc-client + working-directory: deltachat-rpc-client + run: tox -e lint + + python_tests: + name: Python tests + needs: ["c_library", "python_lint"] + strategy: + fail-fast: false + matrix: + include: + # Currently used Rust version. + - os: ubuntu-latest + python: 3.11 + - os: macos-latest + python: 3.11 + + # PyPy tests + - os: ubuntu-latest + python: pypy3.9 + - os: macos-latest + python: pypy3.9 + + # Minimum Supported Python Version = 3.7 + # This is the minimum version for which manylinux Python wheels are + # built. Test it with minimum supported Rust version. + - os: ubuntu-latest + python: 3.7 + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Download libdeltachat.a + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.rust}}-libdeltachat.a + path: target/debug + - name: Install python - if: ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install tox - if: ${{ matrix.python }} run: pip install tox - - name: Build C library - if: ${{ matrix.python }} - run: cargo build -p deltachat_ffi --features jsonrpc - - name: Run python tests - if: ${{ matrix.python }} env: DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} DCC_RS_TARGET: debug DCC_RS_DEV: ${{ github.workspace }} working-directory: python - run: tox -e lint,mypy,doc,py3 + run: tox -e mypy,doc,py - - name: Build deltachat-rpc-server - if: ${{ matrix.python }} - run: cargo build -p deltachat-rpc-server + aysnc_python_tests: + name: Async Python tests + needs: ["python_lint", "rpc_server"] + strategy: + fail-fast: false + matrix: + include: + # Currently used Rust version. + - os: ubuntu-latest + python: 3.11 + - os: macos-latest + python: 3.11 + + # PyPy tests + - os: ubuntu-latest + python: pypy3.9 + - os: macos-latest + python: pypy3.9 + + # Minimum Supported Python Version = 3.7 + # This is the minimum version for which manylinux Python wheels are + # built. Test it with minimum supported Rust version. + - os: ubuntu-latest + python: 3.7 + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Install python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + + - name: Install tox + run: pip install tox + + - name: Download deltachat-rpc-server + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.rust}}-deltachat-rpc-server + path: target/debug + + - name: Make deltachat-rpc-server executable + run: chmod +x target/debug/deltachat-rpc-server - name: Add deltachat-rpc-server to path - if: ${{ matrix.python }} run: echo ${{ github.workspace }}/target/debug >> $GITHUB_PATH - name: Run deltachat-rpc-client tests - if: ${{ matrix.python }} env: DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} working-directory: deltachat-rpc-client - run: tox -e py3,lint - - - name: Install pypy - if: ${{ matrix.python }} - uses: actions/setup-python@v4 - with: - python-version: "pypy${{ matrix.python }}" - - - name: Run pypy tests - if: ${{ matrix.python }} - env: - DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }} - DCC_RS_TARGET: debug - DCC_RS_DEV: ${{ github.workspace }} - working-directory: python - run: tox -e pypy3 + run: tox -e py diff --git a/CHANGELOG.md b/CHANGELOG.md index ab606b355..024008417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,40 @@ ## [Unreleased] ### Changes +- Increase MSRV to 1.65.0. #4236 +- 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 + +### Fixes +- Fix python bindings README documentation on installing the bindings from source. +- Show a warning if quota list is empty #4261 + +## [1.112.5] - 2023-04-02 ### Fixes +- Run SQL database migrations after receiving a backup from the network. #4287 + +## [1.112.4] - 2023-03-31 + +### Fixes +- Fix call to `auditwheel` in `scripts/run_all.sh`. + +## [1.112.3] - 2023-03-30 + +### Fixes +- `transfer::get_backup` now frees ongoing process when cancelled. #4249 + +## [1.112.2] - 2023-03-30 + +### 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 + +### Fixes +- Do not return media from trashed messages in the "All media" view. #4247 ## [1.112.1] - 2023-03-27 @@ -2337,7 +2368,11 @@ For a full list of changes, please see our closed Pull Requests: https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed -[unreleased]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.1...HEAD +[unreleased]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.5...HEAD [1.111.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.110.0...v1.111.0 [1.112.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.111.0...v1.112.0 [1.112.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.0...v1.112.1 +[1.112.2]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.1...v1.112.2 +[1.112.3]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.2...v1.112.3 +[1.112.4]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.3...v1.112.4 +[1.112.5]: https://github.com/deltachat/deltachat-core-rust/compare/v1.112.4...v1.112.5 diff --git a/Cargo.lock b/Cargo.lock index 93e43686d..b324be423 100644 --- a/Cargo.lock +++ b/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" @@ -99,9 +114,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" dependencies = [ "backtrace", ] @@ -133,7 +148,7 @@ dependencies = [ "asn1-rs-derive", "asn1-rs-impl", "displaydoc", - "nom 7.1.3", + "nom", "num-traits", "rusticata-macros", "thiserror", @@ -146,8 +161,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", "synstructure", ] @@ -158,8 +173,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -189,18 +204,19 @@ dependencies = [ [[package]] name = "async-imap" -version = "0.6.0" -source = "git+https://github.com/async-email/async-imap?branch=master#90270474a5a494669e7c63c13471d189afdc98ae" +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.3", + "nom", "once_cell", "ouroboros", "pin-utils", @@ -253,7 +269,7 @@ dependencies = [ "futures", "hostname", "log", - "nom 7.1.3", + "nom", "pin-project", "thiserror", "tokio", @@ -261,20 +277,20 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[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", @@ -303,14 +319,14 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d8068b6ccb8b34db9de397c7043f91db8b4c66414952c6db944f238c4d3db3" +checksum = "349f8ccfd9221ee7d1f3d4b33e1f8319b3a81ed8f61f2ea40b37b859794b4491" dependencies = [ "async-trait", "axum-core", "base64 0.21.0", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -368,18 +384,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" @@ -431,6 +447,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" + [[package]] name = "blake3" version = "1.3.3" @@ -483,10 +505,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", @@ -526,6 +579,16 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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 = "camino" version = "1.1.3" @@ -605,9 +668,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -661,40 +724,12 @@ version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ - "bitflags", - "clap_lex 0.2.4", + "bitflags 1.3.2", + "clap_lex", "indexmap", "textwrap", ] -[[package]] -name = "clap" -version = "4.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" -dependencies = [ - "bitflags", - "clap_derive", - "clap_lex 0.3.2", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", -] - [[package]] name = "clap_lex" version = "0.2.4" @@ -704,15 +739,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "clap_lex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "clipboard-win" version = "4.5.0" @@ -755,19 +781,6 @@ 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.2" @@ -789,9 +802,9 @@ version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "unicode-xid 0.2.4", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -862,7 +875,7 @@ dependencies = [ "atty", "cast", "ciborium", - "clap 3.2.23", + "clap", "criterion-plot", "futures", "itertools", @@ -955,6 +968,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" @@ -978,6 +1003,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.91" @@ -999,8 +1039,8 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "scratch", "syn 1.0.109", ] @@ -1017,8 +1057,8 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1050,8 +1090,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "strsim", "syn 1.0.109", ] @@ -1064,8 +1104,8 @@ checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "strsim", "syn 1.0.109", ] @@ -1077,7 +1117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.23", + "quote", "syn 1.0.109", ] @@ -1088,7 +1128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core 0.14.3", - "quote 1.0.23", + "quote", "syn 1.0.109", ] @@ -1098,32 +1138,13 @@ 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 1.0.109", -] - [[package]] name = "default-net" -version = "0.13.1" -source = "git+https://github.com/dignifiedquire/default-net.git?rev=7a257095bac009c4be0b93c2979801624fdd337b#7a257095bac009c4be0b93c2979801624fdd337b" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4898b43aed56499fad6b294d15b3e76a51df68079bf492e5daae38ca084e003" dependencies = [ - "dlopen", + "dlopen2", "libc", "memalloc", "netlink-packet-core", @@ -1136,7 +1157,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.112.1" +version = "1.112.5" dependencies = [ "ansi_term", "anyhow", @@ -1147,7 +1168,7 @@ dependencies = [ "async_zip", "backtrace", "base64 0.21.0", - "bitflags", + "brotli", "chrono", "criterion", "deltachat_derive", @@ -1201,6 +1222,7 @@ dependencies = [ "tokio-io-timeout", "tokio-stream", "tokio-tar", + "tokio-util", "toml", "trust-dns-resolver", "url", @@ -1209,7 +1231,7 @@ dependencies = [ [[package]] name = "deltachat-jsonrpc" -version = "1.112.1" +version = "1.112.5" dependencies = [ "anyhow", "async-channel", @@ -1232,7 +1254,7 @@ dependencies = [ [[package]] name = "deltachat-repl" -version = "1.112.1" +version = "1.112.5" dependencies = [ "ansi_term", "anyhow", @@ -1247,7 +1269,7 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.112.1" +version = "1.112.5" dependencies = [ "anyhow", "deltachat", @@ -1265,13 +1287,13 @@ dependencies = [ name = "deltachat_derive" version = "2.0.0" dependencies = [ - "quote 1.0.23", - "syn 1.0.109", + "quote", + "syn 2.0.13", ] [[package]] name = "deltachat_ffi" -version = "1.112.1" +version = "1.112.5" dependencies = [ "anyhow", "deltachat", @@ -1294,7 +1316,18 @@ checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", "der_derive", - "pem-rfc7468", + "pem-rfc7468 0.6.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0" +dependencies = [ + "const-oid", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -1306,7 +1339,7 @@ checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" dependencies = [ "asn1-rs", "displaydoc", - "nom 7.1.3", + "nom", "num-bigint", "num-traits", "rusticata-macros", @@ -1319,37 +1352,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ef71ddb5b3a1f53dee24817c8f70dfa1cb29e804c18d88c228d4bc9c86ee3b9" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] [[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 0.14.3", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] [[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 1.0.109", @@ -1362,8 +1395,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", ] @@ -1400,9 +1433,9 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd" dependencies = [ "dirs-sys", ] @@ -1419,13 +1452,13 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b" dependencies = [ "libc", "redox_users", - "winapi", + "windows-sys 0.45.0", ] [[package]] @@ -1445,32 +1478,32 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] -name = "dlopen" -version = "0.1.8" +name = "dlopen2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +checksum = "b121caccfc363e4d9a4589528f3bef7c71b83c6ed01c8dc68cbeeb7fd29ec698" dependencies = [ - "dlopen_derive", - "lazy_static", + "dlopen2_derive", "libc", + "once_cell", "winapi", ] [[package]] -name = "dlopen_derive" -version = "0.1.4" +name = "dlopen2_derive" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +checksum = "3a09ac8bb8c16a282264c379dffba707b9c998afc7506009137f3c6136888078" dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -1479,10 +1512,22 @@ 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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644d3b8674a5fc5b929ae435bca85c2323d85ccb013a5509c2ac9ee11a6284ba" +dependencies = [ + "der 0.7.1", + "elliptic-curve 0.13.2", + "rfc6979 0.4.0", + "signature 2.0.0", ] [[package]] @@ -1492,7 +1537,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "serde", - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be522bee13fa6d8059f4903a4084aa3bd50725e18150202f0238deb615cd6371" +dependencies = [ + "pkcs8 0.10.1", + "signature 2.0.0", ] [[package]] @@ -1501,8 +1556,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.3", "rand 0.7.3", "serde", "serde_bytes", @@ -1510,6 +1565,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.0", + "serde", + "sha2 0.10.6", + "zeroize", +] + [[package]] name = "educe" version = "0.4.20" @@ -1517,8 +1585,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0188e3c3ba8df5753894d54461f0e39bc91741dc5b22e1c46999ec2c71f4e4" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1534,15 +1602,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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d" +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.1", + "rand_core 0.6.4", + "sec1 0.7.1", "subtle", "zeroize", ] @@ -1559,15 +1648,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" @@ -1674,8 +1757,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1687,8 +1770,8 @@ checksum = "a62bb1df8b45ecb7ffa78dca1c17a438fb193eb083db0b1b494d2a61bcb5096a" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", ] @@ -1721,13 +1804,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.45.0", ] [[package]] @@ -1779,9 +1862,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fast-socks5" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2687b5a6108f18ba8621e0e618a3be1dcc2768632dad24b7cea1f87975375a9" +checksum = "961ce1761191c157145a8c9f0c3ceabecd3a729d65c9a8d443674eaee3420f7e" dependencies = [ "anyhow", "log", @@ -1810,9 +1893,9 @@ dependencies = [ [[package]] name = "fd-lock" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ef1a30ae415c3a691a4f41afddc2dbcd6d70baf338368d85ebc1e8ed92cedb9" +checksum = "9799aefb4a2e4a01cc47610b1dd47c18ab13d991f27bbcaed9296f5a53d5cbad" dependencies = [ "cfg-if", "rustix", @@ -1829,6 +1912,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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" + [[package]] name = "filetime" version = "0.2.20" @@ -1837,7 +1936,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "windows-sys 0.45.0", ] @@ -1861,7 +1960,7 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin 0.9.7", + "spin 0.9.8", ] [[package]] @@ -1900,9 +1999,9 @@ version = "1.0.0" [[package]] name = "futures" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1915,9 +2014,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1925,15 +2024,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1942,9 +2041,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" @@ -1963,32 +2062,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -2009,7 +2108,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", - "version_check 0.9.4", + "version_check", + "zeroize", ] [[package]] @@ -2038,9 +2138,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", @@ -2058,7 +2158,18 @@ 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", ] @@ -2142,6 +2253,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" @@ -2216,7 +2336,7 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" dependencies = [ - "libm", + "libm 0.2.6", ] [[package]] @@ -2295,6 +2415,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" @@ -2324,9 +2453,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", @@ -2344,7 +2473,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f73b1b63179418b20aa81002d616c5f21b4ba257da9bca6989ea64dc573933e0" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -2357,19 +2486,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" @@ -2418,28 +2534,24 @@ checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "iroh" -version = "0.3.0" -source = "git+https://github.com/n0-computer/iroh?branch=main#9ac4cf6e770879c8b2ec0dc6666fe531469e68e3" +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 4.1.8", - "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.0.1", + "portable-atomic", "postcard", "quic-rpc", "quinn", @@ -2453,6 +2565,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-stream", "tokio-util", "tracing", "tracing-futures", @@ -2465,9 +2578,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", @@ -2558,9 +2671,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libm" @@ -2570,9 +2689,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", @@ -2597,9 +2716,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "lock_api" @@ -2730,17 +2849,6 @@ dependencies = [ "windows-sys 0.45.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" @@ -2793,7 +2901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea993e32c77d87f01236c38f572ecb6c311d592e56a06262a007fd2a6e31253c" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -2838,22 +2946,12 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", ] -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check 0.1.5", -] - [[package]] name = "nom" version = "7.1.3" @@ -2902,7 +3000,7 @@ checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" dependencies = [ "byteorder", "lazy_static", - "libm", + "libm 0.2.6", "num-integer", "num-iter", "num-traits", @@ -2918,8 +3016,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -2962,7 +3060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm", + "libm 0.2.6", ] [[package]] @@ -2975,12 +3073,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.3" @@ -3023,7 +3115,7 @@ version = "0.10.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -3038,8 +3130,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3107,8 +3199,8 @@ checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3124,8 +3216,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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7270da3e5caa82afd3deb054cc237905853813aea3859544bc082c3fe55b8d47" +dependencies = [ + "ecdsa 0.16.2", + "elliptic-curve 0.13.2", + "primeorder", "sha2 0.10.6", ] @@ -3135,11 +3239,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.2", + "elliptic-curve 0.13.2", + "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" @@ -3164,7 +3290,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -3193,6 +3319,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" @@ -3201,17 +3336,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", @@ -3220,23 +3357,27 @@ dependencies = [ "derive_builder", "des", "digest 0.10.6", - "ed25519-dalek", + "ed25519-dalek 2.0.0-rc.2", + "elliptic-curve 0.13.2", "flate2", "generic-array", "hex", + "idea", "log", "md-5", - "nom 4.2.3", + "nom", "num-bigint-dig", "num-derive", "num-traits", + "p256 0.13.0", + "p384 0.13.0", "rand 0.8.5", "ripemd", - "rsa", + "rsa 0.9.0-pre.0", "sha1", "sha2 0.10.6", "sha3", - "signature", + "signature 2.0.0", "smallvec", "thiserror", "twofish", @@ -3259,8 +3400,8 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3282,9 +3423,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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "178ba28ece1961eafdff1991bd1744c29564cbab5d803f3ccb4a4895a6c550a7" +dependencies = [ + "der 0.7.1", + "pkcs8 0.10.1", + "spki 0.7.0", "zeroize", ] @@ -3294,8 +3447,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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d2820d87d2b008616e5c27212dd9e0e694fb4c6b522de06094106813328cb49" +dependencies = [ + "der 0.7.1", + "spki 0.7.0", ] [[package]] @@ -3304,6 +3467,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 = "plotters" version = "0.3.4" @@ -3338,18 +3507,12 @@ version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "flate2", "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.0.1" @@ -3374,8 +3537,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4b01218787dd4420daf63875163a787a78294ad48a24e9f6fa8c6507759a79" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3395,6 +3558,15 @@ dependencies = [ "log", ] +[[package]] +name = "primeorder" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7613fdcc0831c10060fa69833ea8fa2caa94b6456f51e25356a885b530a2e3d0" +dependencies = [ + "elliptic-curve 0.13.2", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3402,10 +3574,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", - "version_check 0.9.4", + "version_check", ] [[package]] @@ -3414,25 +3586,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "version_check 0.9.4", + "proc-macro2", + "quote", + "version_check", ] [[package]] name = "proc-macro2" -version = "0.4.30" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" dependencies = [ "unicode-ident", ] @@ -3443,7 +3606,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", @@ -3493,9 +3656,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.27.1" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" +checksum = "e5c1a97b1bc42b1d550bfb48d4262153fe400a12bab1511821736f7eac76d7e2" dependencies = [ "memchr", ] @@ -3550,20 +3713,11 @@ dependencies = [ [[package]] name = "quote" -version = "0.6.13" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2 1.0.51", + "proc-macro2", ] [[package]] @@ -3706,7 +3860,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", ] [[package]] @@ -3716,15 +3879,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.8", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -3742,15 +3905,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[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", @@ -3799,11 +3962,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" @@ -3840,22 +4013,42 @@ 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.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +checksum = "a7bc1d34159d63536b4d89944e9ab5bb952f45db6fa0b8b03c2f8c09fb5b7171" dependencies = [ - "bitflags", + "byteorder", + "digest 0.10.6", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1 0.7.1", + "pkcs8 0.10.1", + "rand_core 0.6.4", + "signature 2.0.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", @@ -3896,16 +4089,16 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] name = "rustix" -version = "0.36.8" +version = "0.37.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +checksum = "d097081ed288dfe45699b72f5b5d648e5f15d64d900c7080273baa20c16a6849" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -3957,7 +4150,7 @@ version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfc8644681285d1fb67a467fb3021bfea306b99b4146b166a1fe3ada965eece" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "clipboard-win", "dirs-next", @@ -4042,10 +4235,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.1", + "generic-array", + "pkcs8 0.10.1", "subtle", "zeroize", ] @@ -4056,7 +4263,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -4084,9 +4291,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.152" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] @@ -4111,20 +4318,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -4245,6 +4452,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.8" @@ -4268,9 +4485,9 @@ checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -4284,9 +4501,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", ] @@ -4298,7 +4515,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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f" +dependencies = [ + "base64ct", + "der 0.7.1", ] [[package]] @@ -4308,7 +4535,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", ] @@ -4318,14 +4545,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", ] @@ -4379,8 +4606,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -4391,25 +4618,25 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", "unicode-ident", ] @@ -4425,10 +4652,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid", ] [[package]] @@ -4451,7 +4678,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -4474,15 +4701,15 @@ checksum = "6aaa6f5d645d1dae4cd0286e9f8bf15b75a31656348e5e106eb1a940abd34b63" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4496,9 +4723,9 @@ dependencies = [ [[package]] name = "testdir" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31eb500f7513b559ed7e0652894268dbe8ef27b6241b783ce274f4741eae137" +checksum = "a45fc921e7c4ad1aedb3484811514f3e5cd187886e0bbf1302c175f7578ef552" dependencies = [ "anyhow", "backtrace", @@ -4521,22 +4748,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] @@ -4614,14 +4841,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot", @@ -4644,13 +4870,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.13", ] [[package]] @@ -4698,7 +4924,7 @@ dependencies = [ "filetime", "futures-core", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "tokio", "tokio-stream", "xattr", @@ -4732,9 +4958,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" dependencies = [ "serde", "serde_spanned", @@ -4753,9 +4979,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.4" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap", "serde", @@ -4811,8 +5037,8 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4969,8 +5195,8 @@ dependencies = [ "darling 0.13.4", "ident_case", "proc-macro-error", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5023,12 +5249,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -5086,12 +5306,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" @@ -5106,12 +5320,11 @@ checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -5162,8 +5375,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", "wasm-bindgen-shared", ] @@ -5186,7 +5399,7 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ - "quote 1.0.23", + "quote", "wasm-bindgen-macro-support", ] @@ -5196,8 +5409,8 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -5408,9 +5621,9 @@ checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winnow" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" dependencies = [ "memchr", ] @@ -5426,12 +5639,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", ] @@ -5446,7 +5659,7 @@ dependencies = [ "data-encoding", "der-parser", "lazy_static", - "nom 7.1.3", + "nom", "oid-registry", "rusticata-macros", "thiserror", @@ -5501,8 +5714,8 @@ checksum = "6bd53ff9053698697b92c2535bf7ecb983fd5d546d690b7c725e5070d6d9a620" dependencies = [ "convert_case 0.5.0", "darling 0.14.3", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5521,8 +5734,8 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "syn 1.0.109", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index d2ce395a9..81e1f7a34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "deltachat" -version = "1.112.1" +version = "1.112.5" edition = "2021" license = "MPL-2.0" -rust-version = "1.64" +rust-version = "1.65" [profile.dev] debug = 0 @@ -25,7 +25,6 @@ panic = 'abort' opt-level = "z" [patch.crates-io] -default-net = { git = "https://github.com/dignifiedquire/default-net.git", rev="7a257095bac009c4be0b93c2979801624fdd337b" } quinn-udp = { git = "https://github.com/quinn-rs/quinn", branch="main" } quinn-proto = { git = "https://github.com/quinn-rs/quinn", branch="main" } @@ -36,13 +35,13 @@ ratelimit = { path = "./deltachat-ratelimit" } anyhow = "1" async-channel = "1.8.0" -async-imap = { git = "https://github.com/async-email/async-imap", branch = "master", default-features = false, features = ["runtime-tokio"] } +async-imap = { version = "0.7.0", default-features = false, features = ["runtime-tokio"] } async-native-tls = { version = "0.5", default-features = false, features = ["runtime-tokio"] } async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] } -async_zip = { version = "0.0.11", default-features = false, features = ["deflate", "fs"] } +async_zip = { version = "0.0.12", default-features = false, features = ["deflate", "fs"] } backtrace = "0.3" base64 = "0.21" -bitflags = "1.3" +brotli = "3.3" chrono = { version = "0.4", default-features=false, features = ["clock", "std"] } email = { git = "https://github.com/deltachat/rust-email", branch = "master" } encoded-words = { git = "https://github.com/async-email/encoded-words", branch = "master" } @@ -52,9 +51,8 @@ futures = "0.3" 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.3.0", default-features = false } -iroh = { git = 'https://github.com/n0-computer/iroh', branch = "main" } +image = { version = "0.24.6", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } +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" @@ -65,14 +63,14 @@ num-traits = "0.2" once_cell = "1.17.0" percent-encoding = "2.2" parking_lot = "0.12" -pgp = { version = "0.9", default-features = false } +pgp = { version = "0.10", default-features = false } pretty_env_logger = { version = "0.4", optional = true } qrcodegen = "1.7.0" -quick-xml = "0.27" +quick-xml = "0.28" rand = "0.8" regex = "1.7" -reqwest = { version = "0.11.14", features = ["json"] } -rusqlite = { version = "0.28", features = ["sqlcipher"] } +reqwest = { version = "0.11.16", features = ["json"] } +rusqlite = { version = "0.29", features = ["sqlcipher"] } rust-hsluv = "0.1" sanitize-filename = "0.4" serde_json = "1.0" @@ -85,10 +83,11 @@ strum_macros = "0.24" tagger = "4.3.4" textwrap = "0.16.0" thiserror = "1" +tokio = { version = "1", features = ["fs", "rt-multi-thread", "macros"] } tokio-io-timeout = "1.2.0" tokio-stream = { version = "0.1.11", features = ["fs"] } tokio-tar = { version = "0.3" } # TODO: integrate tokio into async-tar -tokio = { version = "1", features = ["fs", "rt-multi-thread", "macros"] } +tokio-util = "0.7.7" toml = "0.7" trust-dns-resolver = "0.22" url = "2" @@ -102,7 +101,7 @@ log = "0.4" pretty_env_logger = "0.4" proptest = { version = "1", default-features = false, features = ["std"] } tempfile = "3" -testdir = "0.7.2" +testdir = "0.7.3" tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "macros"] } [workspace] diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 24c402c28..bdac367da 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.112.1" +version = "1.112.5" description = "Deltachat FFI" edition = "2018" readme = "README.md" diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 8cb694c4f..3203d865d 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -2775,6 +2775,12 @@ void dc_backup_provider_wait (dc_backup_provider_t* backup_provider); /** * Frees a dc_backup_provider_t object. * + * If the provider has not yet finished, as indicated by + * dc_backup_provider_wait() or the #DC_EVENT_IMEX_PROGRESS event with value + * of 0 (failed) or 1000 (succeeded), this will also abort any in-progress + * transfer. If this aborts the provider a #DC_EVENT_IMEX_PROGRESS event with + * value 0 (failed) will be emitted. + * * @memberof dc_backup_provider_t * @param backup_provider The backup provider object as created by * dc_backup_provider_new(). diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 968616a5d..7daa9d195 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -160,7 +160,8 @@ pub unsafe extern "C" fn dc_context_open( let ctx = &*context; let passphrase = to_string_lossy(passphrase); block_on(ctx.open(passphrase)) - .log_err(ctx, "dc_context_open() failed") + .context("dc_context_open() failed") + .log_err(ctx) .map(|b| b as libc::c_int) .unwrap_or(0) } @@ -216,16 +217,18 @@ pub unsafe extern "C" fn dc_set_config( if key.starts_with("ui.") { ctx.set_ui_config(&key, value.as_deref()) .await - .with_context(|| format!("Can't set {key} to {value:?}")) - .log_err(ctx, "dc_set_config() failed") + .with_context(|| format!("dc_set_config failed: Can't set {key} to {value:?}")) + .log_err(ctx) .is_ok() as libc::c_int } else { match config::Config::from_str(&key) { Ok(key) => ctx .set_config(key, value.as_deref()) .await - .with_context(|| format!("Can't set {key} to {value:?}")) - .log_err(ctx, "dc_set_config() failed") + .with_context(|| { + format!("dc_set_config() failed: Can't set {key} to {value:?}") + }) + .log_err(ctx) .is_ok() as libc::c_int, Err(_) => { warn!(ctx, "dc_set_config(): invalid key"); @@ -253,7 +256,8 @@ pub unsafe extern "C" fn dc_get_config( if key.starts_with("ui.") { ctx.get_ui_config(&key) .await - .log_err(ctx, "Can't get ui-config") + .context("Can't get ui-config") + .log_err(ctx) .unwrap_or_default() .unwrap_or_default() .strdup() @@ -262,7 +266,8 @@ pub unsafe extern "C" fn dc_get_config( Ok(key) => ctx .get_config(key) .await - .log_err(ctx, "Can't get config") + .context("Can't get config") + .log_err(ctx) .unwrap_or_default() .unwrap_or_default() .strdup(), @@ -414,7 +419,8 @@ pub unsafe extern "C" fn dc_get_oauth2_url( block_on(async move { match oauth2::get_oauth2_url(ctx, &addr, &redirect) .await - .log_err(ctx, "dc_get_oauth2_url failed") + .context("dc_get_oauth2_url failed") + .log_err(ctx) { Ok(Some(res)) => res.strdup(), Ok(None) | Err(_) => ptr::null_mut(), @@ -423,7 +429,12 @@ 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") }); + spawn(async move { + ctx.configure() + .await + .context("Configure failed") + .log_err(&ctx) + }); } #[no_mangle] @@ -448,7 +459,8 @@ pub unsafe extern "C" fn dc_is_configured(context: *mut dc_context_t) -> libc::c block_on(async move { ctx.is_configured() .await - .log_err(ctx, "failed to get configured state") + .context("failed to get configured state") + .log_err(ctx) .unwrap_or_default() as libc::c_int }) } @@ -790,7 +802,8 @@ pub unsafe extern "C" fn dc_preconfigure_keypair( key::store_self_keypair(ctx, &keypair, key::KeyPairUse::Default).await?; Ok::<_, anyhow::Error>(1) }) - .log_err(ctx, "Failed to save keypair") + .context("Failed to save keypair") + .log_err(ctx) .unwrap_or(0) } @@ -817,7 +830,8 @@ pub unsafe extern "C" fn dc_get_chatlist( block_on(async move { match chatlist::Chatlist::try_load(ctx, flags as usize, qs.as_deref(), qi) .await - .log_err(ctx, "Failed to get chatlist") + .context("Failed to get chatlist") + .log_err(ctx) { Ok(list) => { let ffi_list = ChatlistWrapper { context, list }; @@ -842,7 +856,8 @@ pub unsafe extern "C" fn dc_create_chat_by_contact_id( block_on(async move { ChatId::create_for_contact(ctx, ContactId::new(contact_id)) .await - .log_err(ctx, "Failed to create chat from contact_id") + .context("Failed to create chat from contact_id") + .log_err(ctx) .map(|id| id.to_u32()) .unwrap_or(0) }) @@ -862,7 +877,8 @@ pub unsafe extern "C" fn dc_get_chat_id_by_contact_id( block_on(async move { ChatId::lookup_by_contact(ctx, ContactId::new(contact_id)) .await - .log_err(ctx, "Failed to get chat for contact_id") + .context("Failed to get chat for contact_id") + .log_err(ctx) .unwrap_or_default() // unwraps the Result .map(|id| id.to_u32()) .unwrap_or(0) // unwraps the Option @@ -1004,7 +1020,8 @@ pub unsafe extern "C" fn dc_get_msg_reactions( let ctx = &*context; let reactions = if let Ok(reactions) = block_on(get_msg_reactions(ctx, MsgId::new(msg_id))) - .log_err(ctx, "failed dc_get_msg_reactions() call") + .context("failed dc_get_msg_reactions() call") + .log_err(ctx) { reactions } else { @@ -1032,7 +1049,8 @@ pub unsafe extern "C" fn dc_send_webxdc_status_update( &to_string_lossy(json), &to_string_lossy(descr), )) - .log_err(ctx, "Failed to send webxdc update") + .context("Failed to send webxdc update") + .log_err(ctx) .is_ok() as libc::c_int } @@ -1251,7 +1269,8 @@ pub unsafe extern "C" fn dc_get_fresh_msgs( let arr = dc_array_t::from( ctx.get_fresh_msgs() .await - .log_err(ctx, "Failed to get fresh messages") + .context("Failed to get fresh messages") + .log_err(ctx) .unwrap_or_default() .iter() .map(|msg_id| msg_id.to_u32()) @@ -1272,7 +1291,8 @@ pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id block_on(async move { chat::marknoticed_chat(ctx, ChatId::new(chat_id)) .await - .log_err(ctx, "Failed marknoticed chat") + .context("Failed marknoticed chat") + .log_err(ctx) .unwrap_or(()) }) } @@ -1414,7 +1434,8 @@ pub unsafe extern "C" fn dc_set_chat_visibility( ChatId::new(chat_id) .set_visibility(ctx, visibility) .await - .log_err(ctx, "Failed setting chat visibility") + .context("Failed setting chat visibility") + .log_err(ctx) .unwrap_or(()) }) } @@ -1431,7 +1452,9 @@ pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32 ChatId::new(chat_id) .delete(ctx) .await - .ok_or_log_msg(ctx, "Failed chat delete"); + .context("Failed chat delete") + .log_err(ctx) + .ok(); }) } @@ -1447,7 +1470,9 @@ pub unsafe extern "C" fn dc_block_chat(context: *mut dc_context_t, chat_id: u32) ChatId::new(chat_id) .block(ctx) .await - .ok_or_log_msg(ctx, "Failed chat block"); + .context("Failed chat block") + .log_err(ctx) + .ok(); }) } @@ -1463,7 +1488,9 @@ pub unsafe extern "C" fn dc_accept_chat(context: *mut dc_context_t, chat_id: u32 ChatId::new(chat_id) .accept(ctx) .await - .ok_or_log_msg(ctx, "Failed chat accept"); + .context("Failed chat accept") + .log_err(ctx) + .ok(); }) } @@ -1561,7 +1588,8 @@ pub unsafe extern "C" fn dc_create_group_chat( block_on(async move { chat::create_group_chat(ctx, protect, &to_string_lossy(name)) .await - .log_err(ctx, "Failed to create group chat") + .context("Failed to create group chat") + .log_err(ctx) .map(|id| id.to_u32()) .unwrap_or(0) }) @@ -1575,7 +1603,8 @@ pub unsafe extern "C" fn dc_create_broadcast_list(context: *mut dc_context_t) -> } let ctx = &*context; block_on(chat::create_broadcast_list(ctx)) - .log_err(ctx, "Failed to create broadcast list") + .context("Failed to create broadcast list") + .log_err(ctx) .map(|id| id.to_u32()) .unwrap_or(0) } @@ -1597,7 +1626,8 @@ pub unsafe extern "C" fn dc_is_contact_in_chat( ChatId::new(chat_id), ContactId::new(contact_id), )) - .log_err(ctx, "is_contact_in_chat failed") + .context("is_contact_in_chat failed") + .log_err(ctx) .unwrap_or_default() as libc::c_int } @@ -1618,7 +1648,8 @@ pub unsafe extern "C" fn dc_add_contact_to_chat( ChatId::new(chat_id), ContactId::new(contact_id), )) - .log_err(ctx, "Failed to add contact") + .context("Failed to add contact") + .log_err(ctx) .is_ok() as libc::c_int } @@ -1639,7 +1670,8 @@ pub unsafe extern "C" fn dc_remove_contact_from_chat( ChatId::new(chat_id), ContactId::new(contact_id), )) - .log_err(ctx, "Failed to remove contact") + .context("Failed to remove contact") + .log_err(ctx) .is_ok() as libc::c_int } @@ -1758,7 +1790,8 @@ pub unsafe extern "C" fn dc_get_chat_ephemeral_timer( // ignored when ephemeral timer value is used to construct // message headers. block_on(async move { ChatId::new(chat_id).get_ephemeral_timer(ctx).await }) - .log_err(ctx, "Failed to get ephemeral timer") + .context("Failed to get ephemeral timer") + .log_err(ctx) .unwrap_or_default() .to_u32() } @@ -1779,7 +1812,8 @@ pub unsafe extern "C" fn dc_set_chat_ephemeral_timer( ChatId::new(chat_id) .set_ephemeral_timer(ctx, EphemeralTimer::from_u32(timer)) .await - .log_err(ctx, "Failed to set ephemeral timer") + .context("Failed to set ephemeral timer") + .log_err(ctx) .is_ok() as libc::c_int }) } @@ -1855,7 +1889,8 @@ pub unsafe extern "C" fn dc_delete_msgs( let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt); block_on(message::delete_msgs(ctx, &msg_ids)) - .log_err(ctx, "failed dc_delete_msgs() call") + .context("failed dc_delete_msgs() call") + .log_err(ctx) .ok(); } @@ -1919,7 +1954,8 @@ pub unsafe extern "C" fn dc_markseen_msgs( let ctx = &*context; block_on(message::markseen_msgs(ctx, msg_ids)) - .log_err(ctx, "failed dc_markseen_msgs() call") + .context("failed dc_markseen_msgs() call") + .log_err(ctx) .ok(); } @@ -1961,7 +1997,8 @@ pub unsafe extern "C" fn dc_download_full_msg(context: *mut dc_context_t, msg_id } let ctx = &*context; block_on(MsgId::new(msg_id).download_full(ctx)) - .log_err(ctx, "Failed to download message fully.") + .context("Failed to download message fully.") + .log_err(ctx) .ok(); } @@ -2009,7 +2046,8 @@ pub unsafe extern "C" fn dc_create_contact( let name = to_string_lossy(name); block_on(Contact::create(ctx, &name, &to_string_lossy(addr))) - .log_err(ctx, "Cannot create contact") + .context("Cannot create contact") + .log_err(ctx) .map(|id| id.to_u32()) .unwrap_or(0) } @@ -2086,7 +2124,8 @@ pub unsafe extern "C" fn dc_get_blocked_contacts( Box::into_raw(Box::new(dc_array_t::from( Contact::get_all_blocked(ctx) .await - .log_err(ctx, "Can't get blocked contacts") + .context("Can't get blocked contacts") + .log_err(ctx) .unwrap_or_default() .iter() .map(|id| id.to_u32()) @@ -2111,11 +2150,15 @@ pub unsafe extern "C" fn dc_block_contact( if block == 0 { Contact::unblock(ctx, contact_id) .await - .ok_or_log_msg(ctx, "Can't unblock contact"); + .context("Can't unblock contact") + .log_err(ctx) + .ok(); } else { Contact::block(ctx, contact_id) .await - .ok_or_log_msg(ctx, "Can't block contact"); + .context("Can't block contact") + .log_err(ctx) + .ok(); } }); } @@ -2188,7 +2231,8 @@ fn spawn_imex(ctx: Context, what: imex::ImexMode, param1: String, passphrase: Op spawn(async move { imex::imex(&ctx, what, param1.as_ref(), passphrase) .await - .log_err(&ctx, "IMEX failed") + .context("IMEX failed") + .log_err(&ctx) }); } @@ -2374,7 +2418,8 @@ pub unsafe extern "C" fn dc_join_securejoin( securejoin::join_securejoin(ctx, &to_string_lossy(qr)) .await .map(|chatid| chatid.to_u32()) - .log_err(ctx, "failed dc_join_securejoin() call") + .context("failed dc_join_securejoin() call") + .log_err(ctx) .unwrap_or_default() }) } @@ -2396,7 +2441,8 @@ pub unsafe extern "C" fn dc_send_locations_to_chat( ChatId::new(chat_id), seconds as i64, )) - .log_err(ctx, "Failed dc_send_locations_to_chat()") + .context("Failed dc_send_locations_to_chat()") + .log_err(ctx) .ok(); } @@ -2479,7 +2525,8 @@ pub unsafe extern "C" fn dc_delete_all_locations(context: *mut dc_context_t) { block_on(async move { location::delete_all(ctx) .await - .log_err(ctx, "Failed to delete locations") + .context("Failed to delete locations") + .log_err(ctx) .ok() }); } @@ -2763,7 +2810,8 @@ pub unsafe extern "C" fn dc_chatlist_get_summary( .list .get_summary(ctx, index, maybe_chat) .await - .log_err(ctx, "get_summary failed") + .context("get_summary failed") + .log_err(ctx) .unwrap_or_default(); Box::into_raw(Box::new(summary.into())) }) @@ -2791,7 +2839,8 @@ pub unsafe extern "C" fn dc_chatlist_get_summary2( msg_id, None, )) - .log_err(ctx, "get_summary2 failed") + .context("get_summary2 failed") + .log_err(ctx) .unwrap_or_default(); Box::into_raw(Box::new(summary.into())) } @@ -2974,7 +3023,8 @@ pub unsafe extern "C" fn dc_chat_can_send(chat: *mut dc_chat_t) -> libc::c_int { let ffi_chat = &*chat; let ctx = &*ffi_chat.context; block_on(ffi_chat.chat.can_send(ctx)) - .log_err(ctx, "can_send failed") + .context("can_send failed") + .log_err(ctx) .unwrap_or_default() as libc::c_int } @@ -3419,7 +3469,8 @@ pub unsafe extern "C" fn dc_msg_get_summary( let ctx = &*ffi_msg.context; let summary = block_on(ffi_msg.message.get_summary(ctx, maybe_chat)) - .log_err(ctx, "dc_msg_get_summary failed") + .context("dc_msg_get_summary failed") + .log_err(ctx) .unwrap_or_default(); Box::into_raw(Box::new(summary.into())) } @@ -3437,7 +3488,8 @@ pub unsafe extern "C" fn dc_msg_get_summarytext( let ctx = &*ffi_msg.context; let summary = block_on(ffi_msg.message.get_summary(ctx, None)) - .log_err(ctx, "dc_msg_get_summarytext failed") + .context("dc_msg_get_summarytext failed") + .log_err(ctx) .unwrap_or_default(); match usize::try_from(approx_characters) { Ok(chars) => summary.truncated_text(chars).strdup(), @@ -3704,7 +3756,9 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize( .message .latefiling_mediasize(ctx, width, height, duration) }) - .ok_or_log_msg(ctx, "Cannot set media size"); + .context("Cannot set media size") + .log_err(ctx) + .ok(); } #[no_mangle] @@ -3743,7 +3797,8 @@ pub unsafe extern "C" fn dc_msg_set_quote(msg: *mut dc_msg_t, quote: *const dc_m .message .set_quote(&*ffi_msg.context, quote_msg) .await - .log_err(&*ffi_msg.context, "failed to set quote") + .context("failed to set quote") + .log_err(&*ffi_msg.context) .ok(); }); } @@ -3774,7 +3829,8 @@ pub unsafe extern "C" fn dc_msg_get_quoted_msg(msg: *const dc_msg_t) -> *mut dc_ .message .quoted_message(context) .await - .log_err(context, "failed to get quoted message") + .context("failed to get quoted message") + .log_err(context) .unwrap_or(None) }); @@ -3797,7 +3853,8 @@ pub unsafe extern "C" fn dc_msg_get_parent(msg: *const dc_msg_t) -> *mut dc_msg_ .message .parent(context) .await - .log_err(context, "failed to get parent message") + .context("failed to get parent message") + .log_err(context) .unwrap_or(None) }); @@ -3988,7 +4045,8 @@ pub unsafe extern "C" fn dc_contact_is_verified(contact: *mut dc_contact_t) -> l let ctx = &*ffi_contact.context; block_on(ffi_contact.contact.is_verified(ctx)) - .log_err(ctx, "is_verified failed") + .context("is_verified failed") + .log_err(ctx) .unwrap_or_default() as libc::c_int } @@ -4003,7 +4061,8 @@ pub unsafe extern "C" fn dc_contact_get_verifier_addr( let ffi_contact = &*contact; let ctx = &*ffi_contact.context; block_on(ffi_contact.contact.get_verifier_addr(ctx)) - .log_err(ctx, "failed to get verifier for contact") + .context("failed to get verifier for contact") + .log_err(ctx) .unwrap_or_default() .strdup() } @@ -4017,7 +4076,8 @@ pub unsafe extern "C" fn dc_contact_get_verifier_id(contact: *mut dc_contact_t) let ffi_contact = &*contact; let ctx = &*ffi_contact.context; let verifier_contact_id = block_on(ffi_contact.contact.get_verifier_id(ctx)) - .log_err(ctx, "failed to get verifier") + .context("failed to get verifier") + .log_err(ctx) .unwrap_or_default() .unwrap_or_default(); @@ -4169,8 +4229,8 @@ pub unsafe extern "C" fn dc_backup_provider_new( provider, }) .map(|ffi_provider| Box::into_raw(Box::new(ffi_provider))) - .log_err(ctx, "BackupProvider failed") .context("BackupProvider failed") + .log_err(ctx) .set_last_error(ctx) .unwrap_or(ptr::null_mut()) } @@ -4186,8 +4246,8 @@ pub unsafe extern "C" fn dc_backup_provider_get_qr( let ffi_provider = &*provider; let ctx = &*ffi_provider.context; deltachat::qr::format_backup(&ffi_provider.provider.qr()) - .log_err(ctx, "BackupProvider get_qr failed") .context("BackupProvider get_qr failed") + .log_err(ctx) .set_last_error(ctx) .unwrap_or_default() .strdup() @@ -4205,8 +4265,8 @@ pub unsafe extern "C" fn dc_backup_provider_get_qr_svg( let ctx = &*ffi_provider.context; let provider = &ffi_provider.provider; block_on(generate_backup_qr(ctx, &provider.qr())) - .log_err(ctx, "BackupProvider get_qr_svg failed") .context("BackupProvider get_qr_svg failed") + .log_err(ctx) .set_last_error(ctx) .unwrap_or_default() .strdup() @@ -4222,8 +4282,8 @@ pub unsafe extern "C" fn dc_backup_provider_wait(provider: *mut dc_backup_provid let ctx = &*ffi_provider.context; let provider = &mut ffi_provider.provider; block_on(provider) - .log_err(ctx, "Failed to await BackupProvider") .context("Failed to await BackupProvider") + .log_err(ctx) .set_last_error(ctx) .ok(); } @@ -4255,16 +4315,16 @@ pub unsafe extern "C" fn dc_receive_backup( // user from deallocating it by calling unref on the object while we are using it. fn receive_backup(ctx: Context, qr_text: String) -> libc::c_int { let qr = match block_on(qr::check_qr(&ctx, &qr_text)) - .log_err(&ctx, "Invalid QR code") .context("Invalid QR code") + .log_err(&ctx) .set_last_error(&ctx) { Ok(qr) => qr, Err(_) => return 0, }; match block_on(imex::get_backup(&ctx, qr)) - .log_err(&ctx, "Get backup failed") .context("Get backup failed") + .log_err(&ctx) .set_last_error(&ctx) { Ok(_) => 1, @@ -4316,8 +4376,8 @@ where /// /// ```no_compile /// some_dc_rust_api_call_returning_result() - /// .log_err(&context, "My API call failed") /// .context("My API call failed") + /// .log_err(&context) /// .set_last_error(&context) /// .unwrap_or_default() /// ``` @@ -4404,7 +4464,8 @@ pub unsafe extern "C" fn dc_provider_new_from_email_with_dns( let socks5_enabled = block_on(async move { ctx.get_config_bool(config::Config::Socks5Enabled) .await - .log_err(ctx, "Can't get config") + .context("Can't get config") + .log_err(ctx) }); match socks5_enabled { diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 6ffd5f7a7..82b29c3bc 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.112.1" +version = "1.112.5" description = "DeltaChat JSON-RPC API" edition = "2021" default-run = "deltachat-jsonrpc-server" @@ -19,21 +19,21 @@ serde = { version = "1.0", features = ["derive"] } tempfile = "3.3.0" log = "0.4" async-channel = { version = "1.8.0" } -futures = { version = "0.3.26" } -serde_json = "1.0.91" +futures = { version = "0.3.28" } +serde_json = "1.0.95" yerpc = { version = "0.4.3", features = ["anyhow_expose"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } -tokio = { version = "1.25.0" } +tokio = { version = "1.27.0" } sanitize-filename = "0.4" -walkdir = "2.3.2" +walkdir = "2.3.3" base64 = "0.21" # optional dependencies -axum = { version = "0.6.11", optional = true, features = ["ws"] } +axum = { version = "0.6.12", optional = true, features = ["ws"] } env_logger = { version = "0.10.0", optional = true } [dev-dependencies] -tokio = { version = "1.25.0", features = ["full", "rt-multi-thread"] } +tokio = { version = "1.27.0", features = ["full", "rt-multi-thread"] } [features] diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 3ed2605e9..e821a5b68 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1082,17 +1082,17 @@ impl CommandApi { } /// Search messages containing the given query string. - /// Searching can be done globally (chat_id=0) or in a specified chat only (chat_id set). + /// Searching can be done globally (chat_id=None) or in a specified chat only (chat_id set). /// - /// Global chat results are typically displayed using dc_msg_get_summary(), chat - /// search results may just hilite the corresponding messages and present a + /// Global search results are typically displayed using dc_msg_get_summary(), chat + /// search results may just highlight the corresponding messages and present a /// prev/next button. /// - /// For global search, result is limited to 1000 messages, - /// this allows incremental search done fast. - /// So, when getting exactly 1000 results, the result may be truncated; - /// the UIs may display sth. as "1000+ messages found" in this case. - /// Chat search (if a chat_id is set) is not limited. + /// For the global search, the result is limited to 1000 messages, + /// this allows an incremental search done fast. + /// So, when getting exactly 1000 messages, the result actually may be truncated; + /// the UIs may display sth. like "1000+ messages found" in this case. + /// The chat search (if chat_id is set) is not limited. async fn search_messages( &self, account_id: u32, diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index 94e1804a9..5121a87e2 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.1" + "version": "1.112.5" } diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index 5a91bdb74..0fcf6347f 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-repl" -version = "1.112.1" +version = "1.112.5" license = "MPL-2.0" edition = "2021" @@ -8,10 +8,10 @@ edition = "2021" ansi_term = "0.12.1" anyhow = "1" deltachat = { path = "..", features = ["internals"]} -dirs = "4" +dirs = "5" log = "0.4.16" pretty_env_logger = "0.4" -rusqlite = "0.28" +rusqlite = "0.29" rustyline = "11" tokio = { version = "1", features = ["fs", "rt-multi-thread", "macros"] } diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index 9fdc8e91e..dc4f75e12 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -563,7 +563,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu context.maybe_network().await; } "housekeeping" => { - sql::housekeeping(&context).await.ok_or_log(&context); + sql::housekeeping(&context).await.log_err(&context).ok(); } "listchats" | "listarchived" | "chats" => { let listflags = if arg0 == "listarchived" { diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 2f1c988ee..9a9353432 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.1" +version = "1.112.5" description = "DeltaChat JSON-RPC server" edition = "2021" readme = "README.md" @@ -17,9 +17,9 @@ anyhow = "1" env_logger = { version = "0.10.0" } futures-lite = "1.12.0" log = "0.4" -serde_json = "1.0.91" +serde_json = "1.0.95" serde = { version = "1.0", features = ["derive"] } -tokio = { version = "1.25.0", features = ["io-std"] } +tokio = { version = "1.27.0", features = ["io-std"] } yerpc = { version = "0.4.0", features = ["anyhow_expose"] } [features] diff --git a/deltachat_derive/Cargo.toml b/deltachat_derive/Cargo.toml index 094796cda..2ea978c5d 100644 --- a/deltachat_derive/Cargo.toml +++ b/deltachat_derive/Cargo.toml @@ -8,5 +8,5 @@ license = "MPL-2.0" proc-macro = true [dependencies] -syn = "1" +syn = "2" quote = "1" diff --git a/deny.toml b/deny.toml index 803162146..e2f70f17d 100644 --- a/deny.toml +++ b/deny.toml @@ -11,42 +11,50 @@ ignore = [ # Accept some duplicate versions, ideally we work towards this list # becoming empty. Adding versions forces us to revisit this at least # when upgrading. +# Please keep this list alphabetically sorted. skip = [ + { name = "base16ct", version = "0.1.1" }, { name = "base64", version = "<0.21" }, + { name = "bitflags", version = "1.3.2" }, { name = "block-buffer", version = "<0.10" }, - { name = "darling", version = "<0.14" }, + { name = "clap_lex", version = "0.2.4" }, + { name = "clap", version = "3.2.23" }, + { name = "convert_case", version = "0.4.0" }, + { name = "curve25519-dalek", version = "3.2.0" }, { name = "darling_core", version = "<0.14" }, { name = "darling_macro", version = "<0.14" }, + { name = "darling", version = "<0.14" }, + { name = "der", version = "0.6.1" }, { name = "digest", version = "<0.10" }, + { name = "ed25519-dalek", version = "1.0.1" }, + { name = "ed25519", version = "1.5.3" }, { name = "env_logger", version = "<0.10" }, { name = "getrandom", version = "<0.2" }, { name = "hermit-abi", version = "<0.3" }, { name = "humantime", version = "<2.1" }, { name = "idna", version = "<0.3" }, - { name = "nom", version = "<7.1" }, + { name = "libm", version = "0.1.4" }, + { name = "pem-rfc7468", version = "0.6.0" }, + { name = "pkcs8", version = "0.9.0" }, { name = "quick-error", version = "<2.0" }, - { name = "rand", version = "<0.8" }, { name = "rand_chacha", version = "<0.3" }, { name = "rand_core", version = "<0.6" }, + { name = "rand", version = "<0.8" }, + { name = "redox_syscall", version = "0.2.16" }, + { name = "sec1", version = "0.3.0" }, { name = "sha2", version = "<0.10" }, - { name = "time", version = "<0.3" }, - { name = "version_check", version = "<0.9" }, - { name = "wasi", version = "<0.11" }, - { name = "windows-sys", version = "<0.45" }, - { name = "windows_x86_64_msvc", version = "<0.42" }, - { name = "windows_x86_64_gnu", version = "<0.42" }, - { name = "windows_i686_msvc", version = "<0.42" }, - { name = "windows_i686_gnu", version = "<0.42" }, - { name = "windows_aarch64_msvc", version = "<0.42" }, - { name = "unicode-xid", version = "<0.2.4" }, - { name = "syn", version = "<1.0" }, - { name = "quote", version = "<1.0" }, - { name = "proc-macro2", version = "<1.0" }, - { name = "portable-atomic", version = "<1.0" }, + { name = "signature", version = "1.6.4" }, { name = "spin", version = "<0.9.6" }, - { name = "convert_case", version = "0.4.0" }, - { name = "clap_lex", version = "0.2.4" }, - { name = "clap", version = "3.2.23" }, + { name = "spki", version = "0.6.0" }, + { name = "syn", version = "1.0.109" }, + { name = "time", version = "<0.3" }, + { name = "wasi", version = "<0.11" }, + { name = "windows_aarch64_msvc", version = "<0.42" }, + { name = "windows_i686_gnu", version = "<0.42" }, + { name = "windows_i686_msvc", version = "<0.42" }, + { name = "windows-sys", version = "<0.45" }, + { name = "windows_x86_64_gnu", version = "<0.42" }, + { name = "windows_x86_64_msvc", version = "<0.42" }, ] @@ -78,7 +86,5 @@ license-files = [ github = [ "async-email", "deltachat", - "n0-computer", "quinn-rs", - "dignifiedquire", ] diff --git a/package.json b/package.json index 41c9e07e1..a06a0c3f5 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.1" -} \ No newline at end of file + "version": "1.112.5" +} diff --git a/python/README.rst b/python/README.rst index af74606d4..c2b4d87e2 100644 --- a/python/README.rst +++ b/python/README.rst @@ -12,17 +12,17 @@ a low-level Chat/Contact/Message API to user interfaces and bots. Installing pre-built packages (Linux-only) ========================================== -If you have a Linux system you may try to install the ``deltachat`` binary "wheel" packages +If you have a Linux system you may install the ``deltachat`` binary "wheel" packages without any "build-from-source" steps. Otherwise you need to `compile the Delta Chat bindings yourself`__. __ sourceinstall_ -We recommend to first `install virtualenv `_, -then create a fresh Python virtual environment and activate it in your shell:: +We recommend to first create a fresh Python virtual environment +and activate it in your shell:: - virtualenv env # or: python -m venv - source env/bin/activate + python -m venv env + source env/bin/activate Afterwards, invoking ``python`` or ``pip install`` only modifies files in your ``env`` directory and leaves @@ -40,16 +40,14 @@ To verify it worked:: Running tests ============= -Recommended way to run tests is using `tox `_. -After successful binding installation you can install tox -and run the tests:: +Recommended way to run tests is using `scripts/run-python-test.sh` +script provided in the core repository. - pip install tox - tox -e py3 - -This will run all "offline" tests and skip all functional +This script compiles the library in debug mode and runs the tests using `tox`_. +By default it will run all "offline" tests and skip all functional end-to-end tests that require accounts on real e-mail servers. +.. _`tox`: https://tox.wiki .. _livetests: Running "live" tests with temporary accounts @@ -61,13 +59,32 @@ Please feel free to contact us through a github issue or by e-mail and we'll sen export DCC_NEW_TMP_EMAIL= -With this account-creation setting, pytest runs create ephemeral e-mail accounts on the http://testrun.org server. These accounts exists only for one hour and then are removed completely. -One hour is enough to invoke pytest and run all offline and online tests:: +With this account-creation setting, pytest runs create ephemeral e-mail accounts on the http://testrun.org server. +These accounts are removed automatically as they expire. +After setting the variable, either rerun `scripts/run-python-test.sh` +or run offline and online tests with `tox` directly:: - tox -e py3 + tox -e py Each test run creates new accounts. +Developing the bindings +----------------------- + +If you want to develop or debug the bindings, +you can create a testing development environment using `tox`:: + + tox -c python --devenv env + . env/bin/activate + +Inside this environment the bindings are installed +in editable mode (as if installed with `python -m pip install -e`) +together with the testing dependencies like `pytest` and its plugins. + +You can then edit the source code in the development tree +and quickly run `pytest` manually without waiting for `tox` +to recreating the virtual environment each time. + .. _sourceinstall: Installing bindings from source @@ -89,20 +106,34 @@ To install the Delta Chat Python bindings make sure you have Python3 installed. E.g. on Debian-based systems `apt install python3 python3-pip python3-venv` should give you a usable python installation. -Ensure you are in the deltachat-core-rust/python directory, create the -virtual environment with dependencies using tox -and activate it in your shell:: +First, build the core library:: - cd python - tox --devenv env + cargo build --release -p deltachat_ffi --features jsonrpc + +`jsonrpc` feature is required even if not used by the bindings +because `deltachat.h` includes JSON-RPC functions unconditionally. + +Create the virtual environment and activate it: + + python -m venv env source env/bin/activate -You should now be able to build the python bindings using the supplied script:: +Build and install the bindings: - python3 install_python_bindings.py + export DCC_RS_DEV="$PWD" + export DCC_RS_TARGET=release + python -m pip install python -The core compilation and bindings building might take a while, -depending on the speed of your machine. +`DCC_RS_DEV` environment variable specifies the location of +the core development tree. If this variable is not set, +`libdeltachat` library and `deltachat.h` header are expected +to be installed system-wide. + +When `DCC_RS_DEV` is set, `DCC_RS_TARGET` specifies +the build profile name to look up the artifacts +in the target directory. +In this case setting it can be skipped because +`DCC_RS_TARGET=release` is the default. Building manylinux based wheels =============================== diff --git a/python/examples/test_examples.py b/python/examples/test_examples.py index e6b2d53f4..6e4f6ef25 100644 --- a/python/examples/test_examples.py +++ b/python/examples/test_examples.py @@ -24,6 +24,8 @@ def test_echo_quit_plugin(acfactory, lp): lp.sec("creating a temp account to contact the bot") (ac1,) = acfactory.get_online_accounts(1) + botproc.await_resync() + lp.sec("sending a message to the bot") bot_contact = ac1.create_contact(botproc.addr) bot_chat = bot_contact.create_chat() @@ -40,7 +42,7 @@ def test_echo_quit_plugin(acfactory, lp): def test_group_tracking_plugin(acfactory, lp): lp.sec("creating one group-tracking bot and two temp accounts") - botproc = acfactory.run_bot_process(group_tracking, ffi=False) + botproc = acfactory.run_bot_process(group_tracking) ac1, ac2 = acfactory.get_online_accounts(2) @@ -52,6 +54,8 @@ def test_group_tracking_plugin(acfactory, lp): ac1.add_account_plugin(FFIEventLogger(ac1)) ac2.add_account_plugin(FFIEventLogger(ac2)) + botproc.await_resync() + lp.sec("creating bot test group with bot") bot_contact = ac1.create_contact(botproc.addr) ch = ac1.create_group_chat("bot test group") diff --git a/python/install_python_bindings.py b/python/install_python_bindings.py deleted file mode 100755 index 6e216c893..000000000 --- a/python/install_python_bindings.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -""" - setup a python binding development in-place install with cargo debug symbols. -""" - -import os -import subprocess -import sys - -if __name__ == "__main__": - target = os.environ.get("DCC_RS_TARGET") - if target is None: - os.environ["DCC_RS_TARGET"] = target = "debug" - if "DCC_RS_DEV" not in os.environ: - dn = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - os.environ["DCC_RS_DEV"] = dn - - cmd = ["cargo", "build", "-p", "deltachat_ffi", "--features", "jsonrpc"] - - if target == "release": - os.environ["CARGO_PROFILE_RELEASE_LTO"] = "on" - cmd.append("--release") - - print("running:", " ".join(cmd)) - subprocess.check_call(cmd) - subprocess.check_call("rm -rf build/ src/deltachat/*.so src/deltachat/*.dylib src/deltachat/*.dll", shell=True) - - if len(sys.argv) <= 1 or sys.argv[1] != "onlybuild": - subprocess.check_call([sys.executable, "-m", "pip", "install", "-e", "."]) diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index fd6b06ac2..192afb508 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -676,6 +676,13 @@ class BotProcess: print("+++IGN:", line) ignored.append(line) + def await_resync(self): + self.fnmatch_lines( + """ + *Resync: collected * message IDs in folder INBOX* + """, + ) + @pytest.fixture() def tmp_db_path(tmpdir): diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index eb324f071..cfa5655a1 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -567,7 +567,8 @@ def test_moved_markseen(acfactory): with ac2.direct_imap.idle() as idle2: ac2.start_io() - msg = ac2._evtracker.wait_next_incoming_message() + ev = ac2._evtracker.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED") + msg = ac2.get_message_by_id(ev.data2) # Accept the contact request. msg.chat.accept() diff --git a/python/tox.ini b/python/tox.ini index 994f9c4c7..99fd0c703 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -43,7 +43,7 @@ deps = pygments restructuredtext_lint commands = - black --quiet --check --diff setup.py install_python_bindings.py src/deltachat examples/ tests/ + black --quiet --check --diff setup.py src/deltachat examples/ tests/ ruff src/deltachat tests/ examples/ rst-lint --encoding 'utf-8' README.rst diff --git a/scripts/run-python-test.sh b/scripts/run-python-test.sh index d14e833a1..93acd07cc 100755 --- a/scripts/run-python-test.sh +++ b/scripts/run-python-test.sh @@ -12,7 +12,7 @@ export DCC_RS_DEV=`pwd` cd python -python install_python_bindings.py onlybuild +cargo build -p deltachat_ffi --features jsonrpc # remove and inhibit writing PYC files rm -rf tests/__pycache__ @@ -22,4 +22,4 @@ 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,py3 +tox -e doc,py diff --git a/scripts/run_all.sh b/scripts/run_all.sh index fbceb77a3..87ce41ea3 100755 --- a/scripts/run_all.sh +++ b/scripts/run_all.sh @@ -33,7 +33,7 @@ unset DCC_NEW_TMP_EMAIL # E.g. musllinux_1_1 does not have PyPy interpreters as of 2022-07-10 tox --workdir "$TOXWORKDIR" -e py37,py38,py39,py310,py311,pypy37,pypy38,pypy39 --skip-missing-interpreters true -auditwheel repair "$TOXWORKDIR/wheelhouse/deltachat*" -w "$TOXWORKDIR/wheelhouse" +auditwheel repair "$TOXWORKDIR"/wheelhouse/deltachat* -w "$TOXWORKDIR/wheelhouse" echo ----------------------- diff --git a/scripts/set_core_version.py b/scripts/set_core_version.py index 7bc888d1b..63e3ec205 100755 --- a/scripts/set_core_version.py +++ b/scripts/set_core_version.py @@ -56,7 +56,8 @@ def update_package_json(relpath, newversion): json_data = json.loads(f.read()) json_data["version"] = newversion with open(p, "w") as f: - f.write(json.dumps(json_data, sort_keys=True, indent=2)) + json.dump(json_data, f, sort_keys=True, indent=2) + f.write("\n") def main(): diff --git a/src/blob.rs b/src/blob.rs index 93bfbb3c5..c7a3641d2 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -92,7 +92,7 @@ impl<'a> BlobObject<'a> { if attempt >= MAX_ATTEMPT { return Err(err).context("failed to create file"); } else if attempt == 1 && !dir.exists() { - fs::create_dir_all(dir).await.ok_or_log(context); + fs::create_dir_all(dir).await.log_err(context).ok(); } else { name = format!("{}-{}{}", stem, rand::random::(), ext); } diff --git a/src/chat.rs b/src/chat.rs index eaffb476f..8e505d32d 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -35,8 +35,9 @@ use crate::scheduler::InterruptInfo; use crate::smtp::send_msg_to_smtp; use crate::stock_str; use crate::tools::{ - create_id, create_outgoing_rfc724_mid, create_smeared_timestamp, create_smeared_timestamps, - get_abs_path, gm2local_offset, improve_single_line_input, time, IsNoneOrEmpty, + 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, }; use crate::webxdc::WEBXDC_SUFFIX; use crate::{location, sql}; @@ -1580,7 +1581,12 @@ impl Chat { } else { msg.param.get(Param::SendHtml).map(|s| s.to_string()) }; - html.map(|html| new_html_mimepart(html).build().as_string()) + match html { + Some(html) => Some(tokio::task::block_in_place(move || { + buf_compress(new_html_mimepart(html).build().as_string().as_bytes()) + })?), + None => None, + } } else { None }; @@ -1594,7 +1600,8 @@ impl Chat { SET rfc724_mid=?, chat_id=?, from_id=?, to_id=?, timestamp=?, type=?, state=?, txt=?, subject=?, param=?, hidden=?, mime_in_reply_to=?, mime_references=?, mime_modified=?, - mime_headers=?, location_id=?, ephemeral_timer=?, ephemeral_timestamp=? + mime_headers=?, mime_compressed=1, location_id=?, ephemeral_timer=?, + ephemeral_timestamp=? WHERE id=?;", paramsv![ new_rfc724_mid, @@ -1640,10 +1647,11 @@ impl Chat { mime_references, mime_modified, mime_headers, + mime_compressed, location_id, ephemeral_timer, ephemeral_timestamp) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,?,?,?);", paramsv![ new_rfc724_mid, self.id, @@ -2727,12 +2735,14 @@ pub async fn get_chat_media( "SELECT id FROM msgs WHERE (1=? OR chat_id=?) + AND chat_id != ? 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, msg_type, if msg_type2 != Viewtype::Unknown { msg_type2 @@ -3795,6 +3805,7 @@ mod tests { use crate::chatlist::{get_archived_cnt, Chatlist}; use crate::constants::{DC_GCL_ARCHIVED_ONLY, DC_GCL_NO_SPECIALS}; use crate::contact::{Contact, ContactAddress}; + use crate::message::delete_msgs; use crate::receive_imf::receive_imf; use crate::test_utils::TestContext; @@ -5977,7 +5988,7 @@ mod tests { include_bytes!("../test-data/image/avatar64x64.png"), ) .await?; - send_media( + let second_image_msg_id = send_media( &t, chat_id2, Viewtype::Image, @@ -6079,6 +6090,21 @@ mod tests { 4 ); + // Delete an image. + delete_msgs(&t, &[second_image_msg_id]).await?; + assert_eq!( + get_chat_media( + &t, + None, + Viewtype::Image, + Viewtype::Sticker, + Viewtype::Webxdc, + ) + .await? + .len(), + 3 + ); + Ok(()) } } diff --git a/src/configure.rs b/src/configure.rs index 504454b4a..bffdedc44 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -154,7 +154,9 @@ async fn on_configure_completed( Some(stock_str::aeap_explanation_and_link(context, &old_addr, &new_addr).await); chat::add_device_msg(context, None, Some(&mut msg)) .await - .ok_or_log_msg(context, "Cannot add AEAP explanation"); + .context("Cannot add AEAP explanation") + .log_err(context) + .ok(); } } } diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 75fb1c127..55bc6b76d 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -575,7 +575,8 @@ pub(crate) async fn ephemeral_loop(context: &Context, interrupt_receiver: Receiv delete_expired_messages(context, time()) .await - .ok_or_log(context); + .log_err(context) + .ok(); } } diff --git a/src/imap.rs b/src/imap.rs index 6e3437fc0..0e5b15492 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -14,7 +14,7 @@ use std::{ use anyhow::{bail, format_err, Context as _, Result}; use async_channel::Receiver; use async_imap::types::{Fetch, Flag, Name, NameAttribute, UnsolicitedResponse}; -use futures::StreamExt; +use futures::{StreamExt, TryStreamExt}; use num_traits::FromPrimitive; use crate::chat::{self, ChatId, ChatIdBlocked}; @@ -516,8 +516,7 @@ impl Imap { .uid_fetch("1:*", RFC724MID_UID) .await .with_context(|| format!("can't resync folder {folder}"))?; - while let Some(fetch) = list.next().await { - let fetch = fetch?; + while let Some(fetch) = list.try_next().await? { let headers = match get_fetch_headers(&fetch) { Ok(headers) => headers, Err(err) => { @@ -660,7 +659,7 @@ impl Imap { .context("Error fetching UID")?; let mut new_last_seen_uid = None; - while let Some(fetch) = list.next().await.transpose()? { + while let Some(fetch) = list.try_next().await? { if fetch.message == mailbox.exists && fetch.uid.is_some() { new_last_seen_uid = fetch.uid; } @@ -1198,8 +1197,11 @@ impl Imap { .await .context("failed to fetch flags")?; - while let Some(fetch) = list.next().await { - let fetch = fetch.context("failed to get FETCH result")?; + while let Some(fetch) = list + .try_next() + .await + .context("failed to get FETCH result")? + { let uid = if let Some(uid) = fetch.uid { uid } else { @@ -1258,8 +1260,7 @@ impl Imap { .await .context("IMAP Could not fetch")?; - while let Some(fetch) = list.next().await { - let msg = fetch?; + while let Some(msg) = list.try_next().await? { match get_fetch_headers(&msg) { Ok(headers) => { if let Some(from) = mimeparser::get_from(&headers) { @@ -1294,8 +1295,7 @@ impl Imap { .context("IMAP could not fetch")?; let mut msgs = BTreeMap::new(); - while let Some(fetch) = list.next().await { - let msg = fetch?; + while let Some(msg) = list.try_next().await? { if let Some(msg_uid) = msg.uid { // If the mailbox is not empty, results always include // at least one UID, even if last_seen_uid+1 is past @@ -1332,8 +1332,7 @@ impl Imap { .context("IMAP Could not fetch")?; let mut msgs = BTreeMap::new(); - while let Some(fetch) = list.next().await { - let msg = fetch?; + while let Some(msg) = list.try_next().await? { if let Some(msg_uid) = msg.uid { msgs.insert((msg.internal_date(), msg_uid), msg); } @@ -1680,8 +1679,7 @@ impl Imap { let mut delimiter_is_default = true; let mut folder_configs = BTreeMap::new(); - while let Some(folder) = folders.next().await { - let folder = folder?; + while let Some(folder) = folders.try_next().await? { info!(context, "Scanning folder: {:?}", folder); // Update the delimiter iff there is a different one, but only once. diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index 29051e7b9..8b63098b8 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -70,7 +70,9 @@ impl Imap { loop { self.fetch_move_delete(context, folder.name(), folder_meaning) .await - .ok_or_log_msg(context, "Can't fetch new msgs in scanned folder"); + .context("Can't fetch new msgs in scanned folder") + .log_err(context) + .ok(); let session = self.session.as_mut().context("no session")?; // If the server sent an unsocicited EXISTS during the fetch, we need to fetch again @@ -105,7 +107,11 @@ impl Imap { let list = session .list(Some(""), Some("*")) .await? - .filter_map(|f| async { f.ok_or_log_msg(context, "list_folders() can't get folder") }); + .filter_map(|f| async { + f.context("list_folders() can't get folder") + .log_err(context) + .ok() + }); Ok(list.collect().await) } } diff --git a/src/imex.rs b/src/imex.rs index 94f79b8f5..9a1d4cb06 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -91,7 +91,7 @@ pub async fn imex( let ongoing_guard = context.alloc_ongoing().await?; let res = { - let _guard = context.scheduler.pause(context.clone()).await; + let _guard = context.scheduler.pause(context.clone()).await?; imex_inner(context, what, path, passphrase) .race(async { ongoing_guard.await; @@ -396,8 +396,7 @@ async fn imex_inner( export_backup(context, path, passphrase.unwrap_or_default()).await } ImexMode::ImportBackup => { - import_backup(context, path, passphrase.unwrap_or_default()).await?; - context.sql.run_migrations(context).await + import_backup(context, path, passphrase.unwrap_or_default()).await } } } @@ -473,6 +472,7 @@ async fn import_backup( } } + context.sql.run_migrations(context).await?; delete_and_reset_all_device_msgs(context).await?; Ok(()) @@ -758,7 +758,7 @@ async fn export_database(context: &Context, dest: &Path, passphrase: String) -> .with_context(|| format!("path {} is not valid unicode", dest.display()))?; context.sql.set_raw_config_int("backup_time", now).await?; - sql::housekeeping(context).await.ok_or_log(context); + sql::housekeeping(context).await.log_err(context).ok(); context .sql .call_write(|conn| { diff --git a/src/imex/transfer.rs b/src/imex/transfer.rs index 2a93bf268..220bb0344 100644 --- a/src/imex/transfer.rs +++ b/src/imex/transfer.rs @@ -22,7 +22,6 @@ //! getter can not connect to an impersonated provider and the provider does not offer the //! download to an impersonated getter. -use std::cmp::Ordering; use std::future::Future; use std::net::Ipv4Addr; use std::ops::Deref; @@ -32,7 +31,8 @@ use std::task::Poll; use anyhow::{anyhow, bail, ensure, format_err, Context as _, Result}; use futures_lite::StreamExt; -use iroh::get::{DataStream, Options}; +use iroh::blobs::Collection; +use iroh::get::DataStream; use iroh::progress::ProgressEmitter; use iroh::protocol::AuthToken; use iroh::provider::{DataSource, Event, Provider, Ticket}; @@ -43,6 +43,7 @@ use tokio::sync::broadcast::error::RecvError; use tokio::sync::{broadcast, Mutex}; use tokio::task::{JoinHandle, JoinSet}; use tokio_stream::wrappers::ReadDirStream; +use tokio_util::sync::CancellationToken; use crate::blob::BlobDirContents; use crate::chat::delete_and_reset_all_device_msgs; @@ -52,6 +53,8 @@ use crate::{e2ee, EventType}; use super::{export_database, DBFILE_BACKUP_NAME}; +const MAX_CONCURRENT_DIALS: u8 = 16; + /// Provide or send a backup of this device. /// /// This creates a backup of the current device and starts a service which offers another @@ -71,6 +74,8 @@ pub struct BackupProvider { handle: JoinHandle>, /// The ticket to retrieve the backup collection. ticket: Ticket, + /// Guard to cancel the provider on drop. + _drop_guard: tokio_util::sync::DropGuard, } impl BackupProvider { @@ -115,10 +120,12 @@ impl BackupProvider { }, _ = &mut ongoing_guard => Err(format_err!("cancelled")), }?; + let drop_token = CancellationToken::new(); let handle = { let context = context.clone(); + let drop_token = drop_token.clone(); tokio::spawn(async move { - let res = Self::watch_provider(&context, provider, ongoing_guard).await; + let res = Self::watch_provider(&context, provider, ongoing_guard, drop_token).await; // Explicit drop to move the guards into this future drop(paused_guard); @@ -126,7 +133,11 @@ impl BackupProvider { res }) }; - Ok(Self { handle, ticket }) + Ok(Self { + handle, + ticket, + _drop_guard: drop_token.drop_guard(), + }) } /// Creates the provider task. @@ -162,7 +173,7 @@ impl BackupProvider { .spawn()?; context.emit_event(SendProgress::ProviderListening.into()); info!(context, "Waiting for remote to connect"); - let ticket = provider.ticket(hash); + let ticket = provider.ticket(hash)?; Ok((provider, ticket)) } @@ -180,6 +191,7 @@ impl BackupProvider { context: &Context, mut provider: Provider, mut cancel_token: OngoingGuard, + drop_token: CancellationToken, ) -> Result<()> { let mut events = provider.subscribe(); let mut total_size = 0; @@ -240,8 +252,12 @@ impl BackupProvider { }, _ = &mut cancel_token => { provider.shutdown(); - break Err(anyhow!("BackupSender cancelled")); + break Err(anyhow!("BackupProvider cancelled")); }, + _ = drop_token.cancelled() => { + provider.shutdown(); + break Err(anyhow!("BackupProvider dropped")); + } } }; match &res { @@ -361,7 +377,7 @@ pub async fn get_backup(context: &Context, qr: Qr) -> Result<()> { !context.is_configured().await?, "Cannot import backups to accounts in use." ); - let _guard = context.scheduler.pause(context.clone()).await; + let _guard = context.scheduler.pause(context.clone()).await?; // Acquire global "ongoing" mutex. let mut cancel_token = context.alloc_ongoing().await?; @@ -373,122 +389,72 @@ pub async fn get_backup(context: &Context, qr: Qr) -> Result<()> { } async fn get_backup_inner(context: &Context, qr: Qr) -> Result<()> { - let mut ticket = match qr { + let ticket = match qr { Qr::Backup { ticket } => ticket, _ => bail!("QR code for backup must be of type DCBACKUP"), }; - if ticket.addrs.is_empty() { - bail!("ticket is missing addresses to dial"); - } - // Crude sorting, most local wifi's are in the 192.168.0.0/24 range so this will try - // them first. - ticket.addrs.sort_by(|a, b| { - let a = a.to_string(); - let b = b.to_string(); - if a.starts_with("192.168.") && !b.starts_with("192.168.") { - Ordering::Less - } else if b.starts_with("192.168.") && !a.starts_with("192.168.") { - Ordering::Greater - } else { - Ordering::Equal + match transfer_from_provider(context, &ticket).await { + Ok(()) => { + context.sql.run_migrations(context).await?; + delete_and_reset_all_device_msgs(context).await?; + context.emit_event(ReceiveProgress::Completed.into()); + Ok(()) } - }); - for addr in &ticket.addrs { - let opts = Options { - addr: *addr, - peer_id: Some(ticket.peer), - keylog: false, - }; - info!(context, "attempting to contact {}", addr); - match transfer_from_provider(context, &ticket, opts).await { - Ok(_) => { - delete_and_reset_all_device_msgs(context).await?; - context.emit_event(ReceiveProgress::Completed.into()); - return Ok(()); - } - Err(TransferError::ConnectionError(err)) => { - warn!(context, "Connection error: {err:#}."); - continue; - } - Err(TransferError::Other(err)) => { - // Clean up any blobs we already wrote. - let readdir = fs::read_dir(context.get_blobdir()).await?; - let mut readdir = ReadDirStream::new(readdir); - while let Some(dirent) = readdir.next().await { - if let Ok(dirent) = dirent { - fs::remove_file(dirent.path()).await.ok(); - } + Err(err) => { + // Clean up any blobs we already wrote. + let readdir = fs::read_dir(context.get_blobdir()).await?; + let mut readdir = ReadDirStream::new(readdir); + while let Some(dirent) = readdir.next().await { + if let Ok(dirent) = dirent { + fs::remove_file(dirent.path()).await.ok(); } - context.emit_event(ReceiveProgress::Failed.into()); - return Err(err); } + context.emit_event(ReceiveProgress::Failed.into()); + Err(err) } } - Err(anyhow!("failed to contact provider")) } -/// Error during a single transfer attempt. -/// -/// Mostly exists to distinguish between `ConnectionError` and any other errors. -#[derive(Debug, thiserror::Error)] -enum TransferError { - #[error("connection error")] - ConnectionError(#[source] anyhow::Error), - #[error("other")] - Other(#[source] anyhow::Error), -} - -async fn transfer_from_provider( - context: &Context, - ticket: &Ticket, - opts: Options, -) -> Result<(), TransferError> { +async fn transfer_from_provider(context: &Context, ticket: &Ticket) -> Result<()> { let progress = ProgressEmitter::new(0, ReceiveProgress::max_blob_progress()); spawn_progress_proxy(context.clone(), progress.subscribe()); - let mut connected = false; let on_connected = || { context.emit_event(ReceiveProgress::Connected.into()); - connected = true; + async { Ok(()) } + }; + let on_collection = |collection: &Collection| { + context.emit_event(ReceiveProgress::CollectionReceived.into()); + progress.set_total(collection.total_blobs_size()); async { Ok(()) } }; let jobs = Mutex::new(JoinSet::default()); let on_blob = |hash, reader, name| on_blob(context, &progress, &jobs, ticket, hash, reader, name); - let res = iroh::get::run( - ticket.hash, - ticket.token, - opts, + + // Perform the transfer. + let keylog = false; // Do not enable rustls SSLKEYLOGFILE env var functionality + let stats = iroh::get::run_ticket( + ticket, + keylog, + MAX_CONCURRENT_DIALS, on_connected, - |collection| { - context.emit_event(ReceiveProgress::CollectionReceived.into()); - progress.set_total(collection.total_blobs_size()); - async { Ok(()) } - }, + on_collection, on_blob, ) - .await; + .await?; let mut jobs = jobs.lock().await; while let Some(job) = jobs.join_next().await { - job.context("job failed").map_err(TransferError::Other)?; + job.context("job failed")?; } - drop(progress); - match res { - Ok(stats) => { - info!( - context, - "Backup transfer finished, transfer rate is {} Mbps.", - stats.mbits() - ); - Ok(()) - } - Err(err) => match connected { - true => Err(TransferError::Other(err)), - false => Err(TransferError::ConnectionError(err)), - }, - } + info!( + context, + "Backup transfer finished, transfer rate was {} Mbps.", + stats.mbits() + ); + Ok(()) } /// Get callback when a blob is received from the provider. @@ -530,7 +496,7 @@ async fn on_blob( if name.starts_with("db/") { let context = context.clone(); - let token = ticket.token.to_string(); + let token = ticket.token().to_string(); jobs.lock().await.spawn(async move { if let Err(err) = context.sql.import(&path, token).await { error!(context, "cannot import database: {:#?}", err); @@ -692,4 +658,16 @@ mod tests { assert_eq!(out, EventType::ImexProgress(progress)); } } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_drop_provider() { + let mut tcm = TestContextManager::new(); + let ctx = tcm.alice().await; + + let provider = BackupProvider::prepare(&ctx).await.unwrap(); + drop(provider); + ctx.evtracker + .get_matching(|ev| matches!(ev, EventType::ImexProgress(0))) + .await; + } } diff --git a/src/location.rs b/src/location.rs index 375c40662..28864263d 100644 --- a/src/location.rs +++ b/src/location.rs @@ -5,7 +5,6 @@ use std::time::Duration; use anyhow::{ensure, Context as _, Result}; use async_channel::Receiver; -use bitflags::bitflags; use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use tokio::time::timeout; @@ -78,16 +77,15 @@ pub struct Kml { pub curr: Location, } -bitflags! { - #[derive(Default)] - struct KmlTag: i32 { - const UNDEFINED = 0x00; - const PLACEMARK = 0x01; - const TIMESTAMP = 0x02; - const WHEN = 0x04; - const POINT = 0x08; - const COORDINATES = 0x10; - } +#[derive(Default, Debug, Clone, PartialEq, Eq)] +enum KmlTag { + #[default] + Undefined, + Placemark, + PlacemarkTimestamp, + PlacemarkTimestampWhen, + PlacemarkPoint, + PlacemarkPointCoordinates, } impl Kml { @@ -128,12 +126,14 @@ impl Kml { } fn text_cb(&mut self, event: &BytesText) { - if self.tag.contains(KmlTag::WHEN) || self.tag.contains(KmlTag::COORDINATES) { + if self.tag == KmlTag::PlacemarkTimestampWhen + || self.tag == KmlTag::PlacemarkPointCoordinates + { let val = event.unescape().unwrap_or_default(); let val = val.replace(['\n', '\r', '\t', ' '], ""); - if self.tag.contains(KmlTag::WHEN) && val.len() >= 19 { + if self.tag == KmlTag::PlacemarkTimestampWhen && val.len() >= 19 { // YYYY-MM-DDTHH:MM:SSZ // 0 4 7 10 13 16 19 match chrono::NaiveDateTime::parse_from_str(&val, "%Y-%m-%dT%H:%M:%SZ") { @@ -147,7 +147,7 @@ impl Kml { self.curr.timestamp = time(); } } - } else if self.tag.contains(KmlTag::COORDINATES) { + } else if self.tag == KmlTag::PlacemarkPointCoordinates { let parts = val.splitn(2, ',').collect::>(); if let [longitude, latitude] = &parts[..] { self.curr.longitude = longitude.parse().unwrap_or_default(); @@ -162,17 +162,41 @@ impl Kml { .trim() .to_lowercase(); - if tag == "placemark" { - if self.tag.contains(KmlTag::PLACEMARK) - && 0 != self.curr.timestamp - && 0. != self.curr.latitude - && 0. != self.curr.longitude - { - self.locations - .push(std::mem::replace(&mut self.curr, Location::new())); + match self.tag { + KmlTag::PlacemarkTimestampWhen => { + if tag == "when" { + self.tag = KmlTag::PlacemarkTimestamp + } } - self.tag = KmlTag::UNDEFINED; - }; + KmlTag::PlacemarkTimestamp => { + if tag == "timestamp" { + self.tag = KmlTag::Placemark + } + } + KmlTag::PlacemarkPointCoordinates => { + if tag == "coordinates" { + self.tag = KmlTag::PlacemarkPoint + } + } + KmlTag::PlacemarkPoint => { + if tag == "point" { + self.tag = KmlTag::Placemark + } + } + KmlTag::Placemark => { + if tag == "placemark" { + if 0 != self.curr.timestamp + && 0. != self.curr.latitude + && 0. != self.curr.longitude + { + self.locations + .push(std::mem::replace(&mut self.curr, Location::new())); + } + self.tag = KmlTag::Undefined; + } + } + KmlTag::Undefined => {} + } } fn starttag_cb( @@ -196,19 +220,19 @@ impl Kml { .map(|a| a.into_owned()); } } else if tag == "placemark" { - self.tag = KmlTag::PLACEMARK; + self.tag = KmlTag::Placemark; self.curr.timestamp = 0; self.curr.latitude = 0.0; self.curr.longitude = 0.0; self.curr.accuracy = 0.0 - } else if tag == "timestamp" && self.tag.contains(KmlTag::PLACEMARK) { - self.tag = KmlTag::PLACEMARK | KmlTag::TIMESTAMP - } else if tag == "when" && self.tag.contains(KmlTag::TIMESTAMP) { - self.tag = KmlTag::PLACEMARK | KmlTag::TIMESTAMP | KmlTag::WHEN - } else if tag == "point" && self.tag.contains(KmlTag::PLACEMARK) { - self.tag = KmlTag::PLACEMARK | KmlTag::POINT - } else if tag == "coordinates" && self.tag.contains(KmlTag::POINT) { - self.tag = KmlTag::PLACEMARK | KmlTag::POINT | KmlTag::COORDINATES; + } else if tag == "timestamp" && self.tag == KmlTag::Placemark { + self.tag = KmlTag::PlacemarkTimestamp; + } else if tag == "when" && self.tag == KmlTag::PlacemarkTimestamp { + self.tag = KmlTag::PlacemarkTimestampWhen; + } else if tag == "point" && self.tag == KmlTag::Placemark { + self.tag = KmlTag::PlacemarkPoint; + } else if tag == "coordinates" && self.tag == KmlTag::PlacemarkPoint { + self.tag = KmlTag::PlacemarkPointCoordinates; if let Some(acc) = event.attributes().find(|attr| { attr.as_ref() .map(|a| { diff --git a/src/log.rs b/src/log.rs index c755484e6..78e41039f 100644 --- a/src/log.rs +++ b/src/log.rs @@ -65,9 +65,6 @@ pub trait LogExt where Self: std::marker::Sized, { - #[track_caller] - fn log_err_inner(self, context: &Context, msg: Option<&str>) -> Result; - /// Emits a warning if the receiver contains an Err value. /// /// Thanks to the [track_caller](https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller) @@ -76,73 +73,23 @@ where /// Unfortunately, the track_caller feature does not work on async functions (as of Rust 1.50). /// Once it is, you can add `#[track_caller]` to helper functions that use one of the log helpers here /// so that the location of the caller can be seen in the log. (this won't work with the macros, - /// like warn!(), since the file!() and line!() macros don't work with track_caller) + /// like warn!(), since the file!() and line!() macros don't work with track_caller) /// See for progress on this. #[track_caller] - fn log_err(self, context: &Context, msg: &str) -> Result { - self.log_err_inner(context, Some(msg)) - } - - /// Emits a warning if the receiver contains an Err value and returns an [`Option`]. - /// - /// Example: - /// ```text - /// if let Err(e) = do_something() { - /// warn!(context, "{:#}", e); - /// } - /// ``` - /// is equivalent to: - /// ```text - /// do_something().ok_or_log(context); - /// ``` - /// - /// For a note on the `track_caller` feature, see the doc comment on `log_err()`. - #[track_caller] - fn ok_or_log(self, context: &Context) -> Option { - self.log_err_inner(context, None).ok() - } - - /// Like `ok_or_log()`, but you can pass an extra message that is prepended in the log. - /// - /// Example: - /// ```text - /// if let Err(e) = do_something() { - /// warn!(context, "Something went wrong: {:#}", e); - /// } - /// ``` - /// is equivalent to: - /// ```text - /// do_something().ok_or_log_msg(context, "Something went wrong"); - /// ``` - /// and is also equivalent to: - /// ```text - /// use anyhow::Context as _; - /// do_something().context("Something went wrong").ok_or_log(context); - /// ``` - /// - /// For a note on the `track_caller` feature, see the doc comment on `log_err()`. - #[track_caller] - fn ok_or_log_msg(self, context: &Context, msg: &'static str) -> Option { - self.log_err_inner(context, Some(msg)).ok() - } + fn log_err(self, context: &Context) -> Result; } impl LogExt for Result { #[track_caller] - fn log_err_inner(self, context: &Context, msg: Option<&str>) -> Result { + fn log_err(self, context: &Context) -> Result { if let Err(e) = &self { let location = std::panic::Location::caller(); - let separator = if msg.is_none() { "" } else { ": " }; - let msg = msg.unwrap_or_default(); - // We are using Anyhow's .context() and to show the inner error, too, we need the {:#}: let full = format!( - "{file}:{line}: {msg}{separator}{e:#}", + "{file}:{line}: {e:#}", file = location.file(), line = location.line(), - msg = msg, - separator = separator, e = e ); // We can't use the warn!() macro here as the file!() and line!() macros diff --git a/src/message.rs b/src/message.rs index 415618f08..3ec5a99ae 100644 --- a/src/message.rs +++ b/src/message.rs @@ -5,7 +5,6 @@ use std::path::{Path, PathBuf}; use anyhow::{ensure, format_err, Context as _, Result}; use deltachat_derive::{FromSql, ToSql}; -use rusqlite::types::ValueRef; use serde::{Deserialize, Serialize}; use crate::chat::{self, Chat, ChatId}; @@ -29,8 +28,8 @@ use crate::sql; use crate::stock_str; use crate::summary::Summary; use crate::tools::{ - create_smeared_timestamp, get_filebytes, get_filemeta, gm2local_offset, read_file, time, - timestamp_to_str, truncate, + buf_compress, buf_decompress, create_smeared_timestamp, get_filebytes, get_filemeta, + gm2local_offset, read_file, time, timestamp_to_str, truncate, }; /// Message ID, including reserved IDs. @@ -1350,21 +1349,52 @@ pub(crate) fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> /// e.g. because of save_mime_headers is not set /// or the message is not incoming. pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result> { - let headers = context + let (headers, compressed) = context .sql .query_row( - "SELECT mime_headers FROM msgs WHERE id=?;", + "SELECT mime_headers, mime_compressed FROM msgs WHERE id=?", paramsv![msg_id], |row| { - row.get(0).or_else(|err| match row.get_ref(0)? { - ValueRef::Null => Ok(Vec::new()), - ValueRef::Text(text) => Ok(text.to_vec()), - ValueRef::Blob(blob) => Ok(blob.to_vec()), - ValueRef::Integer(_) | ValueRef::Real(_) => Err(err), - }) + let headers = sql::row_get_vec(row, 0)?; + let compressed: bool = row.get(1)?; + Ok((headers, compressed)) }, ) .await?; + if compressed { + return buf_decompress(&headers); + } + + let headers2 = headers.clone(); + let compressed = match tokio::task::block_in_place(move || buf_compress(&headers2)) { + Err(e) => { + warn!(context, "get_mime_headers: buf_compress() failed: {}", e); + return Ok(headers); + } + Ok(o) => o, + }; + let update = |conn: &mut rusqlite::Connection| { + match conn.execute( + "\ + UPDATE msgs SET mime_headers=?, mime_compressed=1 \ + WHERE id=? AND mime_headers!='' AND mime_compressed=0", + params![compressed, msg_id], + ) { + Ok(rows_updated) => ensure!(rows_updated <= 1), + Err(e) => { + warn!(context, "get_mime_headers: UPDATE failed: {}", e); + return Err(e.into()); + } + } + Ok(()) + }; + if let Err(e) = context.sql.call_write(update).await { + warn!( + context, + "get_mime_headers: failed to update mime_headers: {}", e + ); + } + Ok(headers) } @@ -1413,8 +1443,6 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { context.emit_msgs_changed_without_ids(); // Run housekeeping to delete unused blobs. - // We need to use set_raw_config() here since with set_config() it - // wouldn't compile ("recursion in an `async fn`") context.set_config(Config::LastHousekeeping, None).await?; } diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 6d291ae23..ce4bac4c1 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -27,16 +27,13 @@ use crate::simplify::escape_message_footer_marks; use crate::stock_str; use crate::tools::IsNoneOrEmpty; use crate::tools::{ - create_outgoing_rfc724_mid, create_smeared_timestamp, get_filebytes, remove_subject_prefix, - time, + create_outgoing_rfc724_mid, create_smeared_timestamp, remove_subject_prefix, time, }; // attachments of 25 mb brutto should work on the majority of providers // (brutto examples: web.de=50, 1&1=40, t-online.de=32, gmail=25, posteo=50, yahoo=25, all-inkl=100). -// as an upper limit, we double the size; the core won't send messages larger than this // to get the netto sizes, we subtract 1 mb header-overhead and the base64-overhead. pub const RECOMMENDED_FILE_SIZE: u64 = 24 * 1024 * 1024 / 4 * 3; -const UPPER_LIMIT_FILE_SIZE: u64 = 49 * 1024 * 1024 / 4 * 3; #[derive(Debug, Clone)] pub enum Loaded { @@ -1211,15 +1208,8 @@ impl<'a> MimeFactory<'a> { // add attachment part if self.msg.viewtype.has_file() { - if !is_file_size_okay(context, self.msg).await? { - bail!( - "Message exceeds the recommended {} MB.", - RECOMMENDED_FILE_SIZE / 1_000_000, - ); - } else { - let (file_part, _) = build_body_file(context, self.msg, "").await?; - parts.push(file_part); - } + let (file_part, _) = build_body_file(context, self.msg, "").await?; + parts.push(file_part); } if let Some(meta_part) = meta_part { @@ -1483,16 +1473,6 @@ fn recipients_contain_addr(recipients: &[(String, String)], addr: &str) -> bool .any(|(_, cur)| cur.to_lowercase() == addr_lc) } -async fn is_file_size_okay(context: &Context, msg: &Message) -> Result { - match msg.param.get_path(Param::File, context)? { - Some(path) => { - let bytes = get_filebytes(context, &path).await?; - Ok(bytes <= UPPER_LIMIT_FILE_SIZE) - } - None => Ok(false), - } -} - fn render_rfc724_mid(rfc724_mid: &str) -> String { let rfc724_mid = rfc724_mid.trim().to_string(); diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 6d9b242c8..de5009ce4 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -1283,7 +1283,7 @@ impl MimeMessage { if !key.details.users.iter().any(|user| { user.id .id() - .ends_with(&(String::from("<") + &peerstate.addr + ">")) + .ends_with((String::from("<") + &peerstate.addr + ">").as_bytes()) }) { return Ok(false); } diff --git a/src/pgp.rs b/src/pgp.rs index 6cda27632..43ea19f9a 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -10,7 +10,8 @@ use pgp::composed::{ Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey, SignedPublicSubKey, SignedSecretKey, StandaloneSignature, SubkeyParamsBuilder, }; -use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm}; +use pgp::crypto::hash::HashAlgorithm; +use pgp::crypto::sym::SymmetricKeyAlgorithm; use pgp::types::{ CompressionAlgorithm, KeyTrait, Mpi, PublicKeyTrait, SecretKeyTrait, StringToKey, }; @@ -50,7 +51,7 @@ impl<'a> KeyTrait for SignedPublicKeyOrSubkey<'a> { } } - fn algorithm(&self) -> pgp::crypto::PublicKeyAlgorithm { + fn algorithm(&self) -> pgp::crypto::public_key::PublicKeyAlgorithm { match self { Self::Key(k) => k.algorithm(), Self::Subkey(k) => k.algorithm(), @@ -297,7 +298,7 @@ pub fn pk_decrypt( let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.keys().iter().collect(); - let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?; + let (decryptor, _) = msg.decrypt(|| "".into(), &skeys[..])?; let msgs = decryptor.collect::>>()?; if let Some(msg) = msgs.into_iter().next() { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index c4adf7132..01aaa4faa 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -37,7 +37,7 @@ 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::{extract_grpid_from_rfc724_mid, smeared_time}; +use crate::tools::{buf_compress, extract_grpid_from_rfc724_mid, smeared_time}; use crate::{contact, imap}; /// This is the struct that is returned after receiving one email (aka MIME message). @@ -691,7 +691,8 @@ async fn add_parts( } else if allow_creation { if let Ok(chat) = ChatIdBlocked::get_for_contact(context, from_id, create_blocked) .await - .log_err(context, "Failed to get (new) chat for contact") + .context("Failed to get (new) chat for contact") + .log_err(context) { chat_id = Some(chat.id); chat_id_blocked = chat.blocked; @@ -843,7 +844,8 @@ async fn add_parts( // maybe an Autocrypt Setup Message if let Ok(chat) = ChatIdBlocked::get_for_contact(context, ContactId::SELF, Blocked::Not) .await - .log_err(context, "Failed to get (new) chat for contact") + .context("Failed to get (new) chat for contact") + .log_err(context) { chat_id = Some(chat.id); chat_id_blocked = chat.blocked; @@ -1063,11 +1065,12 @@ async fn add_parts( let mut save_mime_modified = mime_parser.is_mime_modified; let mime_headers = if save_mime_headers || save_mime_modified { - if mime_parser.was_encrypted() && !mime_parser.decoded_data.is_empty() { + let headers = if mime_parser.was_encrypted() && !mime_parser.decoded_data.is_empty() { mime_parser.decoded_data.clone() } else { imf_raw.to_vec() - } + }; + tokio::task::block_in_place(move || buf_compress(&headers))? } else { Vec::new() }; @@ -1150,7 +1153,7 @@ INSERT INTO msgs from_id, to_id, timestamp, timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, subject, txt_raw, param, - bytes, mime_headers, mime_in_reply_to, + bytes, mime_headers, mime_compressed, mime_in_reply_to, mime_references, mime_modified, error, ephemeral_timer, ephemeral_timestamp, download_state, hop_info ) @@ -1159,7 +1162,7 @@ INSERT INTO msgs ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, - ?, ?, ?, ?, + ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ? ) @@ -1168,7 +1171,8 @@ SET rfc724_mid=excluded.rfc724_mid, chat_id=excluded.chat_id, from_id=excluded.from_id, to_id=excluded.to_id, timestamp=excluded.timestamp, timestamp_sent=excluded.timestamp_sent, timestamp_rcvd=excluded.timestamp_rcvd, type=excluded.type, state=excluded.state, msgrmsg=excluded.msgrmsg, txt=excluded.txt, subject=excluded.subject, txt_raw=excluded.txt_raw, param=excluded.param, - bytes=excluded.bytes, mime_headers=excluded.mime_headers, mime_in_reply_to=excluded.mime_in_reply_to, + bytes=excluded.bytes, mime_headers=excluded.mime_headers, + mime_compressed=excluded.mime_compressed, mime_in_reply_to=excluded.mime_in_reply_to, mime_references=excluded.mime_references, mime_modified=excluded.mime_modified, error=excluded.error, ephemeral_timer=excluded.ephemeral_timer, ephemeral_timestamp=excluded.ephemeral_timestamp, download_state=excluded.download_state, hop_info=excluded.hop_info "#)?; diff --git a/src/scheduler.rs b/src/scheduler.rs index 8d8118dd8..2404d7e22 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -1,7 +1,8 @@ use std::iter::{self, once}; +use std::num::NonZeroUsize; use std::sync::atomic::Ordering; -use anyhow::{bail, Context as _, Result}; +use anyhow::{bail, Context as _, Error, Result}; use async_channel::{self as channel, Receiver, Sender}; use futures::future::try_join_all; use futures_lite::FutureExt; @@ -43,15 +44,18 @@ impl SchedulerState { /// Whether the scheduler is currently running. pub(crate) async fn is_running(&self) -> bool { let inner = self.inner.read().await; - inner.scheduler.is_some() + matches!(*inner, InnerSchedulerState::Started(_)) } /// Starts the scheduler if it is not yet started. pub(crate) async fn start(&self, context: Context) { let mut inner = self.inner.write().await; - inner.started = true; - if inner.scheduler.is_none() && !inner.paused { - Self::do_start(inner, context).await; + match *inner { + InnerSchedulerState::Started(_) => (), + InnerSchedulerState::Stopped => Self::do_start(inner, context).await, + InnerSchedulerState::Paused { + ref mut started, .. + } => *started = true, } } @@ -60,7 +64,7 @@ impl SchedulerState { info!(context, "starting IO"); let ctx = context.clone(); match Scheduler::start(context).await { - Ok(scheduler) => inner.scheduler = Some(scheduler), + Ok(scheduler) => *inner = InnerSchedulerState::Started(scheduler), Err(err) => error!(&ctx, "Failed to start IO: {:#}", err), } } @@ -68,12 +72,23 @@ impl SchedulerState { /// Stops the scheduler if it is currently running. pub(crate) async fn stop(&self, context: &Context) { let mut inner = self.inner.write().await; - inner.started = false; - Self::do_stop(inner, context).await; + match *inner { + InnerSchedulerState::Started(_) => { + Self::do_stop(inner, context, InnerSchedulerState::Stopped).await + } + InnerSchedulerState::Stopped => (), + InnerSchedulerState::Paused { + ref mut started, .. + } => *started = false, + } } /// Stops the scheduler if it is currently running. - async fn do_stop(mut inner: RwLockWriteGuard<'_, InnerSchedulerState>, context: &Context) { + async fn do_stop( + mut inner: RwLockWriteGuard<'_, InnerSchedulerState>, + context: &Context, + new_state: InnerSchedulerState, + ) { // Sending an event wakes up event pollers (get_next_event) // so the caller of stop_io() can arrange for proper termination. // For this, the caller needs to instruct the event poller @@ -83,8 +98,10 @@ impl SchedulerState { if let Some(debug_logging) = context.debug_logging.read().await.as_ref() { debug_logging.loop_handle.abort(); } - if let Some(scheduler) = inner.scheduler.take() { - scheduler.stop(context).await; + let prev_state = std::mem::replace(&mut *inner, new_state); + match prev_state { + InnerSchedulerState::Started(scheduler) => scheduler.stop(context).await, + InnerSchedulerState::Stopped | InnerSchedulerState::Paused { .. } => (), } } @@ -96,22 +113,63 @@ impl SchedulerState { /// If in the meantime [`SchedulerState::start`] or [`SchedulerState::stop`] is called /// resume will do the right thing and restore the scheduler to the state requested by /// the last call. - pub(crate) async fn pause<'a>(&'_ self, context: Context) -> IoPausedGuard { + pub(crate) async fn pause<'a>(&'_ self, context: Context) -> Result { { let mut inner = self.inner.write().await; - inner.paused = true; - Self::do_stop(inner, &context).await; + match *inner { + InnerSchedulerState::Started(_) => { + let new_state = InnerSchedulerState::Paused { + started: true, + pause_guards_count: NonZeroUsize::new(1).unwrap(), + }; + Self::do_stop(inner, &context, new_state).await; + } + InnerSchedulerState::Stopped => { + *inner = InnerSchedulerState::Paused { + started: false, + pause_guards_count: NonZeroUsize::new(1).unwrap(), + }; + } + InnerSchedulerState::Paused { + ref mut pause_guards_count, + .. + } => { + *pause_guards_count = pause_guards_count + .checked_add(1) + .ok_or_else(|| Error::msg("Too many pause guards active"))? + } + } } + let (tx, rx) = oneshot::channel(); tokio::spawn(async move { rx.await.ok(); let mut inner = context.scheduler.inner.write().await; - inner.paused = false; - if inner.started && inner.scheduler.is_none() { - SchedulerState::do_start(inner, context.clone()).await; + match *inner { + InnerSchedulerState::Started(_) => { + warn!(&context, "IoPausedGuard resume: started instead of paused"); + } + InnerSchedulerState::Stopped => { + warn!(&context, "IoPausedGuard resume: stopped instead of paused"); + } + InnerSchedulerState::Paused { + ref started, + ref mut pause_guards_count, + } => { + if *pause_guards_count == NonZeroUsize::new(1).unwrap() { + match *started { + true => SchedulerState::do_start(inner, context.clone()).await, + false => *inner = InnerSchedulerState::Stopped, + } + } else { + let new_count = pause_guards_count.get() - 1; + // SAFETY: Value was >=2 before due to if condition + *pause_guards_count = NonZeroUsize::new(new_count).unwrap(); + } + } } }); - IoPausedGuard { sender: Some(tx) } + Ok(IoPausedGuard { sender: Some(tx) }) } /// Restarts the scheduler, only if it is running. @@ -126,8 +184,8 @@ impl SchedulerState { /// Indicate that the network likely has come back. pub(crate) async fn maybe_network(&self) { let inner = self.inner.read().await; - let (inbox, oboxes) = match inner.scheduler { - Some(ref scheduler) => { + let (inbox, oboxes) = match *inner { + InnerSchedulerState::Started(ref scheduler) => { scheduler.maybe_network(); let inbox = scheduler.inbox.conn_state.state.connectivity.clone(); let oboxes = scheduler @@ -137,7 +195,7 @@ impl SchedulerState { .collect::>(); (inbox, oboxes) } - None => return, + _ => return, }; drop(inner); connectivity::idle_interrupted(inbox, oboxes).await; @@ -146,15 +204,15 @@ impl SchedulerState { /// Indicate that the network likely is lost. pub(crate) async fn maybe_network_lost(&self, context: &Context) { let inner = self.inner.read().await; - let stores = match inner.scheduler { - Some(ref scheduler) => { + let stores = match *inner { + InnerSchedulerState::Started(ref scheduler) => { scheduler.maybe_network_lost(); scheduler .boxes() .map(|b| b.conn_state.state.connectivity.clone()) .collect() } - None => return, + _ => return, }; drop(inner); connectivity::maybe_network_lost(context, stores).await; @@ -162,45 +220,49 @@ impl SchedulerState { pub(crate) async fn interrupt_inbox(&self, info: InterruptInfo) { let inner = self.inner.read().await; - if let Some(ref scheduler) = inner.scheduler { + if let InnerSchedulerState::Started(ref scheduler) = *inner { scheduler.interrupt_inbox(info); } } pub(crate) async fn interrupt_smtp(&self, info: InterruptInfo) { let inner = self.inner.read().await; - if let Some(ref scheduler) = inner.scheduler { + if let InnerSchedulerState::Started(ref scheduler) = *inner { scheduler.interrupt_smtp(info); } } pub(crate) async fn interrupt_ephemeral_task(&self) { let inner = self.inner.read().await; - if let Some(ref scheduler) = inner.scheduler { + if let InnerSchedulerState::Started(ref scheduler) = *inner { scheduler.interrupt_ephemeral_task(); } } pub(crate) async fn interrupt_location(&self) { let inner = self.inner.read().await; - if let Some(ref scheduler) = inner.scheduler { + if let InnerSchedulerState::Started(ref scheduler) = *inner { scheduler.interrupt_location(); } } pub(crate) async fn interrupt_recently_seen(&self, contact_id: ContactId, timestamp: i64) { let inner = self.inner.read().await; - if let Some(ref scheduler) = inner.scheduler { + if let InnerSchedulerState::Started(ref scheduler) = *inner { scheduler.interrupt_recently_seen(contact_id, timestamp); } } } #[derive(Debug, Default)] -struct InnerSchedulerState { - scheduler: Option, - started: bool, - paused: bool, +enum InnerSchedulerState { + Started(Scheduler), + #[default] + Stopped, + Paused { + started: bool, + pause_guards_count: NonZeroUsize, + }, } /// Guard to make sure the IO Scheduler is resumed. @@ -301,7 +363,7 @@ async fn inbox_loop(ctx: Context, started: Sender<()>, inbox_handlers: ImapConne let next_housekeeping_time = last_housekeeping_time.saturating_add(60 * 60 * 24); if next_housekeeping_time <= time() { - sql::housekeeping(&ctx).await.ok_or_log(&ctx); + sql::housekeeping(&ctx).await.log_err(&ctx).ok(); } } Err(err) => { @@ -410,7 +472,8 @@ async fn fetch_idle( .store_seen_flags_on_imap(ctx) .await .context("store_seen_flags_on_imap") - .ok_or_log(ctx); + .log_err(ctx) + .ok(); } else { warn!(ctx, "No session even though we just prepared it"); } @@ -434,7 +497,8 @@ async fn fetch_idle( delete_expired_imap_messages(ctx) .await .context("delete_expired_imap_messages") - .ok_or_log(ctx); + .log_err(ctx) + .ok(); // Scan additional folders only after finishing fetching the watched folder. // @@ -474,7 +538,8 @@ async fn fetch_idle( .sync_seen_flags(ctx, &watch_folder) .await .context("sync_seen_flags") - .ok_or_log(ctx); + .log_err(ctx) + .ok(); connection.connectivity.set_connected(ctx).await; @@ -770,20 +835,22 @@ impl Scheduler { pub(crate) async fn stop(self, context: &Context) { // Send stop signals to tasks so they can shutdown cleanly. for b in self.boxes() { - b.conn_state.stop().await.ok_or_log(context); + b.conn_state.stop().await.log_err(context).ok(); } - self.smtp.stop().await.ok_or_log(context); + self.smtp.stop().await.log_err(context).ok(); // Actually shutdown tasks. let timeout_duration = std::time::Duration::from_secs(30); for b in once(self.inbox).chain(self.oboxes.into_iter()) { tokio::time::timeout(timeout_duration, b.handle) .await - .ok_or_log(context); + .log_err(context) + .ok(); } tokio::time::timeout(timeout_duration, self.smtp_handle) .await - .ok_or_log(context); + .log_err(context) + .ok(); self.ephemeral_handle.abort(); self.location_handle.abort(); self.recently_seen_loop.abort(); diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index 91edcad61..472b10001 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -14,6 +14,8 @@ use crate::tools::time; use crate::{context::Context, log::LogExt}; use crate::{stock_str, tools}; +use super::InnerSchedulerState; + #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumProperty, PartialOrd, Ord)] pub enum Connectivity { NotConnected = 1000, @@ -226,12 +228,12 @@ impl Context { /// If the connectivity changes, a DC_EVENT_CONNECTIVITY_CHANGED will be emitted. pub async fn get_connectivity(&self) -> Connectivity { let lock = self.scheduler.inner.read().await; - let stores: Vec<_> = match lock.scheduler { - Some(ref sched) => sched + let stores: Vec<_> = match *lock { + InnerSchedulerState::Started(ref sched) => sched .boxes() .map(|b| b.conn_state.state.connectivity.clone()) .collect(), - None => return Connectivity::NotConnected, + _ => return Connectivity::NotConnected, }; drop(lock); @@ -309,15 +311,15 @@ impl Context { // ============================================================================================= let lock = self.scheduler.inner.read().await; - let (folders_states, smtp) = match lock.scheduler { - Some(ref sched) => ( + let (folders_states, smtp) = match *lock { + InnerSchedulerState::Started(ref sched) => ( sched .boxes() .map(|b| (b.meaning, b.conn_state.state.connectivity.clone())) .collect::>(), sched.smtp.state.connectivity.clone(), ), - None => { + _ => { return Err(anyhow!("Not started")); } }; @@ -337,7 +339,7 @@ impl Context { let mut folder_added = false; if let Some(config) = folder.to_config().filter(|c| watched_folders.contains(c)) { - let f = self.get_config(config).await.ok_or_log(self).flatten(); + let f = self.get_config(config).await.log_err(self).ok().flatten(); if let Some(foldername) = f { let detailed = &state.get_detailed().await; @@ -396,64 +398,72 @@ impl Context { if let Some(quota) = &*quota { match "a.recent { Ok(quota) => { - let roots_cnt = quota.len(); - for (root_name, resources) in quota { - use async_imap::types::QuotaResourceName::*; - for resource in resources { - ret += "
  • "; + if !quota.is_empty() { + for (root_name, resources) in quota { + use async_imap::types::QuotaResourceName::*; + for resource in resources { + ret += "
  • "; - // root name is empty eg. for gmail and redundant eg. for riseup. - // therefore, use it only if there are really several roots. - if roots_cnt > 1 && !root_name.is_empty() { - ret += - &format!("{}: ", &*escaper::encode_minimal(root_name)); - } else { - info!(self, "connectivity: root name hidden: \"{}\"", root_name); + // root name is empty eg. for gmail and redundant eg. for riseup. + // therefore, use it only if there are really several roots. + if quota.len() > 1 && !root_name.is_empty() { + ret += &format!( + "{}: ", + &*escaper::encode_minimal(root_name) + ); + } else { + info!( + self, + "connectivity: root name hidden: \"{}\"", root_name + ); + } + + let messages = stock_str::messages(self).await; + let part_of_total_used = stock_str::part_of_total_used( + self, + &resource.usage.to_string(), + &resource.limit.to_string(), + ) + .await; + ret += &match &resource.name { + Atom(resource_name) => { + format!( + "{}: {}", + &*escaper::encode_minimal(resource_name), + part_of_total_used + ) + } + Message => { + format!("{part_of_total_used}: {messages}") + } + Storage => { + // do not use a special title needed for "Storage": + // - it is usually shown directly under the "Storage" headline + // - by the units "1 MB of 10 MB used" there is some difference to eg. "Messages: 1 of 10 used" + // - the string is not longer than the other strings that way (minus title, plus units) - + // additional linebreaks on small displays are unlikely therefore + // - most times, this is the only item anyway + let usage = &format_size(resource.usage * 1024, BINARY); + let limit = &format_size(resource.limit * 1024, BINARY); + stock_str::part_of_total_used(self, usage, limit).await + } + }; + + let percent = resource.get_usage_percentage(); + let color = if percent >= QUOTA_ERROR_THRESHOLD_PERCENTAGE { + "red" + } else if percent >= QUOTA_WARN_THRESHOLD_PERCENTAGE { + "yellow" + } else { + "green" + }; + ret += &format!("
    {percent}%
    "); + + ret += "
  • "; } - - let messages = stock_str::messages(self).await; - let part_of_total_used = stock_str::part_of_total_used( - self, - &resource.usage.to_string(), - &resource.limit.to_string(), - ) - .await; - ret += &match &resource.name { - Atom(resource_name) => { - format!( - "{}: {}", - &*escaper::encode_minimal(resource_name), - part_of_total_used - ) - } - Message => { - format!("{part_of_total_used}: {messages}") - } - Storage => { - // do not use a special title needed for "Storage": - // - it is usually shown directly under the "Storage" headline - // - by the units "1 MB of 10 MB used" there is some difference to eg. "Messages: 1 of 10 used" - // - the string is not longer than the other strings that way (minus title, plus units) - - // additional linebreaks on small displays are unlikely therefore - // - most times, this is the only item anyway - let usage = &format_size(resource.usage * 1024, BINARY); - let limit = &format_size(resource.limit * 1024, BINARY); - stock_str::part_of_total_used(self, usage, limit).await - } - }; - - let percent = resource.get_usage_percentage(); - let color = if percent >= QUOTA_ERROR_THRESHOLD_PERCENTAGE { - "red" - } else if percent >= QUOTA_WARN_THRESHOLD_PERCENTAGE { - "yellow" - } else { - "green" - }; - ret += &format!("
    {percent}%
    "); - - ret += ""; } + } else { + ret += format!("
  • Warning: {domain} claims to support quota but gives no information
  • ").as_str(); } } Err(e) => { @@ -480,14 +490,14 @@ impl Context { /// Returns true if all background work is done. pub async fn all_work_done(&self) -> bool { let lock = self.scheduler.inner.read().await; - let stores: Vec<_> = match lock.scheduler { - Some(ref sched) => sched + let stores: Vec<_> = match *lock { + InnerSchedulerState::Started(ref sched) => sched .boxes() .map(|b| &b.conn_state.state) .chain(once(&sched.smtp.state)) .map(|state| state.connectivity.clone()) .collect(), - None => return false, + _ => return false, }; drop(lock); diff --git a/src/sql.rs b/src/sql.rs index ff149f98c..641b352ec 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -5,7 +5,7 @@ use std::convert::TryFrom; use std::path::{Path, PathBuf}; use anyhow::{bail, Context as _, Result}; -use rusqlite::{self, config::DbConfig, Connection, OpenFlags}; +use rusqlite::{self, config::DbConfig, types::ValueRef, Connection, OpenFlags, Row}; use tokio::sync::{Mutex, MutexGuard, RwLock}; use crate::blob::BlobObject; @@ -57,7 +57,7 @@ pub struct Sql { /// Database file path pub(crate) dbfile: PathBuf, - /// Write transaction mutex. + /// Write transactions mutex. /// /// See [`Self::write_lock`]. write_mtx: Mutex<()>, @@ -696,6 +696,15 @@ fn new_connection(path: &Path, passphrase: &str) -> Result { /// Cleanup the account to restore some storage and optimize the database. pub async fn housekeeping(context: &Context) -> Result<()> { + // Setting `Config::LastHousekeeping` at the beginning avoids endless loops when things do not + // work out for whatever reason or are interrupted by the OS. + if let Err(e) = context + .set_config(Config::LastHousekeeping, Some(&time().to_string())) + .await + { + warn!(context, "Can't set config: {e:#}."); + } + if let Err(err) = remove_unused_files(context).await { warn!( context, @@ -743,13 +752,6 @@ pub async fn housekeeping(context: &Context) -> Result<()> { } } - if let Err(e) = context - .set_config(Config::LastHousekeeping, Some(&time().to_string())) - .await - { - warn!(context, "Can't set config: {e:#}."); - } - context .sql .execute( @@ -757,12 +759,24 @@ pub async fn housekeeping(context: &Context) -> Result<()> { (), ) .await - .ok_or_log_msg(context, "failed to remove old MDNs"); + .context("failed to remove old MDNs") + .log_err(context) + .ok(); info!(context, "Housekeeping done."); Ok(()) } +/// Get the value of a column `idx` of the `row` as `Vec`. +pub fn row_get_vec(row: &Row, idx: usize) -> rusqlite::Result> { + row.get(idx).or_else(|err| match row.get_ref(idx)? { + ValueRef::Null => Ok(Vec::new()), + ValueRef::Text(text) => Ok(text.to_vec()), + ValueRef::Blob(blob) => Ok(blob.to_vec()), + ValueRef::Integer(_) | ValueRef::Real(_) => Err(err), + }) +} + /// Enumerates used files in the blobdir and removes unused ones. pub async fn remove_unused_files(context: &Context) -> Result<()> { let mut files_in_use = HashSet::new(); @@ -895,12 +909,14 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { } } Err(err) => { - warn!( - context, - "Housekeeping: Cannot read dir {}: {:#}.", - p.display(), - err - ); + if !p.ends_with(BLOBS_BACKUP_NAME) { + warn!( + context, + "Housekeeping: Cannot read dir {}: {:#}.", + p.display(), + err + ); + } } } } diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 046db4fb2..55c979a87 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -704,6 +704,13 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid); // Reverted above, as it requires to load the whole DB in memory. sql.set_db_version(99).await?; } + if dbversion < 100 { + sql.execute_migration( + "ALTER TABLE msgs ADD COLUMN mime_compressed INTEGER NOT NULL DEFAULT 0", + 100, + ) + .await?; + } let new_version = sql .get_raw_config_int(VERSION_CFG) @@ -735,14 +742,18 @@ impl Sql { Ok(()) } - async fn execute_migration(&self, query: &'static str, version: i32) -> Result<()> { - self.transaction(move |transaction| { - // set raw config inside the transaction - transaction.execute( - "UPDATE config SET value=? WHERE keyname=?;", - paramsv![format!("{version}"), VERSION_CFG], - )?; + // Sets db `version` in the `transaction`. + 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], + )?; + Ok(()) + } + async fn execute_migration(&self, query: &str, version: i32) -> Result<()> { + self.transaction(move |transaction| { + Self::set_db_version_trans(transaction, version)?; transaction.execute_batch(query)?; Ok(()) diff --git a/src/tools.rs b/src/tools.rs index 17de3e0ef..7ce5eacde 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -5,7 +5,8 @@ use std::borrow::Cow; use std::fmt; -use std::io::Cursor; +use std::io::{Cursor, Write}; +use std::mem; use std::path::{Path, PathBuf}; use std::str::from_utf8; use std::time::{Duration, SystemTime}; @@ -654,6 +655,42 @@ pub(crate) fn single_value(collection: impl IntoIterator) -> Option None } +/// Compressor/decompressor buffer size. +const BROTLI_BUFSZ: usize = 4096; + +/// Compresses `buf` to `Vec` using `brotli`. +/// Note that it handles an empty `buf` as a special value that remains empty after compression, +/// otherwise brotli would add its metadata to it which is not nice because this function is used +/// for compression of strings stored in the db and empty strings are common there. This approach is +/// not strictly correct because nowhere in the brotli documentation is said that an empty buffer +/// can't be a result of compression of some input, but i think this will never break. +pub(crate) fn buf_compress(buf: &[u8]) -> Result> { + if buf.is_empty() { + return Ok(Vec::new()); + } + // level 4 is 2x faster than level 6 (and 54x faster than 10, for comparison). + // with the adaptiveness, we aim to not slow down processing + // single large files too much, esp. on low-budget devices. + // in tests (see #4129), this makes a difference, without compressing much worse. + let q: u32 = if buf.len() > 1_000_000 { 4 } else { 6 }; + let lgwin: u32 = 22; // log2(LZ77 window size), it's the default for brotli CLI tool. + let mut compressor = brotli::CompressorWriter::new(Vec::new(), BROTLI_BUFSZ, q, lgwin); + compressor.write_all(buf)?; + Ok(compressor.into_inner()) +} + +/// Decompresses `buf` to `Vec` using `brotli`. +/// See `buf_compress()` for why we don't pass an empty buffer to brotli decompressor. +pub(crate) fn buf_decompress(buf: &[u8]) -> Result> { + if buf.is_empty() { + return Ok(Vec::new()); + } + let mut decompressor = brotli::DecompressorWriter::new(Vec::new(), BROTLI_BUFSZ); + decompressor.write_all(buf)?; + decompressor.flush()?; + Ok(mem::take(decompressor.get_mut())) +} + #[cfg(test)] mod tests { #![allow(clippy::indexing_slicing)]