mirror of
https://github.com/chatmail/core.git
synced 2026-04-06 15:42:10 +03:00
Compare commits
5 Commits
1.0.0-alph
...
local_hpk_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0be33eafb1 | ||
|
|
5d47d25c1e | ||
|
|
e4f9446e3c | ||
|
|
abbbd0cb67 | ||
|
|
ae9f52e001 |
@@ -13,7 +13,7 @@ restore-workspace: &restore-workspace
|
||||
restore-cache: &restore-cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- cargo-v0-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- repo-source-{{ .Branch }}-{{ .Revision }}
|
||||
|
||||
commands:
|
||||
@@ -53,11 +53,10 @@ jobs:
|
||||
command: cargo generate-lockfile
|
||||
- restore_cache:
|
||||
keys:
|
||||
- cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- cargo-v0-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- run: rustup install $(cat rust-toolchain)
|
||||
- run: rustup default $(cat rust-toolchain)
|
||||
- run: rustup component add --toolchain $(cat rust-toolchain) rustfmt
|
||||
- run: rustup component add --toolchain $(cat rust-toolchain) clippy-preview
|
||||
- run: cargo update
|
||||
- run: cargo fetch
|
||||
- run: rustc +stable --version
|
||||
@@ -68,7 +67,7 @@ jobs:
|
||||
paths:
|
||||
- crate
|
||||
- save_cache:
|
||||
key: cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
key: cargo-v0-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
paths:
|
||||
- "~/.cargo"
|
||||
- "~/.rustup"
|
||||
@@ -161,15 +160,6 @@ jobs:
|
||||
- run: ls -laR workspace
|
||||
- run: ci_scripts/ci_upload.sh workspace/py-docs workspace/wheelhouse
|
||||
|
||||
clippy:
|
||||
executor: default
|
||||
steps:
|
||||
- *restore-workspace
|
||||
- *restore-cache
|
||||
- run:
|
||||
name: Run cargo clippy
|
||||
command: cargo clippy --all
|
||||
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
@@ -185,10 +175,6 @@ workflows:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
|
||||
- clippy:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
|
||||
# Linux Desktop 64bit
|
||||
- test_x86_64-unknown-linux-gnu:
|
||||
requires:
|
||||
|
||||
93
Cargo.lock
generated
93
Cargo.lock
generated
@@ -1,5 +1,18 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"psl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rental 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.0.3"
|
||||
@@ -445,15 +458,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.3"
|
||||
dependencies = [
|
||||
"addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"deltachat_derive 0.1.0",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -488,19 +501,11 @@ dependencies = [
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.3"
|
||||
dependencies = [
|
||||
"deltachat 1.0.0-alpha.4",
|
||||
"deltachat 1.0.0-alpha.3",
|
||||
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1555,6 +1560,39 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psl"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"psl-codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psl-codegen"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"psl-lexer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sequence_trie 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psl-lexer"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "1.5.2"
|
||||
@@ -1797,6 +1835,25 @@ dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rental"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rental-impl 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rental-impl"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.9.19"
|
||||
@@ -1974,6 +2031,11 @@ name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "sequence_trie"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.98"
|
||||
@@ -2608,6 +2670,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22199dd03e5cff19ede8c2b835c93460f998b4716e225d06d740d925ceac5d75"
|
||||
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
|
||||
"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9"
|
||||
"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d"
|
||||
@@ -2774,6 +2837,9 @@ dependencies = [
|
||||
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
||||
"checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum psl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0fcd4da9d98f254ad641dd081207cc14fcbec95dd58ee62ffc9b96f0684fd6c2"
|
||||
"checksum psl-codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "06f94f31e4f36b42e21b831d20bf0efc805b2155624697fb86f987b666518c3b"
|
||||
"checksum psl-lexer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cf84fe23023e855b9a9d038a1b08d5c438d3961d2ced6c2b2358b29fbf74a63"
|
||||
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
@@ -2800,6 +2866,8 @@ dependencies = [
|
||||
"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
|
||||
"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum rental 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "01916ebd9fc2e81978a5dc9542a2fa47f5bb2ca3402e14c7cc42d6e3c5123e1f"
|
||||
"checksum rental-impl 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82260d54cf2cbe9608df161f7e7c98e81fae702aa13af9e4d5d39dc2ffb25ab6"
|
||||
"checksum reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0777154c2c3eb54f5c480db01de845652d941e47191277cc673634c3853939"
|
||||
"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a"
|
||||
"checksum rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6ad8d3632f6745bb671c8637e2aa44015537c5e384789d2ea3235739301ed1e0"
|
||||
@@ -2818,6 +2886,7 @@ dependencies = [
|
||||
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum sequence_trie 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1ee22067b7ccd072eeb64454b9c6e1b33b61cd0d49e895fd48676a184580e0c3"
|
||||
"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
|
||||
"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c"
|
||||
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.3"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MPL"
|
||||
@@ -10,7 +10,6 @@ cc = "1.0.35"
|
||||
pkg-config = "0.3"
|
||||
|
||||
[dependencies]
|
||||
deltachat_derive = { path = "./deltachat_derive" }
|
||||
libc = "0.2.51"
|
||||
pgp = { version = "0.2", default-features = false }
|
||||
hex = "0.3.2"
|
||||
@@ -37,6 +36,7 @@ rustyline = "4.1.0"
|
||||
lazy_static = "1.3.0"
|
||||
regex = "1.1.6"
|
||||
rusqlite = { version = "0.20", features = ["bundled"] }
|
||||
addr = "0.2.0"
|
||||
r2d2_sqlite = "0.12.0"
|
||||
r2d2 = "0.8.5"
|
||||
strum = "0.15.0"
|
||||
@@ -53,8 +53,7 @@ pretty_env_logger = "0.3.0"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"deltachat-ffi",
|
||||
"deltachat_derive",
|
||||
"deltachat-ffi"
|
||||
]
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -89,14 +89,6 @@ $ cargo test --all
|
||||
$ cargo build -p deltachat_ffi --release
|
||||
```
|
||||
|
||||
### Expensive tests
|
||||
|
||||
Some tests are expensive and marked with `#[ignore]`, to run these
|
||||
use the `--ignored` argument to the test binary (not to cargo itself):
|
||||
```sh
|
||||
$ cargo test -- --ignored
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- `vendored`: When using Openssl for TLS, this bundles a vendored version.
|
||||
|
||||
@@ -16,7 +16,7 @@ export BRANCH=${CIRCLE_BRANCH:-test7}
|
||||
#fi
|
||||
|
||||
# run everything else inside docker (TESTS, DOCS, WHEELS)
|
||||
docker run -e DCC_PY_LIVECONFIG -e BRANCH -e TESTS -e DOCS \
|
||||
docker run -e BRANCH -e TESTS -e DOCS \
|
||||
--rm -it -v $(pwd):/mnt -w /mnt \
|
||||
deltachat/coredeps ci_scripts/run_all.sh
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
|
||||
|
||||
|
||||
# python docs to py.delta.chat
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@py.delta.chat mkdir -p build/${BRANCH}
|
||||
rsync -avz \
|
||||
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
|
||||
"$PYDOCDIR/html/" \
|
||||
@@ -38,13 +37,11 @@ pip install devpi-client
|
||||
devpi use https://m.devpi.net
|
||||
devpi login dc --password $DEVPI_LOGIN
|
||||
|
||||
N_BRANCH=${BRANCH//[\/]}
|
||||
|
||||
devpi use dc/$N_BRANCH || {
|
||||
devpi index -c $N_BRANCH
|
||||
devpi use dc/$N_BRANCH
|
||||
devpi use dc/$BRANCH || {
|
||||
devpi index -c $BRANCH
|
||||
devpi use dc/$BRANCH
|
||||
}
|
||||
devpi index $N_BRANCH bases=/root/pypi
|
||||
devpi index $BRANCH bases=/root/pypi
|
||||
devpi upload deltachat*.whl
|
||||
|
||||
popd
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
set -e -x
|
||||
|
||||
# Install Rust
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-07-10 -y
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-04-19 -y
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
rustc --version
|
||||
|
||||
# remove some 300-400 MB that we don't need for automated builds
|
||||
rm -rf /root/.rustup/toolchains/nightly-2019-07-10-x86_64-unknown-linux-gnu/share/
|
||||
rm -rf /root/.rustup/toolchains/nightly-2019-04-19-x86_64-unknown-linux-gnu/share/
|
||||
|
||||
@@ -37,10 +37,6 @@ if [ -n "$TESTS" ]; then
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# run tox
|
||||
# XXX we don't run liveconfig tests because they hang sometimes
|
||||
# see https://github.com/deltachat/deltachat-core-rust/issues/331
|
||||
# unset DCC_PY_LIVECONFIG
|
||||
|
||||
tox --workdir "$TOXWORKDIR" -e lint,py27,py35,py36,py37,auditwheels
|
||||
popd
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.3"
|
||||
description = "Deltachat FFI"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
edition = "2018"
|
||||
@@ -25,3 +25,4 @@ default = ["vendored", "nightly", "ringbuf"]
|
||||
vendored = ["deltachat/vendored"]
|
||||
nightly = ["deltachat/nightly"]
|
||||
ringbuf = ["deltachat/ringbuf"]
|
||||
|
||||
|
||||
@@ -44,14 +44,11 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
Box::into_raw(Box::new(ctx))
|
||||
}
|
||||
|
||||
/// Release the context structure.
|
||||
///
|
||||
/// This function releases the memory of the `dc_context_t` structure.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) {
|
||||
assert!(!context.is_null());
|
||||
let context = &mut *context;
|
||||
context::dc_close(context);
|
||||
context::dc_context_unref(context);
|
||||
Box::from_raw(context);
|
||||
}
|
||||
|
||||
@@ -545,7 +542,7 @@ pub unsafe extern "C" fn dc_get_chat_contacts(
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
dc_array_t::from(dc_chat::dc_get_chat_contacts(context, chat_id)).into_raw()
|
||||
dc_chat::dc_get_chat_contacts(context, chat_id)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -817,7 +814,7 @@ pub unsafe extern "C" fn dc_get_contacts(
|
||||
};
|
||||
|
||||
match Contact::get_all(context, flags, query) {
|
||||
Ok(contacts) => dc_array_t::from(contacts).into_raw(),
|
||||
Ok(contacts) => contacts,
|
||||
Err(_) => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
@@ -837,7 +834,7 @@ pub unsafe extern "C" fn dc_get_blocked_contacts(
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
dc_array_t::from(Contact::get_all_blocked(context)).into_raw()
|
||||
Contact::get_all_blocked(context)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -864,12 +861,7 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo(
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
Contact::get_encrinfo(context, contact_id)
|
||||
.map(|s| s.strdup())
|
||||
.unwrap_or_else(|e| {
|
||||
error!(context, 0, "{}", e);
|
||||
std::ptr::null_mut()
|
||||
})
|
||||
Contact::get_encrinfo(context, contact_id).strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "deltachat_derive"
|
||||
version = "0.1.0"
|
||||
authors = ["Dmitry Bogatov <KAction@debian.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.14.4"
|
||||
quote = "0.6.3"
|
||||
@@ -1,45 +0,0 @@
|
||||
#![recursion_limit = "128"]
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
// For now, assume (not check) that these macroses are applied to enum without
|
||||
// data. If this assumption is violated, compiler error will point to
|
||||
// generated code, which is not very user-friendly.
|
||||
|
||||
#[proc_macro_derive(ToSql)]
|
||||
pub fn to_sql_derive(input: TokenStream) -> TokenStream {
|
||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
|
||||
let gen = quote! {
|
||||
impl rusqlite::types::ToSql for #name {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
||||
let num = *self as i64;
|
||||
let value = rusqlite::types::Value::Integer(num);
|
||||
let output = rusqlite::types::ToSqlOutput::Owned(value);
|
||||
|
||||
std::result::Result::Ok(output)
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(FromSql)]
|
||||
pub fn from_sql_derive(input: TokenStream) -> TokenStream {
|
||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
|
||||
let gen = quote! {
|
||||
impl rusqlite::types::FromSql for #name {
|
||||
fn column_result(col: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let inner = rusqlite::types::FromSql::column_result(col)?;
|
||||
num_traits::FromPrimitive::from_i64(inner).ok_or(rusqlite::types::FromSqlError::InvalidType)
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
@@ -125,7 +125,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
|
||||
let ok_to_continue;
|
||||
let mut current_block: u64;
|
||||
let mut success: libc::c_int = 0;
|
||||
let real_spec: *mut libc::c_char;
|
||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -138,71 +138,77 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
||||
.unwrap();
|
||||
ok_to_continue = true;
|
||||
current_block = 7149356873433890176;
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
if rs.is_none() {
|
||||
error!(context, 0, "Import: No file or folder given.");
|
||||
ok_to_continue = false;
|
||||
current_block = 8522321847195001863;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 7149356873433890176;
|
||||
}
|
||||
real_spec = rs.unwrap_or_default().strdup();
|
||||
}
|
||||
if ok_to_continue {
|
||||
let ok_to_continue2;
|
||||
suffix = dc_get_filesuffix_lc(real_spec);
|
||||
if !suffix.is_null() && strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
||||
read_cnt += 1
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
ok_to_continue2 = false;
|
||||
match current_block {
|
||||
8522321847195001863 => {}
|
||||
_ => {
|
||||
suffix = dc_get_filesuffix_lc(real_spec);
|
||||
if !suffix.is_null()
|
||||
&& strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
||||
read_cnt += 1
|
||||
}
|
||||
current_block = 1622411330066726685;
|
||||
} else {
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, 0, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
read_cnt += 1
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
current_block = 8522321847195001863;
|
||||
} else {
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, 0, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
read_cnt += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
current_block = 1622411330066726685;
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
}
|
||||
}
|
||||
if ok_to_continue2 {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
|
||||
match current_block {
|
||||
8522321847195001863 => {}
|
||||
_ => {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,12 +301,13 @@ unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
||||
let mut contacts = contacts.clone();
|
||||
if !contacts.contains(&1) {
|
||||
contacts.push(1);
|
||||
unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) {
|
||||
if !dc_array_search_id(contacts, 1 as uint32_t, 0 as *mut size_t) {
|
||||
dc_array_add_id(contacts, 1 as uint32_t);
|
||||
}
|
||||
for contact_id in contacts {
|
||||
let cnt = dc_array_get_cnt(contacts);
|
||||
for i in 0..cnt {
|
||||
let contact_id = dc_array_get_id(contacts, i as size_t);
|
||||
let line;
|
||||
let mut line2 = "".to_string();
|
||||
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
|
||||
@@ -464,7 +471,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
event <event-id to test>\n\
|
||||
fileinfo <file>\n\
|
||||
clear -- clear screen\n\
|
||||
exit or quit\n\
|
||||
exit\n\
|
||||
============================================="
|
||||
),
|
||||
},
|
||||
@@ -597,13 +604,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"listchats" | "listarchived" | "chats" => {
|
||||
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
||||
let chatlist = Chatlist::try_load(
|
||||
context,
|
||||
listflags,
|
||||
if arg1.is_empty() { None } else { Some(arg1) },
|
||||
None,
|
||||
)?;
|
||||
let chatlist = Chatlist::try_load(context, listflags, Some(arg1), None)?;
|
||||
|
||||
let mut i: usize;
|
||||
let cnt = chatlist.len();
|
||||
if cnt > 0 {
|
||||
info!(
|
||||
@@ -611,7 +614,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
for i in (0..cnt).rev() {
|
||||
i = cnt - 1;
|
||||
|
||||
while i > 0 {
|
||||
let chat = dc_get_chat(context, chatlist.get_chat_id(i));
|
||||
let temp_subtitle = dc_chat_get_subtitle(chat);
|
||||
let temp_name = dc_chat_get_name(chat);
|
||||
@@ -665,6 +670,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
context, 0,
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
i -= 1
|
||||
}
|
||||
}
|
||||
if dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
|
||||
@@ -828,14 +835,16 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(!sel_chat.is_null(), "No chat selected.");
|
||||
|
||||
let contacts = dc_get_chat_contacts(context, dc_chat_get_id(sel_chat));
|
||||
ensure!(!contacts.is_null(), "Failed to retreive contacts");
|
||||
info!(context, 0, "Memberlist:");
|
||||
|
||||
log_contactlist(context, &contacts);
|
||||
log_contactlist(context, contacts);
|
||||
println!(
|
||||
"{} contacts\nLocation streaming: {}",
|
||||
contacts.len(),
|
||||
dc_array_get_cnt(contacts),
|
||||
dc_is_sending_locations_to_chat(context, dc_chat_get_id(sel_chat)),
|
||||
);
|
||||
dc_array_unref(contacts);
|
||||
}
|
||||
"getlocations" => {
|
||||
let contact_id = arg1.parse().unwrap_or_default();
|
||||
@@ -1055,8 +1064,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
},
|
||||
Some(arg1),
|
||||
)?;
|
||||
log_contactlist(context, &contacts);
|
||||
println!("{} contacts.", contacts.len());
|
||||
if !contacts.is_null() {
|
||||
log_contactlist(context, contacts);
|
||||
println!("{} contacts.", dc_array_get_cnt(contacts) as libc::c_int,);
|
||||
dc_array_unref(contacts);
|
||||
} else {
|
||||
bail!("");
|
||||
}
|
||||
}
|
||||
"addcontact" => {
|
||||
ensure!(!arg1.is_empty(), "Arguments [<name>] <addr> expected.");
|
||||
@@ -1077,7 +1091,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
|
||||
let mut res = format!("Contact info for: {}:\n\n", name_n_addr);
|
||||
|
||||
res += &Contact::get_encrinfo(context, contact_id)?;
|
||||
res += &Contact::get_encrinfo(context, contact_id);
|
||||
|
||||
let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?;
|
||||
let chatlist_cnt = chatlist.len();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//!
|
||||
//! Usage: cargo run --example repl --release -- <databasefile>
|
||||
//! All further options can be set using the set-command (type ? for help).
|
||||
#![feature(ptr_cast)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate deltachat;
|
||||
@@ -334,8 +335,8 @@ const CONTACT_COMMANDS: [&'static str; 6] = [
|
||||
"delcontact",
|
||||
"cleanupcontacts",
|
||||
];
|
||||
const MISC_COMMANDS: [&'static str; 9] = [
|
||||
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "quit", "help",
|
||||
const MISC_COMMANDS: [&'static str; 8] = [
|
||||
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "help",
|
||||
];
|
||||
|
||||
impl Hinter for DcHelper {
|
||||
@@ -455,6 +456,12 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
||||
println!("history saved");
|
||||
{
|
||||
stop_threads(&ctx.read().unwrap());
|
||||
|
||||
unsafe {
|
||||
let mut ctx = ctx.write().unwrap();
|
||||
dc_close(&mut ctx);
|
||||
dc_context_unref(&mut ctx);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -549,7 +556,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
|
||||
}
|
||||
}
|
||||
"exit" | "quit" => return Ok(ExitResult::Exit),
|
||||
"exit" => return Ok(ExitResult::Exit),
|
||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ without any "build-from-source" steps.
|
||||
1. `Install virtualenv <https://virtualenv.pypa.io/en/stable/installation/>`_,
|
||||
then create a fresh python environment and activate it in your shell::
|
||||
|
||||
virtualenv venv # or: python -m venv
|
||||
virtualenv -p python3 venv
|
||||
source venv/bin/activate
|
||||
|
||||
Afterwards, invoking ``python`` or ``pip install`` will only
|
||||
@@ -39,12 +39,6 @@ and push them to a python package index. To install the latest github ``master``
|
||||
|
||||
pip install -i https://m.devpi.net/dc/master deltachat
|
||||
|
||||
.. note::
|
||||
|
||||
If you can help to automate the building of wheels for Mac or Windows,
|
||||
that'd be much appreciated! please then get
|
||||
`in contact with us <https://delta.chat/en/contribute>`_.
|
||||
|
||||
|
||||
Installing bindings from source
|
||||
===============================
|
||||
@@ -54,55 +48,34 @@ to core deltachat library::
|
||||
|
||||
git clone https://github.com/deltachat/deltachat-core-rust
|
||||
cd deltachat-core-rust
|
||||
cargo build -p deltachat_ffi --release
|
||||
|
||||
This will result in a ``libdeltachat.so`` and ``libdeltachat.a`` files
|
||||
in the ``target/release`` directory. These files are needed for
|
||||
creating the python bindings for deltachat::
|
||||
|
||||
cd python
|
||||
DCC_RS_DEV=`pwd`/.. pip install -e .
|
||||
|
||||
If you don't have one active, create and activate a python "virtualenv":
|
||||
Now test if the bindings find the correct library::
|
||||
|
||||
python virtualenv venv # or python -m venv
|
||||
source venv/bin/activate
|
||||
python -c 'import deltachat ; print(deltachat.__version__)'
|
||||
|
||||
Afterwards ``which python`` tells you that it comes out of the "venv"
|
||||
directory that contains all python install artifacts. Let's first
|
||||
install test tools::
|
||||
|
||||
pip install pytest pytest-timeout requests
|
||||
|
||||
then cargo-build and install the deltachat bindings::
|
||||
|
||||
python install_python_bindings.py
|
||||
|
||||
The bindings will be installed in release mode but with debug symbols.
|
||||
The release mode is neccessary because some tests generate RSA keys
|
||||
which is prohibitively slow in debug mode.
|
||||
|
||||
After succcessul binding installation you can finally run the tests::
|
||||
|
||||
pytest -v tests
|
||||
This should print your deltachat bindings version.
|
||||
|
||||
.. note::
|
||||
|
||||
Some tests are sometimes failing/hanging because of
|
||||
https://github.com/deltachat/deltachat-core-rust/issues/331
|
||||
and
|
||||
https://github.com/deltachat/deltachat-core-rust/issues/326
|
||||
If you can help to automate the building of wheels for Mac or Windows,
|
||||
that'd be much appreciated! please then get
|
||||
`in contact with us <https://delta.chat/en/contribute>`_.
|
||||
|
||||
Using a system-installed deltachat-core-rust
|
||||
--------------------------------------------
|
||||
|
||||
running "live" tests (experimental)
|
||||
-----------------------------------
|
||||
|
||||
If you want to run "liveconfig" functional tests you can set
|
||||
``DCC_PY_LIVECONFIG`` to:
|
||||
|
||||
- a particular https-url that you can ask for from the delta
|
||||
chat devs.
|
||||
|
||||
- or the path of a file that contains two lines, each describing
|
||||
via "addr=... mail_pwd=..." a test account login that will
|
||||
be used for the live tests.
|
||||
|
||||
With ``DCC_PY_LIVECONFIG`` set pytest invocations will use real
|
||||
e-mail accounts and run through all functional "liveconfig" tests.
|
||||
|
||||
When calling ``pip`` without specifying the ``DCC_RS_DEV`` environment
|
||||
variable cffi will try to use a ``deltachat.h`` from a system location
|
||||
like ``/usr/local/include`` and will try to dynamically link against a
|
||||
``libdeltachat.so`` in a similar location (e.g. ``/usr/local/lib``).
|
||||
|
||||
|
||||
Code examples
|
||||
@@ -111,34 +84,68 @@ Code examples
|
||||
You may look at `examples <https://py.delta.chat/examples.html>`_.
|
||||
|
||||
|
||||
Running tests
|
||||
=============
|
||||
|
||||
Get a checkout of the `deltachat-core-rust github repository`_ and type::
|
||||
|
||||
pip install tox
|
||||
./run-integration-tests.sh
|
||||
|
||||
If you want to run functional tests with real
|
||||
e-mail test accounts, generate a "liveconfig" file where each
|
||||
lines contains test account settings, for example::
|
||||
|
||||
# 'liveconfig' file specifying imap/smtp accounts
|
||||
addr=some-email@example.org mail_pw=password
|
||||
addr=other-email@example.org mail_pw=otherpassword
|
||||
|
||||
The "keyword=value" style allows to specify any
|
||||
`deltachat account config setting <https://c.delta.chat/classdc__context__t.html#aff3b894f6cfca46cab5248fdffdf083d>`_ so you can also specify smtp or imap servers, ports, ssl modes etc.
|
||||
Typically DC's automatic configuration allows to not specify these settings.
|
||||
|
||||
The ``run-integration-tests.sh`` script will automatically use
|
||||
``python/liveconfig`` if it exists, to manually run tests with this
|
||||
``liveconfig`` file use::
|
||||
|
||||
tox -- --liveconfig liveconfig
|
||||
|
||||
|
||||
.. _`deltachat-core-rust github repository`: https://github.com/deltachat/deltachat-core-rust
|
||||
.. _`deltachat-core`: https://github.com/deltachat/deltachat-core-rust
|
||||
|
||||
Running test using a debug build
|
||||
--------------------------------
|
||||
|
||||
If you need to examine e.g. a coredump you may want to run the tests
|
||||
using a debug build::
|
||||
|
||||
DCC_RS_TARGET=debug ./run-integration-tests.sh -e py37 -- -x -v -k failing_test
|
||||
|
||||
|
||||
Building manylinux1 wheels
|
||||
==========================
|
||||
|
||||
.. note::
|
||||
|
||||
This section may not fully work.
|
||||
|
||||
Building portable manylinux1 wheels which come with libdeltachat.so
|
||||
and all it's dependencies is easy using the provided docker tooling.
|
||||
|
||||
using docker pull / premade images
|
||||
------------------------------------
|
||||
|
||||
We publish a build environment under the ``deltachat/coredeps`` tag so
|
||||
We publish a build environment under the ``deltachat/wheel`` tag so
|
||||
that you can pull it from the ``hub.docker.com`` site's "deltachat"
|
||||
organization::
|
||||
|
||||
$ docker pull deltachat/coredeps
|
||||
$ docker pull deltachat/wheel
|
||||
|
||||
This docker image can be used to run tests and build Python wheels for all interpreters::
|
||||
The ``deltachat/wheel`` image can be used to build both libdeltachat.so
|
||||
and the Python wheels::
|
||||
|
||||
$ bash ci_scripts/ci_run.sh
|
||||
$ docker run --rm -it -v $(pwd):/io/ deltachat/wheel /io/python/wheelbuilder/build-wheels.sh
|
||||
|
||||
This command runs tests and build-wheel scripts in a docker container.
|
||||
This command runs a script within the image, after mounting ``$(pwd)`` as ``/io`` within
|
||||
the docker image. The script is specified as a path within the docker image's filesystem.
|
||||
The resulting wheel files will be in ``python/wheelhouse``.
|
||||
|
||||
|
||||
Optionally build your own docker image
|
||||
@@ -147,10 +154,10 @@ Optionally build your own docker image
|
||||
If you want to build your own custom docker image you can do this::
|
||||
|
||||
$ cd deltachat-core # cd to deltachat-core checkout directory
|
||||
$ docker build -t deltachat/coredeps ci_scripts/docker_coredeps
|
||||
$ docker build -t deltachat/wheel python/wheelbuilder/
|
||||
|
||||
This will use the ``ci_scripts/docker_coredeps/Dockerfile`` to build
|
||||
up docker image called ``deltachat/coredeps``. You can afterwards
|
||||
This will use the ``python/wheelbuilder/Dockerfile`` to build
|
||||
up docker image called ``deltachat/wheel``. You can afterwards
|
||||
find it with::
|
||||
|
||||
$ docker images
|
||||
|
||||
@@ -37,3 +37,16 @@ Message
|
||||
.. autoclass:: deltachat.message.Message
|
||||
:members:
|
||||
|
||||
MessageType
|
||||
------------
|
||||
|
||||
.. autoclass:: deltachat.message.MessageType
|
||||
:members:
|
||||
|
||||
MessageState
|
||||
------------
|
||||
|
||||
.. autoclass:: deltachat.message.MessageState
|
||||
:members:
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ Playing around on the commandline
|
||||
----------------------------------
|
||||
|
||||
Once you have :doc:`installed deltachat bindings <install>`
|
||||
you can start playing from the python interpreter commandline.
|
||||
you can start playing from the python interpreter commandline::
|
||||
|
||||
For example you can type ``python`` and then::
|
||||
|
||||
# instantiate and configure deltachat account
|
||||
|
||||
@@ -6,18 +6,29 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ["DCC_RS_TARGET"] = target = "release"
|
||||
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
|
||||
|
||||
os.environ["RUSTFLAGS"] = "-g"
|
||||
subprocess.check_call([
|
||||
"cargo", "build", "-p", "deltachat_ffi", "--" + target
|
||||
])
|
||||
toml = os.path.join(os.getcwd(), "..", "Cargo.toml")
|
||||
assert os.path.exists(toml)
|
||||
with open(toml) as f:
|
||||
s = orig = f.read()
|
||||
s += "\n"
|
||||
s += "[profile.release]\n"
|
||||
s += "debug = true\n"
|
||||
with open(toml, "w") as f:
|
||||
f.write(s)
|
||||
print("temporarily modifying Cargo.toml to provide release build with debug symbols ")
|
||||
try:
|
||||
subprocess.check_call([
|
||||
"cargo", "build", "-p", "deltachat_ffi", "--" + target
|
||||
])
|
||||
finally:
|
||||
with open(toml, "w") as f:
|
||||
f.write(orig)
|
||||
print("\nreseted Cargo.toml to previous original state")
|
||||
|
||||
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
|
||||
|
||||
subprocess.check_call([
|
||||
|
||||
@@ -6,15 +6,10 @@ import platform
|
||||
import os
|
||||
import cffi
|
||||
import shutil
|
||||
from os.path import dirname as dn
|
||||
from os.path import abspath
|
||||
|
||||
|
||||
def ffibuilder():
|
||||
projdir = os.environ.get('DCC_RS_DEV')
|
||||
if not projdir:
|
||||
p = dn(dn(dn(dn(abspath(__file__)))))
|
||||
projdir = os.environ["DCC_RS_DEV"] = p
|
||||
target = os.environ.get('DCC_RS_TARGET', 'release')
|
||||
if projdir:
|
||||
if platform.system() == 'Darwin':
|
||||
|
||||
@@ -50,9 +50,8 @@ class Account(object):
|
||||
self._configkeys = self.get_config("sys.config_keys").split()
|
||||
self._imex_completed = threading.Event()
|
||||
|
||||
# XXX this can cause "illegal instructions" at test ends so we omit it for now
|
||||
# def __del__(self):
|
||||
# self.shutdown()
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
|
||||
def _check_config_key(self, name):
|
||||
if name not in self._configkeys:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
from deltachat import Account
|
||||
from deltachat import props
|
||||
from deltachat.capi import lib
|
||||
import tempfile
|
||||
|
||||
@@ -36,8 +36,6 @@ def pytest_runtest_call(item):
|
||||
|
||||
|
||||
def pytest_report_header(config, startdir):
|
||||
summary = []
|
||||
|
||||
t = tempfile.mktemp()
|
||||
try:
|
||||
ac = Account(t, eventlogging=False)
|
||||
@@ -45,18 +43,13 @@ def pytest_report_header(config, startdir):
|
||||
ac.shutdown()
|
||||
finally:
|
||||
os.remove(t)
|
||||
summary.extend(['Deltachat core={} sqlite={}'.format(
|
||||
summary = ['Deltachat core={} sqlite={}'.format(
|
||||
info['deltachat_core_version'],
|
||||
info['sqlite_version'],
|
||||
)])
|
||||
|
||||
cfg = config.option.liveconfig
|
||||
)]
|
||||
cfg = config.getoption('--liveconfig')
|
||||
if cfg:
|
||||
if "#" in cfg:
|
||||
url, token = cfg.split("#", 1)
|
||||
summary.append('Liveconfig provider: {}#<token ommitted>'.format(url))
|
||||
else:
|
||||
summary.append('Liveconfig file: {}'.format(cfg))
|
||||
summary.append('Liveconfig: {}'.format(os.path.abspath(cfg)))
|
||||
return summary
|
||||
|
||||
|
||||
@@ -73,56 +66,9 @@ def data():
|
||||
return Data()
|
||||
|
||||
|
||||
class SessionLiveConfigFromFile:
|
||||
def __init__(self, fn):
|
||||
self.fn = fn
|
||||
self.configlist = []
|
||||
for line in open(fn):
|
||||
if line.strip() and not line.strip().startswith('#'):
|
||||
d = {}
|
||||
for part in line.split():
|
||||
name, value = part.split("=")
|
||||
d[name] = value
|
||||
self.configlist.append(d)
|
||||
|
||||
def get(self, index):
|
||||
return self.configlist[index]
|
||||
|
||||
def exists(self):
|
||||
return bool(self.configlist)
|
||||
|
||||
|
||||
class SessionLiveConfigFromURL:
|
||||
def __init__(self, url, create_token):
|
||||
self.configlist = []
|
||||
for i in range(2):
|
||||
res = requests.post(url, json={"token_create_user": int(create_token)})
|
||||
if res.status_code != 200:
|
||||
pytest.skip("creating newtmpuser failed {!r}".format(res))
|
||||
d = res.json()
|
||||
config = dict(addr=d["email"], mail_pw=d["password"])
|
||||
self.configlist.append(config)
|
||||
|
||||
def get(self, index):
|
||||
return self.configlist[index]
|
||||
|
||||
def exists(self):
|
||||
return bool(self.configlist)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def session_liveconfig(request):
|
||||
liveconfig_opt = request.config.option.liveconfig
|
||||
if liveconfig_opt:
|
||||
if liveconfig_opt.startswith("http"):
|
||||
url, create_token = liveconfig_opt.split("#", 1)
|
||||
return SessionLiveConfigFromURL(url, create_token)
|
||||
else:
|
||||
return SessionLiveConfigFromFile(liveconfig_opt)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
def acfactory(pytestconfig, tmpdir, request):
|
||||
fn = pytestconfig.getoption("--liveconfig")
|
||||
|
||||
class AccountMaker:
|
||||
def __init__(self):
|
||||
@@ -136,6 +82,18 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
fin = self._finalizers.pop()
|
||||
fin()
|
||||
|
||||
@props.cached
|
||||
def configlist(self):
|
||||
configlist = []
|
||||
for line in open(fn):
|
||||
if line.strip() and not line.strip().startswith('#'):
|
||||
d = {}
|
||||
for part in line.split():
|
||||
name, value = part.split("=")
|
||||
d[name] = value
|
||||
configlist.append(d)
|
||||
return configlist
|
||||
|
||||
def get_unconfigured_account(self):
|
||||
self.offline_count += 1
|
||||
tmpdb = tmpdir.join("offlinedb%d" % self.offline_count)
|
||||
@@ -158,10 +116,10 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
return ac
|
||||
|
||||
def get_online_configuring_account(self):
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
configdict = session_liveconfig.get(self.live_count)
|
||||
if not fn:
|
||||
pytest.skip("specify a --liveconfig file to run tests with real accounts")
|
||||
self.live_count += 1
|
||||
configdict = self.configlist.pop(0)
|
||||
if "e2ee_enabled" not in configdict:
|
||||
configdict["e2ee_enabled"] = "1"
|
||||
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
||||
|
||||
@@ -19,7 +19,6 @@ deps =
|
||||
pytest
|
||||
pytest-faulthandler
|
||||
pdbpp
|
||||
requests
|
||||
|
||||
[testenv:auditwheels]
|
||||
skipsdist = True
|
||||
@@ -52,7 +51,6 @@ commands =
|
||||
|
||||
|
||||
[pytest]
|
||||
addopts = -v -rs
|
||||
python_files = tests/test_*.py
|
||||
norecursedirs = .tox
|
||||
xfail_strict=true
|
||||
|
||||
@@ -23,7 +23,7 @@ if [ $? != 0 ]; then
|
||||
fi
|
||||
|
||||
pushd python
|
||||
if [ -e "./liveconfig" && -z "$DCC_PY_LIVECONFIG" ]; then
|
||||
if [ -e "./liveconfig" ]; then
|
||||
export DCC_PY_LIVECONFIG=liveconfig
|
||||
fi
|
||||
tox "$@"
|
||||
|
||||
@@ -1 +1 @@
|
||||
nightly-2019-08-13
|
||||
nightly-2019-07-10
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::dc_msg::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Result;
|
||||
use crate::stock::StockMessage;
|
||||
use std::ptr;
|
||||
|
||||
/// An object representing a single chatlist in memory.
|
||||
///
|
||||
@@ -291,7 +290,7 @@ impl<'a> Chatlist<'a> {
|
||||
};
|
||||
|
||||
if (*chat).id == DC_CHAT_ID_ARCHIVED_LINK as u32 {
|
||||
(*ret).text2 = dc_strdup(ptr::null())
|
||||
(*ret).text2 = dc_strdup(0 as *const libc::c_char)
|
||||
} else if lastmsg.is_null() || (*lastmsg).from_id == DC_CONTACT_ID_UNDEFINED as u32 {
|
||||
(*ret).text2 = self.context.stock_str(StockMessage::NoMessages).strdup();
|
||||
} else {
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Context {
|
||||
let rel_path = self.sql.get_config(self, key);
|
||||
rel_path.map(|p| dc_get_abs_path_safe(self, &p).to_str().unwrap().to_string())
|
||||
}
|
||||
Config::SysVersion => Some((&*DC_VERSION_STR).clone()),
|
||||
Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()),
|
||||
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
|
||||
Config::SysConfigKeys => Some(get_config_keys_string()),
|
||||
_ => self.sql.get_config(self, key),
|
||||
@@ -120,7 +120,8 @@ impl Context {
|
||||
value
|
||||
};
|
||||
|
||||
self.sql.set_config(self, key, val)
|
||||
let ret = self.sql.set_config(self, key, val);
|
||||
ret
|
||||
}
|
||||
_ => self.sql.set_config(self, key, value),
|
||||
}
|
||||
|
||||
@@ -1,40 +1,15 @@
|
||||
//! Constants
|
||||
#![allow(non_camel_case_types)]
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use rusqlite as sql;
|
||||
use rusqlite::types::*;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
|
||||
|
||||
use deltachat_derive::*;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DC_VERSION_STR: String = env!("CARGO_PKG_VERSION").to_string();
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)]
|
||||
pub enum MoveState {
|
||||
Undefined = 0,
|
||||
Pending = 1,
|
||||
Stay = 2,
|
||||
Moving = 3,
|
||||
}
|
||||
|
||||
// some defaults
|
||||
pub const DC_E2EE_DEFAULT_ENABLED: i32 = 1;
|
||||
pub const DC_MDNS_DEFAULT_ENABLED: i32 = 1;
|
||||
pub const DC_INBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_SENTBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_MVBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_MVBOX_MOVE_DEFAULT: i32 = 1;
|
||||
|
||||
pub const DC_CHAT_NOT_BLOCKED: i32 = 0;
|
||||
pub const DC_CHAT_MANUALLY_BLOCKED: i32 = 1;
|
||||
pub const DC_CHAT_DEADDROP_BLOCKED: i32 = 2;
|
||||
|
||||
pub const DC_IMAP_SEEN: u32 = 0x1;
|
||||
|
||||
pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
|
||||
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
|
||||
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
|
||||
pub const DC_MOVE_STATE_MOVING: u32 = 3;
|
||||
pub const DC_MOVE_STATE_STAY: u32 = 2;
|
||||
pub const DC_MOVE_STATE_PENDING: u32 = 1;
|
||||
pub const DC_MOVE_STATE_UNDEFINED: u32 = 0;
|
||||
|
||||
pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01;
|
||||
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
|
||||
@@ -172,7 +147,7 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
|
||||
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(i32)]
|
||||
pub enum Viewtype {
|
||||
Unknown = 0,
|
||||
@@ -227,6 +202,23 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for Viewtype {
|
||||
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
|
||||
let num: i64 = self
|
||||
.to_i64()
|
||||
.expect("impossible: Viewtype -> i64 conversion failed");
|
||||
|
||||
Ok(ToSqlOutput::Owned(Value::Integer(num)))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Viewtype {
|
||||
fn column_result(col: ValueRef) -> FromSqlResult<Self> {
|
||||
let inner = FromSql::column_result(col)?;
|
||||
FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType)
|
||||
}
|
||||
}
|
||||
|
||||
// These constants are used as events
|
||||
// reported to the callback given to dc_context_new().
|
||||
// If you do not want to handle an event, it is always safe to return 0,
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::aheader::EncryptPreference;
|
||||
use crate::config::Config;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_e2ee::*;
|
||||
use crate::dc_loginparam::*;
|
||||
use crate::dc_tools::*;
|
||||
@@ -471,13 +472,13 @@ impl<'a> Contact<'a> {
|
||||
context: &Context,
|
||||
listflags: u32,
|
||||
query: Option<impl AsRef<str>>,
|
||||
) -> Result<Vec<u32>> {
|
||||
) -> Result<*mut dc_array_t> {
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut add_self = false;
|
||||
let mut ret = Vec::new();
|
||||
let mut ret = dc_array_t::new(100);
|
||||
|
||||
if (listflags & DC_GCL_VERIFIED_ONLY) > 0 || query.is_some() {
|
||||
let s3str_like_cmd = format!(
|
||||
@@ -508,7 +509,7 @@ impl<'a> Contact<'a> {
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
for id in ids {
|
||||
ret.push(id? as u32);
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
@@ -536,7 +537,7 @@ impl<'a> Contact<'a> {
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
for id in ids {
|
||||
ret.push(id? as u32);
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -544,10 +545,10 @@ impl<'a> Contact<'a> {
|
||||
}
|
||||
|
||||
if 0 != listflags & DC_GCL_ADD_SELF as u32 && add_self {
|
||||
ret.push(DC_CONTACT_ID_SELF as u32);
|
||||
ret.add_id(DC_CONTACT_ID_SELF as u32);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
Ok(ret.into_raw())
|
||||
}
|
||||
|
||||
pub fn get_blocked_cnt(context: &Context) -> usize {
|
||||
@@ -563,27 +564,27 @@ impl<'a> Contact<'a> {
|
||||
}
|
||||
|
||||
/// Get blocked contacts.
|
||||
pub fn get_all_blocked(context: &Context) -> Vec<u32> {
|
||||
pub fn get_all_blocked(context: &Context) -> *mut dc_array_t {
|
||||
context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(name||addr),id;",
|
||||
params![DC_CONTACT_ID_LAST_SPECIAL as i32],
|
||||
|row| row.get::<_, u32>(0),
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
ids.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.map_err(Into::into)
|
||||
let mut ret = dc_array_t::new(100);
|
||||
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
|
||||
Ok(ret.into_raw())
|
||||
},
|
||||
)
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|_| std::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns a textual summary of the encryption state for the contact.
|
||||
///
|
||||
/// This function returns a string explaining the encryption state
|
||||
/// of the contact and if the connection is encrypted the
|
||||
/// fingerprints of the keys involved.
|
||||
pub fn get_encrinfo(context: &Context, contact_id: u32) -> Result<String> {
|
||||
pub fn get_encrinfo(context: &Context, contact_id: u32) -> String {
|
||||
let mut ret = String::new();
|
||||
|
||||
if let Ok(contact) = Contact::load_from_db(context, contact_id) {
|
||||
@@ -602,7 +603,7 @@ impl<'a> Contact<'a> {
|
||||
});
|
||||
ret += &p;
|
||||
if self_key.is_none() {
|
||||
dc_ensure_secret_key_exists(context)?;
|
||||
unsafe { dc_ensure_secret_key_exists(context) };
|
||||
self_key = Key::from_self_public(context, &loginparam.addr, &context.sql);
|
||||
}
|
||||
let p = context.stock_str(StockMessage::FingerPrints);
|
||||
@@ -645,7 +646,7 @@ impl<'a> Contact<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
ret
|
||||
}
|
||||
|
||||
/// Delete a contact. The contact is deleted from the local device. It may happen that this is not
|
||||
@@ -909,7 +910,20 @@ pub fn get_first_name<'a>(full_name: &'a str) -> &'a str {
|
||||
|
||||
/// Returns false if addr is an invalid address, otherwise true.
|
||||
pub fn may_be_valid_addr(addr: &str) -> bool {
|
||||
addr.parse::<EmailAddress>().is_ok()
|
||||
if addr.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let at = addr.find('@').unwrap_or_default();
|
||||
if at < 1 {
|
||||
return false;
|
||||
}
|
||||
let dot = addr.find('.').unwrap_or_default();
|
||||
if dot < 1 || dot > addr.len() - 3 || dot < at + 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn addr_normalize(addr: &str) -> &str {
|
||||
|
||||
120
src/context.rs
120
src/context.rs
@@ -19,13 +19,11 @@ use crate::smtp::*;
|
||||
use crate::sql::Sql;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
pub userdata: *mut libc::c_void,
|
||||
pub dbfile: Arc<RwLock<Option<PathBuf>>>,
|
||||
pub dbfile: Arc<RwLock<*mut libc::c_char>>,
|
||||
pub blobdir: Arc<RwLock<*mut libc::c_char>>,
|
||||
pub sql: Sql,
|
||||
pub inbox: Arc<RwLock<Imap>>,
|
||||
@@ -42,8 +40,6 @@ pub struct Context {
|
||||
pub bob: Arc<RwLock<BobStatus>>,
|
||||
pub last_smeared_timestamp: Arc<RwLock<i64>>,
|
||||
pub running_state: Arc<RwLock<RunningState>>,
|
||||
/// Mutex to avoid generating the key for the user more than once.
|
||||
pub generating_key_mutex: Mutex<()>,
|
||||
}
|
||||
|
||||
unsafe impl std::marker::Send for Context {}
|
||||
@@ -57,17 +53,15 @@ pub struct RunningState {
|
||||
|
||||
impl Context {
|
||||
pub fn has_dbfile(&self) -> bool {
|
||||
self.get_dbfile().is_some()
|
||||
!self.get_dbfile().is_null()
|
||||
}
|
||||
|
||||
pub fn has_blobdir(&self) -> bool {
|
||||
!self.get_blobdir().is_null()
|
||||
}
|
||||
|
||||
pub fn get_dbfile(&self) -> Option<PathBuf> {
|
||||
(*self.dbfile.clone().read().unwrap())
|
||||
.as_ref()
|
||||
.map(|x| x.clone())
|
||||
pub fn get_dbfile(&self) -> *const libc::c_char {
|
||||
*self.dbfile.clone().read().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_blobdir(&self) -> *const libc::c_char {
|
||||
@@ -83,14 +77,6 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dc_close(&self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RunningState {
|
||||
fn default() -> Self {
|
||||
RunningState {
|
||||
@@ -134,7 +120,7 @@ pub fn dc_context_new(
|
||||
) -> Context {
|
||||
Context {
|
||||
blobdir: Arc::new(RwLock::new(std::ptr::null_mut())),
|
||||
dbfile: Arc::new(RwLock::new(None)),
|
||||
dbfile: Arc::new(RwLock::new(std::ptr::null_mut())),
|
||||
inbox: Arc::new(RwLock::new({
|
||||
Imap::new(
|
||||
cb_get_config,
|
||||
@@ -145,7 +131,7 @@ pub fn dc_context_new(
|
||||
})),
|
||||
userdata,
|
||||
cb,
|
||||
os_name,
|
||||
os_name: os_name,
|
||||
running_state: Arc::new(RwLock::new(Default::default())),
|
||||
sql: Sql::new(),
|
||||
smtp: Arc::new(Mutex::new(Smtp::new())),
|
||||
@@ -176,7 +162,16 @@ pub fn dc_context_new(
|
||||
))),
|
||||
probe_imap_network: Arc::new(RwLock::new(false)),
|
||||
perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
|
||||
generating_key_mutex: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn no_crashes_on_context_deref() {
|
||||
let mut ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
|
||||
unsafe { dc_context_unref(&mut ctx) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +201,7 @@ unsafe fn cb_precheck_imf(
|
||||
) -> libc::c_int {
|
||||
let mut rfc724_mid_exists: libc::c_int = 0i32;
|
||||
let msg_id: uint32_t;
|
||||
let mut old_server_folder: *mut libc::c_char = ptr::null_mut();
|
||||
let mut old_server_folder: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut old_server_uid: uint32_t = 0i32 as uint32_t;
|
||||
let mut mark_seen: libc::c_int = 0i32;
|
||||
msg_id = dc_rfc724_mid_exists(
|
||||
@@ -234,7 +229,7 @@ unsafe fn cb_precheck_imf(
|
||||
"[move] detected moved message {}",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
|
||||
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
}
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
@@ -245,7 +240,7 @@ unsafe fn cb_precheck_imf(
|
||||
}
|
||||
}
|
||||
free(old_server_folder as *mut libc::c_void);
|
||||
rfc724_mid_exists
|
||||
return rfc724_mid_exists;
|
||||
}
|
||||
|
||||
fn cb_set_config(context: &Context, key: &str, value: Option<&str>) {
|
||||
@@ -263,6 +258,12 @@ fn cb_get_config(context: &Context, key: &str) -> Option<String> {
|
||||
context.sql.get_config(context, key)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_context_unref(context: &mut Context) {
|
||||
if 0 != dc_is_open(context) {
|
||||
dc_close(context);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_close(context: &Context) {
|
||||
info!(context, 0, "disconnecting INBOX-watch",);
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
@@ -286,14 +287,18 @@ pub unsafe fn dc_close(context: &Context) {
|
||||
|
||||
context.sql.close(context);
|
||||
let mut dbfile = context.dbfile.write().unwrap();
|
||||
*dbfile = None;
|
||||
free(*dbfile as *mut libc::c_void);
|
||||
*dbfile = 0 as *mut libc::c_char;
|
||||
let mut blobdir = context.blobdir.write().unwrap();
|
||||
free(*blobdir as *mut libc::c_void);
|
||||
*blobdir = ptr::null_mut();
|
||||
*blobdir = 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_is_open(context: &Context) -> libc::c_int {
|
||||
context.sql.is_open() as libc::c_int
|
||||
match context.sql.is_open() {
|
||||
true => 1,
|
||||
false => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_userdata(context: &mut Context) -> *mut libc::c_void {
|
||||
@@ -305,14 +310,14 @@ pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) ->
|
||||
if 0 != dc_is_open(context) {
|
||||
return false;
|
||||
}
|
||||
*context.dbfile.write().unwrap() = Some(PathBuf::from(dbfile));
|
||||
if blobdir.is_some() && !blobdir.unwrap().is_empty() {
|
||||
*context.dbfile.write().unwrap() = dbfile.strdup();
|
||||
if blobdir.is_some() && blobdir.unwrap().len() > 0 {
|
||||
let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup();
|
||||
*context.blobdir.write().unwrap() = dir;
|
||||
} else {
|
||||
let dir = dbfile.to_string() + "-blobs";
|
||||
dc_create_folder(context, &dir);
|
||||
*context.blobdir.write().unwrap() = dir.strdup();
|
||||
let dir = (dbfile.to_string() + "-blobs").strdup();
|
||||
dc_create_folder(context, dir);
|
||||
*context.blobdir.write().unwrap() = dir;
|
||||
}
|
||||
// Create/open sqlite database, this may already use the blobdir
|
||||
let dbfile_path = std::path::Path::new(dbfile);
|
||||
@@ -440,7 +445,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
public_key_count={}\n\
|
||||
fingerprint={}\n\
|
||||
level=awesome\n",
|
||||
&*DC_VERSION_STR,
|
||||
as_str(DC_VERSION_STR as *const u8 as *const _),
|
||||
rusqlite::version(),
|
||||
sqlite3_threadsafe(),
|
||||
// arch
|
||||
@@ -449,10 +454,11 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
real_msgs,
|
||||
deaddrop_msgs,
|
||||
contacts,
|
||||
context
|
||||
.get_dbfile()
|
||||
.as_ref()
|
||||
.map_or(unset, |p| p.to_str().unwrap()),
|
||||
if context.has_dbfile() {
|
||||
as_str(context.get_dbfile())
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
dbversion,
|
||||
if context.has_blobdir() {
|
||||
as_str(context.get_blobdir())
|
||||
@@ -481,7 +487,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
|
||||
(&*DC_VERSION_STR).strdup()
|
||||
dc_strdup(DC_VERSION_STR as *const u8 as *const libc::c_char)
|
||||
}
|
||||
|
||||
pub fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
|
||||
@@ -499,12 +505,13 @@ pub fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
|
||||
&[10, 9, if 0 != show_deaddrop { 2 } else { 0 }],
|
||||
|row| row.get(0),
|
||||
|rows| {
|
||||
let mut ret = Vec::new();
|
||||
let mut ret = dc_array_t::new(128);
|
||||
|
||||
for row in rows {
|
||||
let id: u32 = row?;
|
||||
ret.push(id);
|
||||
let id = row?;
|
||||
ret.add_id(id);
|
||||
}
|
||||
Ok(dc_array_t::from(ret).into_raw())
|
||||
Ok(ret.into_raw())
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
@@ -538,7 +545,7 @@ pub fn dc_search_msgs(
|
||||
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;"
|
||||
};
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut ret = dc_array_t::new(100);
|
||||
|
||||
let success = context
|
||||
.sql
|
||||
@@ -548,7 +555,7 @@ pub fn dc_search_msgs(
|
||||
|row| row.get::<_, i32>(0),
|
||||
|rows| {
|
||||
for id in rows {
|
||||
ret.push(id? as u32);
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
@@ -556,7 +563,7 @@ pub fn dc_search_msgs(
|
||||
.is_ok();
|
||||
|
||||
if success {
|
||||
return dc_array_t::from(ret).into_raw();
|
||||
return ret.into_raw();
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
@@ -584,24 +591,3 @@ pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn no_crashes_on_context_deref() {
|
||||
let ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
|
||||
std::mem::drop(ctx);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_context_double_close() {
|
||||
let ctx = dc_context_new(None, std::ptr::null_mut(), None);
|
||||
unsafe {
|
||||
dc_close(&ctx);
|
||||
dc_close(&ctx);
|
||||
}
|
||||
std::mem::drop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
149
src/dc_array.rs
149
src/dc_array.rs
@@ -147,12 +147,6 @@ impl dc_array_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u32>> for dc_array_t {
|
||||
fn from(array: Vec<u32>) -> Self {
|
||||
dc_array_t::Uint(array.iter().map(|&x| x as uintptr_t).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<dc_location>> for dc_array_t {
|
||||
fn from(array: Vec<dc_location>) -> Self {
|
||||
dc_array_t::Locations(array)
|
||||
@@ -160,18 +154,22 @@ impl From<Vec<dc_location>> for dc_array_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_unref(array: *mut dc_array_t) {
|
||||
assert!(!array.is_null());
|
||||
if array.is_null() {
|
||||
return;
|
||||
}
|
||||
Box::from_raw(array);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_uint(array: *mut dc_array_t, item: uintptr_t) {
|
||||
assert!(!array.is_null());
|
||||
(*array).add_uint(item);
|
||||
if !array.is_null() {
|
||||
(*array).add_uint(item);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_id(array: *mut dc_array_t, item: uint32_t) {
|
||||
assert!(!array.is_null());
|
||||
(*array).add_id(item);
|
||||
if !array.is_null() {
|
||||
(*array).add_id(item);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void) {
|
||||
@@ -179,62 +177,97 @@ pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_cnt(array: *const dc_array_t) -> size_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).len()
|
||||
if array.is_null() {
|
||||
0
|
||||
} else {
|
||||
(*array).len()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_uint(array: *const dc_array_t, index: size_t) -> uintptr_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_uint(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_uint(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_id(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_id(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut libc::c_void {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_ptr(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
std::ptr::null_mut()
|
||||
} else {
|
||||
(*array).get_ptr(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_latitude(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_latitude(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_longitude(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_longitude(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_accuracy(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_accuracy(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) -> i64 {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_timestamp(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_timestamp(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_chat_id(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_chat_id(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_contact_id(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_contact_id(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
assert!(!array.is_null());
|
||||
(*array).get_msg_id(index)
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_msg_id(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *mut libc::c_char {
|
||||
assert!(!array.is_null());
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
if let dc_array_t::Locations(v) = &*array {
|
||||
if let Some(s) = &v[index].marker {
|
||||
@@ -243,7 +276,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
} else {
|
||||
panic!("Not an array of locations");
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +291,9 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
|
||||
* 1=Location was reported independently.
|
||||
*/
|
||||
pub unsafe fn dc_array_is_independent(array: *const dc_array_t, index: size_t) -> libc::c_int {
|
||||
assert!(!array.is_null());
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if let dc_array_t::Locations(v) = &*array {
|
||||
v[index].independent as libc::c_int
|
||||
@@ -272,8 +307,9 @@ pub unsafe fn dc_array_search_id(
|
||||
needle: uint32_t,
|
||||
ret_index: *mut size_t,
|
||||
) -> bool {
|
||||
assert!(!array.is_null());
|
||||
|
||||
if array.is_null() {
|
||||
return false;
|
||||
}
|
||||
if let Some(i) = (*array).search_id(needle as uintptr_t) {
|
||||
if !ret_index.is_null() {
|
||||
*ret_index = i
|
||||
@@ -285,8 +321,9 @@ pub unsafe fn dc_array_search_id(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_raw(array: *const dc_array_t) -> *const uintptr_t {
|
||||
assert!(!array.is_null());
|
||||
|
||||
if array.is_null() {
|
||||
return 0 as *const uintptr_t;
|
||||
}
|
||||
if let dc_array_t::Uint(v) = &*array {
|
||||
v.as_ptr()
|
||||
} else {
|
||||
@@ -303,24 +340,27 @@ pub fn dc_array_new_locations(initsize: size_t) -> *mut dc_array_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_empty(array: *mut dc_array_t) {
|
||||
assert!(!array.is_null());
|
||||
|
||||
if array.is_null() {
|
||||
return;
|
||||
}
|
||||
(*array).clear()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
|
||||
assert!(!array.is_null());
|
||||
|
||||
(*array).clone().into_raw()
|
||||
if array.is_null() {
|
||||
std::ptr::null_mut()
|
||||
} else {
|
||||
(*array).clone().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_string(
|
||||
array: *const dc_array_t,
|
||||
sep: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
assert!(!array.is_null());
|
||||
assert!(!sep.is_null());
|
||||
|
||||
if array.is_null() || sep.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
if let dc_array_t::Uint(v) = &*array {
|
||||
let cnt = v.len();
|
||||
let sep = as_str(sep);
|
||||
@@ -366,6 +406,10 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(dc_array_get_id(arr, -1i32 as size_t), 0);
|
||||
assert_eq!(dc_array_get_id(arr, 1000 as size_t), 0);
|
||||
assert_eq!(dc_array_get_id(arr, 1001 as size_t), 0);
|
||||
|
||||
dc_array_empty(arr);
|
||||
|
||||
assert_eq!(dc_array_get_cnt(arr), 0);
|
||||
@@ -394,13 +438,4 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dc_array_out_of_bounds() {
|
||||
let arr = dc_array_new(7);
|
||||
for i in 0..1000 {
|
||||
unsafe { dc_array_add_id(arr, (i + 2) as uint32_t) };
|
||||
}
|
||||
unsafe { dc_array_get_id(arr, 1000) };
|
||||
}
|
||||
}
|
||||
|
||||
163
src/dc_chat.rs
163
src/dc_chat.rs
@@ -13,7 +13,6 @@ use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
/**
|
||||
* @class dc_chat_t
|
||||
@@ -25,6 +24,7 @@ use std::ptr;
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct Chat<'a> {
|
||||
magic: uint32_t,
|
||||
pub id: uint32_t,
|
||||
pub type_0: libc::c_int,
|
||||
pub name: *mut libc::c_char,
|
||||
@@ -65,6 +65,7 @@ pub unsafe fn dc_create_chat_by_msg_id(context: &Context, msg_id: uint32_t) -> u
|
||||
|
||||
pub unsafe fn dc_chat_new<'a>(context: &'a Context) -> *mut Chat<'a> {
|
||||
let chat = Chat {
|
||||
magic: 0xc4a7c4a7,
|
||||
id: 0,
|
||||
type_0: 0,
|
||||
name: std::ptr::null_mut(),
|
||||
@@ -80,24 +81,25 @@ pub unsafe fn dc_chat_new<'a>(context: &'a Context) -> *mut Chat<'a> {
|
||||
Box::into_raw(Box::new(chat))
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_unref(chat: *mut Chat) {
|
||||
if chat.is_null() {
|
||||
pub unsafe fn dc_chat_unref(mut chat: *mut Chat) {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return;
|
||||
}
|
||||
dc_chat_empty(chat);
|
||||
(*chat).magic = 0;
|
||||
Box::from_raw(chat);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_empty(mut chat: *mut Chat) {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return;
|
||||
}
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
(*chat).name = ptr::null_mut();
|
||||
(*chat).name = 0 as *mut libc::c_char;
|
||||
(*chat).type_0 = 0i32;
|
||||
(*chat).id = 0i32 as uint32_t;
|
||||
free((*chat).grpid as *mut libc::c_void);
|
||||
(*chat).grpid = ptr::null_mut();
|
||||
(*chat).grpid = 0 as *mut libc::c_char;
|
||||
(*chat).blocked = 0i32;
|
||||
(*chat).gossiped_timestamp = 0;
|
||||
(*chat).param = Params::new();
|
||||
@@ -118,7 +120,7 @@ pub fn dc_block_chat(context: &Context, chat_id: u32, new_blocking: libc::c_int)
|
||||
}
|
||||
|
||||
pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || unsafe { (*chat).magic != 0xc4a7c4a7u32 } {
|
||||
return false;
|
||||
}
|
||||
unsafe { dc_chat_empty(chat) };
|
||||
@@ -180,22 +182,6 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
.strdup();
|
||||
},
|
||||
_ => {
|
||||
unsafe {
|
||||
if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
let contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
let mut chat_name = "Err [Name not found]".to_owned();
|
||||
if !(*contacts).is_empty() {
|
||||
if let Ok(contact) =
|
||||
Contact::get_by_id((*chat).context, contacts[0])
|
||||
{
|
||||
chat_name = contact.get_display_name().to_owned();
|
||||
}
|
||||
}
|
||||
(*chat).name = (&chat_name).strdup();
|
||||
}
|
||||
}
|
||||
|
||||
if unsafe { &(*chat).param }.exists(Param::Selftalk) {
|
||||
unsafe {
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
@@ -233,7 +219,7 @@ pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32
|
||||
contact_id,
|
||||
0i32,
|
||||
&mut chat_id,
|
||||
ptr::null_mut(),
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
if 0 != chat_id {
|
||||
send_event = 1;
|
||||
@@ -350,11 +336,11 @@ pub unsafe fn dc_get_chat_id_by_contact_id(context: &Context, contact_id: uint32
|
||||
let mut chat_id: uint32_t = 0i32 as uint32_t;
|
||||
let mut chat_id_blocked: libc::c_int = 0i32;
|
||||
dc_lookup_real_nchat_by_contact_id(context, contact_id, &mut chat_id, &mut chat_id_blocked);
|
||||
if 0 != chat_id_blocked {
|
||||
return if 0 != chat_id_blocked {
|
||||
0i32 as libc::c_uint
|
||||
} else {
|
||||
chat_id
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_prepare_msg<'a>(
|
||||
@@ -372,7 +358,7 @@ pub unsafe fn dc_prepare_msg<'a>(
|
||||
(*msg).chat_id as uintptr_t,
|
||||
(*msg).id as uintptr_t,
|
||||
);
|
||||
msg_id
|
||||
return msg_id;
|
||||
}
|
||||
|
||||
pub fn msgtype_has_file(msgtype: Viewtype) -> bool {
|
||||
@@ -438,7 +424,11 @@ unsafe fn prepare_msg_common<'a>(
|
||||
} else if !(*msg).param.exists(Param::MimeType) {
|
||||
let mut better_mime = std::ptr::null_mut();
|
||||
|
||||
dc_msg_guess_msgtype_from_suffix(pathNfilename, ptr::null_mut(), &mut better_mime);
|
||||
dc_msg_guess_msgtype_from_suffix(
|
||||
pathNfilename,
|
||||
0 as *mut Viewtype,
|
||||
&mut better_mime,
|
||||
);
|
||||
|
||||
if !better_mime.is_null() {
|
||||
(*msg).param.set(Param::MimeType, as_str(better_mime));
|
||||
@@ -490,12 +480,12 @@ unsafe fn prepare_msg_raw(
|
||||
let mut do_guarantee_e2ee: libc::c_int;
|
||||
let e2ee_enabled: libc::c_int;
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
let mut parent_rfc724_mid = ptr::null_mut();
|
||||
let mut parent_references = ptr::null_mut();
|
||||
let mut parent_in_reply_to = ptr::null_mut();
|
||||
let mut new_rfc724_mid = ptr::null_mut();
|
||||
let mut new_references = ptr::null_mut();
|
||||
let mut new_in_reply_to = ptr::null_mut();
|
||||
let mut parent_rfc724_mid = 0 as *mut libc::c_char;
|
||||
let mut parent_references = 0 as *mut libc::c_char;
|
||||
let mut parent_in_reply_to = 0 as *mut libc::c_char;
|
||||
let mut new_rfc724_mid = 0 as *mut libc::c_char;
|
||||
let mut new_references = 0 as *mut libc::c_char;
|
||||
let mut new_in_reply_to = 0 as *mut libc::c_char;
|
||||
let mut msg_id = 0;
|
||||
let mut to_id = 0;
|
||||
let mut location_id = 0;
|
||||
@@ -521,7 +511,7 @@ unsafe fn prepare_msg_raw(
|
||||
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
(*chat).grpid
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_char
|
||||
},
|
||||
from_c.as_ptr(),
|
||||
);
|
||||
@@ -820,7 +810,7 @@ unsafe fn get_parent_mime_headers(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_is_self_talk(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0;
|
||||
}
|
||||
(*chat).param.exists(Param::Selftalk) as libc::c_int
|
||||
@@ -1065,12 +1055,12 @@ pub unsafe fn dc_get_draft(context: &Context, chat_id: uint32_t) -> *mut dc_msg_
|
||||
}
|
||||
draft_msg_id = get_draft_msg_id(context, chat_id);
|
||||
if draft_msg_id == 0i32 as libc::c_uint {
|
||||
return ptr::null_mut();
|
||||
return 0 as *mut dc_msg_t;
|
||||
}
|
||||
draft_msg = dc_msg_new_untyped(context);
|
||||
if !dc_msg_load_from_db(draft_msg, context, draft_msg_id) {
|
||||
dc_msg_unref(draft_msg);
|
||||
return ptr::null_mut();
|
||||
return 0 as *mut dc_msg_t;
|
||||
}
|
||||
|
||||
draft_msg
|
||||
@@ -1082,7 +1072,7 @@ pub fn dc_get_chat_msgs(
|
||||
flags: uint32_t,
|
||||
marker1before: uint32_t,
|
||||
) -> *mut dc_array_t {
|
||||
let mut ret = Vec::new();
|
||||
let mut ret = dc_array_t::new(512);
|
||||
|
||||
let mut last_day = 0;
|
||||
let cnv_to_local = dc_gm2local_offset();
|
||||
@@ -1092,17 +1082,17 @@ pub fn dc_get_chat_msgs(
|
||||
for row in rows {
|
||||
let (curr_id, ts) = row?;
|
||||
if curr_id as u32 == marker1before {
|
||||
ret.push(DC_MSG_ID_MARKER1 as u32);
|
||||
ret.add_id(1);
|
||||
}
|
||||
if 0 != flags & 0x1 {
|
||||
let curr_local_timestamp = ts + cnv_to_local;
|
||||
let curr_day = (curr_local_timestamp / 86400) as libc::c_int;
|
||||
if curr_day != last_day {
|
||||
ret.push(DC_MSG_ID_LAST_SPECIAL as u32);
|
||||
ret.add_id(9);
|
||||
last_day = curr_day;
|
||||
}
|
||||
}
|
||||
ret.push(curr_id as u32);
|
||||
ret.add_id(curr_id as u32);
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
@@ -1150,7 +1140,7 @@ pub fn dc_get_chat_msgs(
|
||||
};
|
||||
|
||||
if success.is_ok() {
|
||||
dc_array_t::from(ret).into_raw()
|
||||
ret.into_raw()
|
||||
} else {
|
||||
0 as *mut dc_array_t
|
||||
}
|
||||
@@ -1263,11 +1253,11 @@ pub fn dc_get_chat_media(
|
||||
],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
let mut ret = Vec::new();
|
||||
let mut ret = dc_array_t::new(100);
|
||||
for id in ids {
|
||||
ret.push(id? as u32);
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
Ok(dc_array_t::from(ret).into_raw())
|
||||
Ok(ret.into_raw())
|
||||
}
|
||||
).unwrap_or_else(|_| std::ptr::null_mut())
|
||||
}
|
||||
@@ -1282,7 +1272,7 @@ pub unsafe fn dc_get_next_media(
|
||||
) -> uint32_t {
|
||||
let mut ret_msg_id: uint32_t = 0i32 as uint32_t;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let mut list: *mut dc_array_t = ptr::null_mut();
|
||||
let mut list: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
let mut i: libc::c_int;
|
||||
let cnt: libc::c_int;
|
||||
|
||||
@@ -1320,9 +1310,7 @@ pub unsafe fn dc_get_next_media(
|
||||
}
|
||||
}
|
||||
|
||||
if !list.is_null() {
|
||||
dc_array_unref(list);
|
||||
}
|
||||
dc_array_unref(list);
|
||||
dc_msg_unref(msg);
|
||||
ret_msg_id
|
||||
}
|
||||
@@ -1418,12 +1406,12 @@ pub fn dc_delete_chat(context: &Context, chat_id: u32) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
|
||||
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> *mut dc_array_t {
|
||||
/* Normal chats do not include SELF. Group chats do (as it may happen that one is deleted from a
|
||||
groupchat but the chats stays visible, moreover, this makes displaying lists easier) */
|
||||
|
||||
if chat_id == 1 {
|
||||
return Vec::new();
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
|
||||
@@ -1435,11 +1423,19 @@ pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
|
||||
"SELECT cc.contact_id FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \
|
||||
ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;",
|
||||
params![chat_id],
|
||||
|row| row.get::<_, u32>(0),
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
params![chat_id as i32],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
let mut ret = dc_array_t::new(100);
|
||||
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
|
||||
Ok(ret.into_raw())
|
||||
},
|
||||
)
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|_| std::ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
|
||||
@@ -1451,11 +1447,11 @@ pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
|
||||
}
|
||||
|
||||
if 0 != success {
|
||||
obj
|
||||
return obj;
|
||||
} else {
|
||||
dc_chat_unref(obj);
|
||||
ptr::null_mut()
|
||||
}
|
||||
return 0 as *mut Chat;
|
||||
};
|
||||
}
|
||||
|
||||
// handle group chats
|
||||
@@ -1865,7 +1861,7 @@ pub unsafe fn dc_set_chat_profile_image(
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let chat: *mut Chat = dc_chat_new(context);
|
||||
let mut msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let mut new_image_rel: *mut libc::c_char = ptr::null_mut();
|
||||
let mut new_image_rel: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(chat_id <= 9i32 as libc::c_uint) {
|
||||
if !(0i32 == real_group_exists(context, chat_id) || !dc_chat_load_from_db(chat, chat_id)) {
|
||||
if !(dc_is_contact_in_chat(context, chat_id, 1i32 as uint32_t) == 1i32) {
|
||||
@@ -2024,21 +2020,21 @@ pub unsafe fn dc_forward_msgs(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_id(chat: *const Chat) -> uint32_t {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
(*chat).id
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_type(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).type_0
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
dc_strdup((*chat).name)
|
||||
@@ -2046,7 +2042,7 @@ pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
|
||||
|
||||
pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
|
||||
/* returns either the address or the number of chat members */
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
|
||||
@@ -2081,11 +2077,11 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
|
||||
.strdup();
|
||||
}
|
||||
}
|
||||
if !ret.is_null() {
|
||||
return if !ret.is_null() {
|
||||
ret
|
||||
} else {
|
||||
dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dc_get_chat_contact_cnt(context: &Context, chat_id: u32) -> libc::c_int {
|
||||
@@ -2103,8 +2099,9 @@ pub fn dc_get_chat_contact_cnt(context: &Context, chat_id: u32) -> libc::c_int {
|
||||
pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char {
|
||||
let mut image_rel: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
|
||||
if !chat.is_null() {
|
||||
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
|
||||
image_rel = (*chat)
|
||||
.param
|
||||
.get(Param::ProfileImage)
|
||||
@@ -2112,10 +2109,10 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
|
||||
.strdup();
|
||||
if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int {
|
||||
image_abs = dc_get_abs_path((*chat).context, image_rel)
|
||||
} else if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
|
||||
let contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !contacts.is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, contacts[0]) {
|
||||
} else if (*chat).type_0 == 100i32 {
|
||||
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !(*contacts).is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
|
||||
if let Some(img) = contact.get_profile_image() {
|
||||
image_abs = img.strdup();
|
||||
}
|
||||
@@ -2125,18 +2122,20 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
|
||||
}
|
||||
|
||||
free(image_rel as *mut libc::c_void);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
image_abs
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
|
||||
let mut color: uint32_t = 0i32 as uint32_t;
|
||||
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
|
||||
if !chat.is_null() {
|
||||
if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
|
||||
let contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !contacts.is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, contacts[0]) {
|
||||
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
|
||||
if (*chat).type_0 == 100i32 {
|
||||
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !(*contacts).is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
|
||||
color = contact.get_color();
|
||||
}
|
||||
}
|
||||
@@ -2145,12 +2144,14 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
|
||||
}
|
||||
}
|
||||
|
||||
dc_array_unref(contacts);
|
||||
|
||||
color
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).archived
|
||||
@@ -2158,7 +2159,7 @@ pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0;
|
||||
}
|
||||
(*chat).param.get_int(Param::Unpromoted).unwrap_or_default() as libc::c_int
|
||||
@@ -2166,7 +2167,7 @@ pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
((*chat).type_0 == 130i32) as libc::c_int
|
||||
@@ -2174,7 +2175,7 @@ pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_sending_locations(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).is_sending_locations
|
||||
@@ -2236,7 +2237,7 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc
|
||||
}
|
||||
let rfc724_mid = unsafe {
|
||||
dc_create_outgoing_rfc724_mid(
|
||||
ptr::null(),
|
||||
0 as *const libc::c_char,
|
||||
b"@device\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
|
||||
1288
src/dc_configure.rs
1288
src/dc_configure.rs
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@ use lazy_static::lazy_static;
|
||||
use crate::dc_saxparser::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
lazy_static! {
|
||||
static ref LINE_RE: regex::Regex = regex::Regex::new(r"(\r?\n)+").unwrap();
|
||||
@@ -39,7 +38,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
|
||||
starttag_cb: None,
|
||||
endtag_cb: None,
|
||||
text_cb: None,
|
||||
userdata: ptr::null_mut(),
|
||||
userdata: 0 as *mut libc::c_void,
|
||||
};
|
||||
dc_saxparser_init(
|
||||
&mut saxparser,
|
||||
|
||||
341
src/dc_e2ee.rs
341
src/dc_e2ee.rs
@@ -1,8 +1,5 @@
|
||||
//! End-to-end encryption support.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use mmime::clist::*;
|
||||
@@ -19,12 +16,10 @@ use mmime::mmapstring::*;
|
||||
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||
|
||||
use crate::aheader::*;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::*;
|
||||
use crate::dc_securejoin::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::*;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::peerstate::*;
|
||||
@@ -81,6 +76,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let mut peerstates: Vec<Peerstate> = Vec::new();
|
||||
*helper = Default::default();
|
||||
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt guaruanteed={}", e2ee_guaranteed
|
||||
);
|
||||
|
||||
if !(recipients_addr.is_null()
|
||||
|| in_out_message.is_null()
|
||||
|| !(*in_out_message).mm_parent.is_null()
|
||||
@@ -101,11 +101,9 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let addr = context.sql.get_config(context, "configured_addr");
|
||||
|
||||
if let Some(addr) = addr {
|
||||
let pubkey_ret = load_or_generate_self_public_key(context, &addr).map_err(|err| {
|
||||
error!(context, 0, "Failed to load public key: {}", err);
|
||||
err
|
||||
});
|
||||
if let Ok(public_key) = pubkey_ret {
|
||||
if let Some(public_key) =
|
||||
load_or_generate_self_public_key(context, &addr, in_out_message)
|
||||
{
|
||||
/*only for random-seed*/
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
do_encrypt = 1i32;
|
||||
@@ -113,6 +111,10 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
iter1 = (*recipients_addr).first;
|
||||
while !iter1.is_null() {
|
||||
let recipient_addr = to_string((*iter1).data as *const libc::c_char);
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt recipient_addr {}", recipient_addr
|
||||
);
|
||||
if recipient_addr != addr {
|
||||
let peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
||||
@@ -146,7 +148,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
iter1 = if !iter1.is_null() {
|
||||
(*iter1).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,19 +173,19 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
mailprivacy_prepare_mime(in_out_message);
|
||||
let mut part_to_encrypt: *mut mailmime =
|
||||
(*in_out_message).mm_data.mm_message.mm_msg_mime;
|
||||
(*part_to_encrypt).mm_parent = ptr::null_mut();
|
||||
(*part_to_encrypt).mm_parent = 0 as *mut mailmime;
|
||||
let imffields_encrypted: *mut mailimf_fields = mailimf_fields_new_empty();
|
||||
/* mailmime_new_message_data() calls mailmime_fields_new_with_version() which would add the unwanted MIME-Version:-header */
|
||||
let message_to_encrypt: *mut mailmime = mailmime_new(
|
||||
MAILMIME_MESSAGE as libc::c_int,
|
||||
ptr::null(),
|
||||
0 as *const libc::c_char,
|
||||
0i32 as size_t,
|
||||
mailmime_fields_new_empty(),
|
||||
mailmime_get_content_message(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as *mut mailmime_data,
|
||||
0 as *mut mailmime_data,
|
||||
0 as *mut mailmime_data,
|
||||
0 as *mut clist,
|
||||
imffields_encrypted,
|
||||
part_to_encrypt,
|
||||
);
|
||||
@@ -215,7 +217,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let field: *mut mailimf_field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_void
|
||||
})
|
||||
as *mut mailimf_field;
|
||||
if !field.is_null() {
|
||||
@@ -266,28 +268,28 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
imffields_unprotected,
|
||||
mailimf_field_new(
|
||||
MAILIMF_FIELD_SUBJECT as libc::c_int,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as *mut mailimf_return,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_reply_to,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_in_reply_to,
|
||||
0 as *mut mailimf_references,
|
||||
subject,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as *mut mailimf_comments,
|
||||
0 as *mut mailimf_keywords,
|
||||
0 as *mut mailimf_optional_field,
|
||||
),
|
||||
);
|
||||
clist_insert_after(
|
||||
@@ -315,7 +317,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
|
||||
/* create MIME-structure that will contain the encrypted text */
|
||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||
ptr::null_mut(),
|
||||
0 as *mut libc::c_void,
|
||||
0i32 as size_t,
|
||||
b"multipart/encrypted\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
@@ -401,7 +403,7 @@ unsafe fn new_data_part(
|
||||
let encoding_type: libc::c_int;
|
||||
let content_type_str: *mut libc::c_char;
|
||||
let mut do_encoding: libc::c_int;
|
||||
encoding = ptr::null_mut();
|
||||
encoding = 0 as *mut mailmime_mechanism;
|
||||
if default_content_type.is_null() {
|
||||
content_type_str =
|
||||
b"application/octet-stream\x00" as *const u8 as *const libc::c_char as *mut libc::c_char
|
||||
@@ -436,7 +438,7 @@ unsafe fn new_data_part(
|
||||
} else {
|
||||
encoding_type = default_encoding
|
||||
}
|
||||
encoding = mailmime_mechanism_new(encoding_type, ptr::null_mut());
|
||||
encoding = mailmime_mechanism_new(encoding_type, 0 as *mut libc::c_char);
|
||||
if encoding.is_null() {
|
||||
ok_to_continue = false;
|
||||
}
|
||||
@@ -444,10 +446,10 @@ unsafe fn new_data_part(
|
||||
if ok_to_continue {
|
||||
mime_fields = mailmime_fields_new_with_data(
|
||||
encoding,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as *mut libc::c_char,
|
||||
0 as *mut libc::c_char,
|
||||
0 as *mut mailmime_disposition,
|
||||
0 as *mut mailmime_language,
|
||||
);
|
||||
if mime_fields.is_null() {
|
||||
ok_to_continue = false;
|
||||
@@ -477,55 +479,68 @@ unsafe fn new_data_part(
|
||||
mailmime_content_free(content);
|
||||
}
|
||||
}
|
||||
ptr::null_mut()
|
||||
return 0 as *mut mailmime;
|
||||
}
|
||||
|
||||
/// Load public key from database or generate a new one.
|
||||
///
|
||||
/// This will load a public key from the database, generating and
|
||||
/// storing a new one when one doesn't exist yet. Care is taken to
|
||||
/// only generate one key per context even when multiple threads call
|
||||
/// this function concurrently.
|
||||
fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str>) -> Result<Key> {
|
||||
if let Some(key) = Key::from_self_public(context, &self_addr, &context.sql) {
|
||||
return Ok(key);
|
||||
}
|
||||
let _guard = context.generating_key_mutex.lock().unwrap();
|
||||
/*******************************************************************************
|
||||
* Generate Keypairs
|
||||
******************************************************************************/
|
||||
unsafe fn load_or_generate_self_public_key(
|
||||
context: &Context,
|
||||
self_addr: impl AsRef<str>,
|
||||
_random_data_mime: *mut mailmime,
|
||||
) -> Option<Key> {
|
||||
/* avoid double creation (we unlock the database during creation) */
|
||||
static mut S_IN_KEY_CREATION: libc::c_int = 0;
|
||||
|
||||
// Check again in case the key was generated while we were waiting for the lock.
|
||||
if let Some(key) = Key::from_self_public(context, &self_addr, &context.sql) {
|
||||
return Ok(key);
|
||||
let mut key = Key::from_self_public(context, &self_addr, &context.sql);
|
||||
if key.is_some() {
|
||||
return key;
|
||||
}
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
/* create the keypair - this may take a moment, however, as this is in a thread, this is no big deal */
|
||||
if 0 != S_IN_KEY_CREATION {
|
||||
return None;
|
||||
}
|
||||
let key_creation_here = 1;
|
||||
S_IN_KEY_CREATION = 1;
|
||||
|
||||
let start = clock();
|
||||
info!(
|
||||
context,
|
||||
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
|
||||
);
|
||||
match dc_pgp_create_keypair(&self_addr) {
|
||||
Some((public_key, private_key)) => {
|
||||
match dc_key_save_self_keypair(
|
||||
|
||||
if let Some((public_key, private_key)) = dc_pgp_create_keypair(&self_addr) {
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
&self_addr,
|
||||
1i32,
|
||||
&context.sql,
|
||||
) {
|
||||
/*set default*/
|
||||
warn!(context, 0, "Cannot save keypair.",);
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
&self_addr,
|
||||
1,
|
||||
&context.sql,
|
||||
) {
|
||||
true => {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Keypair generated in {:.3}s.",
|
||||
start.elapsed().as_secs()
|
||||
);
|
||||
Ok(public_key)
|
||||
}
|
||||
false => Err(format_err!("Failed to save keypair")),
|
||||
}
|
||||
0,
|
||||
"Keypair generated in {:.3}s.",
|
||||
clock().wrapping_sub(start) as libc::c_double / 1000000 as libc::c_double,
|
||||
);
|
||||
}
|
||||
None => Err(format_err!("Failed to generate keypair")),
|
||||
|
||||
key = Some(public_key);
|
||||
} else {
|
||||
warn!(context, 0, "Cannot create keypair.");
|
||||
}
|
||||
|
||||
if 0 != key_creation_here {
|
||||
S_IN_KEY_CREATION = 0;
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
/* returns 1 if sth. was decrypted, 0 in other cases */
|
||||
@@ -540,23 +555,25 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||
let mut message_time = 0;
|
||||
let mut from: *mut libc::c_char = ptr::null_mut();
|
||||
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut private_keyring = Keyring::default();
|
||||
let mut public_keyring_for_validate = Keyring::default();
|
||||
let mut gossip_headers: *mut mailimf_fields = ptr::null_mut();
|
||||
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
if !(in_out_message.is_null() || imffields.is_null()) {
|
||||
let mut field: *mut mailimf_field =
|
||||
mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_from.is_null() {
|
||||
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list)
|
||||
}
|
||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() {
|
||||
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date;
|
||||
if !orig_date.is_null() {
|
||||
message_time = dc_timestamp_from_date((*orig_date).dt_date_time);
|
||||
if message_time != 0 && message_time > time() {
|
||||
message_time = time()
|
||||
if !imffields.is_null() {
|
||||
let mut field: *mut mailimf_field =
|
||||
mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_from.is_null() {
|
||||
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list)
|
||||
}
|
||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() {
|
||||
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date;
|
||||
if !orig_date.is_null() {
|
||||
message_time = dc_timestamp_from_date((*orig_date).dt_date_time);
|
||||
if message_time != 0 && message_time > time() {
|
||||
message_time = time()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,6 +594,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
let p = Peerstate::from_header(context, header, message_time);
|
||||
info!(context, 0, "setting peerstate from header for {:?}", p.addr);
|
||||
assert!(p.save_to_db(&context.sql, true));
|
||||
peerstate = Some(p);
|
||||
}
|
||||
@@ -647,7 +665,7 @@ unsafe fn update_gossip_peerstates(
|
||||
let field: *mut mailimf_field = (if !cur1.is_null() {
|
||||
(*cur1).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_field;
|
||||
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let optional_field: *const mailimf_optional_field =
|
||||
@@ -699,7 +717,7 @@ unsafe fn update_gossip_peerstates(
|
||||
cur1 = if !cur1.is_null() {
|
||||
(*cur1).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +750,7 @@ unsafe fn decrypt_recursive(
|
||||
{
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut decrypted_mime: *mut mailmime = ptr::null_mut();
|
||||
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
||||
if 0 != decrypt_part(
|
||||
context,
|
||||
(if !cur.is_null() {
|
||||
@@ -747,7 +765,7 @@ unsafe fn decrypt_recursive(
|
||||
) {
|
||||
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
|
||||
let mut dummy: size_t = 0i32 as size_t;
|
||||
let mut test: *mut mailimf_fields = ptr::null_mut();
|
||||
let mut test: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
if mailimf_envelope_and_optional_fields_parse(
|
||||
(*decrypted_mime).mm_mime_start,
|
||||
(*decrypted_mime).mm_length,
|
||||
@@ -778,7 +796,7 @@ unsafe fn decrypt_recursive(
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
@@ -791,7 +809,7 @@ unsafe fn decrypt_recursive(
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -826,12 +844,12 @@ unsafe fn decrypt_part(
|
||||
let mime_data: *mut mailmime_data;
|
||||
let mut mime_transfer_encoding: libc::c_int = MAILMIME_MECHANISM_BINARY as libc::c_int;
|
||||
/* mmap_string_unref()'d if set */
|
||||
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
|
||||
let mut transfer_decoding_buffer: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
/* must not be free()'d */
|
||||
let mut decoded_data: *const libc::c_char = ptr::null_mut();
|
||||
let mut decoded_data: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut decoded_data_bytes: size_t = 0i32 as size_t;
|
||||
let mut sth_decrypted: libc::c_int = 0i32;
|
||||
*ret_decrypted_mime = ptr::null_mut();
|
||||
*ret_decrypted_mime = 0 as *mut mailmime;
|
||||
mime_data = (*mime).mm_data.mm_single;
|
||||
/* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */
|
||||
if !((*mime_data).dt_type != MAILMIME_DATA_TEXT as libc::c_int
|
||||
@@ -845,7 +863,7 @@ unsafe fn decrypt_part(
|
||||
let field: *mut mailmime_field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime_field;
|
||||
if !field.is_null() {
|
||||
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
@@ -857,7 +875,7 @@ unsafe fn decrypt_part(
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -913,7 +931,7 @@ unsafe fn decrypt_part(
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
|
||||
let mut index: size_t = 0i32 as size_t;
|
||||
let mut decrypted_mime: *mut mailmime = ptr::null_mut();
|
||||
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
||||
if mailmime_parse(
|
||||
plain_buf as *const _,
|
||||
plain_bytes,
|
||||
@@ -1011,7 +1029,7 @@ unsafe fn contains_report(mime: *mut mailmime) -> libc::c_int {
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime,
|
||||
) {
|
||||
return 1i32;
|
||||
@@ -1034,52 +1052,36 @@ unsafe fn contains_report(mime: *mut mailmime) -> libc::c_int {
|
||||
/* frees data referenced by "mailmime" but not freed by mailmime_free(). After calling this function, in_out_message cannot be used any longer! */
|
||||
pub unsafe fn dc_e2ee_thanks(helper: &mut dc_e2ee_helper_t) {
|
||||
free(helper.cdata_to_free);
|
||||
helper.cdata_to_free = ptr::null_mut();
|
||||
helper.cdata_to_free = 0 as *mut libc::c_void;
|
||||
}
|
||||
|
||||
/// Ensures a private key exists for the configured user.
|
||||
///
|
||||
/// Normally the private key is generated when the first message is
|
||||
/// sent but in a few locations there are no such guarantees,
|
||||
/// e.g. when exporting keys, and calling this function ensures a
|
||||
/// private key will be present.
|
||||
///
|
||||
/// If this succeeds you are also guaranteed that the
|
||||
/// [Config::ConfiguredAddr] is configured, this address is returned.
|
||||
pub fn dc_ensure_secret_key_exists(context: &Context) -> Result<String> {
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.ok_or(format_err!(concat!(
|
||||
"Failed to get self address, ",
|
||||
"cannot ensure secret key if not configured."
|
||||
)))?;
|
||||
load_or_generate_self_public_key(context, &self_addr)?;
|
||||
Ok(self_addr)
|
||||
/* makes sure, the private key exists, needed only for exporting keys and the case no message was sent before */
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
|
||||
/* normally, the key is generated as soon as the first mail is send
|
||||
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
|
||||
let self_addr = context.sql.get_config(context, "configured_addr");
|
||||
if self_addr.is_none() {
|
||||
warn!(
|
||||
context,
|
||||
0, "Cannot ensure secret key if context is not configured.",
|
||||
);
|
||||
} else if load_or_generate_self_public_key(context, self_addr.unwrap(), 0 as *mut mailmime)
|
||||
.is_some()
|
||||
{
|
||||
/*no random text data for seeding available*/
|
||||
success = 1;
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::test_utils::*;
|
||||
|
||||
mod ensure_secret_key_exists {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_prexisting() {
|
||||
let t = dummy_context();
|
||||
let test_addr = configure_alice_keypair(&t.ctx);
|
||||
assert_eq!(dc_ensure_secret_key_exists(&t.ctx).unwrap(), test_addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_configured() {
|
||||
let t = dummy_context();
|
||||
assert!(dc_ensure_secret_key_exists(&t.ctx).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mailmime_parse() {
|
||||
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
|
||||
@@ -1140,47 +1142,4 @@ Sent with my Delta Chat Messenger: https://delta.chat";
|
||||
|
||||
unsafe { free(decrypted_mime as *mut _) };
|
||||
}
|
||||
|
||||
mod load_or_generate_self_public_key {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_existing() {
|
||||
let t = dummy_context();
|
||||
let addr = configure_alice_keypair(&t.ctx);
|
||||
let key = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // generating keys is expensive
|
||||
fn test_generate() {
|
||||
let t = dummy_context();
|
||||
let addr = "alice@example.org";
|
||||
let key0 = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key0.is_ok());
|
||||
let key1 = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key1.is_ok());
|
||||
assert_eq!(key0.unwrap(), key1.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_generate_concurrent() {
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
let t = dummy_context();
|
||||
let ctx = Arc::new(t.ctx);
|
||||
let ctx0 = Arc::clone(&ctx);
|
||||
let thr0 =
|
||||
thread::spawn(move || load_or_generate_self_public_key(&ctx0, "alice@example.org"));
|
||||
let ctx1 = Arc::clone(&ctx);
|
||||
let thr1 =
|
||||
thread::spawn(move || load_or_generate_self_public_key(&ctx1, "alice@example.org"));
|
||||
let res0 = thr0.join().unwrap();
|
||||
let res1 = thr1.join().unwrap();
|
||||
assert_eq!(res0.unwrap(), res1.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
418
src/dc_imex.rs
418
src/dc_imex.rs
@@ -1,5 +1,4 @@
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mmapstring::*;
|
||||
@@ -62,7 +61,7 @@ pub unsafe fn dc_imex_has_backup(
|
||||
"Backup check: Cannot open directory \"{}\".\x00",
|
||||
dir_name.display(),
|
||||
);
|
||||
return ptr::null_mut();
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
let mut newest_backup_time = 0;
|
||||
let mut newest_backup_path: Option<std::path::PathBuf> = None;
|
||||
@@ -101,8 +100,8 @@ pub unsafe fn dc_imex_has_backup(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
let mut setup_file_name: *mut libc::c_char = ptr::null_mut();
|
||||
let mut msg: *mut dc_msg_t = ptr::null_mut();
|
||||
let mut setup_file_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
|
||||
if dc_alloc_ongoing(context) == 0 {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
@@ -160,7 +159,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
let msg_id = dc_send_msg(context, chat_id, msg);
|
||||
if msg_id != 0 {
|
||||
dc_msg_unref(msg);
|
||||
msg = ptr::null_mut();
|
||||
msg = 0 as *mut dc_msg_t;
|
||||
info!(context, 0, "Wait for setup message being sent ...",);
|
||||
loop {
|
||||
if context
|
||||
@@ -195,15 +194,20 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
setup_code.strdup()
|
||||
}
|
||||
|
||||
/// Renders HTML body of a setup file message.
|
||||
///
|
||||
/// The `passphrase` must be at least 2 characters long.
|
||||
pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
|
||||
ensure!(
|
||||
passphrase.len() >= 2,
|
||||
"Passphrase must be at least 2 chars long."
|
||||
);
|
||||
let self_addr = dc_ensure_secret_key_exists(context)?;
|
||||
unsafe {
|
||||
ensure!(
|
||||
!(dc_ensure_secret_key_exists(context) == 0),
|
||||
"No secret key available."
|
||||
);
|
||||
}
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.ok_or(format_err!("Failed to get self address."))?;
|
||||
let private_key = Key::from_self_private(context, self_addr, &context.sql)
|
||||
.ok_or(format_err!("Failed to get private key."))?;
|
||||
let ac_headers = match context
|
||||
@@ -286,12 +290,12 @@ pub unsafe fn dc_continue_key_transfer(
|
||||
setup_code: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut msg: *mut dc_msg_t = ptr::null_mut();
|
||||
let mut filename: *mut libc::c_char = ptr::null_mut();
|
||||
let mut filecontent: *mut libc::c_char = ptr::null_mut();
|
||||
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut filecontent: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut filebytes: size_t = 0i32 as size_t;
|
||||
let mut armored_key: *mut libc::c_char = ptr::null_mut();
|
||||
let mut norm_sc: *mut libc::c_char = ptr::null_mut();
|
||||
let mut armored_key: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut norm_sc: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(msg_id <= 9i32 as libc::c_uint || setup_code.is_null()) {
|
||||
msg = dc_get_msg(context, msg_id);
|
||||
if msg.is_null()
|
||||
@@ -424,19 +428,19 @@ pub unsafe fn dc_decrypt_setup_file(
|
||||
filecontent: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
let fc_buf: *mut libc::c_char;
|
||||
let mut fc_headerline: *const libc::c_char = ptr::null();
|
||||
let mut fc_base64: *const libc::c_char = ptr::null();
|
||||
let mut binary: *mut libc::c_char = ptr::null_mut();
|
||||
let mut fc_headerline: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut fc_base64: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut binary: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut binary_bytes: size_t = 0i32 as size_t;
|
||||
let mut indx: size_t = 0i32 as size_t;
|
||||
|
||||
let mut payload: *mut libc::c_char = ptr::null_mut();
|
||||
let mut payload: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
fc_buf = dc_strdup(filecontent);
|
||||
if dc_split_armored_data(
|
||||
fc_buf,
|
||||
&mut fc_headerline,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as *mut *const libc::c_char,
|
||||
0 as *mut *const libc::c_char,
|
||||
&mut fc_base64,
|
||||
) && !fc_headerline.is_null()
|
||||
&& strcmp(
|
||||
@@ -480,7 +484,7 @@ pub unsafe fn dc_normalize_setup_code(
|
||||
in_0: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
if in_0.is_null() {
|
||||
return ptr::null_mut();
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
let mut out = String::new();
|
||||
let mut outlen;
|
||||
@@ -509,7 +513,7 @@ pub unsafe fn dc_normalize_setup_code(
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) {
|
||||
let mut ok_to_continue = true;
|
||||
let mut current_block: u64;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut ongoing_allocated_here: libc::c_int = 0;
|
||||
let what: libc::c_int;
|
||||
@@ -517,8 +521,7 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
if !(0 == dc_alloc_ongoing(context)) {
|
||||
ongoing_allocated_here = 1;
|
||||
what = (*job).param.get_int(Param::Cmd).unwrap_or_default();
|
||||
let param1_s = (*job).param.get(Param::Arg).unwrap_or_default();
|
||||
let param1 = CString::yolo(param1_s);
|
||||
let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default());
|
||||
let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default());
|
||||
|
||||
if strlen(param1.as_ptr()) == 0 {
|
||||
@@ -531,45 +534,185 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
} else {
|
||||
if what == 1 || what == 11 {
|
||||
/* before we export anything, make sure the private key exists */
|
||||
if dc_ensure_secret_key_exists(context).is_err() {
|
||||
if 0 == dc_ensure_secret_key_exists(context) {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import/export: Cannot create private key or private key not available.",
|
||||
);
|
||||
ok_to_continue = false;
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
dc_create_folder(context, ¶m1_s);
|
||||
dc_create_folder(context, param1.as_ptr());
|
||||
current_block = 4495394744059808450;
|
||||
}
|
||||
} else {
|
||||
current_block = 4495394744059808450;
|
||||
}
|
||||
if ok_to_continue {
|
||||
match what {
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => match what {
|
||||
1 => {
|
||||
if 0 != export_self_keys(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
current_block = 10991094515395304355;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if 0 != import_self_keys(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
current_block = 11250025114629486028;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
11 => {
|
||||
if 0 != export_backup(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
current_block = 12669919903773909120;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
12 => {
|
||||
if 0 != import_backup(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
current_block = 2973387206439775448;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,10 +740,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
0,
|
||||
"Import \"{}\" to \"{}\".",
|
||||
as_str(backup_to_import),
|
||||
context
|
||||
.get_dbfile()
|
||||
.as_ref()
|
||||
.map_or("<<None>>", |p| p.to_str().unwrap())
|
||||
as_str(context.get_dbfile()),
|
||||
);
|
||||
|
||||
if 0 != dc_is_configured(context) {
|
||||
@@ -608,8 +748,8 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
return 0;
|
||||
}
|
||||
&context.sql.close(&context);
|
||||
dc_delete_file(context, context.get_dbfile().unwrap());
|
||||
if dc_file_exist(context, context.get_dbfile().unwrap()) {
|
||||
dc_delete_file(context, context.get_dbfile());
|
||||
if 0 != dc_file_exist(context, context.get_dbfile()) {
|
||||
error!(
|
||||
context,
|
||||
0, "Cannot import backups: Cannot delete the old file.",
|
||||
@@ -617,19 +757,12 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
return 0;
|
||||
}
|
||||
|
||||
if !dc_copy_file(
|
||||
context,
|
||||
as_path(backup_to_import),
|
||||
context.get_dbfile().unwrap(),
|
||||
) {
|
||||
if 0 == dc_copy_file(context, backup_to_import, context.get_dbfile()) {
|
||||
return 0;
|
||||
}
|
||||
/* error already logged */
|
||||
/* re-open copied database file */
|
||||
if !context
|
||||
.sql
|
||||
.open(&context, &context.get_dbfile().unwrap(), 0)
|
||||
{
|
||||
if !context.sql.open(&context, as_path(context.get_dbfile()), 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -748,20 +881,11 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
context,
|
||||
0,
|
||||
"Backup \"{}\" to \"{}\".",
|
||||
context
|
||||
.get_dbfile()
|
||||
.as_ref()
|
||||
.map_or("<<None>>", |p| p.to_str().unwrap()),
|
||||
as_str(context.get_dbfile()),
|
||||
as_str(dest_pathNfilename),
|
||||
);
|
||||
if dc_copy_file(
|
||||
context,
|
||||
context.get_dbfile().unwrap(),
|
||||
as_path(dest_pathNfilename),
|
||||
) {
|
||||
context
|
||||
.sql
|
||||
.open(&context, &context.get_dbfile().unwrap(), 0);
|
||||
if !(0 == dc_copy_file(context, context.get_dbfile(), dest_pathNfilename)) {
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
closed = false;
|
||||
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
|
||||
/*for logging only*/
|
||||
@@ -917,12 +1041,10 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
}
|
||||
}
|
||||
if closed {
|
||||
context
|
||||
.sql
|
||||
.open(&context, &context.get_dbfile().unwrap(), 0);
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
}
|
||||
if 0 != delete_dest_file {
|
||||
dc_delete_file(context, as_path(dest_pathNfilename));
|
||||
dc_delete_file(context, dest_pathNfilename);
|
||||
}
|
||||
free(dest_pathNfilename as *mut libc::c_void);
|
||||
|
||||
@@ -940,16 +1062,16 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
Maybe we should make the "default" key handlong also a little bit smarter
|
||||
(currently, the last imported key is the standard key unless it contains the string "legacy" in its name) */
|
||||
let mut imported_cnt: libc::c_int = 0;
|
||||
let mut suffix: *mut libc::c_char = ptr::null_mut();
|
||||
let mut path_plus_name: *mut libc::c_char = ptr::null_mut();
|
||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut set_default: libc::c_int;
|
||||
let mut buf: *mut libc::c_char = ptr::null_mut();
|
||||
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf_bytes: size_t = 0 as size_t;
|
||||
// a pointer inside buf, MUST NOT be free()'d
|
||||
let mut private_key: *const libc::c_char;
|
||||
let mut buf2: *mut libc::c_char = ptr::null_mut();
|
||||
let mut buf2: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
// a pointer inside buf2, MUST NOT be free()'d
|
||||
let mut buf2_headerline: *const libc::c_char = ptr::null_mut();
|
||||
let mut buf2_headerline: *const libc::c_char = 0 as *const libc::c_char;
|
||||
if !dir_name.is_null() {
|
||||
let dir = std::path::Path::new(as_str(dir_name));
|
||||
let dir_handle = std::fs::read_dir(dir);
|
||||
@@ -984,7 +1106,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
);
|
||||
info!(context, 0, "Checking: {}", as_str(path_plus_name));
|
||||
free(buf as *mut libc::c_void);
|
||||
buf = ptr::null_mut();
|
||||
buf = 0 as *mut libc::c_char;
|
||||
if 0 == dc_read_file(
|
||||
context,
|
||||
path_plus_name,
|
||||
@@ -1142,7 +1264,7 @@ unsafe fn export_key_to_asc_file(
|
||||
)
|
||||
}
|
||||
info!(context, 0, "Exporting key {}", as_str(file_name),);
|
||||
dc_delete_file(context, as_path(file_name));
|
||||
dc_delete_file(context, file_name);
|
||||
if !key.write_asc_to_file(file_name, context) {
|
||||
error!(context, 0, "Cannot write key to {}", as_str(file_name),);
|
||||
} else {
|
||||
@@ -1162,15 +1284,147 @@ unsafe fn export_key_to_asc_file(
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::key;
|
||||
use crate::test_utils::*;
|
||||
|
||||
unsafe extern "C" fn logging_cb(
|
||||
_ctx: &Context,
|
||||
evt: Event,
|
||||
_d1: uintptr_t,
|
||||
d2: uintptr_t,
|
||||
) -> uintptr_t {
|
||||
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
|
||||
match evt {
|
||||
Event::INFO => println!("I: {}", to_str(d2)),
|
||||
Event::WARNING => println!("W: {}", to_str(d2)),
|
||||
Event::ERROR => println!("E: {}", to_str(d2)),
|
||||
_ => (),
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Create Alice with a pre-generated keypair.
|
||||
fn create_alice_keypair(ctx: &Context) {
|
||||
ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
|
||||
.unwrap();
|
||||
|
||||
// The keypair was created using:
|
||||
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtq",
|
||||
"m1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353",
|
||||
"r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68",
|
||||
"JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6F",
|
||||
"FrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHb",
|
||||
"Iu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3V",
|
||||
"WushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0S",
|
||||
"ut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQ",
|
||||
"sWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEm",
|
||||
"dr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8k",
|
||||
"QrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJW",
|
||||
"yyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj",
|
||||
"5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3",
|
||||
"jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeG",
|
||||
"Kyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl08",
|
||||
"6fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQ",
|
||||
"k6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Ee",
|
||||
"h+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BM",
|
||||
"zcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwb",
|
||||
"YklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP",
|
||||
"12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmh",
|
||||
"o0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugz",
|
||||
"OmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnF",
|
||||
"n7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6",
|
||||
"uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEe",
|
||||
"LrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCIC",
|
||||
"N1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86K",
|
||||
"C2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIdd",
|
||||
"KsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T",
|
||||
"/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZL",
|
||||
"j3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtp",
|
||||
"Do5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9u",
|
||||
"RMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe",
|
||||
"/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH",
|
||||
"95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9",
|
||||
"QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ",
|
||||
"8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//",
|
||||
"wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg",
|
||||
"9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwK",
|
||||
"Gjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPB",
|
||||
"f4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAg",
|
||||
"BQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/",
|
||||
"dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJ",
|
||||
"ywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJ",
|
||||
"uiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6",
|
||||
"RDXIeYJfqrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMl",
|
||||
"ammDliPwsK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKOb",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
let saved = key::dc_key_save_self_keypair(
|
||||
&ctx,
|
||||
&public,
|
||||
&private,
|
||||
"alice@example.org",
|
||||
1,
|
||||
&ctx.sql,
|
||||
);
|
||||
assert_eq!(saved, true, "Failed to save Alice's key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_setup_file() {
|
||||
let t = test_context(Some(logging_cb));
|
||||
|
||||
configure_alice_keypair(&t.ctx);
|
||||
create_alice_keypair(&t.ctx); // Trick things to think we're configured.
|
||||
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
|
||||
println!("{}", &msg);
|
||||
// Check some substrings, indicating things got substituted.
|
||||
@@ -1202,7 +1456,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_render_setup_file_newline_replace() {
|
||||
let t = test_context(Some(ac_setup_msg_cb));
|
||||
configure_alice_keypair(&t.ctx);
|
||||
create_alice_keypair(&t.ctx);
|
||||
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
|
||||
println!("{}", &msg);
|
||||
assert!(msg.contains("<p>hello<br>there</p>"));
|
||||
|
||||
516
src/dc_job.rs
516
src/dc_job.rs
@@ -1,7 +1,6 @@
|
||||
use mmime::mmapstring::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
@@ -102,8 +101,10 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
|
||||
Ok(job)
|
||||
},
|
||||
|jobs| {
|
||||
jobs.collect::<Result<Vec<dc_job_t>, _>>()
|
||||
.map_err(Into::into)
|
||||
let res = jobs
|
||||
.collect::<Result<Vec<dc_job_t>, _>>()
|
||||
.map_err(Into::into);
|
||||
res
|
||||
},
|
||||
);
|
||||
match jobs {
|
||||
@@ -291,9 +292,9 @@ unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: bool) {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
let ok_to_continue;
|
||||
let mut current_block: u64;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf: *mut libc::c_void = ptr::null_mut();
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0i32 as size_t;
|
||||
|
||||
/* connect to SMTP server, if not yet done */
|
||||
@@ -302,87 +303,101 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
||||
|
||||
if !connected {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
ok_to_continue = false;
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 14216916617354591294;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 13109137661213826276;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 13109137661213826276;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let filename_s = job.param.get(Param::File).unwrap_or_default();
|
||||
filename = filename_s.strdup();
|
||||
if strlen(filename) == 0 {
|
||||
warn!(context, 0, "Missing file name for job {}", job.job_id,);
|
||||
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
|
||||
let recipients = job.param.get(Param::Recipients);
|
||||
if recipients.is_none() {
|
||||
warn!(context, 0, "Missing recipients for job {}", job.job_id,);
|
||||
} else {
|
||||
let recipients_list = recipients
|
||||
.unwrap()
|
||||
.split("\x1e")
|
||||
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
||||
Ok(addr) => Some(addr),
|
||||
Err(err) => {
|
||||
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||
this happends if dc_delete_msgs() was called
|
||||
before the generated mime was sent out */
|
||||
let ok_to_continue1;
|
||||
if 0 != job.foreign_id {
|
||||
if 0 == dc_msg_exists(context, job.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
0, "Message {} for job {} does not exist", job.foreign_id, job.job_id,
|
||||
);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
match current_block {
|
||||
13109137661213826276 => {
|
||||
filename = job.param.get(Param::File).unwrap_or_default().strdup();
|
||||
if strlen(filename) == 0 {
|
||||
warn!(context, 0, "Missing file name for job {}", job.job_id,);
|
||||
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
|
||||
let recipients = job.param.get(Param::Recipients);
|
||||
if recipients.is_none() {
|
||||
warn!(context, 0, "Missing recipients for job {}", job.job_id,);
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
/* send message */
|
||||
let body = std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec();
|
||||
|
||||
// hold the smtp lock during sending of a job and
|
||||
// its ok/error response processing. Note that if a message
|
||||
// was sent we need to mark it in the database as we
|
||||
// otherwise might send it twice.
|
||||
let mut sock = context.smtp.lock().unwrap();
|
||||
if 0 == sock.send(context, recipients_list, body) {
|
||||
sock.disconnect();
|
||||
dc_job_try_again_later(job, -1i32, sock.error);
|
||||
} else {
|
||||
dc_delete_file(context, filename_s);
|
||||
if 0 != job.foreign_id {
|
||||
dc_update_msg_state(context, job.foreign_id, DC_STATE_OUT_DELIVERED);
|
||||
let chat_id: i32 = context
|
||||
.sql
|
||||
.query_row_col(
|
||||
context,
|
||||
"SELECT chat_id FROM msgs WHERE id=?",
|
||||
params![job.foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
context.call_cb(
|
||||
Event::MSG_DELIVERED,
|
||||
chat_id as uintptr_t,
|
||||
job.foreign_id as uintptr_t,
|
||||
let recipients_list = recipients
|
||||
.unwrap()
|
||||
.split("\x1e")
|
||||
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
||||
Ok(addr) => Some(addr),
|
||||
Err(err) => {
|
||||
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||
this happends if dc_delete_msgs() was called
|
||||
before the generated mime was sent out */
|
||||
if 0 != job.foreign_id {
|
||||
if 0 == dc_msg_exists(context, job.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Message {} for job {} does not exist",
|
||||
job.foreign_id,
|
||||
job.job_id,
|
||||
);
|
||||
current_block = 14216916617354591294;
|
||||
} else {
|
||||
current_block = 11194104282611034094;
|
||||
}
|
||||
} else {
|
||||
current_block = 11194104282611034094;
|
||||
}
|
||||
match current_block {
|
||||
14216916617354591294 => {}
|
||||
_ => {
|
||||
/* send message */
|
||||
let body =
|
||||
std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec();
|
||||
if 0 == context.smtp.lock().unwrap().send(
|
||||
context,
|
||||
recipients_list,
|
||||
body,
|
||||
) {
|
||||
context.smtp.lock().unwrap().disconnect();
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
-1i32,
|
||||
(*&mut context.smtp.clone().lock().unwrap()).error,
|
||||
);
|
||||
} else {
|
||||
dc_delete_file(context, filename);
|
||||
if 0 != job.foreign_id {
|
||||
dc_update_msg_state(
|
||||
context,
|
||||
job.foreign_id,
|
||||
DC_STATE_OUT_DELIVERED,
|
||||
);
|
||||
let chat_id: i32 = context
|
||||
.sql
|
||||
.query_row_col(
|
||||
context,
|
||||
"SELECT chat_id FROM msgs WHERE id=?",
|
||||
params![job.foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
context.call_cb(
|
||||
Event::MSG_DELIVERED,
|
||||
chat_id as uintptr_t,
|
||||
job.foreign_id as uintptr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(buf);
|
||||
free(filename as *mut libc::c_void);
|
||||
@@ -401,7 +416,7 @@ pub unsafe fn dc_job_try_again_later(
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
let ok_to_continue;
|
||||
let mut current_block: u64;
|
||||
let msg = dc_msg_new_untyped(context);
|
||||
let mut dest_uid: uint32_t = 0i32 as uint32_t;
|
||||
|
||||
@@ -410,47 +425,76 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
ok_to_continue = false;
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 2238328302157162973;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 2473556513754201174;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 2473556513754201174;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
(*msg).server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
match current_block {
|
||||
2473556513754201174 => {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
1 => {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = as_str((*msg).server_folder);
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
(*msg).server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 6379107252614456477;
|
||||
match current_block {
|
||||
12072121998757195963 => {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 12072121998757195963;
|
||||
match current_block {
|
||||
12072121998757195963 => {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
3 => {
|
||||
dc_update_server_uid(context, (*msg).rfc724_mid, &dest_folder, dest_uid);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
@@ -469,7 +513,7 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let ok_to_continue;
|
||||
let current_block: u64;
|
||||
let folder = job
|
||||
.param
|
||||
.get(Param::ServerFolder)
|
||||
@@ -482,109 +526,202 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3, ptr::null());
|
||||
ok_to_continue = false;
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
current_block = 2670689566614003383;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 11006700562992250127;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 11006700562992250127;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
}
|
||||
if 0 != job.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
match current_block {
|
||||
11006700562992250127 => {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid) as libc::c_uint {
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
if 0 != job.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let ok_to_continue;
|
||||
let mut current_block: u64;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
ok_to_continue = false;
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 17792648348530113339;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 15240798224410183470;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 15240798224410183470;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
match inbox.set_seen(context, server_folder, (*msg).server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
dc_job_try_again_later(job, 3i32, ptr::null());
|
||||
}
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder = (*msg).server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
match current_block {
|
||||
15240798224410183470 => {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
let server_folder = CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
match inbox.set_seen(context, server_folder, (*msg).server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
current_block = 12392248546350854223;
|
||||
match current_block {
|
||||
12392248546350854223 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
3 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder =
|
||||
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 4016212065805849280;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 6186957421461061791;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 7746791466490516765;
|
||||
match current_block {
|
||||
12392248546350854223 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder =
|
||||
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 4016212065805849280;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 6186957421461061791;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
unsafe fn dc_send_mdn(context: &Context, msg_id: uint32_t) {
|
||||
let mut mimefactory: dc_mimefactory_t = dc_mimefactory_t {
|
||||
from_addr: ptr::null_mut(),
|
||||
from_displayname: ptr::null_mut(),
|
||||
selfstatus: ptr::null_mut(),
|
||||
recipients_names: ptr::null_mut(),
|
||||
recipients_addr: ptr::null_mut(),
|
||||
from_addr: 0 as *mut libc::c_char,
|
||||
from_displayname: 0 as *mut libc::c_char,
|
||||
selfstatus: 0 as *mut libc::c_char,
|
||||
recipients_names: 0 as *mut clist,
|
||||
recipients_addr: 0 as *mut clist,
|
||||
timestamp: 0,
|
||||
rfc724_mid: ptr::null_mut(),
|
||||
rfc724_mid: 0 as *mut libc::c_char,
|
||||
loaded: DC_MF_NOTHING_LOADED,
|
||||
msg: ptr::null_mut(),
|
||||
chat: ptr::null_mut(),
|
||||
msg: 0 as *mut dc_msg_t,
|
||||
chat: 0 as *mut Chat,
|
||||
increation: 0,
|
||||
in_reply_to: ptr::null_mut(),
|
||||
references: ptr::null_mut(),
|
||||
in_reply_to: 0 as *mut libc::c_char,
|
||||
references: 0 as *mut libc::c_char,
|
||||
req_mdn: 0,
|
||||
out: ptr::null_mut(),
|
||||
out: 0 as *mut MMAPString,
|
||||
out_encrypted: 0,
|
||||
out_gossiped: 0,
|
||||
out_last_added_location_id: 0,
|
||||
error: ptr::null_mut(),
|
||||
error: 0 as *mut libc::c_char,
|
||||
context,
|
||||
};
|
||||
dc_mimefactory_init(&mut mimefactory, context);
|
||||
@@ -667,7 +804,7 @@ unsafe fn dc_add_smtp_job(
|
||||
}
|
||||
free(recipients as *mut libc::c_void);
|
||||
free(pathNfilename as *mut libc::c_void);
|
||||
success
|
||||
return success;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_job_add(
|
||||
@@ -727,6 +864,7 @@ pub unsafe fn dc_interrupt_imap_idle(context: &Context) {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let mut delete_from_server: libc::c_int = 1i32;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
@@ -735,7 +873,6 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
|
||||
|| (*msg).rfc724_mid.is_null()
|
||||
|| *(*msg).rfc724_mid.offset(0isize) as libc::c_int == 0i32)
|
||||
{
|
||||
let ok_to_continue1;
|
||||
/* eg. device messages have no Message-ID */
|
||||
if dc_rfc724_mid_cnt(context, (*msg).rfc724_mid) != 1i32 {
|
||||
info!(
|
||||
@@ -746,35 +883,38 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
|
||||
}
|
||||
/* if this is the last existing part of the message, we delete the message from the server */
|
||||
if 0 != delete_from_server {
|
||||
let ok_to_continue;
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
ok_to_continue = false;
|
||||
current_block = 8913536887710889399;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 5399440093318478209;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
current_block = 5399440093318478209;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mid = CStr::from_ptr((*msg).rfc724_mid).to_str().unwrap();
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut (*msg).server_uid) {
|
||||
dc_job_try_again_later(job, -1i32, 0 as *const libc::c_char);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
match current_block {
|
||||
8913536887710889399 => {}
|
||||
_ => {
|
||||
let mid = CStr::from_ptr((*msg).rfc724_mid).to_str().unwrap();
|
||||
let server_folder = CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut (*msg).server_uid) {
|
||||
dc_job_try_again_later(job, -1i32, 0 as *const libc::c_char);
|
||||
current_block = 8913536887710889399;
|
||||
} else {
|
||||
current_block = 17407779659766490442;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = false;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
current_block = 17407779659766490442;
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
dc_delete_msg_from_db(context, (*msg).id);
|
||||
match current_block {
|
||||
8913536887710889399 => {}
|
||||
_ => {
|
||||
dc_delete_msg_from_db(context, (*msg).id);
|
||||
}
|
||||
}
|
||||
}
|
||||
dc_msg_unref(msg);
|
||||
|
||||
@@ -239,10 +239,10 @@ pub fn dc_get_locations(
|
||||
accuracy: row.get(3)?,
|
||||
timestamp: row.get(4)?,
|
||||
independent: row.get(5)?,
|
||||
msg_id,
|
||||
msg_id: msg_id,
|
||||
contact_id: row.get(7)?,
|
||||
chat_id: row.get(8)?,
|
||||
marker,
|
||||
marker: marker,
|
||||
};
|
||||
Ok(loc)
|
||||
},
|
||||
|
||||
@@ -6,11 +6,14 @@ use crate::dc_tools::*;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
/* * Structure behind dc_lot_t */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_lot_t {
|
||||
pub magic: uint32_t,
|
||||
pub text1_meaning: libc::c_int,
|
||||
pub text1: *mut libc::c_char,
|
||||
pub text2: *mut libc::c_char,
|
||||
@@ -37,13 +40,14 @@ pub unsafe fn dc_lot_new() -> *mut dc_lot_t {
|
||||
lot = calloc(1, ::std::mem::size_of::<dc_lot_t>()) as *mut dc_lot_t;
|
||||
assert!(!lot.is_null());
|
||||
|
||||
(*lot).magic = 0x107107i32 as uint32_t;
|
||||
(*lot).text1_meaning = 0i32;
|
||||
|
||||
lot
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_empty(mut lot: *mut dc_lot_t) {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
free((*lot).text1 as *mut libc::c_void);
|
||||
@@ -62,16 +66,17 @@ pub unsafe fn dc_lot_empty(mut lot: *mut dc_lot_t) {
|
||||
(*lot).id = 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_unref(set: *mut dc_lot_t) {
|
||||
if set.is_null() {
|
||||
pub unsafe fn dc_lot_unref(mut set: *mut dc_lot_t) {
|
||||
if set.is_null() || (*set).magic != 0x107107i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
dc_lot_empty(set);
|
||||
(*set).magic = 0i32 as uint32_t;
|
||||
free(set as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text1(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
@@ -79,7 +84,7 @@ pub unsafe fn dc_lot_get_text1(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text2(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
@@ -87,7 +92,7 @@ pub unsafe fn dc_lot_get_text2(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text1_meaning(lot: *const dc_lot_t) -> libc::c_int {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -95,7 +100,7 @@ pub unsafe fn dc_lot_get_text1_meaning(lot: *const dc_lot_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_state(lot: *const dc_lot_t) -> libc::c_int {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -103,7 +108,7 @@ pub unsafe fn dc_lot_get_state(lot: *const dc_lot_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_id(lot: *const dc_lot_t) -> uint32_t {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -111,7 +116,7 @@ pub unsafe fn dc_lot_get_id(lot: *const dc_lot_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_timestamp(lot: *const dc_lot_t) -> i64 {
|
||||
if lot.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,7 +132,7 @@ pub unsafe fn dc_lot_fill(
|
||||
contact: Option<&Contact>,
|
||||
context: &Context,
|
||||
) {
|
||||
if lot.is_null() || msg.is_null() {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() {
|
||||
return;
|
||||
}
|
||||
if (*msg).state == 19i32 {
|
||||
@@ -166,15 +171,14 @@ pub unsafe fn dc_lot_fill(
|
||||
}
|
||||
}
|
||||
|
||||
let message_text = (*msg).text.as_ref().unwrap();
|
||||
let msgtext_c = (*msg)
|
||||
.text
|
||||
.as_ref()
|
||||
.map(|s| CString::yolo(String::as_str(s)));
|
||||
let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr());
|
||||
|
||||
(*lot).text2 = dc_msg_get_summarytext_by_raw(
|
||||
(*msg).type_0,
|
||||
message_text.strdup(),
|
||||
&mut (*msg).param,
|
||||
160,
|
||||
context,
|
||||
);
|
||||
(*lot).text2 =
|
||||
dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context);
|
||||
|
||||
(*lot).timestamp = dc_msg_get_timestamp(msg);
|
||||
(*lot).state = (*msg).state;
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::ptr;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::{dc_get_version_str, Context};
|
||||
use crate::context::Context;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_e2ee::*;
|
||||
use crate::dc_location::*;
|
||||
@@ -478,19 +478,18 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
.map(|s| format!("/{}", s))
|
||||
.unwrap_or_default();
|
||||
let os_part = CString::new(os_part).expect("String -> CString conversion failed");
|
||||
let version = dc_get_version_str();
|
||||
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
strdup(b"X-Mailer\x00" as *const u8 as *const libc::c_char),
|
||||
dc_mprintf(
|
||||
b"Delta Chat Core %s%s\x00" as *const u8 as *const libc::c_char,
|
||||
version,
|
||||
DC_VERSION_STR as *const u8 as *const libc::c_char,
|
||||
os_part.as_ptr(),
|
||||
),
|
||||
),
|
||||
);
|
||||
free(version.cast());
|
||||
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -961,14 +960,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
message_text = format!("{}\r\n", p2).strdup();
|
||||
let human_mime_part: *mut mailmime = build_body_text(message_text);
|
||||
mailmime_add_part(multipart, human_mime_part);
|
||||
let version = dc_get_version_str();
|
||||
message_text2 =
|
||||
dc_mprintf(b"Reporting-UA: Delta Chat %s\r\nOriginal-Recipient: rfc822;%s\r\nFinal-Recipient: rfc822;%s\r\nOriginal-Message-ID: <%s>\r\nDisposition: manual-action/MDN-sent-automatically; displayed\r\n\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
version,
|
||||
DC_VERSION_STR as *const u8 as *const libc::c_char,
|
||||
(*factory).from_addr, (*factory).from_addr,
|
||||
(*(*factory).msg).rfc724_mid);
|
||||
free(version.cast());
|
||||
let content_type_0: *mut mailmime_content = mailmime_content_new_with_str(
|
||||
b"message/disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
@@ -1044,6 +1041,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
&mut e2ee_helper,
|
||||
);
|
||||
}
|
||||
info!(
|
||||
(*factory).context,
|
||||
0, "encryption successful {}", e2ee_helper.encryption_successfull
|
||||
);
|
||||
|
||||
if 0 != e2ee_helper.encryption_successfull {
|
||||
(*factory).out_encrypted = 1;
|
||||
if 0 != do_gossip {
|
||||
@@ -1314,14 +1316,16 @@ unsafe fn build_body_file(
|
||||
/*******************************************************************************
|
||||
* Render
|
||||
******************************************************************************/
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool {
|
||||
let mut file_size_okay = true;
|
||||
let path = (*msg).param.get(Param::File).unwrap_or_default();
|
||||
let bytes = dc_get_filebytes((*msg).context, &path);
|
||||
let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
|
||||
let bytes = dc_get_filebytes((*msg).context, pathNfilename);
|
||||
|
||||
if bytes > (49 * 1024 * 1024 / 4 * 3) {
|
||||
file_size_okay = false;
|
||||
}
|
||||
free(pathNfilename as *mut _);
|
||||
|
||||
file_size_okay
|
||||
}
|
||||
|
||||
@@ -161,7 +161,12 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
|
||||
}
|
||||
if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Version").is_null() {
|
||||
if !dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
mimeparser.is_send_by_messenger = 1i32
|
||||
}
|
||||
if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() {
|
||||
@@ -196,7 +201,10 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
optional_field = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Content");
|
||||
optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Content\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if !optional_field.is_null() && !(*optional_field).fld_value.is_null() {
|
||||
if strcmp(
|
||||
(*optional_field).fld_value,
|
||||
@@ -304,7 +312,11 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
if mimeparser.parts.len() == 1 {
|
||||
if mimeparser.parts[0].type_0 == 40i32 {
|
||||
if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Voice-Message").is_null()
|
||||
if !dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let part_mut = &mut mimeparser.parts[0];
|
||||
part_mut.type_0 = 41i32
|
||||
@@ -312,7 +324,10 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
let part = &mimeparser.parts[0];
|
||||
if part.type_0 == 40i32 || part.type_0 == 41i32 || part.type_0 == 50i32 {
|
||||
let field_0 = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Duration");
|
||||
let field_0 = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Duration\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if !field_0.is_null() {
|
||||
let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value);
|
||||
if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 {
|
||||
@@ -323,8 +338,10 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
if 0 == mimeparser.decrypting_failed {
|
||||
let dn_field: *const mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Disposition-Notification-To");
|
||||
let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(mimeparser).is_some() {
|
||||
let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list;
|
||||
let mut index_0: size_t = 0i32 as size_t;
|
||||
@@ -442,11 +459,11 @@ pub fn dc_mimeparser_lookup_field(
|
||||
|
||||
pub unsafe fn dc_mimeparser_lookup_optional_field(
|
||||
mimeparser: &dc_mimeparser_t,
|
||||
field_name: &str,
|
||||
field_name: *const libc::c_char,
|
||||
) -> *mut mailimf_optional_field {
|
||||
let field = mimeparser
|
||||
.header
|
||||
.get(field_name)
|
||||
.get(as_str(field_name))
|
||||
.map(|v| *v)
|
||||
.unwrap_or_else(|| std::ptr::null_mut());
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
@@ -1095,7 +1112,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
/* must not be free()'d */
|
||||
let mut decoded_data: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut decoded_data_bytes = 0;
|
||||
let mut simplifier: Option<Simplify> = None;
|
||||
let mut simplifier: Option<dc_simplify_t> = None;
|
||||
if !(mime.is_null() || (*mime).mm_data.mm_single.is_null()) {
|
||||
mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime);
|
||||
mime_data = (*mime).mm_data.mm_single;
|
||||
@@ -1117,7 +1134,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
match mime_type {
|
||||
60 | 70 => {
|
||||
if simplifier.is_none() {
|
||||
simplifier = Some(Simplify::new());
|
||||
simplifier = Some(dc_simplify_t::new());
|
||||
}
|
||||
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
|
||||
let charset = mailmime_content_charset_get((*mime).mm_content_type);
|
||||
@@ -1167,7 +1184,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
/* check header directly as is_send_by_messenger is not yet set up */
|
||||
let is_msgrmsg = (!dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
"Chat-Version",
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null())
|
||||
as libc::c_int;
|
||||
@@ -1175,7 +1192,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
let simplified_txt = simplifier.unwrap().simplify(
|
||||
decoded_data,
|
||||
decoded_data_bytes as libc::c_int,
|
||||
mime_type == 70i32,
|
||||
if mime_type == 70i32 { 1i32 } else { 0i32 },
|
||||
is_msgrmsg,
|
||||
);
|
||||
if !simplified_txt.is_null()
|
||||
@@ -1191,7 +1208,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
} else {
|
||||
free(simplified_txt as *mut libc::c_void);
|
||||
}
|
||||
if simplifier.unwrap().is_forwarded {
|
||||
if 0 != simplifier.unwrap().is_forwarded {
|
||||
mimeparser.is_forwarded = 1i32
|
||||
}
|
||||
current_block = 10261677128829721533;
|
||||
@@ -1379,7 +1396,11 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
free(file_suffix as *mut libc::c_void);
|
||||
free(desired_filename as *mut libc::c_void);
|
||||
free(raw_mime as *mut libc::c_void);
|
||||
(mimeparser.parts.len() > old_part_count) as libc::c_int
|
||||
return if mimeparser.parts.len() > old_part_count {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -1531,8 +1552,10 @@ pub unsafe fn dc_mimeparser_is_mailinglist_message(mimeparser: &dc_mimeparser_t)
|
||||
if !dc_mimeparser_lookup_field(&mimeparser, "List-Id").is_null() {
|
||||
return 1i32;
|
||||
}
|
||||
let precedence: *mut mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(mimeparser, "Precedence");
|
||||
let precedence: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Precedence\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if !precedence.is_null() {
|
||||
if strcasecmp(
|
||||
(*precedence).fld_value,
|
||||
|
||||
@@ -27,13 +27,13 @@ pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u3
|
||||
}
|
||||
|
||||
if dc_is_mvbox(context, folder) {
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Stay);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
if 0 != (*msg).is_dc_message {
|
||||
dc_job_add(context, 200, (*msg).id as libc::c_int, Params::new(), 0);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Moving);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
|
||||
190
src/dc_msg.rs
190
src/dc_msg.rs
@@ -20,11 +20,12 @@ use std::ptr;
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_msg_t<'a> {
|
||||
pub magic: uint32_t,
|
||||
pub id: uint32_t,
|
||||
pub from_id: uint32_t,
|
||||
pub to_id: uint32_t,
|
||||
pub chat_id: uint32_t,
|
||||
pub move_state: MoveState,
|
||||
pub move_state: dc_move_state_t,
|
||||
pub type_0: Viewtype,
|
||||
pub state: libc::c_int,
|
||||
pub hidden: libc::c_int,
|
||||
@@ -35,7 +36,7 @@ pub struct dc_msg_t<'a> {
|
||||
pub context: &'a Context,
|
||||
pub rfc724_mid: *mut libc::c_char,
|
||||
pub in_reply_to: *mut libc::c_char,
|
||||
pub server_folder: Option<String>,
|
||||
pub server_folder: *mut libc::c_char,
|
||||
pub server_uid: uint32_t,
|
||||
pub is_dc_message: libc::c_int,
|
||||
pub starred: libc::c_int,
|
||||
@@ -167,7 +168,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!(
|
||||
"\nFile: {}, {}, bytes\n",
|
||||
as_str(p),
|
||||
dc_get_filebytes(context, as_path(p)) as libc::c_int,
|
||||
dc_get_filebytes(context, p) as libc::c_int,
|
||||
);
|
||||
}
|
||||
free(p as *mut libc::c_void);
|
||||
@@ -193,12 +194,14 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!("\n{}\n", rawtxt);
|
||||
}
|
||||
if !(*msg).rfc724_mid.is_null() && 0 != *(*msg).rfc724_mid.offset(0) as libc::c_int {
|
||||
ret += &format!("\nMessage-ID: {}", as_str((*msg).rfc724_mid));
|
||||
ret += &format!("\nMessage-ID: {}", (*msg).rfc724_mid as libc::c_int);
|
||||
}
|
||||
if let Some(ref server_folder) = (*msg).server_folder {
|
||||
if server_folder != "" {
|
||||
ret += &format!("\nLast seen as: {}/{}", server_folder, (*msg).server_uid);
|
||||
}
|
||||
if !(*msg).server_folder.is_null() && 0 != *(*msg).server_folder.offset(0) as libc::c_int {
|
||||
ret += &format!(
|
||||
"\nLast seen as: {}/{}",
|
||||
to_string((*msg).server_folder),
|
||||
(*msg).server_uid as libc::c_int,
|
||||
);
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
@@ -221,11 +224,12 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a>
|
||||
// approx. max. length returned by dc_get_msg_info()
|
||||
pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut dc_msg_t<'a> {
|
||||
let msg = dc_msg_t {
|
||||
magic: 0x11561156,
|
||||
id: 0,
|
||||
from_id: 0,
|
||||
to_id: 0,
|
||||
chat_id: 0,
|
||||
move_state: MoveState::Undefined,
|
||||
move_state: 0,
|
||||
type_0: viewtype,
|
||||
state: 0,
|
||||
hidden: 0,
|
||||
@@ -236,7 +240,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
|
||||
context,
|
||||
rfc724_mid: std::ptr::null_mut(),
|
||||
in_reply_to: std::ptr::null_mut(),
|
||||
server_folder: None,
|
||||
server_folder: std::ptr::null_mut(),
|
||||
server_uid: 0,
|
||||
is_dc_message: 0,
|
||||
starred: 0,
|
||||
@@ -248,22 +252,25 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_unref(msg: *mut dc_msg_t) {
|
||||
if msg.is_null() {
|
||||
pub unsafe fn dc_msg_unref(mut msg: *mut dc_msg_t) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
dc_msg_empty(msg);
|
||||
(*msg).magic = 0i32 as uint32_t;
|
||||
Box::from_raw(msg);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
free((*msg).rfc724_mid as *mut libc::c_void);
|
||||
(*msg).rfc724_mid = 0 as *mut libc::c_char;
|
||||
free((*msg).in_reply_to as *mut libc::c_void);
|
||||
(*msg).in_reply_to = 0 as *mut libc::c_char;
|
||||
free((*msg).server_folder as *mut libc::c_void);
|
||||
(*msg).server_folder = 0 as *mut libc::c_char;
|
||||
(*msg).param = Params::new();
|
||||
(*msg).hidden = 0i32;
|
||||
}
|
||||
@@ -271,7 +278,7 @@ pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
|
||||
pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret = 0 as *mut libc::c_char;
|
||||
|
||||
if !msg.is_null() {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
match (*msg).param.get(Param::MimeType) {
|
||||
Some(m) => {
|
||||
ret = m.strdup();
|
||||
@@ -355,7 +362,7 @@ pub unsafe fn dc_msg_guess_msgtype_from_suffix(
|
||||
pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut file_abs = 0 as *mut libc::c_char;
|
||||
|
||||
if !msg.is_null() {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if let Some(file_rel) = (*msg).param.get(Param::File) {
|
||||
let file_rel_c = CString::yolo(file_rel);
|
||||
file_abs = dc_get_abs_path((*msg).context, file_rel_c.as_ptr());
|
||||
@@ -378,7 +385,7 @@ pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
* @return 1=Message has location bound to it, 0=No location bound to message.
|
||||
*/
|
||||
pub unsafe fn dc_msg_has_location(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -407,7 +414,10 @@ pub unsafe fn dc_msg_set_location(
|
||||
latitude: libc::c_double,
|
||||
longitude: libc::c_double,
|
||||
) {
|
||||
if msg.is_null() || (latitude == 0.0 && longitude == 0.0) {
|
||||
if msg.is_null()
|
||||
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|
||||
|| (latitude == 0.0 && longitude == 0.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -416,14 +426,14 @@ pub unsafe fn dc_msg_set_location(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
if 0 != (*msg).timestamp_sent {
|
||||
return if 0 != (*msg).timestamp_sent {
|
||||
(*msg).timestamp_sent
|
||||
} else {
|
||||
(*msg).timestamp_sort
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id: u32) -> bool {
|
||||
@@ -450,7 +460,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
Some(s) => s.strdup(),
|
||||
None => std::ptr::null_mut(),
|
||||
};
|
||||
(*msg).server_folder = row.get::<_, Option<String>>(3)?;
|
||||
(*msg).server_folder = row.get::<_, String>(3)?.strdup();
|
||||
(*msg).server_uid = row.get(4)?;
|
||||
(*msg).move_state = row.get(5)?;
|
||||
(*msg).chat_id = row.get(6)?;
|
||||
@@ -462,21 +472,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
(*msg).type_0 = row.get(12)?;
|
||||
(*msg).state = row.get(13)?;
|
||||
(*msg).is_dc_message = row.get(14)?;
|
||||
|
||||
let text;
|
||||
if let rusqlite::types::ValueRef::Text(buf) = row.get_raw(15) {
|
||||
if let Ok(t) = String::from_utf8(buf.to_vec()) {
|
||||
text = t;
|
||||
} else {
|
||||
warn!(context, 0, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id);
|
||||
text = String::from_utf8_lossy(buf).into_owned();
|
||||
}
|
||||
} else {
|
||||
warn!(context, 0, "dc_msg_load_from_db: could not get text column for id {}", id);
|
||||
text = "[ Could not read from db ]".to_string();
|
||||
}
|
||||
(*msg).text = Some(text);
|
||||
|
||||
(*msg).text = row.get::<_, Option<String>>(15)?;
|
||||
(*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default();
|
||||
(*msg).starred = row.get(17)?;
|
||||
(*msg).hidden = row.get(18)?;
|
||||
@@ -492,18 +488,11 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
free(ptr.cast());
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(e) = res {
|
||||
warn!(
|
||||
context,
|
||||
0, "Error in msg_load_from_db for id {} because of {}", id, e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
res.is_ok()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut libc::c_char {
|
||||
@@ -639,13 +628,12 @@ pub fn dc_star_msgs(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> {
|
||||
let mut success = false;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let obj: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
if dc_msg_load_from_db(obj, context, msg_id) {
|
||||
success = true
|
||||
success = 1i32
|
||||
}
|
||||
|
||||
if success {
|
||||
if 0 != success {
|
||||
obj
|
||||
} else {
|
||||
dc_msg_unref(obj);
|
||||
@@ -654,7 +642,7 @@ pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -662,7 +650,7 @@ pub unsafe fn dc_msg_get_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_from_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -670,7 +658,7 @@ pub unsafe fn dc_msg_get_from_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
return if 0 != (*msg).chat_blocked {
|
||||
@@ -681,7 +669,7 @@ pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return Viewtype::Unknown;
|
||||
}
|
||||
|
||||
@@ -689,7 +677,7 @@ pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_state(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -697,7 +685,7 @@ pub unsafe fn dc_msg_get_state(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_received_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -705,7 +693,7 @@ pub unsafe fn dc_msg_get_received_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_sort_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -713,7 +701,7 @@ pub unsafe fn dc_msg_get_sort_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
}
|
||||
if let Some(ref text) = (*msg).text {
|
||||
@@ -727,7 +715,7 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret = 0 as *mut libc::c_char;
|
||||
|
||||
if !msg.is_null() {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if let Some(file) = (*msg).param.get(Param::File) {
|
||||
let file_c = CString::yolo(file);
|
||||
ret = dc_get_filename(file_c.as_ptr());
|
||||
@@ -741,17 +729,20 @@ pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t {
|
||||
if !msg.is_null() {
|
||||
let mut ret = 0;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if let Some(file) = (*msg).param.get(Param::File) {
|
||||
return dc_get_filebytes((*msg).context, &file);
|
||||
let file_c = CString::yolo(file);
|
||||
ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -759,7 +750,7 @@ pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -767,7 +758,7 @@ pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -776,7 +767,7 @@ pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_get_showpadlock(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
if (*msg)
|
||||
@@ -795,29 +786,35 @@ pub unsafe fn dc_msg_get_summary<'a>(
|
||||
msg: *mut dc_msg_t<'a>,
|
||||
mut chat: *const Chat<'a>,
|
||||
) -> *mut dc_lot_t {
|
||||
let mut ok_to_continue = true;
|
||||
let current_block: u64;
|
||||
let ret: *mut dc_lot_t = dc_lot_new();
|
||||
let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
|
||||
|
||||
if !msg.is_null() {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) {
|
||||
if chat.is_null() {
|
||||
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
|
||||
if chat_to_delete.is_null() {
|
||||
ok_to_continue = false;
|
||||
current_block = 15204159476013091401;
|
||||
} else {
|
||||
chat = chat_to_delete;
|
||||
current_block = 7815301370352969686;
|
||||
}
|
||||
} else {
|
||||
current_block = 7815301370352969686;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
|
||||
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
|
||||
{
|
||||
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match current_block {
|
||||
15204159476013091401 => {}
|
||||
_ => {
|
||||
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
|
||||
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
|
||||
{
|
||||
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
|
||||
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +827,7 @@ pub unsafe fn dc_msg_get_summarytext(
|
||||
msg: *mut dc_msg_t,
|
||||
approx_characters: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
}
|
||||
|
||||
@@ -941,7 +938,7 @@ pub unsafe fn dc_msg_has_deviating_timestamp(msg: *const dc_msg_t) -> libc::c_in
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
if (*msg).state >= DC_STATE_OUT_DELIVERED {
|
||||
@@ -952,7 +949,7 @@ pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return false;
|
||||
}
|
||||
0 != (*msg).starred
|
||||
@@ -960,7 +957,7 @@ pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_forwarded(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
if 0 != (*msg).param.get_int(Param::Forwarded).unwrap_or_default() {
|
||||
@@ -972,7 +969,7 @@ pub unsafe fn dc_msg_is_forwarded(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_info(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
let cmd = (*msg).param.get_int(Param::Cmd).unwrap_or_default();
|
||||
@@ -988,7 +985,7 @@ pub unsafe fn dc_msg_is_info(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1000,7 +997,10 @@ pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null() || (*msg).type_0 != Viewtype::File {
|
||||
if msg.is_null()
|
||||
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|
||||
|| (*msg).type_0 != Viewtype::File
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1048,15 +1048,15 @@ pub unsafe fn dc_msg_get_setupcodebegin(msg: *const dc_msg_t) -> *mut libc::c_ch
|
||||
}
|
||||
free(filename as *mut libc::c_void);
|
||||
free(buf as *mut libc::c_void);
|
||||
if !ret.is_null() {
|
||||
return if !ret.is_null() {
|
||||
ret
|
||||
} else {
|
||||
dc_strdup(0 as *const libc::c_char)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_text(mut msg: *mut dc_msg_t, text: *const libc::c_char) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
(*msg).text = if text.is_null() {
|
||||
@@ -1071,7 +1071,7 @@ pub unsafe fn dc_msg_set_file(
|
||||
file: *const libc::c_char,
|
||||
filemime: *const libc::c_char,
|
||||
) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
if !file.is_null() {
|
||||
@@ -1083,7 +1083,7 @@ pub unsafe fn dc_msg_set_file(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_dimension(msg: *mut dc_msg_t, width: libc::c_int, height: libc::c_int) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
(*msg).param.set_int(Param::Width, width);
|
||||
@@ -1091,7 +1091,7 @@ pub unsafe fn dc_msg_set_dimension(msg: *mut dc_msg_t, width: libc::c_int, heigh
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc::c_int) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
(*msg).param.set_int(Param::Duration, duration);
|
||||
@@ -1103,7 +1103,7 @@ pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
height: libc::c_int,
|
||||
duration: libc::c_int,
|
||||
) {
|
||||
if !msg.is_null() {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if width > 0 && height > 0 {
|
||||
(*msg).param.set_int(Param::Width, width);
|
||||
(*msg).param.set_int(Param::Height, height);
|
||||
@@ -1116,7 +1116,7 @@ pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_save_param_to_disk(msg: *mut dc_msg_t) -> bool {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ pub unsafe fn dc_msg_exists(context: &Context, msg_id: uint32_t) -> libc::c_int
|
||||
pub fn dc_update_msg_move_state(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
state: MoveState,
|
||||
state: dc_move_state_t,
|
||||
) -> bool {
|
||||
// we update the move_state for all messages belonging to a given Message-ID
|
||||
// so that the state stay intact when parts are deleted
|
||||
@@ -1201,9 +1201,9 @@ pub fn dc_update_msg_move_state(
|
||||
}
|
||||
|
||||
fn msgstate_can_fail(state: i32) -> bool {
|
||||
DC_STATE_OUT_PREPARING == state
|
||||
return DC_STATE_OUT_PREPARING == state
|
||||
|| DC_STATE_OUT_PENDING == state
|
||||
|| DC_STATE_OUT_DELIVERED == state
|
||||
|| DC_STATE_OUT_DELIVERED == state;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_set_msg_failed(context: &Context, msg_id: uint32_t, error: *const libc::c_char) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ use crate::aheader::EncryptPreference;
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_configure::*;
|
||||
use crate::dc_e2ee::*;
|
||||
@@ -41,7 +42,7 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
let mut group_name_urlencoded = 0 as *mut libc::c_char;
|
||||
let mut qr: Option<String> = None;
|
||||
|
||||
dc_ensure_secret_key_exists(context).ok();
|
||||
dc_ensure_secret_key_exists(context);
|
||||
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
|
||||
if invitenumber.is_null() {
|
||||
invitenumber = dc_create_id().strdup();
|
||||
@@ -148,7 +149,7 @@ pub unsafe fn dc_join_securejoin(context: &Context, qr: *const libc::c_char) ->
|
||||
let mut join_vg: libc::c_int = 0i32;
|
||||
let mut qr_scan: *mut dc_lot_t = 0 as *mut dc_lot_t;
|
||||
info!(context, 0, "Requesting secure-join ...",);
|
||||
dc_ensure_secret_key_exists(context).ok();
|
||||
dc_ensure_secret_key_exists(context);
|
||||
ongoing_allocated = dc_alloc_ongoing(context);
|
||||
if !(ongoing_allocated == 0i32) {
|
||||
qr_scan = dc_check_qr(context, qr);
|
||||
@@ -295,12 +296,14 @@ unsafe fn send_handshake_msg(
|
||||
}
|
||||
|
||||
unsafe fn chat_id_2_contact_id(context: &Context, contact_chat_id: uint32_t) -> uint32_t {
|
||||
let contacts = dc_get_chat_contacts(context, contact_chat_id);
|
||||
if contacts.len() == 1 {
|
||||
contacts[0]
|
||||
} else {
|
||||
0
|
||||
let mut contact_id: uint32_t = 0i32 as uint32_t;
|
||||
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
contact_id = dc_array_get_id(contacts, 0i32 as size_t)
|
||||
}
|
||||
dc_array_unref(contacts);
|
||||
|
||||
contact_id
|
||||
}
|
||||
|
||||
unsafe fn fingerprint_equals_sender(
|
||||
@@ -314,8 +317,8 @@ unsafe fn fingerprint_equals_sender(
|
||||
let mut fingerprint_equal: libc::c_int = 0i32;
|
||||
let contacts = dc_get_chat_contacts(context, contact_chat_id);
|
||||
|
||||
if contacts.len() == 1 {
|
||||
if let Ok(contact) = Contact::load_from_db(context, contacts[0]) {
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) {
|
||||
if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr())
|
||||
{
|
||||
let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint));
|
||||
@@ -329,6 +332,7 @@ unsafe fn fingerprint_equals_sender(
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dc_array_unref(contacts);
|
||||
|
||||
fingerprint_equal
|
||||
}
|
||||
@@ -442,7 +446,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
|
||||
grpid = dc_strdup((*scan).text2)
|
||||
}
|
||||
}
|
||||
if !encrypted_and_signed(mimeparser, scanned_fingerprint_of_alice) {
|
||||
if 0 == encrypted_and_signed(mimeparser, scanned_fingerprint_of_alice) {
|
||||
could_not_establish_secure_connection(
|
||||
context,
|
||||
contact_chat_id,
|
||||
@@ -518,7 +522,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
|
||||
b"Fingerprint not provided.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 4378276786830486580;
|
||||
} else if !encrypted_and_signed(mimeparser, fingerprint) {
|
||||
} else if 0 == encrypted_and_signed(mimeparser, fingerprint) {
|
||||
could_not_establish_secure_connection(
|
||||
context,
|
||||
contact_chat_id,
|
||||
@@ -664,7 +668,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
|
||||
}
|
||||
}
|
||||
if 0 != vg_expect_encrypted {
|
||||
if !encrypted_and_signed(mimeparser, scanned_fingerprint_of_alice) {
|
||||
if 0 == encrypted_and_signed(mimeparser, scanned_fingerprint_of_alice) {
|
||||
could_not_establish_secure_connection(
|
||||
context,
|
||||
contact_chat_id,
|
||||
@@ -883,21 +887,22 @@ unsafe fn mark_peer_as_verified(
|
||||
* Tools: Misc.
|
||||
******************************************************************************/
|
||||
|
||||
// TODO should return bool
|
||||
unsafe fn encrypted_and_signed(
|
||||
mimeparser: &dc_mimeparser_t,
|
||||
expected_fingerprint: *const libc::c_char,
|
||||
) -> bool {
|
||||
) -> libc::c_int {
|
||||
if 0 == mimeparser.e2ee_helper.encrypted {
|
||||
warn!(mimeparser.context, 0, "Message not encrypted.",);
|
||||
return false;
|
||||
return 0i32;
|
||||
}
|
||||
if mimeparser.e2ee_helper.signatures.len() <= 0 {
|
||||
warn!(mimeparser.context, 0, "Message not signed.",);
|
||||
return false;
|
||||
return 0i32;
|
||||
}
|
||||
if expected_fingerprint.is_null() {
|
||||
warn!(mimeparser.context, 0, "Fingerprint for comparison missing.",);
|
||||
return false;
|
||||
return 0i32;
|
||||
}
|
||||
if !mimeparser
|
||||
.e2ee_helper
|
||||
@@ -910,10 +915,10 @@ unsafe fn encrypted_and_signed(
|
||||
"Message does not match expected fingerprint {}.",
|
||||
as_str(expected_fingerprint),
|
||||
);
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
true
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate) {
|
||||
|
||||
@@ -3,18 +3,19 @@ use crate::dc_tools::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Simplify {
|
||||
pub is_forwarded: bool,
|
||||
pub is_cut_at_begin: bool,
|
||||
pub is_cut_at_end: bool,
|
||||
#[repr(C)]
|
||||
pub struct dc_simplify_t {
|
||||
pub is_forwarded: libc::c_int,
|
||||
pub is_cut_at_begin: libc::c_int,
|
||||
pub is_cut_at_end: libc::c_int,
|
||||
}
|
||||
|
||||
impl Simplify {
|
||||
impl dc_simplify_t {
|
||||
pub fn new() -> Self {
|
||||
Simplify {
|
||||
is_forwarded: false,
|
||||
is_cut_at_begin: false,
|
||||
is_cut_at_end: false,
|
||||
dc_simplify_t {
|
||||
is_forwarded: 0,
|
||||
is_cut_at_begin: 0,
|
||||
is_cut_at_end: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ impl Simplify {
|
||||
&mut self,
|
||||
in_unterminated: *const libc::c_char,
|
||||
in_bytes: libc::c_int,
|
||||
is_html: bool,
|
||||
is_html: libc::c_int,
|
||||
is_msgrmsg: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if in_bytes <= 0 {
|
||||
@@ -35,9 +36,9 @@ impl Simplify {
|
||||
/* create a copy of the given buffer */
|
||||
let mut out: *mut libc::c_char;
|
||||
let mut temp: *mut libc::c_char;
|
||||
self.is_forwarded = false;
|
||||
self.is_cut_at_begin = false;
|
||||
self.is_cut_at_end = false;
|
||||
self.is_forwarded = 0i32;
|
||||
self.is_cut_at_begin = 0i32;
|
||||
self.is_cut_at_end = 0i32;
|
||||
out = strndup(
|
||||
in_unterminated as *mut libc::c_char,
|
||||
in_bytes as libc::c_ulong,
|
||||
@@ -45,7 +46,7 @@ impl Simplify {
|
||||
if out.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
if is_html {
|
||||
if 0 != is_html {
|
||||
temp = dc_dehtml(out);
|
||||
if !temp.is_null() {
|
||||
free(out as *mut libc::c_void);
|
||||
@@ -95,7 +96,7 @@ impl Simplify {
|
||||
|| strcmp(line, b"----\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
{
|
||||
footer_mark = 1i32;
|
||||
self.is_cut_at_end = true
|
||||
self.is_cut_at_end = 1i32
|
||||
}
|
||||
if 0 != footer_mark {
|
||||
l_last = l;
|
||||
@@ -114,7 +115,7 @@ impl Simplify {
|
||||
&& strncmp(line1, b"From: \x00" as *const u8 as *const libc::c_char, 6) == 0i32
|
||||
&& *line2.offset(0isize) as libc::c_int == 0i32
|
||||
{
|
||||
self.is_forwarded = true;
|
||||
self.is_forwarded = 1i32;
|
||||
l_first += 3
|
||||
}
|
||||
}
|
||||
@@ -127,7 +128,7 @@ impl Simplify {
|
||||
|| strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|
||||
{
|
||||
l_last = l;
|
||||
self.is_cut_at_end = true;
|
||||
self.is_cut_at_end = 1i32;
|
||||
/* done */
|
||||
break;
|
||||
}
|
||||
@@ -144,7 +145,7 @@ impl Simplify {
|
||||
}
|
||||
if l_lastQuotedLine.is_some() {
|
||||
l_last = l_lastQuotedLine.unwrap();
|
||||
self.is_cut_at_end = true;
|
||||
self.is_cut_at_end = 1i32;
|
||||
if l_last > 1 {
|
||||
if is_empty_line(lines[l_last - 1]) {
|
||||
l_last -= 1
|
||||
@@ -179,12 +180,12 @@ impl Simplify {
|
||||
}
|
||||
if l_lastQuotedLine_0.is_some() {
|
||||
l_first = l_lastQuotedLine_0.unwrap() + 1;
|
||||
self.is_cut_at_begin = true
|
||||
self.is_cut_at_begin = 1i32
|
||||
}
|
||||
}
|
||||
/* re-create buffer from the remaining lines */
|
||||
let mut ret = String::new();
|
||||
if self.is_cut_at_begin {
|
||||
if 0 != self.is_cut_at_begin {
|
||||
ret += "[...]";
|
||||
}
|
||||
/* we write empty lines only in case and non-empty line follows */
|
||||
@@ -210,7 +211,7 @@ impl Simplify {
|
||||
pending_linebreaks = 1i32
|
||||
}
|
||||
}
|
||||
if self.is_cut_at_end && (!self.is_cut_at_begin || 0 != content_lines_added) {
|
||||
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
|
||||
ret += " [...]";
|
||||
}
|
||||
dc_free_splitted_lines(lines);
|
||||
@@ -267,11 +268,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_trim() {
|
||||
unsafe {
|
||||
let mut simplify = Simplify::new();
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let html: *const libc::c_char =
|
||||
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -287,11 +288,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_parse_href() {
|
||||
unsafe {
|
||||
let mut simplify = Simplify::new();
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<a href=url>text</a\x00" as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -307,12 +308,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_bold_text() {
|
||||
unsafe {
|
||||
let mut simplify = Simplify::new();
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<!DOCTYPE name [<!DOCTYPE ...>]><!-- comment -->text <b><?php echo ... ?>bold</b><![CDATA[<>]]>\x00"
|
||||
as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -328,12 +329,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_html_encoded() {
|
||||
unsafe {
|
||||
let mut simplify = Simplify::new();
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<>"'& äÄöÖüÜß fooÆçÇ ♦&noent;‎‏‌‍\x00"
|
||||
as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
|
||||
assert_eq!(
|
||||
strcmp(plain,
|
||||
|
||||
@@ -691,11 +691,11 @@ pub unsafe fn dc_decode_ext_header(to_decode: *const libc::c_char) -> *mut libc:
|
||||
}
|
||||
}
|
||||
free(charset as *mut libc::c_void);
|
||||
if !decoded.is_null() {
|
||||
return if !decoded.is_null() {
|
||||
decoded
|
||||
} else {
|
||||
dc_strdup(to_decode)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
|
||||
|
||||
299
src/dc_tools.rs
299
src/dc_tools.rs
@@ -1,8 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::str::FromStr;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use chrono::{Local, TimeZone};
|
||||
@@ -14,7 +12,6 @@ use crate::dc_array::*;
|
||||
use crate::error::Error;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
const ELLIPSE: &'static str = "[...]";
|
||||
|
||||
@@ -26,21 +23,8 @@ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||
0 != v && 0 == v & v - 1i32
|
||||
}
|
||||
|
||||
/// Duplicates a string
|
||||
///
|
||||
/// returns an empty string if NULL is given, never returns NULL (exits on errors)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string};
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup(str_a);
|
||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
/* string tools */
|
||||
/* dc_strdup() returns empty string if NULL is given, never returns NULL (exits on errors) */
|
||||
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
let ret: *mut libc::c_char;
|
||||
if !s.is_null() {
|
||||
@@ -54,27 +38,13 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
ret
|
||||
}
|
||||
|
||||
/// Duplicates a string, returns null if given string is null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup_keep_null, to_string};
|
||||
/// use std::ffi::{CStr};
|
||||
///
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
/* strdup(NULL) is undefined, safe_strdup_keep_null(NULL) returns NULL in this case */
|
||||
pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
if !s.is_null() {
|
||||
return if !s.is_null() {
|
||||
dc_strdup(s)
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
0 as *mut libc::c_char
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
|
||||
@@ -97,14 +67,50 @@ pub unsafe fn dc_str_replace(
|
||||
haystack: *mut *mut libc::c_char,
|
||||
needle: *const libc::c_char,
|
||||
replacement: *const libc::c_char,
|
||||
) {
|
||||
let haystack_s = to_string(*haystack);
|
||||
let needle_s = to_string(needle);
|
||||
let replacement_s = to_string(replacement);
|
||||
) -> libc::c_int {
|
||||
let mut replacements: libc::c_int = 0i32;
|
||||
let mut start_search_pos: libc::c_int = 0i32;
|
||||
let needle_len: libc::c_int;
|
||||
let replacement_len: libc::c_int;
|
||||
if haystack.is_null()
|
||||
|| (*haystack).is_null()
|
||||
|| needle.is_null()
|
||||
|| *needle.offset(0isize) as libc::c_int == 0i32
|
||||
{
|
||||
return 0i32;
|
||||
}
|
||||
needle_len = strlen(needle) as libc::c_int;
|
||||
replacement_len = (if !replacement.is_null() {
|
||||
strlen(replacement)
|
||||
} else {
|
||||
0
|
||||
}) as libc::c_int;
|
||||
loop {
|
||||
let mut p2: *mut libc::c_char =
|
||||
strstr((*haystack).offset(start_search_pos as isize), needle);
|
||||
if p2.is_null() {
|
||||
break;
|
||||
}
|
||||
start_search_pos =
|
||||
(p2.wrapping_offset_from(*haystack) + replacement_len as isize) as libc::c_int;
|
||||
*p2 = 0i32 as libc::c_char;
|
||||
p2 = p2.offset(needle_len as isize);
|
||||
let new_string: *mut libc::c_char = dc_mprintf(
|
||||
b"%s%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
*haystack,
|
||||
if !replacement.is_null() {
|
||||
replacement
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
p2,
|
||||
);
|
||||
free(*haystack as *mut libc::c_void);
|
||||
*haystack = new_string;
|
||||
replacements += 1
|
||||
}
|
||||
|
||||
free(*haystack as *mut libc::c_void);
|
||||
|
||||
*haystack = haystack_s.replace(&needle_s, &replacement_s).strdup();
|
||||
replacements
|
||||
}
|
||||
|
||||
pub unsafe fn dc_ftoa(f: libc::c_double) -> *mut libc::c_char {
|
||||
@@ -894,10 +900,10 @@ pub unsafe fn dc_get_filename(pathNfilename: *const libc::c_char) -> *mut libc::
|
||||
}
|
||||
if !p.is_null() {
|
||||
p = p.offset(1isize);
|
||||
dc_strdup(p)
|
||||
return dc_strdup(p);
|
||||
} else {
|
||||
dc_strdup(pathNfilename)
|
||||
}
|
||||
return dc_strdup(pathNfilename);
|
||||
};
|
||||
}
|
||||
|
||||
// the case of the suffix is preserved
|
||||
@@ -1080,20 +1086,21 @@ pub unsafe fn dc_get_abs_path(
|
||||
pathNfilename_abs
|
||||
}
|
||||
|
||||
pub fn dc_file_exist(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
dc_get_abs_path_safe(context, &path).exists()
|
||||
pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
|
||||
}
|
||||
|
||||
pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> uint64_t {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
|
||||
let path_abs = dc_get_abs_path_safe(context, as_path(path));
|
||||
match fs::metadata(&path_abs) {
|
||||
Ok(meta) => meta.len() as uint64_t,
|
||||
Err(_err) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
let path = as_path(path);
|
||||
let path_abs = dc_get_abs_path_safe(context, path);
|
||||
let res = if path_abs.is_file() {
|
||||
fs::remove_file(path_abs)
|
||||
} else {
|
||||
@@ -1101,53 +1108,56 @@ pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> b
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(_) => true,
|
||||
Ok(_) => 1,
|
||||
Err(_err) => {
|
||||
warn!(context, 0, "Cannot delete \"{}\".", path.as_ref().display());
|
||||
false
|
||||
warn!(context, 0, "Cannot delete \"{}\".", path.display());
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_copy_file(
|
||||
context: &Context,
|
||||
src: impl AsRef<std::path::Path>,
|
||||
dest: impl AsRef<std::path::Path>,
|
||||
) -> bool {
|
||||
let src_abs = dc_get_abs_path_safe(context, &src);
|
||||
let dest_abs = dc_get_abs_path_safe(context, &dest);
|
||||
src: *const libc::c_char,
|
||||
dest: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let src = as_path(src);
|
||||
let dest = as_path(dest);
|
||||
let src_abs = dc_get_abs_path_safe(context, src);
|
||||
let dest_abs = dc_get_abs_path_safe(context, dest);
|
||||
match fs::copy(&src_abs, &dest_abs) {
|
||||
Ok(_) => true,
|
||||
Ok(_) => 1,
|
||||
Err(_) => {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Cannot copy \"{}\" to \"{}\".",
|
||||
src.as_ref().display(),
|
||||
dest.as_ref().display(),
|
||||
src.display(),
|
||||
dest.display(),
|
||||
);
|
||||
false
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
let path = as_path(path);
|
||||
let path_abs = dc_get_abs_path_safe(context, path);
|
||||
if !path_abs.exists() {
|
||||
match fs::create_dir_all(path_abs) {
|
||||
Ok(_) => true,
|
||||
Ok(_) => 1,
|
||||
Err(_err) => {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot create directory \"{}\".",
|
||||
path.as_ref().display(),
|
||||
path.display(),
|
||||
);
|
||||
false
|
||||
0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
true
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,7 +1266,7 @@ pub unsafe fn dc_get_fine_pathNfilename(
|
||||
dotNSuffix,
|
||||
)
|
||||
}
|
||||
if !dc_file_exist(context, as_path(ret)) {
|
||||
if 0 == dc_file_exist(context, ret) {
|
||||
/* fine filename found */
|
||||
break;
|
||||
} else {
|
||||
@@ -1274,8 +1284,8 @@ pub unsafe fn dc_get_fine_pathNfilename(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_is_blobdir_path(context: &Context, path: *const libc::c_char) -> bool {
|
||||
strncmp(path, context.get_blobdir(), strlen(context.get_blobdir())) == 0
|
||||
|| strncmp(path, b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, 8) == 0
|
||||
return strncmp(path, context.get_blobdir(), strlen(context.get_blobdir())) == 0
|
||||
|| strncmp(path, b"$BLOBDIR\x00" as *const u8 as *const libc::c_char, 8) == 0;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_make_rel_path(context: &Context, path: *mut *mut libc::c_char) {
|
||||
@@ -1310,11 +1320,11 @@ pub unsafe fn dc_make_rel_and_copy(context: &Context, path: *mut *mut libc::c_ch
|
||||
);
|
||||
blobdir_path.is_null()
|
||||
}
|
||||
|| !dc_copy_file(context, as_path(*path), as_path(blobdir_path)))
|
||||
|| 0 == dc_copy_file(context, *path, blobdir_path))
|
||||
{
|
||||
free(*path as *mut libc::c_void);
|
||||
*path = blobdir_path;
|
||||
blobdir_path = ptr::null_mut();
|
||||
blobdir_path = 0 as *mut libc::c_char;
|
||||
dc_make_rel_path(context, path);
|
||||
success = true;
|
||||
}
|
||||
@@ -1452,9 +1462,9 @@ pub trait StrExt {
|
||||
///
|
||||
/// This allocates a new raw C string which must be freed using
|
||||
/// `free`. It takes care of some common pitfalls with using
|
||||
/// [CString.as_ptr].
|
||||
/// [CString::as_ptr].
|
||||
///
|
||||
/// [CString.as_ptr]: std::ffi::CString.as_ptr
|
||||
/// [CString::as_ptr]: std::ffi::CString::as_ptr
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@@ -1558,117 +1568,11 @@ pub fn time() -> i64 {
|
||||
.as_secs() as i64
|
||||
}
|
||||
|
||||
/// Very simple email address wrapper.
|
||||
///
|
||||
/// Represents an email address, right now just the `name@domain` portion.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::EmailAddress;
|
||||
/// let email = match EmailAddress::new("someone@example.com") {
|
||||
/// Ok(addr) => addr,
|
||||
/// Err(e) => panic!("Error parsing address, error was {}", e),
|
||||
/// };
|
||||
/// assert_eq!(&email.local, "someone");
|
||||
/// assert_eq!(&email.domain, "example.com");
|
||||
/// assert_eq!(email.to_string(), "someone@example.com");
|
||||
/// ```
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct EmailAddress {
|
||||
pub local: String,
|
||||
pub domain: String,
|
||||
}
|
||||
|
||||
impl EmailAddress {
|
||||
pub fn new(input: &str) -> Result<Self, Error> {
|
||||
input.parse::<EmailAddress>()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EmailAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}@{}", self.local, self.domain)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for EmailAddress {
|
||||
type Err = Error;
|
||||
|
||||
/// Performs a dead-simple parse of an email address.
|
||||
fn from_str(input: &str) -> Result<EmailAddress, Error> {
|
||||
ensure!(!input.is_empty(), "empty string is not valid");
|
||||
let parts: Vec<&str> = input.rsplitn(2, '@').collect();
|
||||
|
||||
ensure!(parts.len() > 1, "missing '@' character");
|
||||
let local = parts[1];
|
||||
let domain = parts[0];
|
||||
|
||||
ensure!(
|
||||
!local.is_empty(),
|
||||
"empty string is not valid for local part"
|
||||
);
|
||||
ensure!(domain.len() > 3, "domain is too short");
|
||||
|
||||
let dot = domain.find('.');
|
||||
ensure!(dot.is_some(), "invalid domain");
|
||||
ensure!(dot.unwrap() < domain.len() - 2, "invalid domain");
|
||||
|
||||
Ok(EmailAddress {
|
||||
local: local.to_string(),
|
||||
domain: domain.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[test]
|
||||
fn test_dc_strdup() {
|
||||
unsafe {
|
||||
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
|
||||
// Value of str_a_copy should equal foobar
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("foobar").unwrap().as_c_str()
|
||||
);
|
||||
// Address of str_a should be different from str_a_copy
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
|
||||
let str_a = std::ptr::null() as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
// Value of str_a_copy should equal ""
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("").unwrap().as_c_str()
|
||||
);
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_strdup_keep_null() {
|
||||
unsafe {
|
||||
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("foobar").unwrap().as_c_str()
|
||||
);
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
|
||||
let str_a = 0 as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
assert_eq!(str_a.is_null(), true);
|
||||
assert_eq!(str_a_copy.is_null(), true);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_ltrim() {
|
||||
unsafe {
|
||||
@@ -1743,7 +1647,7 @@ mod tests {
|
||||
fn test_dc_str_replace() {
|
||||
unsafe {
|
||||
let mut str: *mut libc::c_char = strdup(b"aaa\x00" as *const u8 as *const libc::c_char);
|
||||
dc_str_replace(
|
||||
let replacements: libc::c_int = dc_str_replace(
|
||||
&mut str,
|
||||
b"a\x00" as *const u8 as *const libc::c_char,
|
||||
b"ab\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1752,6 +1656,7 @@ mod tests {
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"ababab"
|
||||
);
|
||||
assert_eq!(replacements, 3);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
@@ -2181,30 +2086,4 @@ mod tests {
|
||||
assert_eq!(grpid, Some("1234567890123456"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_emailaddress_parse() {
|
||||
assert_eq!(EmailAddress::new("").is_ok(), false);
|
||||
assert_eq!(
|
||||
EmailAddress::new("user@domain.tld").unwrap(),
|
||||
EmailAddress {
|
||||
local: "user".into(),
|
||||
domain: "domain.tld".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(EmailAddress::new("uuu").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("dd.tt").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("tt.dd@uu").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("u@d").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("u@d.").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("u@d.t").is_ok(), false);
|
||||
assert_eq!(
|
||||
EmailAddress::new("u@d.tt").unwrap(),
|
||||
EmailAddress {
|
||||
local: "u".into(),
|
||||
domain: "d.tt".into(),
|
||||
}
|
||||
);
|
||||
assert_eq!(EmailAddress::new("u@.tt").is_ok(), false);
|
||||
assert_eq!(EmailAddress::new("@d.tt").is_ok(), false);
|
||||
}
|
||||
}
|
||||
|
||||
99
src/imap.rs
99
src/imap.rs
@@ -1,9 +1,6 @@
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Condvar, Mutex, RwLock,
|
||||
};
|
||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use crate::constants::*;
|
||||
@@ -21,9 +18,9 @@ pub const DC_ALREADY_DONE: usize = 2;
|
||||
pub const DC_RETRY_LATER: usize = 1;
|
||||
pub const DC_FAILED: usize = 0;
|
||||
|
||||
const PREFETCH_FLAGS: &str = "(UID ENVELOPE)";
|
||||
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
||||
const FETCH_FLAGS: &str = "(FLAGS)";
|
||||
const PREFETCH_FLAGS: &'static str = "(UID ENVELOPE)";
|
||||
const BODY_FLAGS: &'static str = "(FLAGS BODY.PEEK[])";
|
||||
const FETCH_FLAGS: &'static str = "(FLAGS)";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Imap {
|
||||
@@ -38,8 +35,6 @@ pub struct Imap {
|
||||
session: Arc<Mutex<Option<Session>>>,
|
||||
stream: Arc<RwLock<Option<net::TcpStream>>>,
|
||||
connected: Arc<Mutex<bool>>,
|
||||
|
||||
should_reconnect: AtomicBool,
|
||||
}
|
||||
|
||||
struct OAuth2 {
|
||||
@@ -204,8 +199,8 @@ impl Session {
|
||||
|
||||
pub fn create<S: AsRef<str>>(&mut self, mailbox_name: S) -> imap::error::Result<()> {
|
||||
match self {
|
||||
Session::Secure(i) => i.create(mailbox_name),
|
||||
Session::Insecure(i) => i.create(mailbox_name),
|
||||
Session::Secure(i) => i.subscribe(mailbox_name),
|
||||
Session::Insecure(i) => i.subscribe(mailbox_name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,8 +260,8 @@ impl Session {
|
||||
|
||||
pub fn idle(&mut self) -> imap::error::Result<IdleHandle> {
|
||||
match self {
|
||||
Session::Secure(i) => i.idle().map(IdleHandle::Secure),
|
||||
Session::Insecure(i) => i.idle().map(IdleHandle::Insecure),
|
||||
Session::Secure(i) => i.idle().map(|h| IdleHandle::Secure(h)),
|
||||
Session::Insecure(i) => i.idle().map(|h| IdleHandle::Insecure(h)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +313,7 @@ pub struct ImapConfig {
|
||||
pub selected_folder: Option<String>,
|
||||
pub selected_mailbox: Option<imap::types::Mailbox>,
|
||||
pub selected_folder_needs_expunge: bool,
|
||||
pub should_reconnect: bool,
|
||||
pub can_idle: bool,
|
||||
pub has_xlist: bool,
|
||||
pub imap_delimiter: char,
|
||||
@@ -336,6 +332,7 @@ impl Default for ImapConfig {
|
||||
selected_folder: None,
|
||||
selected_mailbox: None,
|
||||
selected_folder_needs_expunge: false,
|
||||
should_reconnect: false,
|
||||
can_idle: false,
|
||||
has_xlist: false,
|
||||
imap_delimiter: '.',
|
||||
@@ -363,7 +360,6 @@ impl Imap {
|
||||
precheck_imf,
|
||||
receive_imf,
|
||||
connected: Arc::new(Mutex::new(false)),
|
||||
should_reconnect: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +368,7 @@ impl Imap {
|
||||
}
|
||||
|
||||
pub fn should_reconnect(&self) -> bool {
|
||||
self.should_reconnect.load(Ordering::Relaxed)
|
||||
self.config.read().unwrap().should_reconnect
|
||||
}
|
||||
|
||||
fn setup_handle_if_needed(&self, context: &Context) -> bool {
|
||||
@@ -385,7 +381,7 @@ impl Imap {
|
||||
}
|
||||
|
||||
if self.is_connected() && self.stream.read().unwrap().is_some() {
|
||||
self.should_reconnect.store(false, Ordering::Relaxed);
|
||||
self.config.write().unwrap().should_reconnect = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -455,7 +451,7 @@ impl Imap {
|
||||
}
|
||||
};
|
||||
|
||||
self.should_reconnect.store(false, Ordering::Relaxed);
|
||||
self.config.write().unwrap().should_reconnect = false;
|
||||
|
||||
match login_res {
|
||||
Ok((session, stream)) => {
|
||||
@@ -543,7 +539,7 @@ impl Imap {
|
||||
let mut config = self.config.write().unwrap();
|
||||
config.addr = addr.to_string();
|
||||
config.imap_server = imap_server.to_string();
|
||||
config.imap_port = imap_port;
|
||||
config.imap_port = imap_port.into();
|
||||
config.imap_user = imap_user.to_string();
|
||||
config.imap_pw = imap_pw.to_string();
|
||||
config.server_flags = server_flags;
|
||||
@@ -554,12 +550,14 @@ impl Imap {
|
||||
return false;
|
||||
}
|
||||
|
||||
let (teardown, can_idle, has_xlist) = match &mut *self.session.lock().unwrap() {
|
||||
let teardown: bool;
|
||||
|
||||
match &mut *self.session.lock().unwrap() {
|
||||
Some(ref mut session) => {
|
||||
if let Ok(caps) = session.capabilities() {
|
||||
if !context.sql.is_open() {
|
||||
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
|
||||
(true, false, false)
|
||||
teardown = true;
|
||||
} else {
|
||||
let can_idle = caps.has("IDLE");
|
||||
let has_xlist = caps.has("XLIST");
|
||||
@@ -576,23 +574,24 @@ impl Imap {
|
||||
lp.mail_user,
|
||||
caps_list,
|
||||
);
|
||||
(false, can_idle, has_xlist)
|
||||
self.config.write().unwrap().can_idle = can_idle;
|
||||
self.config.write().unwrap().has_xlist = has_xlist;
|
||||
*self.connected.lock().unwrap() = true;
|
||||
teardown = false;
|
||||
}
|
||||
} else {
|
||||
(true, false, false)
|
||||
teardown = true;
|
||||
}
|
||||
}
|
||||
None => (true, false, false),
|
||||
};
|
||||
|
||||
None => {
|
||||
teardown = true;
|
||||
}
|
||||
}
|
||||
if teardown {
|
||||
self.unsetup_handle(context);
|
||||
self.free_connect_params();
|
||||
false
|
||||
} else {
|
||||
self.config.write().unwrap().can_idle = can_idle;
|
||||
self.config.write().unwrap().has_xlist = has_xlist;
|
||||
*self.connected.lock().unwrap() = true;
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -690,8 +689,9 @@ impl Imap {
|
||||
err
|
||||
);
|
||||
|
||||
self.config.write().unwrap().selected_folder = None;
|
||||
self.should_reconnect.store(true, Ordering::Relaxed);
|
||||
let mut config = self.config.write().unwrap();
|
||||
config.selected_folder = None;
|
||||
config.should_reconnect = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -777,7 +777,7 @@ impl Imap {
|
||||
match session.fetch(set, PREFETCH_FLAGS) {
|
||||
Ok(list) => list,
|
||||
Err(_err) => {
|
||||
self.should_reconnect.store(true, Ordering::Relaxed);
|
||||
self.config.write().unwrap().should_reconnect = true;
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
@@ -822,7 +822,7 @@ impl Imap {
|
||||
match session.uid_fetch(set, PREFETCH_FLAGS) {
|
||||
Ok(list) => list,
|
||||
Err(err) => {
|
||||
warn!(context, 0, "failed to fetch uids: {}", err);
|
||||
eprintln!("fetch err: {:?}", err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -928,13 +928,15 @@ impl Imap {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut retry_later = false;
|
||||
|
||||
let set = format!("{}", server_uid);
|
||||
|
||||
let msgs = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_fetch(set, BODY_FLAGS) {
|
||||
Ok(msgs) => msgs,
|
||||
Err(err) => {
|
||||
self.should_reconnect.store(true, Ordering::Relaxed);
|
||||
self.config.write().unwrap().should_reconnect = true;
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
@@ -944,11 +946,17 @@ impl Imap {
|
||||
self.should_reconnect(),
|
||||
err
|
||||
);
|
||||
return 0;
|
||||
|
||||
if self.should_reconnect() {
|
||||
// maybe we should also retry on other errors, however, we should check this carefully, as this may result in a dead lock!
|
||||
retry_later = true;
|
||||
}
|
||||
|
||||
return if retry_later { 0 } else { 1 };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
return if retry_later { 0 } else { 1 };
|
||||
};
|
||||
|
||||
if msgs.is_empty() {
|
||||
@@ -996,7 +1004,11 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
1
|
||||
if retry_later {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn idle(&self, context: &Context) {
|
||||
@@ -1061,7 +1073,7 @@ impl Imap {
|
||||
context,
|
||||
0, "IMAP-IDLE wait cancelled, we will reconnect soon."
|
||||
);
|
||||
self.should_reconnect.store(true, Ordering::Relaxed);
|
||||
self.config.write().unwrap().should_reconnect = true;
|
||||
}
|
||||
_ => {
|
||||
warn!(context, 0, "IMAP-IDLE returns unknown value: {}", err);
|
||||
@@ -1564,23 +1576,20 @@ impl Imap {
|
||||
info!(context, 0, "MVBOX-folder created.",);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("create error: {:?}", err);
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot create MVBOX-folder, using trying INBOX subfolder. ({})",
|
||||
err
|
||||
0, "Cannot create MVBOX-folder, using trying INBOX subfolder."
|
||||
);
|
||||
|
||||
match session.create(&fallback_folder) {
|
||||
Ok(_) => {
|
||||
mvbox_folder = Some(fallback_folder);
|
||||
info!(
|
||||
context,
|
||||
0, "MVBOX-folder created as INBOX subfolder. ({})", err
|
||||
);
|
||||
info!(context, 0, "MVBOX-folder created as INBOX subfolder.",);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, 0, "Cannot create MVBOX-folder. ({})", err);
|
||||
eprintln!("create error: {:?}", err);
|
||||
warn!(context, 0, "Cannot create MVBOX-folder.",);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ impl Key {
|
||||
}
|
||||
|
||||
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
|
||||
if bytes.is_empty() {
|
||||
if 0 == bytes.len() {
|
||||
return None;
|
||||
}
|
||||
let res: Result<Key, _> = match key_type {
|
||||
@@ -283,7 +283,7 @@ impl Key {
|
||||
Key::Public(_) => None,
|
||||
Key::Secret(k) => {
|
||||
let pub_key = k.public_key();
|
||||
pub_key.sign(k, || "".into()).map(Key::Public).ok()
|
||||
pub_key.sign(k, || "".into()).map(|k| Key::Public(k)).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
#![deny(clippy::correctness)]
|
||||
// TODO: make all of these errors, such that clippy actually passes.
|
||||
#![warn(clippy::all, clippy::perf, clippy::not_unsafe_ptr_arg_deref)]
|
||||
// This is nice, but for now just annoying.
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
#![feature(ptr_wrapping_offset_from)]
|
||||
#![feature(c_variadic, ptr_wrapping_offset_from, ptr_cast)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
@@ -166,6 +166,7 @@ impl<'a> Peerstate<'a> {
|
||||
|
||||
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
||||
info!(context, 0, "peerstate.from_addr {}", addr);
|
||||
Self::from_stmt(context, query, &[addr])
|
||||
}
|
||||
|
||||
@@ -187,6 +188,7 @@ impl<'a> Peerstate<'a> {
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
{
|
||||
info!(context, 0, "from_stmt query {:?}", query);
|
||||
context
|
||||
.sql
|
||||
.query_row(query, params, |row| {
|
||||
@@ -198,38 +200,28 @@ impl<'a> Peerstate<'a> {
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(row.get(0)?);
|
||||
info!(context, 0, "from_stmt res.addr {:?} starting", res.addr);
|
||||
res.last_seen = row.get(1)?;
|
||||
res.last_seen_autocrypt = row.get(2)?;
|
||||
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
||||
res.gossip_timestamp = row.get(5)?;
|
||||
let pkf: String = row.get(7)?;
|
||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
||||
|
||||
let t: Result<String, rusqlite::Error> = row.get(8);
|
||||
let gkf: String = match t {
|
||||
Err(_) => String::from(""),
|
||||
Ok(res) => res,
|
||||
};
|
||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
||||
|
||||
let t: Result<String, rusqlite::Error> = row.get(10);
|
||||
let vkf: String = match t {
|
||||
Err(_) => String::from(""),
|
||||
Ok(res) => res,
|
||||
};
|
||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
||||
|
||||
res.public_key_fingerprint = row.get(7)?;
|
||||
if res
|
||||
.public_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.public_key_fingerprint = None;
|
||||
}
|
||||
res.gossip_key_fingerprint = row.get(8)?;
|
||||
if res
|
||||
.gossip_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.gossip_key_fingerprint = None;
|
||||
}
|
||||
res.verified_key_fingerprint = row.get(10)?;
|
||||
if res
|
||||
.verified_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.verified_key_fingerprint = None;
|
||||
}
|
||||
res.public_key = row
|
||||
.get(4)
|
||||
.ok()
|
||||
@@ -242,7 +234,6 @@ impl<'a> Peerstate<'a> {
|
||||
.get(9)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
|
||||
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
|
||||
VerifiedKey::Gossip
|
||||
} else if vk == res.public_key {
|
||||
@@ -426,6 +417,10 @@ impl<'a> Peerstate<'a> {
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
info!(
|
||||
self.context,
|
||||
0, "update acpeerstates with peerstate {:?}", self
|
||||
);
|
||||
success = sql::execute(
|
||||
self.context,
|
||||
sql,
|
||||
|
||||
13
src/pgp.rs
13
src/pgp.rs
@@ -2,7 +2,6 @@ use std::collections::HashSet;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CStr;
|
||||
use std::io::Cursor;
|
||||
use std::ptr;
|
||||
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||
@@ -30,19 +29,19 @@ pub unsafe fn dc_split_armored_data(
|
||||
let mut line: *mut libc::c_char = buf;
|
||||
let mut p1: *mut libc::c_char = buf;
|
||||
let mut p2: *mut libc::c_char;
|
||||
let mut headerline: *mut libc::c_char = ptr::null_mut();
|
||||
let mut base64: *mut libc::c_char = ptr::null_mut();
|
||||
let mut headerline: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut base64: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !ret_headerline.is_null() {
|
||||
*ret_headerline = 0 as *const libc::c_char
|
||||
}
|
||||
if !ret_setupcodebegin.is_null() {
|
||||
*ret_setupcodebegin = ptr::null_mut();
|
||||
*ret_setupcodebegin = 0 as *const libc::c_char
|
||||
}
|
||||
if !ret_preferencrypt.is_null() {
|
||||
*ret_preferencrypt = ptr::null();
|
||||
*ret_preferencrypt = 0 as *const libc::c_char
|
||||
}
|
||||
if !ret_base64.is_null() {
|
||||
*ret_base64 = ptr::null();
|
||||
*ret_base64 = 0 as *const libc::c_char
|
||||
}
|
||||
if !(buf.is_null() || ret_headerline.is_null()) {
|
||||
dc_remove_cr_chars(buf);
|
||||
@@ -144,7 +143,7 @@ pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
|
||||
.key_type(PgpKeyType::Rsa(2048))
|
||||
.can_create_certificates(true)
|
||||
.can_sign(true)
|
||||
.primary_user_id(user_id)
|
||||
.primary_user_id(user_id.into())
|
||||
.passphrase(None)
|
||||
.preferred_symmetric_algorithms(smallvec![
|
||||
SymmetricKeyAlgorithm::AES256,
|
||||
|
||||
21
src/sql.rs
21
src/sql.rs
@@ -4,6 +4,7 @@ use std::sync::{Arc, RwLock};
|
||||
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
|
||||
use thread_local_object::ThreadLocal;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::{Error, Result};
|
||||
@@ -286,7 +287,7 @@ impl Sql {
|
||||
|
||||
fn table_exists(conn: &Connection, name: impl AsRef<str>) -> Result<bool> {
|
||||
let mut exists = false;
|
||||
conn.pragma(None, "table_info", &name.as_ref().to_string(), |_row| {
|
||||
conn.pragma(None, "table_info", &format!("{}", name.as_ref()), |_row| {
|
||||
// will only be executed if the info was found
|
||||
exists = true;
|
||||
Ok(())
|
||||
@@ -688,6 +689,10 @@ fn open(
|
||||
"ALTER TABLE msgs ADD COLUMN move_state INTEGER DEFAULT 1;",
|
||||
params![],
|
||||
)?;
|
||||
assert_eq!(DC_MOVE_STATE_UNDEFINED as libc::c_int, 0);
|
||||
assert_eq!(DC_MOVE_STATE_PENDING as libc::c_int, 1);
|
||||
assert_eq!(DC_MOVE_STATE_STAY as libc::c_int, 2);
|
||||
assert_eq!(DC_MOVE_STATE_MOVING as libc::c_int, 3);
|
||||
|
||||
dbversion = 48;
|
||||
sql.set_config_int(context, "dbversion", 48)?;
|
||||
@@ -830,7 +835,7 @@ where
|
||||
&err,
|
||||
querystr.as_ref()
|
||||
);
|
||||
Err(err)
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1003,10 +1008,10 @@ pub fn housekeeping(context: &Context) {
|
||||
let name_f = entry.file_name();
|
||||
let name_s = name_f.to_string_lossy();
|
||||
|
||||
if is_file_in_use(&files_in_use, None, &name_s)
|
||||
|| is_file_in_use(&files_in_use, Some(".increation"), &name_s)
|
||||
|| is_file_in_use(&files_in_use, Some(".waveform"), &name_s)
|
||||
|| is_file_in_use(&files_in_use, Some("-preview.jpg"), &name_s)
|
||||
if is_file_in_use(&mut files_in_use, None, &name_s)
|
||||
|| is_file_in_use(&mut files_in_use, Some(".increation"), &name_s)
|
||||
|| is_file_in_use(&mut files_in_use, Some(".waveform"), &name_s)
|
||||
|| is_file_in_use(&mut files_in_use, Some("-preview.jpg"), &name_s)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1042,8 +1047,8 @@ pub fn housekeeping(context: &Context) {
|
||||
unreferenced_count,
|
||||
entry.file_name()
|
||||
);
|
||||
let path = entry.path();
|
||||
dc_delete_file(context, path);
|
||||
let path = entry.path().to_c_string().unwrap();
|
||||
dc_delete_file(context, path.as_ptr());
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
@@ -2,15 +2,9 @@
|
||||
//!
|
||||
//! This module is only compiled for test runs.
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
use libc::uintptr_t;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Event, KeyType};
|
||||
use crate::context::{dc_context_new, dc_open, Context};
|
||||
use crate::key;
|
||||
use crate::types::dc_callback_t;
|
||||
|
||||
/// A Context and temporary directory.
|
||||
@@ -50,127 +44,3 @@ pub fn test_context(cb: Option<dc_callback_t>) -> TestContext {
|
||||
pub fn dummy_context() -> TestContext {
|
||||
test_context(None)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn logging_cb(
|
||||
_ctx: &Context,
|
||||
evt: Event,
|
||||
_d1: uintptr_t,
|
||||
d2: uintptr_t,
|
||||
) -> uintptr_t {
|
||||
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
|
||||
match evt {
|
||||
Event::INFO => println!("I: {}", to_str(d2)),
|
||||
Event::WARNING => println!("W: {}", to_str(d2)),
|
||||
Event::ERROR => println!("E: {}", to_str(d2)),
|
||||
_ => (),
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Creates Alice with a pre-generated keypair.
|
||||
///
|
||||
/// Returns the address of the keypair created (alice@example.org).
|
||||
pub fn configure_alice_keypair(ctx: &Context) -> String {
|
||||
let addr = String::from("alice@example.org");
|
||||
ctx.set_config(Config::ConfiguredAddr, Some(&addr)).unwrap();
|
||||
|
||||
// The keypair was created using:
|
||||
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtq",
|
||||
"m1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353",
|
||||
"r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68",
|
||||
"JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6F",
|
||||
"FrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHb",
|
||||
"Iu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3V",
|
||||
"WushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0S",
|
||||
"ut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQ",
|
||||
"sWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEm",
|
||||
"dr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8k",
|
||||
"QrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJW",
|
||||
"yyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj",
|
||||
"5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3",
|
||||
"jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeG",
|
||||
"Kyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl08",
|
||||
"6fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQ",
|
||||
"k6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Ee",
|
||||
"h+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BM",
|
||||
"zcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwb",
|
||||
"YklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP",
|
||||
"12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmh",
|
||||
"o0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugz",
|
||||
"OmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnF",
|
||||
"n7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6",
|
||||
"uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEe",
|
||||
"LrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCIC",
|
||||
"N1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86K",
|
||||
"C2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIdd",
|
||||
"KsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T",
|
||||
"/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZL",
|
||||
"j3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtp",
|
||||
"Do5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9u",
|
||||
"RMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe",
|
||||
"/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH",
|
||||
"95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9",
|
||||
"QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ",
|
||||
"8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//",
|
||||
"wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg",
|
||||
"9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwK",
|
||||
"Gjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPB",
|
||||
"f4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAg",
|
||||
"BQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/",
|
||||
"dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJ",
|
||||
"ywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJ",
|
||||
"uiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6",
|
||||
"RDXIeYJfqrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMl",
|
||||
"ammDliPwsK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKOb",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql);
|
||||
assert_eq!(saved, true, "Failed to save Alice's key");
|
||||
addr
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ pub use rusqlite::ffi::*;
|
||||
pub type dc_callback_t =
|
||||
unsafe extern "C" fn(_: &Context, _: Event, _: uintptr_t, _: uintptr_t) -> uintptr_t;
|
||||
|
||||
pub type dc_move_state_t = u32;
|
||||
|
||||
pub type dc_receive_imf_t = unsafe fn(
|
||||
_: &Context,
|
||||
_: *const libc::c_char,
|
||||
|
||||
148
tests/stress.rs
148
tests/stress.rs
@@ -10,6 +10,7 @@ use deltachat::config;
|
||||
use deltachat::constants::*;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_array::*;
|
||||
use deltachat::dc_chat::*;
|
||||
use deltachat::dc_configure::*;
|
||||
use deltachat::dc_imex::*;
|
||||
@@ -56,15 +57,39 @@ unsafe fn stress_functions(context: &Context) {
|
||||
);
|
||||
|
||||
if 0 != dc_is_open(context) {
|
||||
if dc_file_exist(context, "$BLOBDIR/foobar")
|
||||
|| dc_file_exist(context, "$BLOBDIR/dada")
|
||||
|| dc_file_exist(context, "$BLOBDIR/foobar.dadada")
|
||||
|| dc_file_exist(context, "$BLOBDIR/foobar-folder")
|
||||
if 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
) || 0
|
||||
!= dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
|| 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
|| 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
{
|
||||
dc_delete_file(context, "$BLOBDIR/foobar");
|
||||
dc_delete_file(context, "$BLOBDIR/dada");
|
||||
dc_delete_file(context, "$BLOBDIR/foobar.dadada");
|
||||
dc_delete_file(context, "$BLOBDIR/foobar-folder");
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
dc_write_file(
|
||||
context,
|
||||
@@ -72,10 +97,25 @@ unsafe fn stress_functions(context: &Context) {
|
||||
b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void,
|
||||
7i32 as size_t,
|
||||
);
|
||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
|
||||
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
dc_get_filebytes(context, "$BLOBDIR/foobar",),
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobarx\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
dc_get_filebytes(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
7i32 as libc::c_ulonglong
|
||||
);
|
||||
|
||||
@@ -93,10 +133,23 @@ unsafe fn stress_functions(context: &Context) {
|
||||
context,
|
||||
b"/BLOBDIR/fofo\x00" as *const u8 as *const libc::c_char,
|
||||
));
|
||||
assert!(dc_file_exist(context, as_path(abs_path)));
|
||||
assert_ne!(0, dc_file_exist(context, abs_path));
|
||||
free(abs_path as *mut libc::c_void);
|
||||
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
|
||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_copy_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
dc_get_filebytes(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
7
|
||||
);
|
||||
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0;
|
||||
@@ -117,11 +170,41 @@ unsafe fn stress_functions(context: &Context) {
|
||||
);
|
||||
|
||||
free(buf as *mut _);
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
|
||||
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
|
||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/foobar-folder"));
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_create_folder(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename(
|
||||
context,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -154,7 +237,7 @@ unsafe fn stress_functions(context: &Context) {
|
||||
),
|
||||
0
|
||||
);
|
||||
assert!(dc_delete_file(context, as_path(fn0)));
|
||||
assert_ne!(0, dc_delete_file(context, fn0));
|
||||
free(fn0 as *mut libc::c_void);
|
||||
free(fn1 as *mut libc::c_void);
|
||||
}
|
||||
@@ -742,14 +825,22 @@ fn test_dc_mimeparser_with_context() {
|
||||
"inner-subject",
|
||||
);
|
||||
|
||||
let mut of: *mut mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A");
|
||||
let mut of: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"X-Special-A\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "special-a",);
|
||||
|
||||
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Foo");
|
||||
of = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Foo\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "Bar",);
|
||||
|
||||
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version");
|
||||
of = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",);
|
||||
assert_eq!(mimeparser.parts.len(), 1);
|
||||
|
||||
@@ -800,16 +891,19 @@ fn test_get_contacts() {
|
||||
unsafe {
|
||||
let context = create_test_context();
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("some2")).unwrap();
|
||||
assert_eq!(contacts.len(), 0);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
let id = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap();
|
||||
assert_ne!(id, 0);
|
||||
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("bob")).unwrap();
|
||||
assert_eq!(contacts.len(), 1);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 1);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("alice")).unwrap();
|
||||
assert_eq!(contacts.len(), 0);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user