mirror of
https://github.com/chatmail/core.git
synced 2026-10-18 02:43:02 +03:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af20b14077 | ||
|
|
d338748115 |
+30
-20
@@ -12,7 +12,7 @@ restore-workspace: &restore-workspace
|
||||
restore-cache: &restore-cache
|
||||
restore_cache:
|
||||
keys:
|
||||
- cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- repo-source-{{ .Branch }}-{{ .Revision }}
|
||||
|
||||
commands:
|
||||
@@ -23,9 +23,20 @@ commands:
|
||||
steps:
|
||||
- *restore-workspace
|
||||
- *restore-cache
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
# TODO: move into image
|
||||
- run:
|
||||
name: Install Docker client
|
||||
command: |
|
||||
set -x
|
||||
VER="18.09.2"
|
||||
curl -L -o /tmp/docker-$VER.tgz https://download.docker.com/linux/static/stable/x86_64/docker-$VER.tgz
|
||||
tar -xz -C /tmp -f /tmp/docker-$VER.tgz
|
||||
mv /tmp/docker/* /usr/bin
|
||||
- run:
|
||||
name: Test (<< parameters.target >>)
|
||||
command: TARGET=<< parameters.target >> ci_scripts/run-rust-test.sh
|
||||
command: TARGET=<< parameters.target >> ci/run.sh
|
||||
no_output_timeout: 15m
|
||||
|
||||
jobs:
|
||||
@@ -41,7 +52,7 @@ jobs:
|
||||
command: cargo generate-lockfile
|
||||
- restore_cache:
|
||||
keys:
|
||||
- cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
- cargo-v1-{{ 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
|
||||
@@ -50,14 +61,13 @@ jobs:
|
||||
- run: cargo fetch
|
||||
- run: rustc +stable --version
|
||||
- run: rustc +$(cat rust-toolchain) --version
|
||||
# make sure this git repo doesn't grow too big
|
||||
- run: git gc
|
||||
- run: rm -rf .git
|
||||
- persist_to_workspace:
|
||||
root: /mnt
|
||||
paths:
|
||||
- crate
|
||||
- save_cache:
|
||||
key: cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
key: cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||
paths:
|
||||
- "~/.cargo"
|
||||
- "~/.rustup"
|
||||
@@ -92,7 +102,7 @@ jobs:
|
||||
- run: cargo fetch
|
||||
- run:
|
||||
name: Test
|
||||
command: TARGET=x86_64-apple-darwin ci_scripts/run-rust-test.sh
|
||||
command: TARGET=x86_64-apple-darwin ci/run.sh
|
||||
|
||||
test_x86_64-unknown-linux-gnu:
|
||||
executor: default
|
||||
@@ -114,18 +124,18 @@ jobs:
|
||||
|
||||
|
||||
build_test_docs_wheel:
|
||||
docker:
|
||||
- image: deltachat/coredeps
|
||||
environment:
|
||||
TESTS: 1
|
||||
DOCS: 1
|
||||
working_directory: /mnt/crate
|
||||
machine: True
|
||||
steps:
|
||||
- *restore-workspace
|
||||
- *restore-cache
|
||||
- checkout
|
||||
# - run: docker pull deltachat/doxygen
|
||||
- run: docker pull deltachat/coredeps
|
||||
- run:
|
||||
name: build docs, run tests and build wheels
|
||||
command: ci_scripts/run-python.sh
|
||||
command: ci_scripts/ci_run.sh
|
||||
environment:
|
||||
TESTS: 1
|
||||
DOCS: 1
|
||||
|
||||
- run:
|
||||
name: copying docs and wheels to workspace
|
||||
command: |
|
||||
@@ -133,6 +143,7 @@ jobs:
|
||||
# cp -av docs workspace/c-docs
|
||||
cp -av python/.docker-tox/wheelhouse workspace/
|
||||
cp -av python/doc/_build/ workspace/py-docs
|
||||
|
||||
- persist_to_workspace:
|
||||
root: workspace
|
||||
paths:
|
||||
@@ -165,16 +176,15 @@ workflows:
|
||||
|
||||
test:
|
||||
jobs:
|
||||
- cargo_fetch
|
||||
- build_test_docs_wheel:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
- build_test_docs_wheel
|
||||
- upload_docs_wheels:
|
||||
requires:
|
||||
- build_test_docs_wheel
|
||||
- cargo_fetch
|
||||
- rustfmt:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
|
||||
- clippy:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
|
||||
Generated
+17
-16
@@ -502,7 +502,7 @@ dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mmime 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mmime 0.1.2-alpha.0 (git+https://github.com/dignifiedquire/mmime?rev=bccd2c2)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -524,8 +524,8 @@ dependencies = [
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -533,11 +533,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "deltachat-provider-overview"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211#366b41a7503973e4ffac3aa5173b419f2f03c211"
|
||||
dependencies = [
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -554,7 +555,7 @@ name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.4"
|
||||
dependencies = [
|
||||
"deltachat 1.0.0-alpha.4",
|
||||
"deltachat-provider-overview 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"deltachat-provider-overview 0.1.0 (git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211)",
|
||||
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1257,8 +1258,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mmime"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.1.2-alpha.0"
|
||||
source = "git+https://github.com/dignifiedquire/mmime?rev=bccd2c2#bccd2c2c89e9241e05f321c963f638affdccad96"
|
||||
dependencies = [
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2347,18 +2348,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.16.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.16.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2974,7 +2975,7 @@ dependencies = [
|
||||
"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c"
|
||||
"checksum darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1"
|
||||
"checksum debug_stub_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "496b7f8a2f853313c3ca370641d7ff3e42c32974fdccda8f0684599ed0a3ff6b"
|
||||
"checksum deltachat-provider-overview 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bef7b3626b0f859878db86ed54e4eef317adbcc3bcc3617eb38dec52e3f40e3"
|
||||
"checksum deltachat-provider-overview 0.1.0 (git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211)" = "<none>"
|
||||
"checksum derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ac53fa6a3cda160df823a9346442525dcaf1e171999a1cf23e67067e4fd64d4"
|
||||
"checksum derive_builder_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0288a23da9333c246bb18c143426074a6ae96747995c5819d2947b64cd942b37"
|
||||
"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839"
|
||||
@@ -3056,7 +3057,7 @@ dependencies = [
|
||||
"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10"
|
||||
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum mmime 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "befb13ecb83a4344d5c268a36463fc1b3526a78bfded316ddfaa955b5d018b91"
|
||||
"checksum mmime 0.1.2-alpha.0 (git+https://github.com/dignifiedquire/mmime?rev=bccd2c2)" = "<none>"
|
||||
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
||||
@@ -3168,8 +3169,8 @@ dependencies = [
|
||||
"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c"
|
||||
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
|
||||
"checksum strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81"
|
||||
"checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f"
|
||||
"checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e"
|
||||
"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ num-traits = "0.2.6"
|
||||
native-tls = "0.2.3"
|
||||
lettre = "0.9.0"
|
||||
imap = { git = "https://github.com/jonhoo/rust-imap", rev = "281d2eb8ab50dc656ceff2ae749ca5045f334e15" }
|
||||
mmime = "0.1.2"
|
||||
mmime = { git = "https://github.com/dignifiedquire/mmime", rev = "bccd2c2" }
|
||||
base64 = "0.10"
|
||||
charset = "0.1"
|
||||
percent-encoding = "2.0"
|
||||
@@ -36,8 +36,8 @@ regex = "1.1.6"
|
||||
rusqlite = { version = "0.20", features = ["bundled"] }
|
||||
r2d2_sqlite = "0.12.0"
|
||||
r2d2 = "0.8.5"
|
||||
strum = "0.16.0"
|
||||
strum_macros = "0.16.0"
|
||||
strum = "0.15.0"
|
||||
strum_macros = "0.15.0"
|
||||
thread-local-object = "0.1.0"
|
||||
backtrace = "0.3.33"
|
||||
byteorder = "1.3.1"
|
||||
|
||||
@@ -39,4 +39,8 @@ fi
|
||||
|
||||
# Run all the test configurations:
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT_RELEASE
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT_RELEASE_IGNORED
|
||||
|
||||
# Build the ffi lib
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT_FFI_RELEASE
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
# perform CI jobs on PRs and after merges to master.
|
||||
# triggered from .circleci/config.yml
|
||||
|
||||
set -e -x
|
||||
|
||||
export BRANCH=${CIRCLE_BRANCH:-test7}
|
||||
|
||||
# run doxygen on c-source (needed by later doc-generation steps).
|
||||
# XXX modifies the host filesystem docs/xml and docs/html directories
|
||||
# XXX which you can then only remove with sudo as they belong to root
|
||||
|
||||
# XXX we don't do doxygen doc generation with Rust anymore, needs to be
|
||||
# substituted with rust-docs
|
||||
#if [ -n "$DOCS" ] ; then
|
||||
# docker run --rm -it -v $PWD:/mnt -w /mnt/docs deltachat/doxygen doxygen
|
||||
#fi
|
||||
|
||||
# run everything else inside docker (TESTS, DOCS, WHEELS)
|
||||
docker run -e DCC_PY_LIVECONFIG -e BRANCH -e TESTS -e DOCS \
|
||||
--rm -it -v $(pwd):/mnt -w /mnt \
|
||||
deltachat/coredeps ci_scripts/run_all.sh
|
||||
|
||||
@@ -36,25 +36,20 @@ if [ -n "$TESTS" ]; then
|
||||
rm -rf src/deltachat/__pycache__
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# run tox. The circle-ci project env-var-setting DCC_PY_LIVECONFIG
|
||||
# allows running of "liveconfig" tests but for speed reasons
|
||||
# we run them only for the highest python version we support
|
||||
|
||||
# we split out qr-tests run to minimize likelyness of flaky tests
|
||||
# (some qr tests are pretty heavy in terms of send/received
|
||||
# messages and rust's imap code likely has concurrency problems)
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- -k "qr"
|
||||
unset DCC_PY_LIVECONFIG
|
||||
tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
|
||||
tox --workdir "$TOXWORKDIR" -e auditwheels
|
||||
# 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,py35,py36,py37,auditwheels -- -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py35,py36,py37 -- -k "qr"
|
||||
popd
|
||||
fi
|
||||
|
||||
|
||||
# if [ -n "$DOCS" ]; then
|
||||
# echo -----------------------
|
||||
# echo generating python docs
|
||||
# echo -----------------------
|
||||
# (cd python && tox --workdir "$TOXWORKDIR" -e doc)
|
||||
# fi
|
||||
if [ -n "$DOCS" ]; then
|
||||
echo -----------------------
|
||||
echo generating python docs
|
||||
echo -----------------------
|
||||
(cd python && tox --workdir "$TOXWORKDIR" -e doc)
|
||||
fi
|
||||
@@ -16,7 +16,7 @@ crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
deltachat = { path = "../", default-features = false }
|
||||
deltachat-provider-overview = "0.1.0"
|
||||
deltachat-provider-overview = { git = "https://github.com/deltachat/provider-overview", rev = "366b41a7503973e4ffac3aa5173b419f2f03c211" }
|
||||
libc = "0.2"
|
||||
human-panic = "1.0.1"
|
||||
num-traits = "0.2.6"
|
||||
|
||||
@@ -610,8 +610,12 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Execute pending mvbox-jobs.
|
||||
* This function and dc_perform_mvbox_fetch() and dc_perform_mvbox_idle()
|
||||
* Fetch new messages from the MVBOX, if any.
|
||||
* The MVBOX is a folder on the account where chat messages are moved to.
|
||||
* The moving is done to not disturb shared accounts that are used by both,
|
||||
* Delta Chat and a classical MUA.
|
||||
*
|
||||
* This function and dc_perform_mvbox_idle()
|
||||
* must be called from the same thread, typically in a loop.
|
||||
*
|
||||
* Example:
|
||||
@@ -619,7 +623,6 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
* void* mvbox_thread_func(void* context)
|
||||
* {
|
||||
* while (true) {
|
||||
* dc_perform_mvbox_jobs(context);
|
||||
* dc_perform_mvbox_fetch(context);
|
||||
* dc_perform_mvbox_idle(context);
|
||||
* }
|
||||
@@ -633,26 +636,13 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
*
|
||||
* // network becomes available again -
|
||||
* // the interrupt causes dc_perform_mvbox_idle() in the thread above
|
||||
* // to return so that jobs are executed and messages are fetched.
|
||||
* // to return so that and messages are fetched.
|
||||
* dc_maybe_network(context);
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_mvbox_jobs (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch new messages from the MVBOX, if any.
|
||||
* The MVBOX is a folder on the account where chat messages are moved to.
|
||||
* The moving is done to not disturb shared accounts that are used by both,
|
||||
* Delta Chat and a classical MUA.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_mvbox_fetch (dc_context_t* context);
|
||||
|
||||
|
||||
@@ -689,39 +679,6 @@ void dc_perform_mvbox_idle (dc_context_t* context);
|
||||
*/
|
||||
void dc_interrupt_mvbox_idle (dc_context_t* context);
|
||||
|
||||
/**
|
||||
* Execute pending sentbox-jobs.
|
||||
* This function and dc_perform_sentbox_fetch() and dc_perform_sentbox_idle()
|
||||
* must be called from the same thread, typically in a loop.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* void* sentbox_thread_func(void* context)
|
||||
* {
|
||||
* while (true) {
|
||||
* dc_perform_sentbox_jobs(context);
|
||||
* dc_perform_sentbox_fetch(context);
|
||||
* dc_perform_sentbox_idle(context);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // start sentbox-thread that runs forever
|
||||
* pthread_t sentbox_thread;
|
||||
* pthread_create(&sentbox_thread, NULL, sentbox_thread_func, context);
|
||||
*
|
||||
* ... program runs ...
|
||||
*
|
||||
* // network becomes available again -
|
||||
* // the interrupt causes dc_perform_sentbox_idle() in the thread above
|
||||
* // to return so that jobs are executed and messages are fetched.
|
||||
* dc_maybe_network(context);
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_sentbox_jobs (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch new messages from the Sent folder, if any.
|
||||
|
||||
+55
-108
@@ -24,9 +24,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
use deltachat::contact::Contact;
|
||||
use deltachat::context::Context;
|
||||
use deltachat::dc_tools::{
|
||||
as_path, as_str, dc_strdup, to_string, to_string_lossy, OsStrExt, StrExt,
|
||||
};
|
||||
use deltachat::dc_tools::{as_path, as_str, dc_strdup, to_string, OsStrExt, StrExt};
|
||||
use deltachat::*;
|
||||
|
||||
// as C lacks a good and portable error handling,
|
||||
@@ -188,7 +186,7 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
let os_name = if os_name.is_null() {
|
||||
String::from("DcFFI")
|
||||
} else {
|
||||
to_string_lossy(os_name)
|
||||
dc_tools::to_string_lossy(os_name)
|
||||
};
|
||||
let ffi_ctx = ContextWrapper {
|
||||
cb,
|
||||
@@ -473,18 +471,6 @@ pub unsafe extern "C" fn dc_perform_mvbox_fetch(context: *mut dc_context_t) {
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_mvbox_jobs(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_perform_mvbox_jobs()");
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| job::perform_mvbox_jobs(ctx))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_mvbox_idle(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
@@ -521,18 +507,6 @@ pub unsafe extern "C" fn dc_perform_sentbox_fetch(context: *mut dc_context_t) {
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_sentbox_jobs(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_perform_sentbox_jobs()");
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| job::perform_sentbox_jobs(ctx))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_sentbox_idle(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
@@ -737,7 +711,7 @@ pub unsafe extern "C" fn dc_send_text_msg(
|
||||
return 0;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
let text_to_send = to_string_lossy(text_to_send);
|
||||
let text_to_send = dc_tools::to_string_lossy(text_to_send);
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
chat::send_text_msg(ctx, chat_id, text_to_send)
|
||||
@@ -938,12 +912,6 @@ pub unsafe extern "C" fn dc_get_next_media(
|
||||
eprintln!("ignoring careless call to dc_get_next_media()");
|
||||
return 0;
|
||||
}
|
||||
let direction = if dir < 0 {
|
||||
chat::Direction::Backward
|
||||
} else {
|
||||
chat::Direction::Forward
|
||||
};
|
||||
|
||||
let ffi_context = &*context;
|
||||
let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {}", msg_type));
|
||||
let or_msg_type2 =
|
||||
@@ -952,7 +920,7 @@ pub unsafe extern "C" fn dc_get_next_media(
|
||||
from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {}", or_msg_type3));
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
chat::get_next_media(ctx, msg_id, direction, msg_type, or_msg_type2, or_msg_type3)
|
||||
chat::get_next_media(ctx, msg_id, dir, msg_type, or_msg_type2, or_msg_type3)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
@@ -1084,8 +1052,7 @@ pub unsafe extern "C" fn dc_is_contact_in_chat(
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| chat::is_contact_in_chat(ctx, chat_id, contact_id))
|
||||
.unwrap_or_default()
|
||||
.into()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1181,7 +1148,7 @@ pub unsafe extern "C" fn dc_get_msg_info(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::get_msg_info(ctx, msg_id).strdup())
|
||||
.with_inner(|ctx| message::dc_get_msg_info(ctx, msg_id))
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1196,11 +1163,7 @@ pub unsafe extern "C" fn dc_get_mime_headers(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
message::get_mime_headers(ctx, msg_id)
|
||||
.map(|s| s.strdup())
|
||||
.unwrap_or_else(|| ptr::null_mut())
|
||||
})
|
||||
.with_inner(|ctx| message::dc_get_mime_headers(ctx, msg_id))
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1215,11 +1178,8 @@ pub unsafe extern "C" fn dc_delete_msgs(
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::delete_msgs(ctx, ids))
|
||||
.with_inner(|ctx| message::dc_delete_msgs(ctx, msg_ids, msg_cnt))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
@@ -1238,11 +1198,9 @@ pub unsafe extern "C" fn dc_forward_msgs(
|
||||
eprintln!("ignoring careless call to dc_forward_msgs()");
|
||||
return;
|
||||
}
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| chat::forward_msgs(ctx, ids, chat_id))
|
||||
.with_inner(|ctx| chat::forward_msgs(ctx, msg_ids, msg_cnt, chat_id))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
@@ -1268,11 +1226,9 @@ pub unsafe extern "C" fn dc_markseen_msgs(
|
||||
eprintln!("ignoring careless call to dc_markseen_msgs()");
|
||||
return;
|
||||
}
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::markseen_msgs(ctx, ids))
|
||||
.with_inner(|ctx| message::dc_markseen_msgs(ctx, msg_ids, msg_cnt as usize))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1287,12 +1243,9 @@ pub unsafe extern "C" fn dc_star_msgs(
|
||||
eprintln!("ignoring careless call to dc_star_msgs()");
|
||||
return;
|
||||
}
|
||||
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::star_msgs(ctx, ids, star == 1))
|
||||
.with_inner(|ctx| message::dc_star_msgs(ctx, msg_ids, msg_cnt, star))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1305,7 +1258,7 @@ pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) ->
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
let message = match message::Message::load_from_db(ctx, msg_id) {
|
||||
let message = match message::dc_get_msg(ctx, msg_id) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
error!(ctx, "Error getting msg #{}: {}", msg_id, e);
|
||||
@@ -2199,7 +2152,7 @@ pub unsafe extern "C" fn dc_msg_new(
|
||||
let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {}", viewtype));
|
||||
let msg = MessageWrapper {
|
||||
context,
|
||||
message: message::Message::new(viewtype),
|
||||
message: message::dc_msg_new(viewtype),
|
||||
};
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
@@ -2221,7 +2174,7 @@ pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_id()
|
||||
message::dc_msg_get_id(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2231,7 +2184,7 @@ pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_from_id()
|
||||
message::dc_msg_get_from_id(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2241,7 +2194,7 @@ pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_chat_id()
|
||||
message::dc_msg_get_chat_id(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2251,9 +2204,7 @@ pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg
|
||||
.message
|
||||
.get_viewtype()
|
||||
message::dc_msg_get_viewtype(&ffi_msg.message)
|
||||
.to_i64()
|
||||
.expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int
|
||||
}
|
||||
@@ -2265,7 +2216,7 @@ pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_state() as libc::c_int
|
||||
message::dc_msg_get_state(&ffi_msg.message) as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2275,7 +2226,7 @@ pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg_t) -> i64 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_timestamp()
|
||||
message::dc_msg_get_timestamp(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2285,7 +2236,7 @@ pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg_t) -> i6
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_received_timestamp()
|
||||
message::dc_msg_get_received_timestamp(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2295,7 +2246,7 @@ pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg_t) -> i64 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_sort_timestamp()
|
||||
message::dc_msg_get_sort_timestamp(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2305,7 +2256,7 @@ pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg_t) -> *mut libc::c_cha
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_text().unwrap_or_default().strdup()
|
||||
message::dc_msg_get_text(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2318,9 +2269,7 @@ pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg_t) -> *mut libc::c_cha
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
ffi_msg
|
||||
.message
|
||||
.get_file(ctx)
|
||||
message::dc_msg_get_file(ctx, &ffi_msg.message)
|
||||
.and_then(|p| p.to_c_string().ok())
|
||||
.map(|cs| dc_strdup(cs.as_ptr()))
|
||||
.unwrap_or_else(|| "".strdup())
|
||||
@@ -2335,7 +2284,7 @@ pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_filename().unwrap_or_default().strdup()
|
||||
message::dc_msg_get_filename(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2345,7 +2294,7 @@ pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg_t) -> *mut libc::c
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_filemime().strdup()
|
||||
message::dc_msg_get_filemime(&ffi_msg.message).strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2357,7 +2306,7 @@ pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg_t) -> u64 {
|
||||
let ffi_msg = &*msg;
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| ffi_msg.message.get_filebytes(ctx))
|
||||
.with_inner(|ctx| message::dc_msg_get_filebytes(ctx, &ffi_msg.message))
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
@@ -2368,7 +2317,7 @@ pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_width()
|
||||
message::dc_msg_get_width(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2378,7 +2327,7 @@ pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_height()
|
||||
message::dc_msg_get_height(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2388,7 +2337,7 @@ pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_duration()
|
||||
message::dc_msg_get_duration(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2398,7 +2347,7 @@ pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg_t) -> libc::c_i
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.get_showpadlock() as libc::c_int
|
||||
message::dc_msg_get_showpadlock(&ffi_msg.message) as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2420,7 +2369,7 @@ pub unsafe extern "C" fn dc_msg_get_summary(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
let lot = ffi_msg.message.get_summary(ctx, maybe_chat);
|
||||
let lot = message::dc_msg_get_summary(ctx, &mut ffi_msg.message, maybe_chat);
|
||||
Box::into_raw(Box::new(lot))
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
@@ -2439,12 +2388,13 @@ pub unsafe extern "C" fn dc_msg_get_summarytext(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
ffi_msg
|
||||
.message
|
||||
.get_summarytext(ctx, approx_characters.try_into().unwrap())
|
||||
message::dc_msg_get_summarytext(
|
||||
ctx,
|
||||
&mut ffi_msg.message,
|
||||
approx_characters.try_into().unwrap(),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
.unwrap_or_else(|_| "".strdup())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2454,7 +2404,7 @@ pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg_t) -> l
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.has_deviating_timestamp().into()
|
||||
message::dc_msg_has_deviating_timestamp(&ffi_msg.message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2464,7 +2414,7 @@ pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.has_location() as libc::c_int
|
||||
message::dc_msg_has_location(&ffi_msg.message) as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2474,7 +2424,7 @@ pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_sent().into()
|
||||
message::dc_msg_is_sent(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2484,7 +2434,7 @@ pub unsafe extern "C" fn dc_msg_is_starred(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_starred().into()
|
||||
message::dc_msg_is_starred(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2494,7 +2444,7 @@ pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_forwarded().into()
|
||||
message::dc_msg_is_forwarded(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2504,7 +2454,7 @@ pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_info().into()
|
||||
message::dc_msg_is_info(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2514,7 +2464,7 @@ pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_increation().into()
|
||||
message::dc_msg_is_increation(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2524,7 +2474,7 @@ pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_i
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
ffi_msg.message.is_setupmessage().into()
|
||||
message::dc_msg_is_setupmessage(&ffi_msg.message).into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2536,9 +2486,8 @@ pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut l
|
||||
let ffi_msg = &*msg;
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| ffi_msg.message.get_setupcodebegin(ctx).unwrap_or_default())
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
.with_inner(|ctx| message::dc_msg_get_setupcodebegin(ctx, &ffi_msg.message))
|
||||
.unwrap_or_else(|_| "".strdup())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2549,7 +2498,7 @@ pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg_t, text: *mut libc::c_
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
// TODO: {text} equal to NULL is treated as "", which is strange. Does anyone rely on it?
|
||||
ffi_msg.message.set_text(as_opt_str(text).map(Into::into))
|
||||
message::dc_msg_set_text(&mut ffi_msg.message, text)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2558,12 +2507,12 @@ pub unsafe extern "C" fn dc_msg_set_file(
|
||||
file: *mut libc::c_char,
|
||||
filemime: *mut libc::c_char,
|
||||
) {
|
||||
if msg.is_null() || file.is_null() {
|
||||
if msg.is_null() {
|
||||
eprintln!("ignoring careless call to dc_msg_set_file()");
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
ffi_msg.message.set_file(as_str(file), as_opt_str(filemime))
|
||||
message::dc_msg_set_file(&mut ffi_msg.message, file, filemime)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2577,7 +2526,7 @@ pub unsafe extern "C" fn dc_msg_set_dimension(
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
ffi_msg.message.set_dimension(width, height)
|
||||
message::dc_msg_set_dimension(&mut ffi_msg.message, width, height)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2587,7 +2536,7 @@ pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc:
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
ffi_msg.message.set_duration(duration)
|
||||
message::dc_msg_set_duration(&mut ffi_msg.message, duration)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2601,7 +2550,7 @@ pub unsafe extern "C" fn dc_msg_set_location(
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
ffi_msg.message.set_location(latitude, longitude)
|
||||
message::dc_msg_set_location(&mut ffi_msg.message, latitude, longitude)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2619,9 +2568,7 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
ffi_msg
|
||||
.message
|
||||
.latefiling_mediasize(ctx, width, height, duration)
|
||||
message::dc_msg_latefiling_mediasize(ctx, &mut ffi_msg.message, width, height, duration)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -2863,7 +2810,7 @@ fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(as_str(s))
|
||||
Some(dc_tools::as_str(s))
|
||||
}
|
||||
|
||||
pub mod providers;
|
||||
|
||||
+127
-88
@@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -16,12 +16,12 @@ use deltachat::error::Error;
|
||||
use deltachat::job::*;
|
||||
use deltachat::location;
|
||||
use deltachat::lot::LotState;
|
||||
use deltachat::message::{self, Message, MessageState};
|
||||
use deltachat::message::*;
|
||||
use deltachat::peerstate::*;
|
||||
use deltachat::qr::*;
|
||||
use deltachat::sql;
|
||||
use deltachat::x::*;
|
||||
use deltachat::Event;
|
||||
use libc::free;
|
||||
|
||||
/// Reset database tables. This function is called from Core cmdline.
|
||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||
@@ -94,20 +94,24 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
||||
let data = dc_read_file(context, filename)?;
|
||||
unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) -> libc::c_int {
|
||||
/* mainly for testing, may be called by dc_import_spec() */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut data: *mut libc::c_char = ptr::null_mut();
|
||||
let mut data_bytes = 0;
|
||||
if !(dc_read_file(
|
||||
context,
|
||||
filename,
|
||||
&mut data as *mut *mut libc::c_char as *mut *mut libc::c_void,
|
||||
&mut data_bytes,
|
||||
) == 0i32)
|
||||
{
|
||||
dc_receive_imf(context, data, data_bytes, "import", 0, 0);
|
||||
success = 1;
|
||||
}
|
||||
free(data as *mut libc::c_void);
|
||||
|
||||
unsafe {
|
||||
dc_receive_imf(
|
||||
context,
|
||||
data.as_ptr() as *const _,
|
||||
data.len(),
|
||||
"import",
|
||||
0,
|
||||
0,
|
||||
)
|
||||
};
|
||||
Ok(())
|
||||
success
|
||||
}
|
||||
|
||||
/// Import a file to the database.
|
||||
@@ -118,113 +122,142 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(),
|
||||
/// @param context The context as created by dc_context_new().
|
||||
/// @param spec The file or directory to import. NULL for the last command.
|
||||
/// @return 1=success, 0=error.
|
||||
fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
if !context.sql.is_open() {
|
||||
error!(context, "Import: Database not opened.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let real_spec: String;
|
||||
let mut read_cnt = 0;
|
||||
let ok_to_continue;
|
||||
let mut success: libc::c_int = 0;
|
||||
let real_spec: *mut libc::c_char;
|
||||
let mut suffix: *mut libc::c_char = ptr::null_mut();
|
||||
let mut read_cnt: libc::c_int = 0;
|
||||
|
||||
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
||||
if !spec.is_null() {
|
||||
real_spec = to_string(spec);
|
||||
real_spec = dc_strdup(spec);
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(&real_spec))
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
||||
.unwrap();
|
||||
ok_to_continue = true;
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
if rs.is_none() {
|
||||
error!(context, "Import: No file or folder given.");
|
||||
return 0;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
real_spec = rs.unwrap();
|
||||
real_spec = rs.unwrap_or_default().strdup();
|
||||
}
|
||||
if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
|
||||
if suffix == "eml" {
|
||||
if dc_poke_eml_file(context, &real_spec).is_ok() {
|
||||
if ok_to_continue {
|
||||
let ok_to_continue2;
|
||||
suffix = dc_get_filesuffix_lc(as_str(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
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(&real_spec);
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
|
||||
return 0;
|
||||
ok_to_continue2 = true;
|
||||
} 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!("{}/{}", &real_spec, name);
|
||||
info!(context, "Import: {}", path_plus_name);
|
||||
if dc_poke_eml_file(context, path_plus_name).is_ok() {
|
||||
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,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
ok_to_continue2 = false;
|
||||
} 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, "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
|
||||
}
|
||||
}
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
}
|
||||
}
|
||||
if ok_to_continue2 {
|
||||
info!(
|
||||
context,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id: 0,
|
||||
msg_id: 0,
|
||||
});
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
info!(
|
||||
context,
|
||||
"Import: {} items read from \"{}\".", read_cnt, &real_spec
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id: 0,
|
||||
msg_id: 0,
|
||||
});
|
||||
}
|
||||
1
|
||||
|
||||
free(real_spec as *mut libc::c_void);
|
||||
free(suffix as *mut libc::c_void);
|
||||
success
|
||||
}
|
||||
|
||||
unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||
let contact = Contact::get_by_id(context, msg.get_from_id()).expect("invalid contact");
|
||||
let contact = Contact::get_by_id(context, dc_msg_get_from_id(msg)).expect("invalid contact");
|
||||
let contact_name = contact.get_name();
|
||||
let contact_id = contact.get_id();
|
||||
|
||||
let statestr = match msg.get_state() {
|
||||
let statestr = match dc_msg_get_state(msg) {
|
||||
MessageState::OutPending => " o",
|
||||
MessageState::OutDelivered => " √",
|
||||
MessageState::OutMdnRcvd => " √√",
|
||||
MessageState::OutFailed => " !!",
|
||||
_ => "",
|
||||
};
|
||||
let temp2 = dc_timestamp_to_str(msg.get_timestamp());
|
||||
let msgtext = msg.get_text();
|
||||
let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
|
||||
let msgtext = dc_msg_get_text(msg);
|
||||
info!(
|
||||
context,
|
||||
"{}#{}{}{}: {} (Contact#{}): {} {}{}{}{} [{}]",
|
||||
prefix.as_ref(),
|
||||
msg.get_id() as libc::c_int,
|
||||
if msg.get_showpadlock() { "🔒" } else { "" },
|
||||
if msg.has_location() { "📍" } else { "" },
|
||||
dc_msg_get_id(msg) as libc::c_int,
|
||||
if dc_msg_get_showpadlock(msg) {
|
||||
"🔒"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if dc_msg_has_location(msg) { "📍" } else { "" },
|
||||
&contact_name,
|
||||
contact_id,
|
||||
msgtext.unwrap_or_default(),
|
||||
if msg.is_starred() { "★" } else { "" },
|
||||
if msg.get_from_id() == 1 as libc::c_uint {
|
||||
as_str(msgtext),
|
||||
if dc_msg_is_starred(msg) { "★" } else { "" },
|
||||
if dc_msg_get_from_id(msg) == 1 as libc::c_uint {
|
||||
""
|
||||
} else if msg.get_state() == MessageState::InSeen {
|
||||
} else if dc_msg_get_state(msg) == MessageState::InSeen {
|
||||
"[SEEN]"
|
||||
} else if msg.get_state() == MessageState::InNoticed {
|
||||
} else if dc_msg_get_state(msg) == MessageState::InNoticed {
|
||||
"[NOTICED]"
|
||||
} else {
|
||||
"[FRESH]"
|
||||
},
|
||||
if msg.is_info() { "[INFO]" } else { "" },
|
||||
if dc_msg_is_info(msg) { "[INFO]" } else { "" },
|
||||
statestr,
|
||||
&temp2,
|
||||
);
|
||||
free(msgtext as *mut libc::c_void);
|
||||
}
|
||||
|
||||
unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error> {
|
||||
@@ -245,7 +278,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error
|
||||
);
|
||||
lines_out += 1
|
||||
}
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
let msg = dc_get_msg(context, msg_id)?;
|
||||
log_msg(context, "Msg", &msg);
|
||||
}
|
||||
}
|
||||
@@ -434,14 +467,15 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"get-setupcodebegin" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let msg_id: u32 = arg1.parse()?;
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
if msg.is_setupmessage() {
|
||||
let setupcodebegin = msg.get_setupcodebegin(context);
|
||||
let msg = dc_get_msg(context, msg_id)?;
|
||||
if dc_msg_is_setupmessage(&msg) {
|
||||
let setupcodebegin = dc_msg_get_setupcodebegin(context, &msg);
|
||||
println!(
|
||||
"The setup code for setup message Msg#{} starts with: {}",
|
||||
msg_id,
|
||||
setupcodebegin.unwrap_or_default(),
|
||||
as_str(setupcodebegin),
|
||||
);
|
||||
free(setupcodebegin as *mut libc::c_void);
|
||||
} else {
|
||||
bail!("Msg#{} is no setup message.", msg_id,);
|
||||
}
|
||||
@@ -791,14 +825,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||
ensure!(!arg1.is_empty(), "No file given.");
|
||||
|
||||
let mut msg = Message::new(if arg0 == "sendimage" {
|
||||
let mut msg = dc_msg_new(if arg0 == "sendimage" {
|
||||
Viewtype::Image
|
||||
} else {
|
||||
Viewtype::File
|
||||
});
|
||||
msg.set_file(arg1, None);
|
||||
dc_msg_set_file(&mut msg, arg1_c, ptr::null());
|
||||
if !arg2.is_empty() {
|
||||
msg.set_text(Some(arg2.to_string()));
|
||||
dc_msg_set_text(&mut msg, arg2_c);
|
||||
}
|
||||
chat::send_msg(context, sel_chat.as_ref().unwrap().get_id(), &mut msg)?;
|
||||
}
|
||||
@@ -820,8 +854,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||
|
||||
if !arg1.is_empty() {
|
||||
let mut draft = Message::new(Viewtype::Text);
|
||||
draft.set_text(Some(arg1.to_string()));
|
||||
let mut draft = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut draft, arg1_c);
|
||||
chat::set_draft(
|
||||
context,
|
||||
sel_chat.as_ref().unwrap().get_id(),
|
||||
@@ -870,8 +904,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"msginfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let id = arg1.parse()?;
|
||||
let res = message::get_msg_info(context, id);
|
||||
println!("{}", res);
|
||||
let res = dc_get_msg_info(context, id);
|
||||
println!("{}", as_str(res));
|
||||
}
|
||||
"listfresh" => {
|
||||
let msglist = context.get_fresh_msgs();
|
||||
@@ -888,25 +922,30 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
let mut msg_ids = [0; 1];
|
||||
let chat_id = arg2.parse()?;
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
chat::forward_msgs(context, &msg_ids, chat_id);
|
||||
chat::forward_msgs(context, msg_ids.as_mut_ptr(), 1, chat_id);
|
||||
}
|
||||
"markseen" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut msg_ids = [0; 1];
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
message::markseen_msgs(context, &msg_ids);
|
||||
dc_markseen_msgs(context, msg_ids.as_mut_ptr(), 1);
|
||||
}
|
||||
"star" | "unstar" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut msg_ids = [0; 1];
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
message::star_msgs(context, &msg_ids, arg0 == "star");
|
||||
dc_star_msgs(
|
||||
context,
|
||||
msg_ids.as_mut_ptr(),
|
||||
1,
|
||||
if arg0 == "star" { 1 } else { 0 },
|
||||
);
|
||||
}
|
||||
"delmsg" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut ids = [0; 1];
|
||||
ids[0] = arg1.parse()?;
|
||||
message::delete_msgs(context, &ids);
|
||||
dc_delete_msgs(context, ids.as_mut_ptr(), 1);
|
||||
}
|
||||
"listcontacts" | "contacts" | "listverified" => {
|
||||
let contacts = Contact::get_all(
|
||||
@@ -989,7 +1028,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"fileinfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
||||
|
||||
if let Ok(buf) = dc_read_file(context, &arg1) {
|
||||
if let Some(buf) = dc_read_file_safe(context, &arg1) {
|
||||
let (width, height) = dc_get_filemeta(&buf)?;
|
||||
println!("width={}, height={}", width, height);
|
||||
} else {
|
||||
|
||||
@@ -23,9 +23,11 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||
use deltachat::config;
|
||||
use deltachat::configure::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::job::*;
|
||||
use deltachat::oauth2::*;
|
||||
use deltachat::securejoin::*;
|
||||
use deltachat::x::*;
|
||||
use deltachat::Event;
|
||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||
use rustyline::config::OutputStreamType;
|
||||
@@ -439,6 +441,11 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
let mut args = line.splitn(2, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
let arg1_c = if arg1.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg1.strdup()
|
||||
};
|
||||
|
||||
match arg0 {
|
||||
"connect" => {
|
||||
@@ -514,6 +521,8 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
|
||||
Ok(ExitResult::Continue)
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ class Account(object):
|
||||
:returns: a :class:`deltachat.chatting.Chat` object.
|
||||
"""
|
||||
bytes_name = name.encode("utf8")
|
||||
chat_id = lib.dc_create_group_chat(self._dc_context, int(verified), bytes_name)
|
||||
chat_id = lib.dc_create_group_chat(self._dc_context, verified, bytes_name)
|
||||
return Chat(self, chat_id)
|
||||
|
||||
def get_chats(self):
|
||||
@@ -378,16 +378,7 @@ class Account(object):
|
||||
raise ValueError("could not join group")
|
||||
return Chat(self, chat_id)
|
||||
|
||||
#
|
||||
# meta API for start/stop and event based processing
|
||||
#
|
||||
|
||||
def wait_next_incoming_message(self):
|
||||
""" wait for and return next incoming message. """
|
||||
ev = self._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||
return self.get_message_by_id(ev[2])
|
||||
|
||||
def start_threads(self, mvbox=False, sentbox=False):
|
||||
def start_threads(self):
|
||||
""" start IMAP/SMTP threads (and configure account if it hasn't happened).
|
||||
|
||||
:raises: ValueError if 'addr' or 'mail_pw' are not configured.
|
||||
@@ -395,7 +386,7 @@ class Account(object):
|
||||
"""
|
||||
if not self.is_configured():
|
||||
self.configure()
|
||||
self._threads.start(mvbox=mvbox, sentbox=sentbox)
|
||||
self._threads.start()
|
||||
|
||||
def stop_threads(self, wait=True):
|
||||
""" stop IMAP/SMTP threads. """
|
||||
@@ -436,14 +427,10 @@ class IOThreads:
|
||||
def is_started(self):
|
||||
return len(self._name2thread) > 0
|
||||
|
||||
def start(self, imap=True, smtp=True, mvbox=False, sentbox=False):
|
||||
def start(self, imap=True, smtp=True):
|
||||
assert not self.is_started()
|
||||
if imap:
|
||||
self._start_one_thread("inbox", self.imap_thread_run)
|
||||
if mvbox:
|
||||
self._start_one_thread("mvbox", self.mvbox_thread_run)
|
||||
if sentbox:
|
||||
self._start_one_thread("sentbox", self.sentbox_thread_run)
|
||||
self._start_one_thread("imap", self.imap_thread_run)
|
||||
if smtp:
|
||||
self._start_one_thread("smtp", self.smtp_thread_run)
|
||||
|
||||
@@ -456,35 +443,17 @@ class IOThreads:
|
||||
self._thread_quitflag = True
|
||||
lib.dc_interrupt_imap_idle(self._dc_context)
|
||||
lib.dc_interrupt_smtp_idle(self._dc_context)
|
||||
lib.dc_interrupt_mvbox_idle(self._dc_context)
|
||||
lib.dc_interrupt_sentbox_idle(self._dc_context)
|
||||
if wait:
|
||||
for name, thread in self._name2thread.items():
|
||||
thread.join()
|
||||
|
||||
def imap_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "INBOX THREAD START")
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_imap_jobs(self._dc_context)
|
||||
lib.dc_perform_imap_fetch(self._dc_context)
|
||||
lib.dc_perform_imap_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "INBOX THREAD FINISHED")
|
||||
|
||||
def mvbox_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "MVBOX THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_mvbox_jobs(self._dc_context)
|
||||
lib.dc_perform_mvbox_fetch(self._dc_context)
|
||||
lib.dc_perform_mvbox_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "MVBOX THREAD FINISHED")
|
||||
|
||||
def sentbox_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "SENTBOX THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_sentbox_jobs(self._dc_context)
|
||||
lib.dc_perform_sentbox_fetch(self._dc_context)
|
||||
lib.dc_perform_sentbox_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "SENTBOX THREAD FINISHED")
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD FINISHED")
|
||||
|
||||
def smtp_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "SMTP THREAD START")
|
||||
|
||||
@@ -109,13 +109,6 @@ class Chat(object):
|
||||
"""
|
||||
return not lib.dc_chat_is_unpromoted(self._dc_chat)
|
||||
|
||||
def is_verified(self):
|
||||
""" return True if this chat is a verified group.
|
||||
|
||||
:returns: True if chat is verified, False otherwise.
|
||||
"""
|
||||
return lib.dc_chat_is_verified(self._dc_chat)
|
||||
|
||||
def get_name(self):
|
||||
""" return name of this chat.
|
||||
|
||||
|
||||
@@ -101,10 +101,6 @@ class Message(object):
|
||||
""" return True if this message is a setup message. """
|
||||
return lib.dc_msg_is_setupmessage(self._dc_msg)
|
||||
|
||||
def is_encrypted(self):
|
||||
""" return True if this message was encrypted. """
|
||||
return bool(lib.dc_msg_get_showpadlock(self._dc_msg))
|
||||
|
||||
def get_message_info(self):
|
||||
""" Return informational text for a single message.
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
lib.dc_set_config(ac._dc_context, b"configured", b"1")
|
||||
return ac
|
||||
|
||||
def get_online_config(self):
|
||||
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)
|
||||
@@ -161,12 +161,8 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
ac = self.make_account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
ac._evlogger.set_timeout(30)
|
||||
return ac, dict(configdict)
|
||||
|
||||
def get_online_configuring_account(self, mvbox=False, sentbox=False):
|
||||
ac, configdict = self.get_online_config()
|
||||
ac.configure(**configdict)
|
||||
ac.start_threads(mvbox=mvbox, sentbox=sentbox)
|
||||
ac.start_threads()
|
||||
return ac
|
||||
|
||||
def get_two_online_accounts(self):
|
||||
@@ -210,13 +206,12 @@ def lp():
|
||||
return Printer()
|
||||
|
||||
|
||||
def wait_configuration_progress(account, min_target, max_target=1001):
|
||||
min_target = min(min_target, max_target)
|
||||
def wait_configuration_progress(account, target):
|
||||
while 1:
|
||||
evt_name, data1, data2 = \
|
||||
account._evlogger.get_matching("DC_EVENT_CONFIGURE_PROGRESS")
|
||||
if data1 >= min_target and data1 <= max_target:
|
||||
print("** CONFIG PROGRESS {}".format(min_target), account)
|
||||
if data1 >= target:
|
||||
print("** CONFIG PROGRESS {}".format(target), account)
|
||||
break
|
||||
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class TestOfflineChat:
|
||||
def chat1(self, ac1):
|
||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||
chat = ac1.create_chat_by_contact(contact1)
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
||||
return chat
|
||||
|
||||
def test_display(self, chat1):
|
||||
@@ -337,14 +337,14 @@ class TestOnlineAccount:
|
||||
def get_chat(self, ac1, ac2):
|
||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
return chat
|
||||
|
||||
def test_one_account_send(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
c2 = ac1.create_contact(email=ac1.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
wait_successful_IMAP_SMTP_connection(ac1)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
|
||||
@@ -365,16 +365,6 @@ class TestOnlineAccount:
|
||||
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||
assert msg_in.text == "message1"
|
||||
|
||||
def test_mvbox_sentbox_threads(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
wait_configuration_progress(ac2, 1000)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
chat.send_text("message1")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
|
||||
def test_forward_messages(self, acfactory):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
@@ -440,8 +430,8 @@ class TestOnlineAccount:
|
||||
ac2.mark_seen_messages([msg_in])
|
||||
lp.step("1")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
||||
assert ev[1] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev[2] > const.DC_MSG_ID_LAST_SPECIAL
|
||||
assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL
|
||||
lp.step("2")
|
||||
assert msg_out.is_out_mdn_received()
|
||||
|
||||
@@ -453,7 +443,6 @@ class TestOnlineAccount:
|
||||
|
||||
lp.sec("sending text message from ac1 to ac2")
|
||||
msg_out = chat.send_text("message1")
|
||||
assert not msg_out.is_encrypted()
|
||||
|
||||
lp.sec("wait for ac2 to receive message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
@@ -471,7 +460,6 @@ class TestOnlineAccount:
|
||||
assert ev[2] > msg_out.id
|
||||
msg_back = ac1.get_message_by_id(ev[2])
|
||||
assert msg_back.text == "message-back"
|
||||
assert msg_back.is_encrypted()
|
||||
|
||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
@@ -576,38 +564,6 @@ class TestOnlineAccount:
|
||||
assert ch.id >= 10
|
||||
wait_securejoin_inviter_progress(ac1, 1000)
|
||||
|
||||
def test_qr_verified_group_and_chatting(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
lp.sec("ac1: create verified-group QR, ac2 scans and joins")
|
||||
chat1 = ac1.create_group_chat("hello", verified=True)
|
||||
assert chat1.is_verified()
|
||||
qr = chat1.get_join_qr()
|
||||
lp.sec("ac2: start QR-code based join-group protocol")
|
||||
chat2 = ac2.qr_join_chat(qr)
|
||||
assert chat2.id >= 10
|
||||
wait_securejoin_inviter_progress(ac1, 1000)
|
||||
|
||||
lp.sec("ac2: read member added message")
|
||||
msg = ac2.wait_next_incoming_message()
|
||||
assert msg.is_encrypted()
|
||||
assert "added" in msg.text.lower()
|
||||
|
||||
lp.sec("ac1: send message")
|
||||
msg_out = chat1.send_text("hello")
|
||||
assert msg_out.is_encrypted()
|
||||
|
||||
lp.sec("ac2: read message and check it's verified chat")
|
||||
msg = ac2.wait_next_incoming_message()
|
||||
assert msg.text == "hello"
|
||||
assert msg.chat.is_verified()
|
||||
assert msg.is_encrypted()
|
||||
|
||||
lp.sec("ac2: send message and let ac1 read it")
|
||||
chat2.send_text("world")
|
||||
msg = ac1.wait_next_incoming_message()
|
||||
assert msg.text == "world"
|
||||
assert msg.is_encrypted()
|
||||
|
||||
def test_set_get_profile_image(self, acfactory, data, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
|
||||
@@ -660,32 +616,3 @@ class TestOnlineAccount:
|
||||
chat1b = ac1.create_chat_by_message(ev[2])
|
||||
assert chat1b.get_profile_image() is None
|
||||
assert chat.get_profile_image() is None
|
||||
|
||||
|
||||
class TestOnlineConfigureFails:
|
||||
def test_invalid_password(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"], mail_pw="123")
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_user(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr="x" + configdict["addr"], mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_domain(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"] + "x", mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "could not connect" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
@@ -4,7 +4,7 @@ from deltachat import const
|
||||
from conftest import wait_configuration_progress, wait_msgs_changed
|
||||
|
||||
|
||||
class TestOnlineInCreation:
|
||||
class TestInCreation:
|
||||
def test_forward_increation(self, acfactory, data, lp):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
|
||||
@@ -59,16 +59,6 @@ def test_wrong_db(tmpdir):
|
||||
assert not lib.dc_open(dc_context, p.strpath.encode("ascii"), ffi.NULL)
|
||||
|
||||
|
||||
def test_empty_blobdir(tmpdir):
|
||||
# Apparently some client code expects this to be the same as passing NULL.
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
db_fname = tmpdir.join("hello.db")
|
||||
assert lib.dc_open(ctx, db_fname.strpath.encode("ascii"), b"")
|
||||
|
||||
|
||||
def test_event_defines():
|
||||
assert const.DC_EVENT_INFO == 100
|
||||
assert const.DC_CONTACT_ID_SELF
|
||||
|
||||
+2
-2
@@ -19,12 +19,12 @@ deps =
|
||||
pytest-rerunfailures
|
||||
pytest-timeout
|
||||
pytest-xdist
|
||||
auditwheel
|
||||
pdbpp
|
||||
requests
|
||||
|
||||
[testenv:auditwheels]
|
||||
skipsdist = True
|
||||
deps = auditwheel
|
||||
commands =
|
||||
python tests/auditwheels.py {toxworkdir}/wheelhouse
|
||||
|
||||
@@ -45,7 +45,7 @@ commands =
|
||||
[testenv:doc]
|
||||
basepython = python3.5
|
||||
deps =
|
||||
sphinx==2.2.0
|
||||
sphinx==2.0.1
|
||||
breathe
|
||||
|
||||
changedir = doc
|
||||
|
||||
+174
-166
@@ -1,4 +1,6 @@
|
||||
use std::ffi::CString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use crate::chatlist::*;
|
||||
use crate::config::*;
|
||||
@@ -10,10 +12,11 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
/// An object representing a single chat in memory.
|
||||
/// Chat objects are created using eg. `Chat::load_from_db`
|
||||
@@ -153,7 +156,7 @@ impl Chat {
|
||||
}
|
||||
let cnt = get_chat_contact_cnt(context, self.id);
|
||||
return context
|
||||
.stock_string_repl_int(StockMessage::Member, cnt as i32)
|
||||
.stock_string_repl_int(StockMessage::Member, cnt)
|
||||
.into();
|
||||
}
|
||||
|
||||
@@ -230,14 +233,15 @@ impl Chat {
|
||||
self.is_sending_locations
|
||||
}
|
||||
|
||||
fn prepare_msg_raw(
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn prepare_msg_raw(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
msg: &mut Message,
|
||||
timestamp: i64,
|
||||
) -> Result<u32, Error> {
|
||||
let mut do_guarantee_e2ee: bool;
|
||||
let e2ee_enabled: bool;
|
||||
let mut do_guarantee_e2ee: libc::c_int;
|
||||
let e2ee_enabled: libc::c_int;
|
||||
let mut new_references = "".into();
|
||||
let mut new_in_reply_to = "".into();
|
||||
let mut msg_id = 0;
|
||||
@@ -253,7 +257,7 @@ impl Chat {
|
||||
}
|
||||
|
||||
if (self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup)
|
||||
&& !is_contact_in_chat(context, self.id, 1 as u32)
|
||||
&& 0 == is_contact_in_chat(context, self.id, 1 as u32)
|
||||
{
|
||||
emit_event!(
|
||||
context,
|
||||
@@ -268,7 +272,7 @@ impl Chat {
|
||||
Chattype::Group | Chattype::VerifiedGroup => Some(self.grpid.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
dc_create_outgoing_rfc724_mid(grpid, &from)
|
||||
dc_create_outgoing_rfc724_mid_safe(grpid, &from)
|
||||
};
|
||||
|
||||
if self.typ == Chattype::Single {
|
||||
@@ -298,13 +302,14 @@ impl Chat {
|
||||
if we guarantee E2EE, and circumstances change
|
||||
so that E2EE is no longer available at a later point (reset, changed settings),
|
||||
we do not send the message out at all */
|
||||
do_guarantee_e2ee = false;
|
||||
do_guarantee_e2ee = 0;
|
||||
e2ee_enabled = context
|
||||
.sql
|
||||
.get_config_int(context, "e2ee_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
== 1;
|
||||
if e2ee_enabled && msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0 {
|
||||
.unwrap_or_else(|| 1);
|
||||
if 0 != e2ee_enabled
|
||||
&& msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0
|
||||
{
|
||||
let mut can_encrypt = 1;
|
||||
let mut all_mutual = 1;
|
||||
|
||||
@@ -349,13 +354,13 @@ impl Chat {
|
||||
|
||||
if 0 != can_encrypt {
|
||||
if 0 != all_mutual {
|
||||
do_guarantee_e2ee = true;
|
||||
do_guarantee_e2ee = 1;
|
||||
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
|
||||
do_guarantee_e2ee = true;
|
||||
do_guarantee_e2ee = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if do_guarantee_e2ee {
|
||||
if 0 != do_guarantee_e2ee {
|
||||
msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
}
|
||||
msg.param.remove(Param::ErroneousE2ee);
|
||||
@@ -481,7 +486,7 @@ pub fn create_by_msg_id(context: &Context, msg_id: u32) -> Result<u32, Error> {
|
||||
let mut chat_id = 0;
|
||||
let mut send_event = false;
|
||||
|
||||
if let Ok(msg) = Message::load_from_db(context, msg_id) {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, msg_id) {
|
||||
if let Ok(chat) = Chat::load_from_db(context, msg.chat_id) {
|
||||
if chat.id > DC_CHAT_ID_LAST_SPECIAL {
|
||||
chat_id = chat.id;
|
||||
@@ -688,13 +693,13 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res
|
||||
// - from FILE to AUDIO/VIDEO/IMAGE
|
||||
// - from FILE/IMAGE to GIF */
|
||||
if let Some((better_type, better_mime)) =
|
||||
message::guess_msgtype_from_suffix(Path::new(&path_filename))
|
||||
dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename))
|
||||
{
|
||||
msg.type_0 = better_type;
|
||||
msg.param.set(Param::MimeType, better_mime);
|
||||
}
|
||||
} else if !msg.param.exists(Param::MimeType) {
|
||||
if let Some((_, mime)) = message::guess_msgtype_from_suffix(Path::new(&path_filename)) {
|
||||
if let Some((_, mime)) = dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename)) {
|
||||
msg.param.set(Param::MimeType, mime);
|
||||
}
|
||||
}
|
||||
@@ -713,7 +718,7 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res
|
||||
msg.state = MessageState::OutPending;
|
||||
}
|
||||
|
||||
msg.id = chat.prepare_msg_raw(context, msg, dc_create_smeared_timestamp(context))?;
|
||||
msg.id = unsafe { chat.prepare_msg_raw(context, msg, dc_create_smeared_timestamp(context))? };
|
||||
msg.chat_id = chat_id;
|
||||
|
||||
Ok(msg.id)
|
||||
@@ -741,7 +746,7 @@ fn last_msg_in_chat_encrypted(context: &Context, sql: &Sql, chat_id: u32) -> boo
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> libc::c_int {
|
||||
/* this function works for group and for normal chats, however, it is more useful for group chats.
|
||||
DC_CONTACT_ID_SELF may be used to check, if the user itself is in a group chat (DC_CONTACT_ID_SELF is not added to normal chats) */
|
||||
|
||||
@@ -751,7 +756,7 @@ pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> b
|
||||
"SELECT contact_id FROM chats_contacts WHERE chat_id=? AND contact_id=?;",
|
||||
params![chat_id as i32, contact_id as i32],
|
||||
)
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default() as libc::c_int
|
||||
}
|
||||
|
||||
// Should return Result
|
||||
@@ -780,11 +785,11 @@ pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u3
|
||||
chat_id == 0 || chat_id == msg.chat_id,
|
||||
"Inconsistent chat ID"
|
||||
);
|
||||
message::update_msg_state(context, msg.id, MessageState::OutPending);
|
||||
dc_update_msg_state(context, msg.id, MessageState::OutPending);
|
||||
}
|
||||
|
||||
ensure!(
|
||||
job_send_msg(context, msg.id) != 0,
|
||||
unsafe { job_send_msg(context, msg.id) } != 0,
|
||||
"Failed to initiate send job"
|
||||
);
|
||||
|
||||
@@ -806,111 +811,101 @@ pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u3
|
||||
// avoid hanging if user tampers with db
|
||||
break;
|
||||
} else {
|
||||
if let Ok(mut copy) = Message::load_from_db(context, id as u32) {
|
||||
if let Ok(mut copy) = dc_get_msg(context, id as u32) {
|
||||
// TODO: handle cleanup and return early instead
|
||||
send_msg(context, 0, &mut copy).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
msg.param.remove(Param::PrepForwards);
|
||||
msg.save_param_to_disk(context);
|
||||
dc_msg_save_param_to_disk(context, msg);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(msg.id)
|
||||
}
|
||||
|
||||
pub fn send_text_msg(context: &Context, chat_id: u32, text_to_send: String) -> Result<u32, Error> {
|
||||
pub unsafe fn send_text_msg(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
text_to_send: String,
|
||||
) -> Result<u32, Error> {
|
||||
ensure!(
|
||||
chat_id > DC_CHAT_ID_LAST_SPECIAL,
|
||||
"bad chat_id = {} <= 9",
|
||||
chat_id
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
msg.text = Some(text_to_send);
|
||||
send_msg(context, chat_id, &mut msg)
|
||||
}
|
||||
|
||||
// passing `None` as message jsut deletes the draft
|
||||
pub fn set_draft(context: &Context, chat_id: u32, msg: Option<&mut Message>) {
|
||||
pub unsafe fn set_draft(context: &Context, chat_id: u32, msg: Option<&mut Message>) {
|
||||
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return;
|
||||
}
|
||||
|
||||
let changed = match msg {
|
||||
None => maybe_delete_draft(context, chat_id),
|
||||
Some(msg) => set_draft_raw(context, chat_id, msg),
|
||||
};
|
||||
|
||||
if changed {
|
||||
if set_draft_raw(context, chat_id, msg) {
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete draft message in specified chat, if there is one.
|
||||
///
|
||||
/// Return {true}, if message was deleted, {false} otherwise.
|
||||
fn maybe_delete_draft(context: &Context, chat_id: u32) -> bool {
|
||||
let draft = get_draft_msg_id(context, chat_id);
|
||||
if draft != 0 {
|
||||
Message::delete_from_db(context, draft);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Set provided message as draft message for specified chat.
|
||||
///
|
||||
/// Return true on success, false on database error.
|
||||
fn do_set_draft(context: &Context, chat_id: u32, msg: &mut Message) -> bool {
|
||||
match msg.type_0 {
|
||||
Viewtype::Unknown => return false,
|
||||
Viewtype::Text => {
|
||||
if msg.text.as_ref().map_or(false, |s| s.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(path_filename) = msg.param.get(Param::File) {
|
||||
let mut path_filename = path_filename.to_string();
|
||||
if msg.is_increation() && !dc_is_blobdir_path(context, &path_filename) {
|
||||
return false;
|
||||
}
|
||||
if !dc_make_rel_and_copy(context, &mut path_filename) {
|
||||
return false;
|
||||
}
|
||||
msg.param.set(Param::File, path_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"INSERT INTO msgs (chat_id, from_id, timestamp, type, state, txt, param, hidden) \
|
||||
VALUES (?,?,?, ?,?,?,?,?);",
|
||||
params![
|
||||
chat_id as i32,
|
||||
1,
|
||||
time(),
|
||||
msg.type_0,
|
||||
MessageState::OutDraft,
|
||||
msg.text.as_ref().map(String::as_str).unwrap_or(""),
|
||||
msg.param.to_string(),
|
||||
1,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
};
|
||||
}
|
||||
|
||||
// similar to as dc_set_draft() but does not emit an event
|
||||
fn set_draft_raw(context: &Context, chat_id: u32, msg: &mut Message) -> bool {
|
||||
let deleted = maybe_delete_draft(context, chat_id);
|
||||
let set = do_set_draft(context, chat_id, msg);
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn set_draft_raw(context: &Context, chat_id: u32, mut msg: Option<&mut Message>) -> bool {
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
|
||||
// Can't inline. Both functions above must be called, no shortcut!
|
||||
deleted || set
|
||||
let mut sth_changed = false;
|
||||
|
||||
let prev_draft_msg_id = get_draft_msg_id(context, chat_id);
|
||||
if 0 != prev_draft_msg_id {
|
||||
dc_delete_msg_from_db(context, prev_draft_msg_id);
|
||||
sth_changed = true;
|
||||
}
|
||||
|
||||
if let Some(ref mut msg) = msg {
|
||||
// save new draft
|
||||
if msg.type_0 == Viewtype::Text {
|
||||
OK_TO_CONTINUE = msg.text.as_ref().map_or(false, |s| !s.is_empty());
|
||||
} else if msgtype_has_file(msg.type_0) {
|
||||
if let Some(path_filename) = msg.param.get(Param::File) {
|
||||
let mut path_filename = path_filename.to_string();
|
||||
if dc_msg_is_increation(msg) && !dc_is_blobdir_path(context, &path_filename) {
|
||||
OK_TO_CONTINUE = false;
|
||||
} else if !dc_make_rel_and_copy(context, &mut path_filename) {
|
||||
OK_TO_CONTINUE = false;
|
||||
} else {
|
||||
msg.param.set(Param::File, path_filename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
if OK_TO_CONTINUE {
|
||||
if sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"INSERT INTO msgs (chat_id, from_id, timestamp, type, state, txt, param, hidden) \
|
||||
VALUES (?,?,?, ?,?,?,?,?);",
|
||||
params![
|
||||
chat_id as i32,
|
||||
1,
|
||||
time(),
|
||||
msg.type_0,
|
||||
MessageState::OutDraft,
|
||||
msg.text.as_ref().map(String::as_str).unwrap_or(""),
|
||||
msg.param.to_string(),
|
||||
1,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
sth_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
sth_changed
|
||||
}
|
||||
|
||||
fn get_draft_msg_id(context: &Context, chat_id: u32) -> u32 {
|
||||
@@ -930,7 +925,7 @@ pub fn get_draft(context: &Context, chat_id: u32) -> Result<Option<Message>, Err
|
||||
if draft_msg_id == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(Message::load_from_db(context, draft_msg_id)?))
|
||||
Ok(Some(dc_msg_load_from_db(context, draft_msg_id)?))
|
||||
}
|
||||
|
||||
pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before: u32) -> Vec<u32> {
|
||||
@@ -948,7 +943,7 @@ pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before:
|
||||
}
|
||||
if 0 != flags & 0x1 {
|
||||
let curr_local_timestamp = ts + cnv_to_local;
|
||||
let curr_day = curr_local_timestamp / 86400;
|
||||
let curr_day = (curr_local_timestamp / 86400) as libc::c_int;
|
||||
if curr_day != last_day {
|
||||
ret.push(DC_MSG_ID_LAST_SPECIAL);
|
||||
last_day = curr_day;
|
||||
@@ -1115,25 +1110,17 @@ pub fn get_chat_media(
|
||||
).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Indicates the direction over which to iterate.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum Direction {
|
||||
Forward = 1,
|
||||
Backward = -1,
|
||||
}
|
||||
|
||||
pub fn get_next_media(
|
||||
pub unsafe fn get_next_media(
|
||||
context: &Context,
|
||||
curr_msg_id: u32,
|
||||
direction: Direction,
|
||||
dir: libc::c_int,
|
||||
msg_type: Viewtype,
|
||||
msg_type2: Viewtype,
|
||||
msg_type3: Viewtype,
|
||||
) -> u32 {
|
||||
let mut ret = 0;
|
||||
|
||||
if let Ok(msg) = Message::load_from_db(context, curr_msg_id) {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, curr_msg_id) {
|
||||
let list = get_chat_media(
|
||||
context,
|
||||
msg.chat_id,
|
||||
@@ -1147,16 +1134,13 @@ pub fn get_next_media(
|
||||
);
|
||||
for i in 0..list.len() {
|
||||
if curr_msg_id == list[i] {
|
||||
match direction {
|
||||
Direction::Forward => {
|
||||
if i + 1 < list.len() {
|
||||
ret = list[i + 1]
|
||||
}
|
||||
if dir > 0 {
|
||||
if i + 1 < list.len() {
|
||||
ret = list[i + 1]
|
||||
}
|
||||
Direction::Backward => {
|
||||
if i >= 1 {
|
||||
ret = list[i - 1];
|
||||
}
|
||||
} else if dir < 0 {
|
||||
if i >= 1 {
|
||||
ret = list[i - 1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1273,14 +1257,16 @@ pub fn get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn create_group_chat(
|
||||
pub unsafe fn create_group_chat(
|
||||
context: &Context,
|
||||
verified: VerifiedStatus,
|
||||
chat_name: impl AsRef<str>,
|
||||
) -> Result<u32, Error> {
|
||||
ensure!(!chat_name.as_ref().is_empty(), "Invalid chat name");
|
||||
|
||||
let draft_txt = context.stock_string_repl_str(StockMessage::NewGroupDraft, &chat_name);
|
||||
let draft_txt =
|
||||
CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, &chat_name))
|
||||
.unwrap();
|
||||
let grpid = dc_create_id();
|
||||
|
||||
sql::execute(
|
||||
@@ -1302,9 +1288,9 @@ pub fn create_group_chat(
|
||||
|
||||
if chat_id != 0 {
|
||||
if add_to_chat_contacts_table(context, chat_id, 1) {
|
||||
let mut draft_msg = Message::new(Viewtype::Text);
|
||||
draft_msg.set_text(Some(draft_txt));
|
||||
set_draft_raw(context, chat_id, &mut draft_msg);
|
||||
let mut draft_msg = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut draft_msg, draft_txt.as_ptr());
|
||||
set_draft_raw(context, chat_id, Some(&mut draft_msg));
|
||||
}
|
||||
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
@@ -1330,16 +1316,16 @@ pub fn add_to_chat_contacts_table(context: &Context, chat_id: u32, contact_id: u
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
pub fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
add_contact_to_chat_ex(context, chat_id, contact_id, false)
|
||||
pub unsafe fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
add_contact_to_chat_ex(context, chat_id, contact_id, 0)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub(crate) fn add_contact_to_chat_ex(
|
||||
pub fn add_contact_to_chat_ex(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
contact_id: u32,
|
||||
from_handshake: bool,
|
||||
flags: libc::c_int,
|
||||
) -> bool {
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
let mut success = false;
|
||||
@@ -1348,7 +1334,7 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
if contact.is_err() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return false;
|
||||
}
|
||||
let mut msg = Message::default();
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
|
||||
reset_gossiped_timestamp(context, chat_id);
|
||||
let contact = contact.unwrap();
|
||||
@@ -1358,7 +1344,7 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
if !(!real_group_exists(context, chat_id)
|
||||
|| !Contact::real_exists_by_id(context, contact_id) && contact_id != DC_CONTACT_ID_SELF)
|
||||
{
|
||||
if !is_contact_in_chat(context, chat_id, 1 as u32) {
|
||||
if !(is_contact_in_chat(context, chat_id, 1 as u32) == 1) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
@@ -1367,7 +1353,8 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
);
|
||||
} else {
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if from_handshake && chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1
|
||||
if 0 != flags & 0x1
|
||||
&& chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1
|
||||
{
|
||||
chat.param.remove(Param::Unpromoted);
|
||||
chat.update_param(context).unwrap();
|
||||
@@ -1380,8 +1367,8 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
// ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly.
|
||||
// if SELF is not in the group, members cannot be added at all.
|
||||
|
||||
if is_contact_in_chat(context, chat_id, contact_id) {
|
||||
if !from_handshake {
|
||||
if 0 != is_contact_in_chat(context, chat_id, contact_id) {
|
||||
if 0 == flags & 0x1 {
|
||||
success = true;
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
@@ -1413,7 +1400,7 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
));
|
||||
msg.param.set_int(Param::Cmd, 4);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.param.set_int(Param::Arg2, from_handshake.into());
|
||||
msg.param.set_int(Param::Arg2, flags);
|
||||
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
@@ -1480,7 +1467,7 @@ pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_contact_from_chat(
|
||||
pub unsafe fn remove_contact_from_chat(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
contact_id: u32,
|
||||
@@ -1495,14 +1482,14 @@ pub fn remove_contact_from_chat(
|
||||
"Cannot remove special contact"
|
||||
);
|
||||
|
||||
let mut msg = Message::default();
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
let mut success = false;
|
||||
|
||||
/* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */
|
||||
/* this allows to delete pending references to deleted contacts. Of course, this should _not_ happen. */
|
||||
if let Ok(chat) = Chat::load_from_db(context, chat_id) {
|
||||
if real_group_exists(context, chat_id) {
|
||||
if !is_contact_in_chat(context, chat_id, 1 as u32) {
|
||||
if !(is_contact_in_chat(context, chat_id, 1 as u32) == 1) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
@@ -1581,7 +1568,7 @@ pub fn is_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Re
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_chat_name(
|
||||
pub unsafe fn set_chat_name(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
new_name: impl AsRef<str>,
|
||||
@@ -1593,12 +1580,12 @@ pub fn set_chat_name(
|
||||
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
|
||||
|
||||
let chat = Chat::load_from_db(context, chat_id)?;
|
||||
let mut msg = Message::default();
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
|
||||
if real_group_exists(context, chat_id) {
|
||||
if &chat.name == new_name.as_ref() {
|
||||
success = true;
|
||||
} else if !is_contact_in_chat(context, chat_id, 1) {
|
||||
} else if !(is_contact_in_chat(context, chat_id, 1) == 1) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup("Cannot set chat name; self not in group".into())
|
||||
@@ -1660,7 +1647,7 @@ pub fn set_chat_profile_image(
|
||||
|
||||
if real_group_exists(context, chat_id) {
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if !is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF) {
|
||||
if !(is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF) == 1i32) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
@@ -1682,7 +1669,7 @@ pub fn set_chat_profile_image(
|
||||
chat.param.set(Param::ProfileImage, &new_image_rel);
|
||||
if chat.update_param(context).is_ok() {
|
||||
if chat.is_promoted() {
|
||||
let mut msg = Message::default();
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
msg.param
|
||||
.set_int(Param::Cmd, SystemMessage::GroupImageChanged as i32);
|
||||
msg.type_0 = Viewtype::Text;
|
||||
@@ -1714,8 +1701,13 @@ pub fn set_chat_profile_image(
|
||||
bail!("Failed to set profile image");
|
||||
}
|
||||
|
||||
pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
if msg_ids.is_empty() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
pub unsafe fn forward_msgs(
|
||||
context: &Context,
|
||||
msg_ids: *const u32,
|
||||
msg_cnt: libc::c_int,
|
||||
chat_id: u32,
|
||||
) {
|
||||
if msg_ids.is_null() || msg_cnt <= 0 || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1724,13 +1716,14 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
|
||||
unarchive(context, chat_id).unwrap();
|
||||
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
|
||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_ids.len());
|
||||
let idsstr = msg_ids
|
||||
.into_iter()
|
||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
|
||||
let idsstr = std::slice::from_raw_parts(msg_ids, msg_cnt as usize)
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(String::with_capacity(2 * msg_ids.len()), |acc, (i, n)| {
|
||||
(if i == 0 { acc } else { acc + "," }) + &n.to_string()
|
||||
});
|
||||
.fold(
|
||||
String::with_capacity(2 * msg_cnt as usize),
|
||||
|acc, (i, n)| (if i == 0 { acc } else { acc + "," }) + &n.to_string(),
|
||||
);
|
||||
|
||||
let ids = context
|
||||
.sql
|
||||
@@ -1747,7 +1740,7 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
|
||||
for id in ids {
|
||||
let src_msg_id = id;
|
||||
let msg = Message::load_from_db(context, src_msg_id as u32);
|
||||
let msg = dc_msg_load_from_db(context, src_msg_id as u32);
|
||||
if msg.is_err() {
|
||||
break;
|
||||
}
|
||||
@@ -1778,7 +1771,7 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
msg.param.set(Param::PrepForwards, new_msg_id.to_string());
|
||||
}
|
||||
|
||||
msg.save_param_to_disk(context);
|
||||
dc_msg_save_param_to_disk(context, &mut msg);
|
||||
msg.param = save_param;
|
||||
} else {
|
||||
msg.state = MessageState::OutPending;
|
||||
@@ -1802,15 +1795,15 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_chat_contact_cnt(context: &Context, chat_id: u32) -> usize {
|
||||
pub fn get_chat_contact_cnt(context: &Context, chat_id: u32) -> libc::c_int {
|
||||
context
|
||||
.sql
|
||||
.query_get_value::<_, isize>(
|
||||
.query_get_value(
|
||||
context,
|
||||
"SELECT COUNT(*) FROM chats_contacts WHERE chat_id=?;",
|
||||
params![chat_id as i32],
|
||||
)
|
||||
.unwrap_or_default() as usize
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn get_chat_cnt(context: &Context) -> usize {
|
||||
@@ -1847,7 +1840,12 @@ pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32,
|
||||
}
|
||||
|
||||
pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
|
||||
let rfc724_mid = unsafe {
|
||||
dc_create_outgoing_rfc724_mid(
|
||||
ptr::null(),
|
||||
b"@device\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
|
||||
if context.sql.execute(
|
||||
"INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);",
|
||||
@@ -1859,13 +1857,21 @@ pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
Viewtype::Text,
|
||||
MessageState::InNoticed,
|
||||
text.as_ref(),
|
||||
rfc724_mid,
|
||||
as_str(rfc724_mid),
|
||||
]
|
||||
).is_err() {
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
return;
|
||||
}
|
||||
|
||||
let msg_id = sql::get_rowid(context, &context.sql, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
let msg_id = sql::get_rowid(
|
||||
context,
|
||||
&context.sql,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id });
|
||||
}
|
||||
|
||||
@@ -1901,14 +1907,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_draft() {
|
||||
let t = dummy_context();
|
||||
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF).unwrap();
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.set_text(Some("hello".to_string()));
|
||||
set_draft(&t.ctx, chat_id, Some(&mut msg));
|
||||
let draft = get_draft(&t.ctx, chat_id).unwrap().unwrap();
|
||||
let msg_text = msg.get_text();
|
||||
let draft_text = draft.get_text();
|
||||
assert_eq!(msg_text, draft_text);
|
||||
unsafe {
|
||||
let t = dummy_context();
|
||||
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF).unwrap();
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut msg, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
set_draft(&t.ctx, chat_id, Some(&mut msg));
|
||||
let draft = get_draft(&t.ctx, chat_id).unwrap().unwrap();
|
||||
let msg_text = dc_msg_get_text(&msg);
|
||||
let draft_text = dc_msg_get_text(&draft);
|
||||
assert_eq!(as_str(msg_text), as_str(draft_text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ use crate::contact::*;
|
||||
use crate::context::*;
|
||||
use crate::error::Result;
|
||||
use crate::lot::Lot;
|
||||
use crate::message::Message;
|
||||
use crate::message::*;
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
/// An object representing a single chatlist in memory.
|
||||
@@ -271,7 +271,7 @@ impl Chatlist {
|
||||
let mut lastcontact = None;
|
||||
|
||||
let lastmsg = if 0 != lastmsg_id {
|
||||
if let Ok(lastmsg) = Message::load_from_db(context, lastmsg_id) {
|
||||
if let Ok(lastmsg) = dc_msg_load_from_db(context, lastmsg_id) {
|
||||
if lastmsg.from_id != 1 as libc::c_uint
|
||||
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
@@ -6,6 +5,7 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::x::*;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
/* ******************************************************************************
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
use std::ptr;
|
||||
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
@@ -8,6 +5,8 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
/* ******************************************************************************
|
||||
@@ -47,7 +46,7 @@ pub unsafe fn outlk_autodiscover(
|
||||
ok_to_continue = true;
|
||||
break;
|
||||
}
|
||||
libc::memset(
|
||||
memset(
|
||||
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
|
||||
0,
|
||||
::std::mem::size_of::<outlk_autodiscover_t>(),
|
||||
|
||||
+1
-34
@@ -18,7 +18,7 @@ use auto_mozilla::moz_autoconfigure;
|
||||
macro_rules! progress {
|
||||
($context:tt, $progress:expr) => {
|
||||
assert!(
|
||||
$progress <= 1000,
|
||||
$progress > 0 && $progress <= 1000,
|
||||
"value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success"
|
||||
);
|
||||
$context.call_cb($crate::events::Event::ConfigureProgress($progress));
|
||||
@@ -660,36 +660,3 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::config::*;
|
||||
use crate::configure::dc_job_do_DC_JOB_CONFIGURE_IMAP;
|
||||
use crate::job::*;
|
||||
use crate::param::*;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_no_panic_on_bad_credentials() {
|
||||
let t = dummy_context();
|
||||
t.ctx
|
||||
.set_config(Config::Addr, Some("probably@unexistant.addr"))
|
||||
.unwrap();
|
||||
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
|
||||
let job = Job {
|
||||
job_id: 1,
|
||||
action: Action::ConfigureImap,
|
||||
foreign_id: 0,
|
||||
desired_timestamp: 0,
|
||||
added_timestamp: 0,
|
||||
tries: 0,
|
||||
param: Params::new(),
|
||||
try_again: 0,
|
||||
pending_error: None,
|
||||
};
|
||||
unsafe {
|
||||
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx, &job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -60,10 +60,6 @@ const DC_GCM_ADDDAYMARKER: usize = 0x01;
|
||||
pub const DC_GCL_VERIFIED_ONLY: usize = 0x01;
|
||||
pub const DC_GCL_ADD_SELF: usize = 0x02;
|
||||
|
||||
// values for DC_PARAM_FORCE_PLAINTEXT
|
||||
pub(crate) const DC_FP_NO_AUTOCRYPT_HEADER: i32 = 2;
|
||||
pub(crate) const DC_FP_ADD_AUTOCRYPT_HEADER: i32 = 1;
|
||||
|
||||
/// param1 is a directory where the keys are written to
|
||||
const DC_IMEX_EXPORT_SELF_KEYS: usize = 1;
|
||||
/// param1 is a directory where the keys are searched in and read from
|
||||
@@ -126,7 +122,7 @@ const DC_MAX_GET_INFO_LEN: usize = 100000;
|
||||
|
||||
pub const DC_CONTACT_ID_UNDEFINED: u32 = 0;
|
||||
pub const DC_CONTACT_ID_SELF: u32 = 1;
|
||||
pub const DC_CONTACT_ID_DEVICE: u32 = 2;
|
||||
const DC_CONTACT_ID_DEVICE: u32 = 2;
|
||||
pub const DC_CONTACT_ID_LAST_SPECIAL: u32 = 9;
|
||||
|
||||
pub const DC_CREATE_MVBOX: usize = 1;
|
||||
|
||||
+7
-7
@@ -16,7 +16,7 @@ use crate::job_thread::JobThread;
|
||||
use crate::key::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::lot::Lot;
|
||||
use crate::message::{self, Message};
|
||||
use crate::message::*;
|
||||
use crate::param::Params;
|
||||
use crate::smtp::*;
|
||||
use crate::sql::Sql;
|
||||
@@ -144,8 +144,8 @@ impl Context {
|
||||
let l2 = LoginParam::from_database(self, "configured_");
|
||||
let displayname = self.sql.get_config(self, "displayname");
|
||||
let chats = get_chat_cnt(self) as usize;
|
||||
let real_msgs = message::get_real_msg_cnt(self) as usize;
|
||||
let deaddrop_msgs = message::get_deaddrop_msg_cnt(self) as usize;
|
||||
let real_msgs = dc_get_real_msg_cnt(self) as usize;
|
||||
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(self) as usize;
|
||||
let contacts = Contact::get_real_cnt(self) as usize;
|
||||
let is_configured = self
|
||||
.sql
|
||||
@@ -354,15 +354,15 @@ impl Context {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(msg) = Message::load_from_db(self, msg_id) {
|
||||
if msg.is_setupmessage() {
|
||||
if let Ok(msg) = dc_msg_new_load(self, msg_id) {
|
||||
if dc_msg_is_setupmessage(&msg) {
|
||||
// do not move setup messages;
|
||||
// there may be a non-delta device that wants to handle it
|
||||
return;
|
||||
}
|
||||
|
||||
if self.is_mvbox(folder) {
|
||||
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay);
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
@@ -374,7 +374,7 @@ impl Context {
|
||||
Params::new(),
|
||||
0,
|
||||
);
|
||||
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving);
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Moving);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
-59
@@ -2,7 +2,6 @@ use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{free, strcmp, strlen, strstr};
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
@@ -19,11 +18,12 @@ use crate::error::*;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::key::*;
|
||||
use crate::message::Message;
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::pgp::*;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
// import/export and tools
|
||||
// param1 is a directory where the keys are written to
|
||||
@@ -127,7 +127,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
dc_get_fine_path_filename(context, "$BLOBDIR", "autocrypt-setup-message.html");
|
||||
if dc_write_file(context, &setup_file_name, setup_file_content.as_bytes()) {
|
||||
if let Ok(chat_id) = chat::create_by_contact_id(context, 1) {
|
||||
msg = Message::default();
|
||||
msg = dc_msg_new_untyped();
|
||||
msg.type_0 = Viewtype::File;
|
||||
msg.param
|
||||
.set(Param::File, setup_file_name.to_string_lossy());
|
||||
@@ -135,8 +135,7 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
msg.param
|
||||
.set(Param::MimeType, "application/autocrypt-setup");
|
||||
msg.param.set_int(Param::Cmd, 6);
|
||||
msg.param
|
||||
.set_int(Param::ForcePlaintext, DC_FP_NO_AUTOCRYPT_HEADER);
|
||||
msg.param.set_int(Param::ForcePlaintext, 2);
|
||||
|
||||
if !context
|
||||
.running_state
|
||||
@@ -158,8 +157,8 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
if let Ok(msg) = Message::load_from_db(context, msg_id) {
|
||||
if msg.is_sent() {
|
||||
if let Ok(msg) = dc_get_msg(context, msg_id) {
|
||||
if dc_msg_is_sent(&msg) {
|
||||
info!(context, "... setup message sent.",);
|
||||
break;
|
||||
}
|
||||
@@ -265,19 +264,19 @@ pub unsafe fn dc_continue_key_transfer(
|
||||
return false;
|
||||
}
|
||||
|
||||
let msg = Message::load_from_db(context, msg_id);
|
||||
let msg = dc_get_msg(context, msg_id);
|
||||
if msg.is_err() {
|
||||
error!(context, "Message is no Autocrypt Setup Message.");
|
||||
return false;
|
||||
}
|
||||
let msg = msg.unwrap();
|
||||
if !msg.is_setupmessage() {
|
||||
if !dc_msg_is_setupmessage(&msg) {
|
||||
error!(context, "Message is no Autocrypt Setup Message.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(filename) = msg.get_file(context) {
|
||||
if let Ok(buf) = dc_read_file(context, filename) {
|
||||
if let Some(filename) = dc_msg_get_file(context, &msg) {
|
||||
if let Some(buf) = dc_read_file_safe(context, filename) {
|
||||
norm_sc = dc_normalize_setup_code(context, setup_code);
|
||||
if norm_sc.is_null() {
|
||||
warn!(context, "Cannot normalize Setup Code.",);
|
||||
@@ -768,8 +767,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
|
||||
} else {
|
||||
info!(context, "EXPORTing filename={}", name);
|
||||
let curr_pathNfilename = context.get_blobdir().join(entry.file_name());
|
||||
if let Ok(buf) =
|
||||
dc_read_file(context, &curr_pathNfilename)
|
||||
if let Some(buf) =
|
||||
dc_read_file_safe(context, &curr_pathNfilename)
|
||||
{
|
||||
if buf.is_empty() {
|
||||
continue;
|
||||
@@ -844,6 +843,7 @@ 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 set_default: libc::c_int;
|
||||
let mut buf: *mut libc::c_char = ptr::null_mut();
|
||||
// a pointer inside buf, MUST NOT be free()'d
|
||||
@@ -858,26 +858,23 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry_fn = entry.unwrap().file_name();
|
||||
let name_f = entry_fn.to_string_lossy();
|
||||
|
||||
match dc_get_filesuffix_lc(&name_f) {
|
||||
Some(suffix) => {
|
||||
if suffix != ".asc" {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
free(suffix as *mut libc::c_void);
|
||||
let name_f = entry.file_name();
|
||||
let name_c = name_f.to_c_string().unwrap();
|
||||
suffix = dc_get_filesuffix_lc(name_f.to_string_lossy());
|
||||
if suffix.is_null()
|
||||
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let path_plus_name = dir.join(&entry_fn);
|
||||
let path_plus_name = dir.join(entry.file_name());
|
||||
info!(context, "Checking: {}", path_plus_name.display());
|
||||
|
||||
free(buf.cast());
|
||||
buf = ptr::null_mut();
|
||||
|
||||
if let Ok(buf_r) = dc_read_file(context, &path_plus_name) {
|
||||
if let Some(buf_r) = dc_read_file_safe(context, &path_plus_name) {
|
||||
buf = buf_r.as_ptr() as *mut _;
|
||||
std::mem::forget(buf_r);
|
||||
} else {
|
||||
@@ -909,7 +906,12 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
}
|
||||
}
|
||||
set_default = 1;
|
||||
if name_f.contains("legacy") {
|
||||
if !strstr(
|
||||
name_c.as_ptr(),
|
||||
b"legacy\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
info!(
|
||||
context,
|
||||
"Treating \"{}\" as a legacy private key.",
|
||||
@@ -938,6 +940,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
}
|
||||
}
|
||||
|
||||
free(suffix as *mut libc::c_void);
|
||||
free(buf as *mut libc::c_void);
|
||||
free(buf2 as *mut libc::c_void);
|
||||
|
||||
@@ -958,23 +961,22 @@ unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> bool
|
||||
let public_key = Key::from_slice(&public_key_blob, KeyType::Public);
|
||||
let private_key_blob: Vec<u8> = row.get(2)?;
|
||||
let private_key = Key::from_slice(&private_key_blob, KeyType::Private);
|
||||
let is_default: i32 = row.get(3)?;
|
||||
let is_default = row.get(3)?;
|
||||
|
||||
Ok((id, public_key, private_key, is_default))
|
||||
},
|
||||
|keys| {
|
||||
for key_pair in keys {
|
||||
let (id, public_key, private_key, is_default) = key_pair?;
|
||||
let id = Some(id).filter(|_| is_default != 0);
|
||||
if let Some(key) = public_key {
|
||||
if export_key_to_asc_file(context, dir, id, &key) {
|
||||
if export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1;
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
if let Some(key) = private_key {
|
||||
if export_key_to_asc_file(context, dir, id, &key) {
|
||||
if export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1;
|
||||
}
|
||||
} else {
|
||||
@@ -996,15 +998,26 @@ unsafe fn export_self_keys(context: &Context, dir: *const libc::c_char) -> bool
|
||||
unsafe fn export_key_to_asc_file(
|
||||
context: &Context,
|
||||
dir: *const libc::c_char,
|
||||
id: Option<i64>,
|
||||
id: libc::c_int,
|
||||
key: &Key,
|
||||
is_default: libc::c_int,
|
||||
) -> bool {
|
||||
let mut success = false;
|
||||
let file_name = {
|
||||
let kind = if key.is_public() { "public" } else { "private" };
|
||||
let id = id.map_or("default".into(), |i| i.to_string());
|
||||
let dir = as_path(dir);
|
||||
|
||||
as_path(dir).join(format!("{}-key-{}.asc", kind, &id))
|
||||
let file_name = if 0 != is_default {
|
||||
let name = format!(
|
||||
"{}-key-default.asc",
|
||||
if key.is_public() { "public" } else { "private" },
|
||||
);
|
||||
dir.join(name)
|
||||
} else {
|
||||
let name = format!(
|
||||
"{}-key-{}.asc",
|
||||
if key.is_public() { "public" } else { "private" },
|
||||
id
|
||||
);
|
||||
dir.join(name)
|
||||
};
|
||||
info!(context, "Exporting key {}", file_name.display());
|
||||
dc_delete_file(context, &file_name);
|
||||
@@ -1012,7 +1025,7 @@ unsafe fn export_key_to_asc_file(
|
||||
if !key.write_asc_to_file(&file_name, context) {
|
||||
error!(context, "Cannot write key to {}", file_name.display());
|
||||
} else {
|
||||
context.call_cb(Event::ImexFileWritten(file_name));
|
||||
context.call_cb(Event::ImexFileWritten(file_name.clone()));
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -1078,25 +1091,4 @@ mod tests {
|
||||
assert_eq!(setupcode.chars().nth(34).unwrap(), '-');
|
||||
assert_eq!(setupcode.chars().nth(39).unwrap(), '-');
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_export_key_to_asc_file() {
|
||||
unsafe {
|
||||
let context = dummy_context();
|
||||
let base64 = include_str!("../test-data/key/public.asc");
|
||||
let key = Key::from_base64(base64, KeyType::Public).unwrap();
|
||||
let blobdir = CString::yolo("$BLOBDIR");
|
||||
assert!(export_key_to_asc_file(
|
||||
&context.ctx,
|
||||
blobdir.as_ptr(),
|
||||
None,
|
||||
&key
|
||||
));
|
||||
let blobdir = context.ctx.get_blobdir().to_str().unwrap();
|
||||
let filename = format!("{}/public-key-default.asc", blobdir);
|
||||
let bytes = std::fs::read(&filename).unwrap();
|
||||
|
||||
assert_eq!(bytes, key.to_asc(None).into_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+922
-562
File diff suppressed because it is too large
Load Diff
+697
-517
File diff suppressed because it is too large
Load Diff
+83
-49
@@ -2,13 +2,13 @@ use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use itertools::join;
|
||||
use libc::{free, strcmp, strlen};
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::*;
|
||||
use mmime::mailimf_types::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mailmime_types::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
@@ -23,12 +23,13 @@ use crate::error::Result;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::location;
|
||||
use crate::message::{self, MessageState};
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::securejoin::handle_securejoin_handshake;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum CreateEvent {
|
||||
@@ -84,6 +85,8 @@ pub unsafe fn dc_receive_imf(
|
||||
let mut add_delete_job: libc::c_int = 0;
|
||||
let mut insert_msg_id = 0;
|
||||
|
||||
// Message-ID from the header
|
||||
let rfc724_mid = std::ptr::null_mut();
|
||||
let mut sent_timestamp = 0;
|
||||
let mut created_db_entries = Vec::new();
|
||||
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
|
||||
@@ -93,9 +96,12 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
// helper method to handle early exit and memory cleanup
|
||||
let cleanup = |context: &Context,
|
||||
rfc724_mid: *mut libc::c_char,
|
||||
create_event_to_send: &Option<CreateEvent>,
|
||||
created_db_entries: &Vec<(usize, usize)>,
|
||||
rr_event_to_send: &Vec<(u32, u32)>| {
|
||||
free(rfc724_mid.cast());
|
||||
|
||||
if let Some(create_event_to_send) = create_event_to_send {
|
||||
for (chat_id, msg_id) in created_db_entries {
|
||||
let event = match create_event_to_send {
|
||||
@@ -178,28 +184,6 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
|
||||
// Add parts
|
||||
|
||||
let rfc724_mid = match mime_parser.get_rfc724_mid() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
// missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS
|
||||
match dc_create_incoming_rfc724_mid(sent_timestamp, from_id, &to_ids) {
|
||||
Some(x) => x.to_string(),
|
||||
None => {
|
||||
error!(context, "can not create incoming rfc724_mid");
|
||||
cleanup(
|
||||
context,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if mime_parser.get_last_nonmeta().is_some() {
|
||||
if let Err(err) = add_parts(
|
||||
context,
|
||||
@@ -211,7 +195,7 @@ pub unsafe fn dc_receive_imf(
|
||||
server_folder.as_ref(),
|
||||
server_uid,
|
||||
&mut to_ids,
|
||||
&rfc724_mid,
|
||||
rfc724_mid,
|
||||
&mut sent_timestamp,
|
||||
&mut from_id,
|
||||
from_id_blocked,
|
||||
@@ -229,6 +213,7 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -278,11 +263,14 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
info!(
|
||||
context,
|
||||
"received message {} has Message-Id: {}", server_uid, rfc724_mid
|
||||
"received message {} has Message-Id: {}",
|
||||
server_uid,
|
||||
to_string(rfc724_mid)
|
||||
);
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -299,7 +287,7 @@ unsafe fn add_parts(
|
||||
server_folder: impl AsRef<str>,
|
||||
server_uid: u32,
|
||||
to_ids: &mut Vec<u32>,
|
||||
rfc724_mid: &str,
|
||||
mut rfc724_mid: *mut libc::c_char,
|
||||
sent_timestamp: &mut i64,
|
||||
from_id: &mut u32,
|
||||
from_id_blocked: i32,
|
||||
@@ -348,16 +336,42 @@ unsafe fn add_parts(
|
||||
}
|
||||
}
|
||||
|
||||
// get Message-ID; if the header is lacking one, generate one based on fields that do never
|
||||
// change. (missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS)
|
||||
if let Some(field) = mime_parser.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
|
||||
let fld_message_id = (*field).fld_data.fld_message_id;
|
||||
if !fld_message_id.is_null() {
|
||||
rfc724_mid = dc_strdup((*fld_message_id).mid_value)
|
||||
}
|
||||
}
|
||||
|
||||
if rfc724_mid.is_null() {
|
||||
rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids);
|
||||
if rfc724_mid.is_null() {
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Cannot create Message-ID");
|
||||
}
|
||||
}
|
||||
|
||||
// check, if the mail is already in our database - if so, just update the folder/uid
|
||||
// (if the mail was moved around) and finish. (we may get a mail twice eg. if it is
|
||||
// moved between folders. make sure, this check is done eg. before securejoin-processing) */
|
||||
if let Ok((old_server_folder, old_server_uid, _)) =
|
||||
message::rfc724_mid_exists(context, &rfc724_mid)
|
||||
{
|
||||
if old_server_folder != server_folder.as_ref() || old_server_uid != server_uid {
|
||||
message::update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
let mut old_server_folder = std::ptr::null_mut();
|
||||
let mut old_server_uid = 0;
|
||||
|
||||
if 0 != dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
) {
|
||||
if as_str(old_server_folder) != server_folder.as_ref() || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
}
|
||||
|
||||
free(old_server_folder.cast());
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Message already in DB");
|
||||
}
|
||||
@@ -653,7 +667,7 @@ unsafe fn add_parts(
|
||||
}
|
||||
|
||||
stmt.execute(params![
|
||||
rfc724_mid,
|
||||
as_str(rfc724_mid),
|
||||
server_folder.as_ref(),
|
||||
server_uid as libc::c_int,
|
||||
*chat_id as libc::c_int,
|
||||
@@ -684,8 +698,13 @@ unsafe fn add_parts(
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
*insert_msg_id =
|
||||
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
*insert_msg_id = sql::get_rowid_with_conn(
|
||||
context,
|
||||
conn,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
created_db_entries.push((*chat_id as usize, *insert_msg_id as usize));
|
||||
}
|
||||
Ok(())
|
||||
@@ -741,7 +760,10 @@ unsafe fn handle_reports(
|
||||
for report_root in &mime_parser.reports {
|
||||
let report_root = *report_root;
|
||||
let mut mdn_consumed = 0;
|
||||
let report_type = mailmime_find_ct_parameter(report_root, "report-type");
|
||||
let report_type = mailmime_find_ct_parameter(
|
||||
report_root,
|
||||
b"report-type\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
|
||||
if report_root.is_null() || report_type.is_null() || (*report_type).pa_value.is_null() {
|
||||
continue;
|
||||
@@ -792,13 +814,22 @@ unsafe fn handle_reports(
|
||||
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
if let Ok(report_body) = mailmime_transfer_decode(report_data) {
|
||||
let mut report_body = std::ptr::null();
|
||||
let mut report_body_bytes = 0;
|
||||
let mut to_mmap_string_unref = std::ptr::null_mut();
|
||||
|
||||
if mailmime_transfer_decode(
|
||||
report_data,
|
||||
&mut report_body,
|
||||
&mut report_body_bytes,
|
||||
&mut to_mmap_string_unref,
|
||||
) {
|
||||
let mut report_parsed = std::ptr::null_mut();
|
||||
let mut dummy = 0;
|
||||
|
||||
if mailmime_parse(
|
||||
report_body.as_ptr() as *const _,
|
||||
report_body.len(),
|
||||
report_body,
|
||||
report_body_bytes,
|
||||
&mut dummy,
|
||||
&mut report_parsed,
|
||||
) == MAIL_NO_ERROR as libc::c_int
|
||||
@@ -833,10 +864,10 @@ unsafe fn handle_reports(
|
||||
let mut chat_id_0 = 0;
|
||||
let mut msg_id = 0;
|
||||
|
||||
if message::mdn_from_ext(
|
||||
if 0 != dc_mdn_from_ext(
|
||||
context,
|
||||
from_id,
|
||||
as_str(rfc724_mid_0),
|
||||
rfc724_mid_0,
|
||||
sent_timestamp,
|
||||
&mut chat_id_0,
|
||||
&mut msg_id,
|
||||
@@ -850,6 +881,9 @@ unsafe fn handle_reports(
|
||||
}
|
||||
mailmime_free(report_parsed);
|
||||
}
|
||||
if !to_mmap_string_unref.is_null() {
|
||||
mmap_string_unref(to_mmap_string_unref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1163,7 +1197,7 @@ unsafe fn create_or_lookup_group(
|
||||
|
||||
// check if the sender is a member of the existing group -
|
||||
// if not, we'll recreate the group list
|
||||
if chat_id != 0 && !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
if chat_id != 0 && 0 == chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
recreate_member_list = 1;
|
||||
}
|
||||
|
||||
@@ -1836,11 +1870,11 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
while !cur.is_null() {
|
||||
if 0 != is_msgrmsg_rfc724_mid(
|
||||
context,
|
||||
if !cur.is_null() {
|
||||
as_str((*cur).data as *const libc::c_char)
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
""
|
||||
},
|
||||
ptr::null_mut()
|
||||
}) as *const libc::c_char,
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1855,15 +1889,15 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
}
|
||||
|
||||
/// Check if a message is a reply to any messenger message.
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: &str) -> libc::c_int {
|
||||
if rfc724_mid.is_empty() {
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int {
|
||||
if rfc724_mid.is_null() {
|
||||
return 0;
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.exists(
|
||||
"SELECT id FROM msgs WHERE rfc724_mid=? AND msgrmsg!=0 AND chat_id>9;",
|
||||
params![rfc724_mid],
|
||||
params![as_str(rfc724_mid)],
|
||||
)
|
||||
.unwrap_or_default() as libc::c_int
|
||||
}
|
||||
|
||||
+13
-11
@@ -3,13 +3,13 @@ use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use charset::Charset;
|
||||
use libc::{free, strlen};
|
||||
use mmime::mailmime_decode::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
use percent_encoding::{percent_decode, utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
|
||||
use crate::dc_tools::*;
|
||||
use crate::x::*;
|
||||
|
||||
/**
|
||||
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
||||
@@ -25,7 +25,7 @@ use crate::dc_tools::*;
|
||||
* @return Returns the encoded string which must be free()'d when no longed needed.
|
||||
* On errors, NULL is returned.
|
||||
*/
|
||||
pub unsafe fn dc_encode_header_words(to_encode_r: impl AsRef<str>) -> String {
|
||||
pub unsafe fn dc_encode_header_words(to_encode_r: impl AsRef<str>) -> *mut libc::c_char {
|
||||
let to_encode =
|
||||
CString::new(to_encode_r.as_ref().as_bytes()).expect("invalid cstring to_encode");
|
||||
|
||||
@@ -117,9 +117,7 @@ pub unsafe fn dc_encode_header_words(to_encode_r: impl AsRef<str>) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
let s = to_string(ret_str);
|
||||
free(ret_str.cast());
|
||||
s
|
||||
ret_str
|
||||
}
|
||||
|
||||
unsafe fn quote_word(
|
||||
@@ -338,8 +336,6 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use libc::strcmp;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[test]
|
||||
@@ -362,15 +358,19 @@ mod tests {
|
||||
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "just ascii test");
|
||||
free(buf1 as *mut libc::c_void);
|
||||
|
||||
assert_eq!(dc_encode_header_words("abcdef"), "abcdef");
|
||||
buf1 = dc_encode_header_words("abcdef");
|
||||
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "abcdef");
|
||||
free(buf1 as *mut libc::c_void);
|
||||
|
||||
let r = dc_encode_header_words(
|
||||
buf1 = dc_encode_header_words(
|
||||
std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec())
|
||||
.unwrap(),
|
||||
);
|
||||
assert!(r.starts_with("=?utf-8"));
|
||||
assert_eq!(
|
||||
strncmp(buf1, b"=?utf-8\x00" as *const u8 as *const libc::c_char, 7),
|
||||
0
|
||||
);
|
||||
|
||||
buf1 = r.strdup();
|
||||
let buf2: *mut libc::c_char = dc_decode_header_words(buf1);
|
||||
assert_eq!(
|
||||
strcmp(
|
||||
@@ -379,6 +379,7 @@ mod tests {
|
||||
),
|
||||
0
|
||||
);
|
||||
free(buf1 as *mut libc::c_void);
|
||||
free(buf2 as *mut libc::c_void);
|
||||
|
||||
buf1 = dc_decode_header_words(
|
||||
@@ -392,6 +393,7 @@ mod tests {
|
||||
),
|
||||
0
|
||||
);
|
||||
free(buf1 as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+472
-214
File diff suppressed because it is too large
Load Diff
+160
-52
@@ -6,7 +6,6 @@ use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use libc::{free, strcmp, strlen, strncmp};
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::*;
|
||||
use mmime::mailimf_types::*;
|
||||
@@ -31,6 +30,7 @@ use crate::keyring::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::pgp::*;
|
||||
use crate::securejoin::handle_degrade_event;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct E2eeHelper {
|
||||
@@ -53,11 +53,11 @@ impl E2eeHelper {
|
||||
pub unsafe fn encrypt(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
recipients_addr: &Vec<String>,
|
||||
force_unencrypted: bool,
|
||||
e2ee_guaranteed: bool,
|
||||
recipients_addr: *const clist,
|
||||
force_unencrypted: libc::c_int,
|
||||
e2ee_guaranteed: libc::c_int,
|
||||
min_verified: libc::c_int,
|
||||
do_gossip: bool,
|
||||
do_gossip: libc::c_int,
|
||||
mut in_out_message: *mut mailmime,
|
||||
) {
|
||||
let mut ok_to_continue = true;
|
||||
@@ -69,7 +69,10 @@ impl E2eeHelper {
|
||||
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
let mut peerstates: Vec<Peerstate> = Vec::new();
|
||||
|
||||
if !(in_out_message.is_null() || !(*in_out_message).mm_parent.is_null() || plain.is_null())
|
||||
if !(recipients_addr.is_null()
|
||||
|| in_out_message.is_null()
|
||||
|| !(*in_out_message).mm_parent.is_null()
|
||||
|| plain.is_null())
|
||||
{
|
||||
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
|
||||
let prefer_encrypt = if 0
|
||||
@@ -92,16 +95,19 @@ impl E2eeHelper {
|
||||
});
|
||||
if let Ok(public_key) = pubkey_ret {
|
||||
/*only for random-seed*/
|
||||
if prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed {
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
do_encrypt = 1i32;
|
||||
for recipient_addr in recipients_addr.iter() {
|
||||
if *recipient_addr != addr {
|
||||
let mut iter1: *mut clistiter;
|
||||
iter1 = (*recipients_addr).first;
|
||||
while !iter1.is_null() {
|
||||
let recipient_addr = to_string((*iter1).data as *const libc::c_char);
|
||||
if recipient_addr != addr {
|
||||
let peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
||||
if peerstate.is_some()
|
||||
&& (peerstate.as_ref().unwrap().prefer_encrypt
|
||||
== EncryptPreference::Mutual
|
||||
|| e2ee_guaranteed)
|
||||
|| 0 != e2ee_guaranteed)
|
||||
{
|
||||
let peerstate = peerstate.unwrap();
|
||||
info!(
|
||||
@@ -124,6 +130,11 @@ impl E2eeHelper {
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter1 = if !iter1.is_null() {
|
||||
(*iter1).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
let sign_key = if 0 != do_encrypt {
|
||||
@@ -137,7 +148,7 @@ impl E2eeHelper {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if force_unencrypted {
|
||||
if 0 != force_unencrypted {
|
||||
do_encrypt = 0i32
|
||||
}
|
||||
imffields_unprotected = mailmime_find_mailimf_fields(in_out_message);
|
||||
@@ -164,7 +175,7 @@ impl E2eeHelper {
|
||||
imffields_encrypted,
|
||||
part_to_encrypt,
|
||||
);
|
||||
if do_gossip {
|
||||
if 0 != do_gossip {
|
||||
let i_cnt = peerstates.len() as libc::c_int;
|
||||
if i_cnt > 1 {
|
||||
let mut i = 0;
|
||||
@@ -186,39 +197,63 @@ impl E2eeHelper {
|
||||
}
|
||||
}
|
||||
/* memoryhole headers */
|
||||
// XXX we can't use clist's into_iter()
|
||||
// because the loop body also removes items
|
||||
let mut cur: *mut clistiter =
|
||||
(*(*imffields_unprotected).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let field: *mut mailimf_field = (*cur).data as *mut mailimf_field;
|
||||
let mut move_to_encrypted = false;
|
||||
let mut move_to_encrypted: libc::c_int = 0i32;
|
||||
let field: *mut mailimf_field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
})
|
||||
as *mut mailimf_field;
|
||||
if !field.is_null() {
|
||||
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
move_to_encrypted = true;
|
||||
move_to_encrypted = 1i32
|
||||
} else if (*field).fld_type
|
||||
== MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|
||||
{
|
||||
let opt_field = (*field).fld_data.fld_optional_field;
|
||||
let opt_field: *mut mailimf_optional_field =
|
||||
(*field).fld_data.fld_optional_field;
|
||||
if !opt_field.is_null() && !(*opt_field).fld_name.is_null()
|
||||
{
|
||||
let fld_name = to_string_lossy((*opt_field).fld_name);
|
||||
if fld_name.starts_with("Secure-Join")
|
||||
|| fld_name.starts_with("Chat-")
|
||||
if strncmp(
|
||||
(*opt_field).fld_name,
|
||||
b"Secure-Join\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
11,
|
||||
) == 0
|
||||
|| strncmp(
|
||||
(*opt_field).fld_name,
|
||||
b"Chat-\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
5,
|
||||
) == 0
|
||||
&& strcmp(
|
||||
(*opt_field).fld_name,
|
||||
b"Chat-Version\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
) != 0
|
||||
{
|
||||
move_to_encrypted = true;
|
||||
move_to_encrypted = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if move_to_encrypted {
|
||||
if 0 != move_to_encrypted {
|
||||
mailimf_fields_add(imffields_encrypted, field);
|
||||
cur = clist_delete((*imffields_unprotected).fld_list, cur);
|
||||
cur = clist_delete((*imffields_unprotected).fld_list, cur)
|
||||
} else {
|
||||
cur = (*cur).next;
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
let subject: *mut mailimf_subject = mailimf_subject_new("...".strdup());
|
||||
let subject: *mut mailimf_subject = mailimf_subject_new(dc_strdup(
|
||||
b"...\x00" as *const u8 as *const libc::c_char,
|
||||
));
|
||||
mailimf_fields_add(
|
||||
imffields_unprotected,
|
||||
mailimf_field_new(
|
||||
@@ -345,6 +380,7 @@ impl E2eeHelper {
|
||||
}
|
||||
|
||||
pub unsafe fn decrypt(&mut self, context: &Context, in_out_message: *mut mailmime) {
|
||||
let mut iterations: libc::c_int;
|
||||
/* return values: 0=nothing to decrypt/cannot decrypt, 1=sth. decrypted
|
||||
(to detect parts that could not be decrypted, simply look for left "multipart/encrypted" MIME types */
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
@@ -419,7 +455,8 @@ impl E2eeHelper {
|
||||
public_keyring_for_validate.add_ref(key);
|
||||
}
|
||||
}
|
||||
for iterations in 0..10 {
|
||||
iterations = 0i32;
|
||||
while iterations < 10i32 {
|
||||
let mut has_unencrypted_parts: libc::c_int = 0i32;
|
||||
if decrypt_recursive(
|
||||
context,
|
||||
@@ -434,15 +471,11 @@ impl E2eeHelper {
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* if we're here, sth. was encrypted. if we're on top-level,
|
||||
and there are no additional unencrypted parts in the message
|
||||
the encryption was fine (signature is handled separately and
|
||||
returned as `signatures`) */
|
||||
if iterations == 0 && 0 == has_unencrypted_parts {
|
||||
if iterations == 0i32 && 0 == has_unencrypted_parts {
|
||||
self.encrypted = true;
|
||||
}
|
||||
iterations += 1;
|
||||
}
|
||||
/* check for Autocrypt-Gossip */
|
||||
if !gossip_headers.is_null() {
|
||||
self.gossipped_addr = update_gossip_peerstates(
|
||||
context,
|
||||
@@ -610,13 +643,19 @@ unsafe fn update_gossip_peerstates(
|
||||
imffields: *mut mailimf_fields,
|
||||
gossip_headers: *const mailimf_fields,
|
||||
) -> HashSet<String> {
|
||||
let mut cur1: *mut clistiter;
|
||||
let mut recipients: Option<HashSet<String>> = None;
|
||||
let mut gossipped_addr: HashSet<String> = Default::default();
|
||||
|
||||
for cur_data in (*(*gossip_headers).fld_list).into_iter() {
|
||||
let field: *mut mailimf_field = cur_data as *mut _;
|
||||
cur1 = (*(*gossip_headers).fld_list).first;
|
||||
while !cur1.is_null() {
|
||||
let field: *mut mailimf_field = (if !cur1.is_null() {
|
||||
(*cur1).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailimf_field;
|
||||
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let optional_field = (*field).fld_data.fld_optional_field;
|
||||
let optional_field: *const mailimf_optional_field =
|
||||
(*field).fld_data.fld_optional_field;
|
||||
if !optional_field.is_null()
|
||||
&& !(*optional_field).fld_name.is_null()
|
||||
&& strcasecmp(
|
||||
@@ -660,6 +699,11 @@ unsafe fn update_gossip_peerstates(
|
||||
}
|
||||
}
|
||||
}
|
||||
cur1 = if !cur1.is_null() {
|
||||
(*cur1).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
gossipped_addr
|
||||
@@ -676,6 +720,7 @@ unsafe fn decrypt_recursive(
|
||||
) -> Result<()> {
|
||||
ensure!(!mime.is_null(), "Invalid mime reference");
|
||||
let ct: *mut mailmime_content;
|
||||
let mut cur: *mut clistiter;
|
||||
|
||||
if (*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int {
|
||||
ct = (*mime).mm_content_type;
|
||||
@@ -686,18 +731,23 @@ unsafe fn decrypt_recursive(
|
||||
b"encrypted\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut decrypted_mime: *mut mailmime = ptr::null_mut();
|
||||
if decrypt_part(
|
||||
context,
|
||||
cur_data as *mut mailmime,
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailmime,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
ret_valid_signatures,
|
||||
&mut decrypted_mime,
|
||||
) {
|
||||
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
|
||||
let mut dummy: libc::size_t = 0;
|
||||
let mut dummy: libc::size_t = 0i32 as libc::size_t;
|
||||
let mut test: *mut mailimf_fields = ptr::null_mut();
|
||||
if mailimf_envelope_and_optional_fields_parse(
|
||||
(*decrypted_mime).mm_mime_start,
|
||||
@@ -714,13 +764,23 @@ unsafe fn decrypt_recursive(
|
||||
mailmime_free(mime);
|
||||
return Ok(());
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
*ret_has_unencrypted_parts = 1i32
|
||||
} else {
|
||||
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
if decrypt_recursive(
|
||||
context,
|
||||
cur_data as *mut mailmime,
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailmime,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
ret_valid_signatures,
|
||||
@@ -731,6 +791,11 @@ unsafe fn decrypt_recursive(
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (*mime).mm_type == MAILMIME_MESSAGE as libc::c_int {
|
||||
@@ -780,12 +845,25 @@ unsafe fn decrypt_part(
|
||||
|| (*mime_data).dt_data.dt_text.dt_length <= 0)
|
||||
{
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
for cur_data in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
|
||||
let field: *mut mailmime_field = cur_data as *mut _;
|
||||
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
&& !(*field).fld_data.fld_encoding.is_null()
|
||||
{
|
||||
mime_transfer_encoding = (*(*field).fld_data.fld_encoding).enc_type
|
||||
let mut cur: *mut clistiter;
|
||||
cur = (*(*(*mime).mm_mime_fields).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let field: *mut mailmime_field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailmime_field;
|
||||
if !field.is_null() {
|
||||
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
&& !(*field).fld_data.fld_encoding.is_null()
|
||||
{
|
||||
mime_transfer_encoding = (*(*field).fld_data.fld_encoding).enc_type
|
||||
}
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -912,10 +990,23 @@ unsafe fn contains_report(mime: *mut mailmime) -> bool {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for cur_data in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
|
||||
if contains_report(cur_data as *mut mailmime) {
|
||||
let mut cur: *mut clistiter;
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
if contains_report(
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailmime,
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
} else if (*mime).mm_type == MAILMIME_MESSAGE as libc::c_int {
|
||||
if contains_report((*mime).mm_data.mm_message.mm_msg_mime) {
|
||||
@@ -1000,8 +1091,25 @@ Sent with my Delta Chat Messenger: https://delta.chat";
|
||||
};
|
||||
unsafe {
|
||||
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
|
||||
let data = mailmime_transfer_decode(msg1).unwrap();
|
||||
println!("{:?}", String::from_utf8_lossy(&data));
|
||||
let mut decoded_data = ptr::null();
|
||||
let mut decoded_data_bytes = 0;
|
||||
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
|
||||
|
||||
assert!(mailmime_transfer_decode(
|
||||
msg1,
|
||||
&mut decoded_data,
|
||||
&mut decoded_data_bytes,
|
||||
&mut transfer_decoding_buffer,
|
||||
));
|
||||
println!(
|
||||
"{:?}",
|
||||
String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
decoded_data as *const u8,
|
||||
decoded_data_bytes as usize,
|
||||
))
|
||||
);
|
||||
|
||||
free(decoded_data as *mut _);
|
||||
}
|
||||
|
||||
assert_eq!(res, 0);
|
||||
|
||||
+75
-56
@@ -1,4 +1,6 @@
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::ptr;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Condvar, Mutex, RwLock,
|
||||
@@ -8,22 +10,21 @@ use std::time::{Duration, SystemTime};
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_receive_imf::dc_receive_imf;
|
||||
use crate::dc_tools::CStringExt;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use crate::job::{job_add, Action};
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::{self, update_msg_move_state, update_server_uid};
|
||||
use crate::message::{dc_rfc724_mid_exists, dc_update_msg_move_state, dc_update_server_uid};
|
||||
use crate::oauth2::dc_get_oauth2_access_token;
|
||||
use crate::param::Params;
|
||||
|
||||
const DC_IMAP_SEEN: usize = 0x0001;
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ImapResult {
|
||||
Failed,
|
||||
RetryLater,
|
||||
AlreadyDone,
|
||||
Success,
|
||||
}
|
||||
const DC_SUCCESS: usize = 3;
|
||||
const DC_ALREADY_DONE: usize = 2;
|
||||
const DC_RETRY_LATER: usize = 1;
|
||||
const DC_FAILED: usize = 0;
|
||||
|
||||
const PREFETCH_FLAGS: &str = "(UID ENVELOPE)";
|
||||
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
||||
@@ -820,7 +821,10 @@ impl Imap {
|
||||
.message_id
|
||||
.expect("missing message id");
|
||||
|
||||
if !precheck_imf(context, &message_id, folder.as_ref(), cur_uid) {
|
||||
if 0 == unsafe {
|
||||
let message_id_c = CString::yolo(message_id);
|
||||
precheck_imf(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
|
||||
} {
|
||||
// check passed, go fetch the rest
|
||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||
info!(
|
||||
@@ -1131,12 +1135,12 @@ impl Imap {
|
||||
uid: u32,
|
||||
dest_folder: S2,
|
||||
dest_uid: &mut u32,
|
||||
) -> ImapResult {
|
||||
let mut res = ImapResult::RetryLater;
|
||||
) -> usize {
|
||||
let mut res = DC_RETRY_LATER;
|
||||
let set = format!("{}", uid);
|
||||
|
||||
if uid == 0 {
|
||||
res = ImapResult::Failed;
|
||||
res = DC_FAILED;
|
||||
} else if folder.as_ref() == dest_folder.as_ref() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1146,7 +1150,7 @@ impl Imap {
|
||||
dest_folder.as_ref()
|
||||
);
|
||||
|
||||
res = ImapResult::AlreadyDone;
|
||||
res = DC_ALREADY_DONE;
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
@@ -1166,7 +1170,7 @@ impl Imap {
|
||||
let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_mv(&set, &dest_folder) {
|
||||
Ok(_) => {
|
||||
res = ImapResult::Success;
|
||||
res = DC_SUCCESS;
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -1206,22 +1210,22 @@ impl Imap {
|
||||
warn!(context, "Cannot mark message as \"Deleted\".",);
|
||||
}
|
||||
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
||||
res = ImapResult::Success;
|
||||
res = DC_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if res == ImapResult::Success {
|
||||
if res == DC_SUCCESS {
|
||||
// TODO: is this correct?
|
||||
*dest_uid = uid;
|
||||
}
|
||||
|
||||
if res == ImapResult::RetryLater {
|
||||
if res == DC_RETRY_LATER {
|
||||
if self.should_reconnect() {
|
||||
ImapResult::RetryLater
|
||||
DC_RETRY_LATER
|
||||
} else {
|
||||
ImapResult::Failed
|
||||
DC_FAILED
|
||||
}
|
||||
} else {
|
||||
res
|
||||
@@ -1255,11 +1259,11 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||
let mut res = ImapResult::RetryLater;
|
||||
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
||||
let mut res = DC_RETRY_LATER;
|
||||
|
||||
if uid == 0 {
|
||||
res = ImapResult::Failed
|
||||
res = DC_FAILED
|
||||
} else if self.is_connected() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1277,28 +1281,28 @@ impl Imap {
|
||||
} else if self.add_flag(context, uid, "\\Seen") == 0 {
|
||||
warn!(context, "Cannot mark message as seen.",);
|
||||
} else {
|
||||
res = ImapResult::Success
|
||||
res = DC_SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
if res == ImapResult::RetryLater {
|
||||
if res == DC_RETRY_LATER {
|
||||
if self.should_reconnect() {
|
||||
ImapResult::RetryLater
|
||||
DC_RETRY_LATER
|
||||
} else {
|
||||
ImapResult::Failed
|
||||
DC_FAILED
|
||||
}
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
||||
// returns 0=job should be retried later, 1=job done, 2=job done and flag just set
|
||||
let mut res = ImapResult::RetryLater;
|
||||
let mut res = DC_RETRY_LATER;
|
||||
let set = format!("{}", uid);
|
||||
|
||||
if uid == 0 {
|
||||
res = ImapResult::Failed;
|
||||
res = DC_FAILED;
|
||||
} else if self.is_connected() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1368,21 +1372,21 @@ impl Imap {
|
||||
.unwrap_or_else(|| false);
|
||||
|
||||
res = if flag_set {
|
||||
ImapResult::AlreadyDone
|
||||
DC_ALREADY_DONE
|
||||
} else if self.add_flag(context, uid, "$MDNSent") != 0 {
|
||||
ImapResult::Success
|
||||
DC_SUCCESS
|
||||
} else {
|
||||
res
|
||||
};
|
||||
|
||||
if res == ImapResult::Success {
|
||||
if res == DC_SUCCESS {
|
||||
info!(context, "$MDNSent just set and MDN will be sent.");
|
||||
} else {
|
||||
info!(context, "$MDNSent already set and MDN already sent.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = ImapResult::Success;
|
||||
res = DC_SUCCESS;
|
||||
info!(
|
||||
context,
|
||||
"Cannot store $MDNSent flags, risk sending duplicate MDN.",
|
||||
@@ -1391,11 +1395,11 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
if res == ImapResult::RetryLater {
|
||||
if res == DC_RETRY_LATER {
|
||||
if self.should_reconnect() {
|
||||
ImapResult::RetryLater
|
||||
DC_RETRY_LATER
|
||||
} else {
|
||||
ImapResult::Failed
|
||||
DC_FAILED
|
||||
}
|
||||
} else {
|
||||
res
|
||||
@@ -1639,28 +1643,43 @@ fn get_folder_meaning(folder_name: &imap::types::Name) -> FolderMeaning {
|
||||
}
|
||||
}
|
||||
|
||||
fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server_uid: u32) -> bool {
|
||||
let mut rfc724_mid_exists = false;
|
||||
let mut mark_seen = false;
|
||||
|
||||
if let Ok((old_server_folder, old_server_uid, msg_id)) =
|
||||
message::rfc724_mid_exists(context, &rfc724_mid)
|
||||
{
|
||||
rfc724_mid_exists = true;
|
||||
|
||||
if old_server_folder.is_empty() && old_server_uid == 0 {
|
||||
info!(context, "[move] detected bbc-self {}", rfc724_mid,);
|
||||
mark_seen = true;
|
||||
} else if old_server_folder != server_folder {
|
||||
info!(context, "[move] detected moved message {}", rfc724_mid,);
|
||||
update_msg_move_state(context, &rfc724_mid, MoveState::Stay);
|
||||
unsafe fn precheck_imf(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
server_folder: &str,
|
||||
server_uid: u32,
|
||||
) -> libc::c_int {
|
||||
let mut rfc724_mid_exists: libc::c_int = 0i32;
|
||||
let msg_id: u32;
|
||||
let mut old_server_folder: *mut libc::c_char = ptr::null_mut();
|
||||
let mut old_server_uid: u32 = 0i32 as u32;
|
||||
let mut mark_seen: libc::c_int = 0i32;
|
||||
msg_id = dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
);
|
||||
if msg_id != 0i32 as libc::c_uint {
|
||||
rfc724_mid_exists = 1i32;
|
||||
if *old_server_folder.offset(0isize) as libc::c_int == 0i32
|
||||
&& old_server_uid == 0i32 as libc::c_uint
|
||||
{
|
||||
info!(context, "[move] detected bbc-self {}", as_str(rfc724_mid),);
|
||||
mark_seen = 1i32
|
||||
} else if as_str(old_server_folder) != server_folder {
|
||||
info!(
|
||||
context,
|
||||
"[move] detected moved message {}",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
if old_server_folder != server_folder || old_server_uid != server_uid {
|
||||
update_server_uid(context, &rfc724_mid, server_folder, server_uid);
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
}
|
||||
context.do_heuristics_moves(server_folder, msg_id);
|
||||
|
||||
if mark_seen {
|
||||
if 0 != mark_seen {
|
||||
job_add(
|
||||
context,
|
||||
Action::MarkseenMsgOnImap,
|
||||
@@ -1670,6 +1689,6 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
libc::free(old_server_folder as *mut libc::c_void);
|
||||
rfc724_mid_exists
|
||||
}
|
||||
|
||||
+79
-68
@@ -1,6 +1,9 @@
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use mmime::clist::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::chat;
|
||||
@@ -14,9 +17,10 @@ use crate::events::Event;
|
||||
use crate::imap::*;
|
||||
use crate::location;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
use crate::x::*;
|
||||
|
||||
/// Thread IDs
|
||||
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
||||
@@ -137,7 +141,7 @@ impl Job {
|
||||
}
|
||||
|
||||
if let Some(filename) = self.param.get(Param::File) {
|
||||
if let Ok(body) = dc_read_file(context, filename) {
|
||||
if let Some(body) = dc_read_file_safe(context, filename) {
|
||||
if let Some(recipients) = self.param.get(Param::Recipients) {
|
||||
let recipients_list = recipients
|
||||
.split("\x1e")
|
||||
@@ -153,7 +157,7 @@ impl Job {
|
||||
/* 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 != self.foreign_id && !message::exists(context, self.foreign_id) {
|
||||
if 0 != self.foreign_id && !dc_msg_exists(context, self.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
"Message {} for job {} does not exist", self.foreign_id, self.job_id,
|
||||
@@ -172,7 +176,7 @@ impl Job {
|
||||
} else {
|
||||
dc_delete_file(context, filename);
|
||||
if 0 != self.foreign_id {
|
||||
message::update_msg_state(
|
||||
dc_update_msg_state(
|
||||
context,
|
||||
self.foreign_id,
|
||||
MessageState::OutDelivered,
|
||||
@@ -223,7 +227,7 @@ impl Job {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
@@ -243,19 +247,15 @@ impl Job {
|
||||
msg.server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) {
|
||||
ImapResult::RetryLater => {
|
||||
) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
ImapResult::Success => {
|
||||
message::update_server_uid(
|
||||
context,
|
||||
&msg.rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
3 => {
|
||||
dc_update_server_uid(context, msg.rfc724_mid, &dest_folder, dest_uid);
|
||||
}
|
||||
ImapResult::Failed | ImapResult::AlreadyDone => {}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,11 +267,13 @@ impl Job {
|
||||
let mut delete_from_server = 1;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if let Ok(mut msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if !msg.rfc724_mid.is_empty() {
|
||||
if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
if !(msg.rfc724_mid.is_null()
|
||||
|| unsafe { *msg.rfc724_mid.offset(0isize) as libc::c_int == 0 })
|
||||
{
|
||||
let ok_to_continue1;
|
||||
/* eg. device messages have no Message-ID */
|
||||
if message::rfc724_mid_cnt(context, &msg.rfc724_mid) != 1 {
|
||||
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
|
||||
info!(
|
||||
context,
|
||||
"The message is deleted from the server when all parts are deleted.",
|
||||
@@ -293,10 +295,9 @@ impl Job {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mid = msg.rfc724_mid;
|
||||
let mid = unsafe { 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)
|
||||
{
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut msg.server_uid) {
|
||||
self.try_again_later(-1i32, None);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
@@ -309,7 +310,7 @@ impl Job {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
Message::delete_from_db(context, msg.id);
|
||||
dc_delete_msg_from_db(context, msg.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,11 +333,11 @@ impl Job {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
match inbox.set_seen(context, server_folder, msg.server_uid) {
|
||||
ImapResult::Failed => {}
|
||||
ImapResult::RetryLater => {
|
||||
match inbox.set_seen(context, server_folder, msg.server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
_ => {
|
||||
@@ -348,14 +349,15 @@ impl Job {
|
||||
{
|
||||
let folder = msg.server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.set_mdnsent(context, folder, msg.server_uid) {
|
||||
ImapResult::RetryLater => {
|
||||
match inbox.set_mdnsent(context, folder, msg.server_uid) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
ImapResult::Success => {
|
||||
3 => {
|
||||
send_mdn(context, msg.id);
|
||||
}
|
||||
ImapResult::Failed | ImapResult::AlreadyDone => {}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,7 +390,7 @@ impl Job {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if inbox.set_seen(context, &folder, uid) == ImapResult::Failed {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
@@ -402,8 +404,8 @@ impl Job {
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if ImapResult::RetryLater
|
||||
== inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
self.try_again_later(3, None);
|
||||
}
|
||||
@@ -640,12 +642,12 @@ pub fn job_action_exists(context: &Context, action: Action) -> bool {
|
||||
|
||||
/* special case for DC_JOB_SEND_MSG_TO_SMTP */
|
||||
#[allow(non_snake_case)]
|
||||
pub fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
|
||||
/* load message data */
|
||||
let mimefactory = dc_mimefactory_load_msg(context, msg_id);
|
||||
if mimefactory.is_err() {
|
||||
if mimefactory.is_err() || mimefactory.as_ref().unwrap().from_addr.is_null() {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot load data to send, maybe the message is deleted in between.",
|
||||
@@ -667,48 +669,53 @@ pub fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
mimefactory.msg.param.set_int(Param::Width, 0);
|
||||
mimefactory.msg.param.set_int(Param::Height, 0);
|
||||
|
||||
if let Ok(buf) = dc_read_file(context, pathNfilename) {
|
||||
if let Some(buf) = dc_read_file_safe(context, pathNfilename) {
|
||||
if let Ok((width, height)) = dc_get_filemeta(&buf) {
|
||||
mimefactory.msg.param.set_int(Param::Width, width as i32);
|
||||
mimefactory.msg.param.set_int(Param::Height, height as i32);
|
||||
}
|
||||
}
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* create message */
|
||||
if let Err(msg) = unsafe { dc_mimefactory_render(context, &mut mimefactory) } {
|
||||
let e = msg.to_string();
|
||||
message::set_msg_failed(context, msg_id, Some(e));
|
||||
if !dc_mimefactory_render(context, &mut mimefactory) {
|
||||
dc_set_msg_failed(context, msg_id, as_opt_str(mimefactory.error));
|
||||
} else if 0
|
||||
!= mimefactory
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
&& !mimefactory.out_encrypted
|
||||
&& 0 == mimefactory.out_encrypted
|
||||
{
|
||||
/* unrecoverable */
|
||||
warn!(
|
||||
context,
|
||||
"e2e encryption unavailable {} - {:?}",
|
||||
msg_id,
|
||||
mimefactory.msg.param.get_int(Param::GuranteeE2ee),
|
||||
);
|
||||
message::set_msg_failed(
|
||||
dc_set_msg_failed(
|
||||
context,
|
||||
msg_id,
|
||||
Some("End-to-end-encryption unavailable unexpectedly."),
|
||||
);
|
||||
} else {
|
||||
if !vec_contains_lowercase(&mimefactory.recipients_addr, &mimefactory.from_addr) {
|
||||
mimefactory.recipients_names.push("".to_string());
|
||||
mimefactory
|
||||
.recipients_addr
|
||||
.push(mimefactory.from_addr.to_string());
|
||||
/* unrecoverable */
|
||||
if !clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr) {
|
||||
clist_insert_after(
|
||||
mimefactory.recipients_names,
|
||||
(*mimefactory.recipients_names).last,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
clist_insert_after(
|
||||
mimefactory.recipients_addr,
|
||||
(*mimefactory.recipients_addr).last,
|
||||
dc_strdup(mimefactory.from_addr) as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
if mimefactory.out_gossiped {
|
||||
if 0 != mimefactory.out_gossiped {
|
||||
chat::set_gossiped_timestamp(context, mimefactory.msg.chat_id, time());
|
||||
}
|
||||
if 0 != mimefactory.out_last_added_location_id {
|
||||
@@ -727,7 +734,7 @@ pub fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
}
|
||||
}
|
||||
}
|
||||
if mimefactory.out_encrypted
|
||||
if 0 != mimefactory.out_encrypted
|
||||
&& mimefactory
|
||||
.msg
|
||||
.param
|
||||
@@ -736,7 +743,7 @@ pub fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
== 0
|
||||
{
|
||||
mimefactory.msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
|
||||
}
|
||||
success = add_smtp_job(context, Action::SendMsgToSmtp, &mut mimefactory);
|
||||
}
|
||||
@@ -756,14 +763,6 @@ pub fn perform_imap_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_imap_jobs ended.",);
|
||||
}
|
||||
|
||||
pub fn perform_mvbox_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_mbox_jobs EMPTY (for now).",);
|
||||
}
|
||||
|
||||
pub fn perform_sentbox_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_sentbox_jobs EMPTY (for now).",);
|
||||
}
|
||||
|
||||
fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
let query = if !probe_network {
|
||||
// processing for first-try and after backoff-timeouts:
|
||||
@@ -937,7 +936,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
}
|
||||
} else {
|
||||
if job.action == Action::SendMsgToSmtp {
|
||||
message::set_msg_failed(context, job.foreign_id, job.pending_error.as_ref());
|
||||
dc_set_msg_failed(context, job.foreign_id, job.pending_error.as_ref());
|
||||
}
|
||||
job.delete(context);
|
||||
}
|
||||
@@ -990,18 +989,20 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
}
|
||||
|
||||
fn send_mdn(context: &Context, msg_id: u32) {
|
||||
if let Ok(mut mimefactory) = dc_mimefactory_load_mdn(context, msg_id) {
|
||||
if unsafe { dc_mimefactory_render(context, &mut mimefactory) }.is_ok() {
|
||||
if let Ok(mut mimefactory) = unsafe { dc_mimefactory_load_mdn(context, msg_id) } {
|
||||
if unsafe { dc_mimefactory_render(context, &mut mimefactory) } {
|
||||
add_smtp_job(context, Action::SendMdn, &mut mimefactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) -> libc::c_int {
|
||||
fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_t) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut recipients: *mut libc::c_char = ptr::null_mut();
|
||||
let mut param = Params::new();
|
||||
let path_filename = dc_get_fine_path_filename(context, "$BLOBDIR", &mimefactory.rfc724_mid);
|
||||
let path_filename =
|
||||
dc_get_fine_path_filename(context, "$BLOBDIR", as_str(mimefactory.rfc724_mid));
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(*mimefactory.out).str_0 as *const u8,
|
||||
@@ -1012,17 +1013,24 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
|
||||
error!(
|
||||
context,
|
||||
"Could not write message <{}> to \"{}\".",
|
||||
mimefactory.rfc724_mid,
|
||||
to_string(mimefactory.rfc724_mid),
|
||||
path_filename.display(),
|
||||
);
|
||||
} else {
|
||||
let recipients = mimefactory.recipients_addr.join("\x1e");
|
||||
recipients = unsafe {
|
||||
dc_str_from_clist(
|
||||
mimefactory.recipients_addr,
|
||||
b"\x1e\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
param.set(Param::File, path_filename.to_string_lossy());
|
||||
param.set(Param::Recipients, &recipients);
|
||||
param.set(Param::Recipients, as_str(recipients));
|
||||
job_add(
|
||||
context,
|
||||
action,
|
||||
(if mimefactory.loaded == Loaded::Message {
|
||||
(if mimefactory.loaded as libc::c_uint
|
||||
== DC_MF_MSG_LOADED as libc::c_int as libc::c_uint
|
||||
{
|
||||
mimefactory.msg.id
|
||||
} else {
|
||||
0
|
||||
@@ -1032,6 +1040,9 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
|
||||
);
|
||||
success = 1;
|
||||
}
|
||||
unsafe {
|
||||
free(recipients.cast());
|
||||
}
|
||||
success
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ pub mod qr;
|
||||
mod smtp;
|
||||
pub mod sql;
|
||||
mod stock;
|
||||
pub mod x;
|
||||
|
||||
pub mod dc_array;
|
||||
mod dc_dehtml;
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::Message;
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
@@ -214,7 +214,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
|
||||
.is_ok()
|
||||
{
|
||||
if 0 != seconds && !is_sending_locations_before {
|
||||
msg = Message::new(Viewtype::Text);
|
||||
msg = dc_msg_new(Viewtype::Text);
|
||||
msg.text =
|
||||
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
|
||||
msg.param.set_int(Param::Cmd, 8);
|
||||
@@ -601,7 +601,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
|
||||
// the easiest way to determine this, is to check for an empty message queue.
|
||||
// (might not be 100%, however, as positions are sent combined later
|
||||
// and dc_set_location() is typically called periodically, this is ok)
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
msg.hidden = true;
|
||||
msg.param.set_int(Param::Cmd, 9);
|
||||
Some((chat_id, msg))
|
||||
|
||||
+619
-506
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -3,7 +3,6 @@ use std::convert::TryInto;
|
||||
use std::io::Cursor;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{strchr, strlen, strncmp, strspn, strstr};
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||
SignedSecretKey, SubkeyParamsBuilder,
|
||||
@@ -16,6 +15,7 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::x::*;
|
||||
|
||||
pub unsafe fn dc_split_armored_data(
|
||||
buf: *mut libc::c_char,
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::key::*;
|
||||
use crate::lot::LotState;
|
||||
use crate::message::Message;
|
||||
use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::qr::check_qr;
|
||||
@@ -266,7 +266,7 @@ fn send_handshake_msg(
|
||||
fingerprint: Option<String>,
|
||||
grpid: impl AsRef<str>,
|
||||
) {
|
||||
let mut msg = Message::default();
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
msg.type_0 = Viewtype::Text;
|
||||
msg.text = Some(format!("Secure-Join: {}", step));
|
||||
msg.hidden = true;
|
||||
@@ -522,7 +522,7 @@ pub fn handle_securejoin_handshake(
|
||||
error!(context, "Chat {} not found.", &field_grpid);
|
||||
return ret;
|
||||
} else {
|
||||
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, true);
|
||||
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, 0x1i32);
|
||||
}
|
||||
} else {
|
||||
send_handshake_msg(context, contact_chat_id, "vc-contact-confirm", "", None, "");
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use libc::free;
|
||||
|
||||
/// Stock strings
|
||||
///
|
||||
@@ -132,7 +133,7 @@ impl Context {
|
||||
Cow::Borrowed(id.fallback())
|
||||
} else {
|
||||
let ret = to_string(ptr);
|
||||
unsafe { libc::free(ptr as *mut libc::c_void) };
|
||||
unsafe { free(ptr as *mut libc::c_void) };
|
||||
Cow::Owned(ret)
|
||||
}
|
||||
}
|
||||
|
||||
+87
-4
@@ -68,11 +68,94 @@ pub fn configure_alice_keypair(ctx: &Context) -> String {
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public =
|
||||
key::Key::from_base64(include_str!("../test-data/key/public.asc"), KeyType::Public)
|
||||
.unwrap();
|
||||
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(
|
||||
include_str!("../test-data/key/private.asc"),
|
||||
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();
|
||||
|
||||
+5
-7
@@ -15,21 +15,19 @@ if __name__ == "__main__":
|
||||
unsafe = s.count("unsafe")
|
||||
free = s.count("free(")
|
||||
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
|
||||
chars = s.count("c_char") + s.count("CStr")
|
||||
filestats.append((fn, unsafe, free, gotoblocks, chars))
|
||||
filestats.append((fn, unsafe, free, gotoblocks))
|
||||
|
||||
sum_unsafe, sum_free, sum_gotoblocks, sum_chars = 0, 0, 0, 0
|
||||
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0
|
||||
|
||||
for fn, unsafe, free, gotoblocks, chars in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
print("{0: <25} unsafe: {1: >3} free: {2: >3} ok_to_cont: {3: >3} chars: {4: >3}".format(str(fn), unsafe, free, gotoblocks, chars))
|
||||
for fn, unsafe, free, gotoblocks in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
print("{0: <30} unsafe: {1: >3} free: {2: >3} ok_to_continue: {3: >3}".format(str(fn), unsafe, free, gotoblocks))
|
||||
sum_unsafe += unsafe
|
||||
sum_free += free
|
||||
sum_gotoblocks += gotoblocks
|
||||
sum_chars += chars
|
||||
|
||||
|
||||
print()
|
||||
print("total unsafe:", sum_unsafe)
|
||||
print("total free:", sum_free)
|
||||
print("total ok_to_continue:", sum_gotoblocks)
|
||||
print("total c_chars:", sum_chars)
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
pub use libc::{
|
||||
calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp,
|
||||
strcpy, strcspn, strlen, strncmp, strncpy, strrchr, strspn, strstr, strtol, system,
|
||||
};
|
||||
|
||||
pub unsafe fn strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let slen = strlen(s);
|
||||
let result = malloc(slen + 1);
|
||||
if result.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
memcpy(result, s as *const _, slen + 1);
|
||||
result as *mut _
|
||||
}
|
||||
|
||||
pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let end = std::cmp::min(n as usize, unsafe { strlen(s) });
|
||||
unsafe {
|
||||
let result = malloc(end + 1);
|
||||
memcpy(result, s as *const _, end);
|
||||
std::ptr::write_bytes(result.offset(end as isize), b'\x00', 1);
|
||||
|
||||
result as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
||||
let s1 = std::ffi::CStr::from_ptr(s1)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
let s2 = std::ffi::CStr::from_ptr(s2)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
if s1 == s2 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dc_tools::to_string;
|
||||
|
||||
#[test]
|
||||
fn test_strndup() {
|
||||
unsafe {
|
||||
let res = strndup(b"helloworld\x00" as *const u8 as *const libc::c_char, 4);
|
||||
assert_eq!(
|
||||
to_string(res),
|
||||
to_string(b"hell\x00" as *const u8 as *const libc::c_char)
|
||||
);
|
||||
assert_eq!(strlen(res), 4);
|
||||
free(res as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1lFrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSXAMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchwoFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtqm1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6FFrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHbIu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3VWushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0Sut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQsWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEmdr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8kQrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJWyyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeGKyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIddKsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZLj3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtpDo5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9uRMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwKGjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPBf4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAgBQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6
|
||||
@@ -1,13 +0,0 @@
|
||||
Return-Path: <x@testrun.org>
|
||||
Received: from hq5.merlinux.eu
|
||||
by hq5.merlinux.eu (Dovecot) with LMTP id yRKOBakcfV1AewAAPzvFDg
|
||||
; Sat, 14 Sep 2019 19:00:25 +0200
|
||||
Received: from localhost (unknown 7.165.105.24])
|
||||
by hq5.merlinux.eu (Postfix) with ESMTPSA id 8D9844E023;
|
||||
Sat, 14 Sep 2019 19:00:22 +0200 (CEST)
|
||||
message-id: <2dfdbde7@example.org>
|
||||
Date: Sat, 14 Sep 2019 19:00:13 +0200
|
||||
From: lmn <x@tux.org>
|
||||
To: abc <abc@bcd.com>, def <def@def.de>,
|
||||
jik
|
||||
|
||||
+67
-2
@@ -1,8 +1,11 @@
|
||||
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use deltachat::chat::{self, Chat};
|
||||
use deltachat::config;
|
||||
use deltachat::contact::*;
|
||||
@@ -12,9 +15,9 @@ use deltachat::dc_tools::*;
|
||||
use deltachat::keyring::*;
|
||||
use deltachat::oauth2::*;
|
||||
use deltachat::pgp::*;
|
||||
use deltachat::x::*;
|
||||
use deltachat::Event;
|
||||
use libc::{free, strcmp, strdup, strlen, strncmp};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use libc;
|
||||
|
||||
/* some data used for testing
|
||||
******************************************************************************/
|
||||
@@ -27,6 +30,68 @@ static mut S_EM_SETUPFILE: *const libc::c_char =
|
||||
as *const u8 as *const libc::c_char;
|
||||
|
||||
unsafe fn stress_functions(context: &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")
|
||||
{
|
||||
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");
|
||||
}
|
||||
assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content"));
|
||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
|
||||
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
|
||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar"), 7);
|
||||
|
||||
let abs_path = context
|
||||
.get_blobdir()
|
||||
.join("foobar")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
assert!(dc_is_blobdir_path(context, &abs_path));
|
||||
assert!(dc_is_blobdir_path(context, "$BLOBDIR/fofo",));
|
||||
assert!(!dc_is_blobdir_path(context, "/BLOBDIR/fofo",));
|
||||
assert!(dc_file_exist(context, &abs_path));
|
||||
|
||||
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
|
||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
|
||||
|
||||
let mut buf: *mut libc::c_void = ptr::null_mut();
|
||||
let mut buf_bytes: libc::size_t = 0;
|
||||
|
||||
assert_eq!(
|
||||
dc_read_file(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
&mut buf,
|
||||
&mut buf_bytes,
|
||||
),
|
||||
1
|
||||
);
|
||||
assert_eq!(buf_bytes, 7);
|
||||
assert_eq!(
|
||||
std::str::from_utf8(std::slice::from_raw_parts(buf as *const u8, buf_bytes)).unwrap(),
|
||||
"content"
|
||||
);
|
||||
|
||||
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"));
|
||||
let fn0 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
||||
assert_eq!(fn0, PathBuf::from("$BLOBDIR/foobar.dadada"));
|
||||
|
||||
assert!(dc_write_file(context, &fn0, b"content"));
|
||||
let fn1 = dc_get_fine_path_filename(context, "$BLOBDIR", "foobar.dadada");
|
||||
assert_eq!(fn1, PathBuf::from("$BLOBDIR/foobar-1.dadada"));
|
||||
|
||||
assert!(dc_delete_file(context, &fn0));
|
||||
|
||||
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
|
||||
|
||||
assert!(!res.contains(" probably_never_a_key "));
|
||||
|
||||
Reference in New Issue
Block a user