Compare commits

..
Author SHA1 Message Date
B. Petersen af20b14077 change oder of typedefs, function-definitions and defines
as c is top-down, we start with the typedefs
so that functions can use them freely.
after that, the functions are declared
and finally the #defines (for less noise in the function sections).
grouping is done by classes.
2019-09-19 12:04:16 +02:00
B. Petersen d338748115 add missing doxygen commands, fix typo 2019-09-19 11:41:27 +02:00
47 changed files with 3904 additions and 2802 deletions
+30 -20
View File
@@ -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
View File
@@ -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
View File
@@ -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
+22
View File
@@ -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
+1 -1
View File
@@ -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"
+7 -50
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+9
View File
@@ -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)
}
+7 -38
View File
@@ -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")
-7
View File
@@ -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.
-4
View File
@@ -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.
+5 -10
View File
@@ -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
+5 -78
View File
@@ -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)
+1 -1
View File
@@ -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()
-10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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;
/* ******************************************************************************
+3 -4
View 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+697 -517
View File
File diff suppressed because it is too large Load Diff
+83 -49
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+160 -52
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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!(
"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",
"zPqgJCGwjTglkixw+aSTXw=="
),
KeyType::Private,
)
.unwrap();
+5 -7
View File
@@ -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)
+67
View File
@@ -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
View File
@@ -1 +0,0 @@
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
@@ -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
View File
@@ -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 "));