mirror of
https://github.com/chatmail/core.git
synced 2026-09-22 04:58:47 +03:00
Compare commits
66 Commits
hpk-verifi
...
refactor/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e571750f96 | ||
|
|
0f22b75207 | ||
|
|
13991d8dc5 | ||
|
|
75d9eb08f7 | ||
|
|
8cf571c78a | ||
|
|
77a7efc920 | ||
|
|
de604e744e | ||
|
|
24c0a833bd | ||
|
|
45f011c63c | ||
|
|
bc86201b44 | ||
|
|
b82af9fff3 | ||
|
|
3a1e74a306 | ||
|
|
e4cca92910 | ||
|
|
102220834c | ||
|
|
24d744b94c | ||
|
|
1df6229e99 | ||
|
|
c23e98ff83 | ||
|
|
b7c81f37c0 | ||
|
|
5c3a7e4119 | ||
|
|
a94acef49b | ||
|
|
7f5b362eda | ||
|
|
ba5b3ad675 | ||
|
|
c1e4d1e7a4 | ||
|
|
dd8744b74e | ||
|
|
b775ecca08 | ||
|
|
b8f211a013 | ||
|
|
51534b2fae | ||
|
|
710db2ba0a | ||
|
|
32ef0d4dc3 | ||
|
|
b3cd80ba6d | ||
|
|
3f053f899e | ||
|
|
22b4d1734c | ||
|
|
46a71e81a0 | ||
|
|
b4851187ba | ||
|
|
0252969f7e | ||
|
|
f86cec4844 | ||
|
|
cd2e36da92 | ||
|
|
1b13107181 | ||
|
|
6fbde21995 | ||
|
|
a6608513ac | ||
|
|
d43c225be3 | ||
|
|
1802d7658d | ||
|
|
275f5d713f | ||
|
|
e40cfeec58 | ||
|
|
275b4b8d36 | ||
|
|
77cef632c7 | ||
|
|
db2064de14 | ||
|
|
e251c7b1c8 | ||
|
|
2fe98775f9 | ||
|
|
187179d87b | ||
|
|
dd03f6e8af | ||
|
|
07b32241bd | ||
|
|
abfff96cd4 | ||
|
|
735bdd1c20 | ||
|
|
9cae075b6f | ||
|
|
2317518e5e | ||
|
|
477af413c6 | ||
|
|
93f0f5ccae | ||
|
|
79b92727cc | ||
|
|
8dfd04672f | ||
|
|
603761e4b7 | ||
|
|
467c09f491 | ||
|
|
a953b494cb | ||
|
|
dca9afa10b | ||
|
|
23d2d87c24 | ||
|
|
c6b2d640ae |
@@ -4,6 +4,9 @@ executors:
|
||||
docker:
|
||||
- image: filecoin/rust:latest
|
||||
working_directory: /mnt/crate
|
||||
doxygen:
|
||||
docker:
|
||||
- image: hrektts/doxygen
|
||||
|
||||
restore-workspace: &restore-workspace
|
||||
attach_workspace:
|
||||
@@ -113,6 +116,18 @@ jobs:
|
||||
target: "aarch64-linux-android"
|
||||
|
||||
|
||||
build_doxygen:
|
||||
executor: doxygen
|
||||
steps:
|
||||
- checkout
|
||||
- run: bash ci_scripts/run-doxygen.sh
|
||||
- run: mkdir -p workspace/c-docs
|
||||
- run: cp -av deltachat-ffi/{html,xml} workspace/c-docs/
|
||||
- persist_to_workspace:
|
||||
root: workspace
|
||||
paths:
|
||||
- c-docs
|
||||
|
||||
build_test_docs_wheel:
|
||||
docker:
|
||||
- image: deltachat/coredeps
|
||||
@@ -148,7 +163,7 @@ jobs:
|
||||
at: workspace
|
||||
- run: pyenv global 3.5.2
|
||||
- run: ls -laR workspace
|
||||
- run: ci_scripts/ci_upload.sh workspace/py-docs workspace/wheelhouse
|
||||
- run: ci_scripts/ci_upload.sh workspace/py-docs workspace/wheelhouse workspace/c-docs
|
||||
|
||||
clippy:
|
||||
executor: default
|
||||
@@ -166,18 +181,21 @@ workflows:
|
||||
test:
|
||||
jobs:
|
||||
- cargo_fetch
|
||||
- build_doxygen
|
||||
|
||||
- build_test_docs_wheel:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
- upload_docs_wheels:
|
||||
requires:
|
||||
- build_test_docs_wheel
|
||||
- build_doxygen
|
||||
- rustfmt:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
- clippy:
|
||||
requires:
|
||||
- cargo_fetch
|
||||
- cargo_fetch
|
||||
|
||||
# Linux Desktop 64bit
|
||||
- test_x86_64-unknown-linux-gnu:
|
||||
|
||||
259
Cargo.lock
generated
259
Cargo.lock
generated
@@ -57,10 +57,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.11"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -88,7 +88,7 @@ version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -139,7 +139,7 @@ version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -226,7 +226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -247,7 +247,7 @@ dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -276,7 +276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -301,7 +301,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "circular"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -345,7 +345,7 @@ dependencies = [
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -375,7 +375,7 @@ name = "crc32fast"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -392,8 +392,8 @@ name = "crossbeam-epoch"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -413,13 +413,13 @@ name = "crossbeam-utils"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -435,7 +435,7 @@ dependencies = [
|
||||
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -500,14 +500,14 @@ dependencies = [
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jetscii 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
"lettre 0.9.2 (git+https://github.com/deltachat/lettre)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mmime 0.1.2",
|
||||
"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)",
|
||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pgp 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -516,11 +516,11 @@ dependencies = [
|
||||
"r2d2_sqlite 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (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)",
|
||||
@@ -633,13 +633,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "1.0.0-pre.1"
|
||||
version = "1.0.0-pre.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -653,7 +654,7 @@ name = "encoding_rs"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -743,12 +744,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -815,7 +817,7 @@ name = "getrandom"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -860,6 +862,11 @@ name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.1.5"
|
||||
@@ -931,7 +938,7 @@ dependencies = [
|
||||
"http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -941,9 +948,9 @@ dependencies = [
|
||||
"tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1025,11 +1032,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1072,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "lettre"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/deltachat/lettre#aeec999c27a70870e4b7b149e45f24188c1ff351"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1080,10 +1086,10 @@ dependencies = [
|
||||
"hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1091,8 +1097,8 @@ name = "lexical-core"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1118,15 +1124,6 @@ name = "linked-hash-map"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.2.0"
|
||||
@@ -1148,7 +1145,7 @@ name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1220,7 +1217,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1233,7 +1230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1275,9 +1272,9 @@ dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1289,7 +1286,7 @@ name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1301,14 +1298,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -1405,15 +1402,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.24"
|
||||
version = "0.10.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1431,7 +1428,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.49"
|
||||
version = "0.9.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1458,29 +1455,12 @@ dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packed_simd"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1503,24 +1483,12 @@ dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1535,7 +1503,7 @@ name = "parking_lot_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1556,7 +1524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pgp"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1570,17 +1538,17 @@ dependencies = [
|
||||
"cast5 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"circular 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc24 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1616,7 +1584,7 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1641,7 +1609,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1721,7 +1689,7 @@ name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1939,7 +1907,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.9.20"
|
||||
version = "0.9.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1947,7 +1915,7 @@ dependencies = [
|
||||
"cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1957,13 +1925,13 @@ dependencies = [
|
||||
"mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1993,7 +1961,7 @@ dependencies = [
|
||||
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2096,11 +2064,6 @@ dependencies = [
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.0.0"
|
||||
@@ -2152,14 +2115,14 @@ name = "serde_derive"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.5 (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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.40"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2222,7 +2185,7 @@ dependencies = [
|
||||
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2247,11 +2210,6 @@ name = "smallvec"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "0.3.4"
|
||||
@@ -2289,14 +2247,14 @@ version = "0.16.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.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.5 (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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.1.1"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -2334,7 +2292,7 @@ name = "syn"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2372,7 +2330,7 @@ name = "tempfile"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2434,9 +2392,9 @@ dependencies = [
|
||||
"tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2480,7 +2438,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2489,7 +2447,7 @@ dependencies = [
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2512,24 +2470,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-threadpool"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2568,7 +2526,7 @@ name = "try_from"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2673,7 +2631,7 @@ name = "uuid"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2856,7 +2814,7 @@ dependencies = [
|
||||
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
|
||||
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
|
||||
"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
|
||||
@@ -2884,10 +2842,10 @@ dependencies = [
|
||||
"checksum cast5 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce5759b4c52ca74f9a98421817c882f1fd9b0071ae41cd61ab9f9d059c04fd6"
|
||||
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
|
||||
"checksum cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "190e7b55d3a27cf8879becf61035a141cbc783f3258a41d16d1706719f991345"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f426e64df1c3de26cbf44593c6ffff5dbfd43bbf9de0d075058558126b3fc73"
|
||||
"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
|
||||
"checksum circular 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82945ea9ff134eba321833377d0c485f5c6fb4c8e26cfec199174e2970d5385a"
|
||||
"checksum circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea"
|
||||
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
|
||||
@@ -2901,7 +2859,7 @@ dependencies = [
|
||||
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
|
||||
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3e061727ebef83bbccac7c27b9a5ff9fd83094d34cb20f4005440a9562a27de7"
|
||||
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
|
||||
"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d"
|
||||
"checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6"
|
||||
"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c"
|
||||
@@ -2916,7 +2874,7 @@ dependencies = [
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
||||
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
|
||||
"checksum ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81956bcf7ef761fb4e1d88de3fa181358a0d26cbcb9755b587a08f9119824b86"
|
||||
"checksum ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)" = "845aaacc16f01178f33349e7c992ecd0cee095aa5e577f0f4dee35971bd36455"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9"
|
||||
"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
|
||||
@@ -2930,7 +2888,7 @@ dependencies = [
|
||||
"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
"checksum fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
|
||||
"checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682"
|
||||
"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
@@ -2946,6 +2904,7 @@ dependencies = [
|
||||
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
|
||||
"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e"
|
||||
"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4"
|
||||
"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
|
||||
@@ -2961,19 +2920,18 @@ dependencies = [
|
||||
"checksum imap 1.0.2 (git+https://github.com/jonhoo/rust-imap?rev=281d2eb8ab50dc656ceff2ae749ca5045f334e15)" = "<none>"
|
||||
"checksum imap-proto 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b92ca529b24c5f80a950abe993d3883df6fe6791d4a46b1fda1eb339796c589"
|
||||
"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum jetscii 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5f25cca2463cb19dbb1061eb3bd38a8b5e4ce1cc5a5a9fc0e02de486d92b9b05"
|
||||
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728"
|
||||
"checksum lettre 0.9.2 (git+https://github.com/deltachat/lettre)" = "<none>"
|
||||
"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
|
||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||
"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25"
|
||||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff"
|
||||
"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
@@ -2986,13 +2944,13 @@ dependencies = [
|
||||
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
|
||||
"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf"
|
||||
"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
|
||||
"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10"
|
||||
"checksum miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "304f66c19be2afa56530fa7c39796192eef38618da8d19df725ad7c6d6b2aaae"
|
||||
"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 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"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
|
||||
"checksum num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd60678022301da54082fcc383647fc895cba2795f868c871d58d29c8922595"
|
||||
@@ -3003,29 +2961,26 @@ dependencies = [
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15"
|
||||
"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449"
|
||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
"checksum openssl-src 111.6.0+1.1.1d (registry+https://github.com/rust-lang/crates.io-index)" = "b9c2da1de8a7a3f860919c01540b03a6db16de042405a8a07a5e9d0b4b825d9c"
|
||||
"checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884"
|
||||
"checksum openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)" = "2c42dcccb832556b5926bc9ae61e8775f2a61e725ab07ab3d1e7fcf8ae62c3b6"
|
||||
"checksum os_type 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7edc011af0ae98b7f88cf7e4a83b70a54a75d2b8cb013d6efd02e5956207e9eb"
|
||||
"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
|
||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
|
||||
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
|
||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
|
||||
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb80b37b7debf9a98dc0caca3ed40ddf1d383691208763d0458df0b91521020f"
|
||||
"checksum pgp 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1c4b0aed94774465356a8cb00525c7312c465072293ff53ed7b39f4f9cbefb41"
|
||||
"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea"
|
||||
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
|
||||
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
||||
"checksum pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
|
||||
"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0"
|
||||
"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
|
||||
"checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
|
||||
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
||||
@@ -3057,7 +3012,7 @@ dependencies = [
|
||||
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
|
||||
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6d896143a583047512e59ac54a215cb203c29cc941917343edea3be8df9c78"
|
||||
"checksum reqwest 0.9.21 (registry+https://github.com/rust-lang/crates.io-index)" = "02b7e953e14c6f3102b7e8d1f1ee3abf5ecee80b427f5565c9389835cecae95c"
|
||||
"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a"
|
||||
"checksum rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6ad8d3632f6745bb671c8637e2aa44015537c5e384789d2ea3235739301ed1e0"
|
||||
"checksum rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a194373ef527035645a1bc21b10dc2125f73497e6e155771233eb187aedd051"
|
||||
@@ -3071,7 +3026,6 @@ dependencies = [
|
||||
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
|
||||
"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
|
||||
"checksum scheduled-thread-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd07742e081ff6c077f5f6b283f12f32b9e7cc765b316160d66289b74546fbb3"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
|
||||
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
|
||||
@@ -3079,7 +3033,7 @@ dependencies = [
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
|
||||
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
|
||||
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
|
||||
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
|
||||
"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
|
||||
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
|
||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
@@ -3088,14 +3042,13 @@ dependencies = [
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7"
|
||||
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||
"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 subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
|
||||
"checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799"
|
||||
"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"
|
||||
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
@@ -3114,10 +3067,10 @@ dependencies = [
|
||||
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
|
||||
"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac"
|
||||
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
|
||||
"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
|
||||
"checksum tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c56391be9805bc80163151c0b9e5164ee64f4b0200962c346fea12773158f22d"
|
||||
"checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7"
|
||||
"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
|
||||
"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19"
|
||||
"checksum tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd2c6a3885302581f4401c82af70d792bb9df1700e7437b0aeb4ada94d5388c"
|
||||
"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e"
|
||||
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
|
||||
@@ -10,7 +10,7 @@ deltachat_derive = { path = "./deltachat_derive" }
|
||||
mmime = { version = "0.1.2", path = "./mmime" }
|
||||
|
||||
libc = "0.2.51"
|
||||
pgp = { version = "0.2", default-features = false }
|
||||
pgp = "0.2.3"
|
||||
hex = "0.3.2"
|
||||
sha2 = "0.8.0"
|
||||
rand = "0.6.5"
|
||||
@@ -19,7 +19,7 @@ reqwest = "0.9.15"
|
||||
num-derive = "0.2.5"
|
||||
num-traits = "0.2.6"
|
||||
native-tls = "0.2.3"
|
||||
lettre = "0.9.0"
|
||||
lettre = { git = "https://github.com/deltachat/lettre" }
|
||||
imap = { git = "https://github.com/jonhoo/rust-imap", rev = "281d2eb8ab50dc656ceff2ae749ca5045f334e15" }
|
||||
base64 = "0.10"
|
||||
charset = "0.1"
|
||||
|
||||
@@ -7,9 +7,9 @@ fi
|
||||
|
||||
set -xe
|
||||
|
||||
#DOXYDOCDIR=${1:?directory where doxygen docs to be found}
|
||||
PYDOCDIR=${1:?directory with python docs}
|
||||
WHEELHOUSEDIR=${2:?directory with pre-built wheels}
|
||||
DOXYDOCDIR=${3:?directory where doxygen docs to be found}
|
||||
|
||||
export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
|
||||
|
||||
@@ -22,10 +22,11 @@ rsync -avz \
|
||||
delta@py.delta.chat:build/${BRANCH}
|
||||
|
||||
# C docs to c.delta.chat
|
||||
#rsync -avz \
|
||||
# -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
|
||||
# "$DOXYDOCDIR/html/" \
|
||||
# delta@py.delta.chat:build-c/${BRANCH}
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@c.delta.chat mkdir -p build-c/${BRANCH}
|
||||
rsync -avz \
|
||||
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
|
||||
"$DOXYDOCDIR/html/" \
|
||||
delta@c.delta.chat:build-c/${BRANCH}
|
||||
|
||||
echo -----------------------
|
||||
echo upload wheels
|
||||
|
||||
7
ci_scripts/run-doxygen.sh
Executable file
7
ci_scripts/run-doxygen.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
cd deltachat-ffi
|
||||
doxygen
|
||||
|
||||
@@ -402,6 +402,18 @@ int dc_set_config (dc_context_t* context, const char*
|
||||
*/
|
||||
char* dc_get_config (dc_context_t* context, const char* key);
|
||||
|
||||
/**
|
||||
* Set stock string translation.
|
||||
*
|
||||
* The function will emit warnings if it returns an error state.
|
||||
*
|
||||
* @param context The context object
|
||||
* @param stock_id the integer id of the stock message (DC_STR_*)
|
||||
* @param stock_msg the message to be used
|
||||
* @return int (==0 on error, 1 on success)
|
||||
*/
|
||||
int dc_set_stock_translation(dc_context_t* context, uint32_t, const char* value);
|
||||
|
||||
|
||||
/**
|
||||
* Get information about the context.
|
||||
@@ -3924,6 +3936,26 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*/
|
||||
#define DC_EVENT_IMAP_MESSAGE_MOVED 105
|
||||
|
||||
/**
|
||||
* Emitted when a new blob file was successfully written
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) path name
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_NEW_BLOB_FILE 150
|
||||
|
||||
/**
|
||||
* Emitted when a blob file was successfully deleted
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) path name
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_DELETED_BLOB_FILE 151
|
||||
|
||||
/**
|
||||
* The library-user should write a warning string to the log.
|
||||
* Passed to the callback given to dc_context_new().
|
||||
@@ -4169,16 +4201,10 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
|
||||
|
||||
/**
|
||||
* Requeste a localized string from the frontend.
|
||||
* (DEPRECATED, DC_EVENT_GET_STRING is not emmitted anymore. Use
|
||||
* dc_set_stock_translation() to pre-fill translations for stock
|
||||
* messages.
|
||||
*
|
||||
* @param data1 (int) ID of the string to request, one of the DC_STR_* constants.
|
||||
* @param data2 (int) The count. If the requested string contains a placeholder for a numeric value,
|
||||
* the ui may use this value to return different strings on different plural forms.
|
||||
* @return (const char*) Null-terminated UTF-8 string.
|
||||
* The string will be free()'d by the core,
|
||||
* so it must be allocated using malloc() or a compatible function.
|
||||
* Return 0 if the ui cannot provide the requested string
|
||||
* the core will use a default string in english language then.
|
||||
*/
|
||||
#define DC_EVENT_GET_STRING 2091
|
||||
|
||||
@@ -4296,7 +4322,8 @@ void dc_array_add_id (dc_array_t*, uint32_t); // depreca
|
||||
#define DC_STR_MSGLOCATIONENABLED 64
|
||||
#define DC_STR_MSGLOCATIONDISABLED 65
|
||||
#define DC_STR_LOCATION 66
|
||||
#define DC_STR_COUNT 66
|
||||
#define DC_STR_STICKER 67
|
||||
#define DC_STR_COUNT 67
|
||||
|
||||
void dc_str_unref (char*);
|
||||
|
||||
|
||||
@@ -24,9 +24,8 @@ 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_lossy, OsStrExt, StrExt};
|
||||
use deltachat::stock::StockMessage;
|
||||
use deltachat::*;
|
||||
|
||||
// as C lacks a good and portable error handling,
|
||||
@@ -127,11 +126,13 @@ impl ContextWrapper {
|
||||
| Event::SmtpMessageSent(msg)
|
||||
| Event::ImapMessageDeleted(msg)
|
||||
| Event::ImapMessageMoved(msg)
|
||||
| Event::NewBlobFile(msg)
|
||||
| Event::DeletedBlobFile(msg)
|
||||
| Event::Warning(msg)
|
||||
| Event::Error(msg)
|
||||
| Event::ErrorNetwork(msg)
|
||||
| Event::ErrorSelfNotInGroup(msg) => {
|
||||
let data2 = CString::new(msg).unwrap();
|
||||
let data2 = CString::new(msg).unwrap_or_default();
|
||||
ffi_cb(self, event_id, 0, data2.as_ptr() as uintptr_t)
|
||||
}
|
||||
Event::MsgsChanged { chat_id, msg_id }
|
||||
@@ -150,7 +151,7 @@ impl ContextWrapper {
|
||||
ffi_cb(self, event_id, progress as uintptr_t, 0)
|
||||
}
|
||||
Event::ImexFileWritten(file) => {
|
||||
let data1 = file.to_c_string().unwrap();
|
||||
let data1 = file.to_c_string().unwrap_or_default();
|
||||
ffi_cb(self, event_id, data1.as_ptr() as uintptr_t, 0)
|
||||
}
|
||||
Event::SecurejoinInviterProgress {
|
||||
@@ -166,12 +167,6 @@ impl ContextWrapper {
|
||||
contact_id as uintptr_t,
|
||||
progress as uintptr_t,
|
||||
),
|
||||
Event::GetString { id, count } => ffi_cb(
|
||||
self,
|
||||
event_id,
|
||||
id.to_u32().unwrap_or_default() as uintptr_t,
|
||||
count as uintptr_t,
|
||||
),
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
@@ -342,6 +337,35 @@ pub unsafe extern "C" fn dc_get_config(
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_set_stock_translation(
|
||||
context: *mut dc_context_t,
|
||||
stock_id: u32,
|
||||
stock_msg: *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
if context.is_null() || stock_msg.is_null() {
|
||||
eprintln!("ignoring careless call to dc_set_stock_string");
|
||||
return 0;
|
||||
}
|
||||
let msg = as_str(stock_msg).to_string();
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| match StockMessage::from_u32(stock_id) {
|
||||
Some(id) => match ctx.set_stock_translation(id, msg) {
|
||||
Ok(()) => 1,
|
||||
Err(err) => {
|
||||
warn!(ctx, "set_stock_translation failed: {}", err);
|
||||
0
|
||||
}
|
||||
},
|
||||
None => {
|
||||
warn!(ctx, "invalid stock message id {}", stock_id);
|
||||
0
|
||||
}
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_get_info(context: *mut dc_context_t) -> *mut libc::c_char {
|
||||
if context.is_null() {
|
||||
@@ -379,8 +403,8 @@ pub unsafe extern "C" fn dc_get_oauth2_url(
|
||||
return ptr::null_mut(); // NULL explicitly defined as "unknown"
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
let addr = to_string(addr);
|
||||
let redirect = to_string(redirect);
|
||||
let addr = to_string_lossy(addr);
|
||||
let redirect = to_string_lossy(redirect);
|
||||
ffi_context
|
||||
.with_inner(|ctx| match oauth2::dc_get_oauth2_url(ctx, addr, redirect) {
|
||||
Some(res) => res.strdup(),
|
||||
@@ -1620,9 +1644,7 @@ pub unsafe extern "C" fn dc_stop_ongoing_process(context: *mut dc_context_t) {
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| configure::dc_stop_ongoing_process(ctx))
|
||||
.ok();
|
||||
ffi_context.with_inner(|ctx| ctx.stop_ongoing()).ok();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2136,7 +2158,7 @@ pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut
|
||||
let ffi_context = &*ffi_chat.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| match ffi_chat.chat.get_profile_image(ctx) {
|
||||
Some(p) => p.to_str().unwrap().to_string().strdup(),
|
||||
Some(p) => p.to_string_lossy().strdup(),
|
||||
None => ptr::null_mut(),
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
@@ -2481,7 +2503,7 @@ pub unsafe extern "C" fn dc_msg_get_summarytext(
|
||||
.with_inner(|ctx| {
|
||||
ffi_msg
|
||||
.message
|
||||
.get_summarytext(ctx, approx_characters.try_into().unwrap())
|
||||
.get_summarytext(ctx, approx_characters.try_into().unwrap_or_default())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
@@ -2773,7 +2795,7 @@ pub unsafe extern "C" fn dc_contact_get_profile_image(
|
||||
ffi_contact
|
||||
.contact
|
||||
.get_profile_image(ctx)
|
||||
.map(|p| p.to_str().unwrap().to_string().strdup())
|
||||
.map(|p| p.to_string_lossy().strdup())
|
||||
.unwrap_or_else(|| std::ptr::null_mut())
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::str::FromStr;
|
||||
use deltachat::chat::{self, Chat};
|
||||
use deltachat::chatlist::*;
|
||||
use deltachat::config;
|
||||
use deltachat::configure::*;
|
||||
use deltachat::constants::*;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
@@ -119,13 +118,13 @@ fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
|
||||
/* 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 = to_string_lossy(spec);
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(&real_spec))
|
||||
.set_raw_config(context, "import_spec", Some(&real_spec))
|
||||
.unwrap();
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
let rs = context.sql.get_raw_config(context, "import_spec");
|
||||
if rs.is_none() {
|
||||
error!(context, "Import: No file or folder given.");
|
||||
return 0;
|
||||
@@ -471,7 +470,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(0 != dc_reset_tables(context, bits), "Reset failed");
|
||||
}
|
||||
"stop" => {
|
||||
dc_stop_ongoing_process(context);
|
||||
context.stop_ongoing();
|
||||
}
|
||||
"set" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <key> missing.");
|
||||
|
||||
@@ -43,7 +43,6 @@ use self::cmdline::*;
|
||||
|
||||
fn receive_event(_context: &Context, event: Event) -> libc::uintptr_t {
|
||||
match event {
|
||||
Event::GetString { .. } => {}
|
||||
Event::Info(msg) => {
|
||||
/* do not show the event as this would fill the screen */
|
||||
println!("{}", msg);
|
||||
|
||||
@@ -35,93 +35,90 @@ fn cb(_ctx: &Context, event: Event) -> usize {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = dir.path().join("db.sqlite");
|
||||
println!("creating database {:?}", dbfile);
|
||||
let ctx =
|
||||
Context::new(Box::new(cb), "FakeOs".into(), dbfile).expect("Failed to create context");
|
||||
let running = Arc::new(RwLock::new(true));
|
||||
let info = ctx.get_info();
|
||||
let duration = time::Duration::from_millis(4000);
|
||||
println!("info: {:#?}", info);
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = dir.path().join("db.sqlite");
|
||||
println!("creating database {:?}", dbfile);
|
||||
let ctx =
|
||||
Context::new(Box::new(cb), "FakeOs".into(), dbfile).expect("Failed to create context");
|
||||
let running = Arc::new(RwLock::new(true));
|
||||
let info = ctx.get_info();
|
||||
let duration = time::Duration::from_millis(4000);
|
||||
println!("info: {:#?}", info);
|
||||
|
||||
let ctx = Arc::new(ctx);
|
||||
let ctx1 = ctx.clone();
|
||||
let r1 = running.clone();
|
||||
let t1 = thread::spawn(move || {
|
||||
while *r1.read().unwrap() {
|
||||
perform_imap_jobs(&ctx1);
|
||||
if *r1.read().unwrap() {
|
||||
perform_imap_fetch(&ctx1);
|
||||
|
||||
let ctx = Arc::new(ctx);
|
||||
let ctx1 = ctx.clone();
|
||||
let r1 = running.clone();
|
||||
let t1 = thread::spawn(move || {
|
||||
while *r1.read().unwrap() {
|
||||
perform_imap_jobs(&ctx1);
|
||||
if *r1.read().unwrap() {
|
||||
perform_imap_fetch(&ctx1);
|
||||
|
||||
if *r1.read().unwrap() {
|
||||
perform_imap_idle(&ctx1);
|
||||
}
|
||||
perform_imap_idle(&ctx1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let ctx1 = ctx.clone();
|
||||
let r1 = running.clone();
|
||||
let t2 = thread::spawn(move || {
|
||||
while *r1.read().unwrap() {
|
||||
perform_smtp_jobs(&ctx1);
|
||||
if *r1.read().unwrap() {
|
||||
perform_smtp_idle(&ctx1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
println!("configuring");
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
assert_eq!(args.len(), 2, "missing password");
|
||||
let pw = args[1].clone();
|
||||
ctx.set_config(config::Config::Addr, Some("d@testrun.org"))
|
||||
.unwrap();
|
||||
ctx.set_config(config::Config::MailPw, Some(&pw)).unwrap();
|
||||
configure(&ctx);
|
||||
|
||||
thread::sleep(duration);
|
||||
|
||||
println!("sending a message");
|
||||
let contact_id =
|
||||
Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com").unwrap();
|
||||
let chat_id = chat::create_by_contact_id(&ctx, contact_id).unwrap();
|
||||
chat::send_text_msg(&ctx, chat_id, "Hi, here is my first message!".into()).unwrap();
|
||||
|
||||
println!("fetching chats..");
|
||||
let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap();
|
||||
|
||||
for i in 0..chats.len() {
|
||||
let summary = chats.get_summary(&ctx, 0, None);
|
||||
let text1 = summary.get_text1();
|
||||
let text2 = summary.get_text2();
|
||||
println!("chat: {} - {:?} - {:?}", i, text1, text2,);
|
||||
}
|
||||
});
|
||||
|
||||
thread::sleep(duration);
|
||||
let ctx1 = ctx.clone();
|
||||
let r1 = running.clone();
|
||||
let t2 = thread::spawn(move || {
|
||||
while *r1.read().unwrap() {
|
||||
perform_smtp_jobs(&ctx1);
|
||||
if *r1.read().unwrap() {
|
||||
perform_smtp_idle(&ctx1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// let msglist = dc_get_chat_msgs(&ctx, chat_id, 0, 0);
|
||||
// for i in 0..dc_array_get_cnt(msglist) {
|
||||
// let msg_id = dc_array_get_id(msglist, i);
|
||||
// let msg = dc_get_msg(context, msg_id);
|
||||
// let text = CStr::from_ptr(dc_msg_get_text(msg)).unwrap();
|
||||
// println!("Message {}: {}\n", i + 1, text.to_str().unwrap());
|
||||
// dc_msg_unref(msg);
|
||||
// }
|
||||
// dc_array_unref(msglist);
|
||||
println!("configuring");
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
assert_eq!(args.len(), 2, "missing password");
|
||||
let pw = args[1].clone();
|
||||
ctx.set_config(config::Config::Addr, Some("d@testrun.org"))
|
||||
.unwrap();
|
||||
ctx.set_config(config::Config::MailPw, Some(&pw)).unwrap();
|
||||
configure(&ctx);
|
||||
|
||||
println!("stopping threads");
|
||||
thread::sleep(duration);
|
||||
|
||||
*running.clone().write().unwrap() = false;
|
||||
deltachat::job::interrupt_imap_idle(&ctx);
|
||||
deltachat::job::interrupt_smtp_idle(&ctx);
|
||||
println!("sending a message");
|
||||
let contact_id = Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com").unwrap();
|
||||
let chat_id = chat::create_by_contact_id(&ctx, contact_id).unwrap();
|
||||
chat::send_text_msg(&ctx, chat_id, "Hi, here is my first message!".into()).unwrap();
|
||||
|
||||
println!("joining");
|
||||
t1.join().unwrap();
|
||||
t2.join().unwrap();
|
||||
println!("fetching chats..");
|
||||
let chats = Chatlist::try_load(&ctx, 0, None, None).unwrap();
|
||||
|
||||
println!("closing");
|
||||
for i in 0..chats.len() {
|
||||
let summary = chats.get_summary(&ctx, 0, None);
|
||||
let text1 = summary.get_text1();
|
||||
let text2 = summary.get_text2();
|
||||
println!("chat: {} - {:?} - {:?}", i, text1, text2,);
|
||||
}
|
||||
|
||||
thread::sleep(duration);
|
||||
|
||||
// let msglist = dc_get_chat_msgs(&ctx, chat_id, 0, 0);
|
||||
// for i in 0..dc_array_get_cnt(msglist) {
|
||||
// let msg_id = dc_array_get_id(msglist, i);
|
||||
// let msg = dc_get_msg(context, msg_id);
|
||||
// let text = CStr::from_ptr(dc_msg_get_text(msg)).unwrap();
|
||||
// println!("Message {}: {}\n", i + 1, text.to_str().unwrap());
|
||||
// dc_msg_unref(msg);
|
||||
// }
|
||||
// dc_array_unref(msglist);
|
||||
|
||||
println!("stopping threads");
|
||||
|
||||
*running.clone().write().unwrap() = false;
|
||||
deltachat::job::interrupt_imap_idle(&ctx);
|
||||
deltachat::job::interrupt_smtp_idle(&ctx);
|
||||
|
||||
println!("joining");
|
||||
t1.join().unwrap();
|
||||
t2.join().unwrap();
|
||||
|
||||
println!("closing");
|
||||
}
|
||||
|
||||
@@ -17,12 +17,12 @@ pub unsafe fn charconv(
|
||||
assert!(!fromcode.is_null(), "invalid fromcode");
|
||||
assert!(!s.is_null(), "invalid input string");
|
||||
if let Some(encoding) =
|
||||
charset::Charset::for_label(CStr::from_ptr(fromcode).to_str().unwrap().as_bytes())
|
||||
charset::Charset::for_label(CStr::from_ptr(fromcode).to_string_lossy().as_bytes())
|
||||
{
|
||||
let data = std::slice::from_raw_parts(s as *const u8, strlen(s));
|
||||
|
||||
let (res, _, _) = encoding.decode(data);
|
||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
||||
let res_c = CString::new(res.as_bytes()).unwrap_or_default();
|
||||
*result = strdup(res_c.as_ptr()) as *mut _;
|
||||
|
||||
MAIL_CHARCONV_NO_ERROR as libc::c_int
|
||||
|
||||
@@ -1598,7 +1598,7 @@ unsafe fn mailimf_date_time_write_driver(
|
||||
(*date_time).dt_sec,
|
||||
(*date_time).dt_zone,
|
||||
);
|
||||
let date_str_c = std::ffi::CString::new(date_str).unwrap();
|
||||
let date_str_c = std::ffi::CString::new(date_str).unwrap_or_default();
|
||||
let r = mailimf_string_write_driver(
|
||||
do_write,
|
||||
data,
|
||||
|
||||
@@ -848,7 +848,7 @@ pub unsafe fn mailmime_generate_boundary() -> *mut libc::c_char {
|
||||
hex::encode(&std::process::id().to_le_bytes()[..2])
|
||||
);
|
||||
|
||||
let c = std::ffi::CString::new(raw).unwrap();
|
||||
let c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
strdup(c.as_ptr())
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ unsafe fn mailmime_disposition_param_write_driver(
|
||||
4 => {
|
||||
let value = (*param).pa_data.pa_size as u32;
|
||||
let raw = format!("{}", value);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
sizestr = strdup(raw_c.as_ptr());
|
||||
len = strlen(b"size=\x00" as *const u8 as *const libc::c_char)
|
||||
.wrapping_add(strlen(sizestr))
|
||||
@@ -542,7 +542,7 @@ unsafe fn mailmime_version_write_driver(
|
||||
}
|
||||
|
||||
let raw = format!("{}.{}", (version >> 16) as i32, (version & 0xffff) as i32);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut versionstr = strdup(raw_c.as_ptr());
|
||||
r = mailimf_string_write_driver(do_write, data, col, versionstr, strlen(versionstr));
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
@@ -1515,8 +1515,8 @@ pub unsafe fn mailmime_data_write_driver(
|
||||
}
|
||||
1 => {
|
||||
let filename = CStr::from_ptr((*mime_data).dt_data.dt_filename)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
if let Ok(file) = std::fs::File::open(filename) {
|
||||
if let Ok(mut text) = memmap::MmapOptions::new().map_copy(&file) {
|
||||
if 0 != (*mime_data).dt_encoded {
|
||||
@@ -1797,7 +1797,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
start = text.offset(i as isize).offset(1isize);
|
||||
|
||||
let raw = format!("={:02X}", (ch as libc::c_int));
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
r = mailimf_string_write_driver(
|
||||
do_write,
|
||||
@@ -1822,7 +1822,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
}
|
||||
start = text.offset(i as isize).offset(1isize);
|
||||
let raw = format!("={:02X}", ch as libc::c_int);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
r = mailimf_string_write_driver(
|
||||
do_write,
|
||||
@@ -1866,7 +1866,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
}
|
||||
start = text.offset(i as isize);
|
||||
let raw = format!("={:02X}", b'\r' as i32);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
r = mailimf_string_write_driver(do_write, data, col, hexstr, 3i32 as size_t);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
@@ -1890,7 +1890,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
"={:02X}\r\n",
|
||||
*text.offset(i.wrapping_sub(1i32 as libc::size_t) as isize) as libc::c_int
|
||||
);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
|
||||
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
|
||||
@@ -1917,7 +1917,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
"={:02X}\r\n",
|
||||
*text.offset(i.wrapping_sub(2i32 as libc::size_t) as isize) as libc::c_int
|
||||
);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
|
||||
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
|
||||
@@ -1938,7 +1938,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
|
||||
(*text.offset(i.wrapping_sub(2i32 as libc::size_t) as isize) as u8 as char),
|
||||
b'\r' as i32
|
||||
);
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap();
|
||||
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
|
||||
let mut hexstr = strdup(raw_c.as_ptr());
|
||||
|
||||
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
|
||||
|
||||
@@ -12,6 +12,10 @@ pub(crate) use libc::{
|
||||
};
|
||||
|
||||
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
||||
if s1.is_null() || s2.is_null() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let s1 = std::ffi::CStr::from_ptr(s1)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
@@ -30,16 +34,23 @@ pub(crate) unsafe fn strncasecmp(
|
||||
s2: *const libc::c_char,
|
||||
n: libc::size_t,
|
||||
) -> 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();
|
||||
let m1 = std::cmp::min(n, s1.len());
|
||||
let m2 = std::cmp::min(n, s2.len());
|
||||
if s1.is_null() || s2.is_null() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if s1[..m1] == s2[..m2] {
|
||||
// s1 and s2 might not be null terminated.
|
||||
|
||||
let s1_slice = std::slice::from_raw_parts(s1 as *const u8, n);
|
||||
let s2_slice = std::slice::from_raw_parts(s2 as *const u8, n);
|
||||
|
||||
let s1 = std::ffi::CStr::from_bytes_with_nul_unchecked(s1_slice)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
let s2 = std::ffi::CStr::from_bytes_with_nul_unchecked(s2_slice)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
|
||||
if s1 == s2 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
|
||||
1
python/doc/_templates/globaltoc.html
vendored
1
python/doc/_templates/globaltoc.html
vendored
@@ -6,7 +6,6 @@
|
||||
<li><a href="{{ pathto('install') }}">install</a></li>
|
||||
<li><a href="{{ pathto('api') }}">high level API</a></li>
|
||||
<li><a href="{{ pathto('lapi') }}">low level API</a></li>
|
||||
<li><a href="{{ pathto('capi') }}">C deltachat.h</a></li>
|
||||
</ul>
|
||||
<b>external links:</b>
|
||||
<ul>
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
low level API reference
|
||||
===================================
|
||||
|
||||
for full C-docs, defines and function checkout :doc:`capi`
|
||||
for full doxygen-generated C-docs, defines and functions please checkout
|
||||
|
||||
https://c.delta.chat
|
||||
|
||||
|
||||
Python low-level capi calls
|
||||
---------------------------
|
||||
|
||||
|
||||
.. automodule:: deltachat.capi.lib
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
""" Account class implementation. """
|
||||
|
||||
from __future__ import print_function
|
||||
import atexit
|
||||
import threading
|
||||
import re
|
||||
import time
|
||||
@@ -49,9 +50,10 @@ class Account(object):
|
||||
raise ValueError("Could not dc_open: {}".format(db_path))
|
||||
self._configkeys = self.get_config("sys.config_keys").split()
|
||||
self._imex_events = Queue()
|
||||
atexit.register(self.shutdown)
|
||||
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
# def __del__(self):
|
||||
# self.shutdown()
|
||||
|
||||
def _check_config_key(self, name):
|
||||
if name not in self._configkeys:
|
||||
@@ -69,6 +71,18 @@ class Account(object):
|
||||
d[key.lower()] = value
|
||||
return d
|
||||
|
||||
def set_stock_translation(self, id, string):
|
||||
""" set stock translation string.
|
||||
|
||||
:param id: id of stock string (const.DC_STR_*)
|
||||
:param value: string to set as new transalation
|
||||
:returns: None
|
||||
"""
|
||||
string = string.encode("utf8")
|
||||
res = lib.dc_set_stock_translation(self._dc_context, id, string)
|
||||
if res == 0:
|
||||
raise ValueError("could not set translation string")
|
||||
|
||||
def set_config(self, name, value):
|
||||
""" set configuration values.
|
||||
|
||||
@@ -258,10 +272,6 @@ class Account(object):
|
||||
""" return Message instance. """
|
||||
return Message.from_db(self, msg_id)
|
||||
|
||||
def get_chat_by_id(self, chat_id):
|
||||
""" return Chat instance. """
|
||||
return Chat(self, chat_id)
|
||||
|
||||
def mark_seen_messages(self, messages):
|
||||
""" mark the given set of messages as seen.
|
||||
|
||||
@@ -415,6 +425,9 @@ class Account(object):
|
||||
raise ValueError("could not join group")
|
||||
return Chat(self, chat_id)
|
||||
|
||||
def stop_ongoing(self):
|
||||
lib.dc_stop_ongoing_process(self._dc_context)
|
||||
|
||||
#
|
||||
# meta API for start/stop and event based processing
|
||||
#
|
||||
@@ -436,7 +449,7 @@ class Account(object):
|
||||
|
||||
def stop_threads(self, wait=True):
|
||||
""" stop IMAP/SMTP threads. """
|
||||
lib.dc_stop_ongoing_process(self._dc_context)
|
||||
self.stop_ongoing()
|
||||
self._threads.stop(wait=wait)
|
||||
|
||||
def shutdown(self, wait=True):
|
||||
@@ -448,6 +461,7 @@ class Account(object):
|
||||
self.stop_threads(wait=wait) # to wait for threads
|
||||
deltachat.clear_context_callback(self._dc_context)
|
||||
del self._dc_context
|
||||
atexit.unregister(self.shutdown)
|
||||
|
||||
def _process_event(self, ctx, evt_name, data1, data2):
|
||||
assert ctx == self._dc_context
|
||||
|
||||
@@ -63,6 +63,8 @@ DC_EVENT_IMAP_CONNECTED = 102
|
||||
DC_EVENT_SMTP_MESSAGE_SENT = 103
|
||||
DC_EVENT_IMAP_MESSAGE_DELETED = 104
|
||||
DC_EVENT_IMAP_MESSAGE_MOVED = 105
|
||||
DC_EVENT_NEW_BLOB_FILE = 150
|
||||
DC_EVENT_DELETED_BLOB_FILE = 151
|
||||
DC_EVENT_WARNING = 300
|
||||
DC_EVENT_ERROR = 400
|
||||
DC_EVENT_ERROR_NETWORK = 401
|
||||
@@ -83,14 +85,61 @@ DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
||||
DC_EVENT_GET_STRING = 2091
|
||||
DC_EVENT_FILE_COPIED = 2055
|
||||
DC_EVENT_IS_OFFLINE = 2081
|
||||
DC_STR_SELFNOTINGRP = 21
|
||||
DC_PROVIDER_STATUS_OK = 1
|
||||
DC_PROVIDER_STATUS_PREPARATION = 2
|
||||
DC_PROVIDER_STATUS_BROKEN = 3
|
||||
DC_STR_NOMESSAGES = 1
|
||||
DC_STR_SELF = 2
|
||||
DC_STR_DRAFT = 3
|
||||
DC_STR_MEMBER = 4
|
||||
DC_STR_CONTACT = 6
|
||||
DC_STR_VOICEMESSAGE = 7
|
||||
DC_STR_DEADDROP = 8
|
||||
DC_STR_IMAGE = 9
|
||||
DC_STR_VIDEO = 10
|
||||
DC_STR_AUDIO = 11
|
||||
DC_STR_FILE = 12
|
||||
DC_STR_STATUSLINE = 13
|
||||
DC_STR_NEWGROUPDRAFT = 14
|
||||
DC_STR_MSGGRPNAME = 15
|
||||
DC_STR_MSGGRPIMGCHANGED = 16
|
||||
DC_STR_MSGADDMEMBER = 17
|
||||
DC_STR_MSGDELMEMBER = 18
|
||||
DC_STR_MSGGROUPLEFT = 19
|
||||
DC_STR_GIF = 23
|
||||
DC_STR_ENCRYPTEDMSG = 24
|
||||
DC_STR_E2E_AVAILABLE = 25
|
||||
DC_STR_ENCR_TRANSP = 27
|
||||
DC_STR_ENCR_NONE = 28
|
||||
DC_STR_CANTDECRYPT_MSG_BODY = 29
|
||||
DC_STR_FINGERPRINTS = 30
|
||||
DC_STR_READRCPT = 31
|
||||
DC_STR_READRCPT_MAILBODY = 32
|
||||
DC_STR_MSGGRPIMGDELETED = 33
|
||||
DC_STR_E2E_PREFERRED = 34
|
||||
DC_STR_CONTACT_VERIFIED = 35
|
||||
DC_STR_CONTACT_NOT_VERIFIED = 36
|
||||
DC_STR_CONTACT_SETUP_CHANGED = 37
|
||||
DC_STR_ARCHIVEDCHATS = 40
|
||||
DC_STR_STARREDMSGS = 41
|
||||
DC_STR_AC_SETUP_MSG_SUBJECT = 42
|
||||
DC_STR_AC_SETUP_MSG_BODY = 43
|
||||
DC_STR_SELFTALK_SUBTITLE = 50
|
||||
DC_STR_CANNOT_LOGIN = 60
|
||||
DC_STR_SERVER_RESPONSE = 61
|
||||
DC_STR_MSGACTIONBYUSER = 62
|
||||
DC_STR_MSGACTIONBYME = 63
|
||||
DC_STR_MSGLOCATIONENABLED = 64
|
||||
DC_STR_MSGLOCATIONDISABLED = 65
|
||||
DC_STR_LOCATION = 66
|
||||
DC_STR_STICKER = 67
|
||||
DC_STR_COUNT = 67
|
||||
# end const generated
|
||||
|
||||
|
||||
def read_event_defines(f):
|
||||
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_QR|DC_MSG|DC_STATE_|'
|
||||
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_QR|DC_MSG|DC_STATE_|DC_STR|'
|
||||
r'DC_CONTACT_ID_|DC_GCL|DC_CHAT|DC_PROVIDER)\S+)\s+([x\d]+).*')
|
||||
for line in f:
|
||||
m = rex.match(line)
|
||||
|
||||
@@ -148,6 +148,27 @@ class TestOfflineChat:
|
||||
chat.set_name("title2")
|
||||
assert chat.get_name() == "title2"
|
||||
|
||||
def test_group_chat_creation_with_translation(self, ac1):
|
||||
ac1.set_stock_translation(const.DC_STR_NEWGROUPDRAFT, "xyz %1$s")
|
||||
ac1._evlogger.consume_events()
|
||||
with pytest.raises(ValueError):
|
||||
ac1.set_stock_translation(const.DC_STR_NEWGROUPDRAFT, "xyz %2$s")
|
||||
ac1._evlogger.get_matching("DC_EVENT_WARNING")
|
||||
with pytest.raises(ValueError):
|
||||
ac1.set_stock_translation(500, "xyz %1$s")
|
||||
ac1._evlogger.get_matching("DC_EVENT_WARNING")
|
||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||
contact2 = ac1.create_contact("some2@hello.com", name="some2")
|
||||
chat = ac1.create_group_chat(name="title1")
|
||||
chat.add_contact(contact1)
|
||||
chat.add_contact(contact2)
|
||||
assert chat.get_name() == "title1"
|
||||
assert contact1 in chat.get_contacts()
|
||||
assert contact2 in chat.get_contacts()
|
||||
assert not chat.is_promoted()
|
||||
msg = chat.get_draft()
|
||||
assert msg.text == "xyz title1"
|
||||
|
||||
@pytest.mark.parametrize("verified", [True, False])
|
||||
def test_group_chat_qr(self, acfactory, ac1, verified):
|
||||
ac2 = acfactory.get_configured_offline_account()
|
||||
@@ -229,7 +250,9 @@ class TestOfflineChat:
|
||||
chat1.send_image(path="notexists")
|
||||
fn = data.get_path("d.png")
|
||||
lp.sec("sending image")
|
||||
chat1.account._evlogger.consume_events()
|
||||
msg = chat1.send_image(fn)
|
||||
chat1.account._evlogger.get_matching("DC_EVENT_NEW_BLOB_FILE")
|
||||
assert msg.is_image()
|
||||
assert msg
|
||||
assert msg.id > 0
|
||||
@@ -348,6 +371,12 @@ class TestOnlineAccount:
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
return chat
|
||||
|
||||
def test_configure_canceled(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
wait_configuration_progress(ac1, 200)
|
||||
ac1.stop_ongoing()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_export_import_self_keys(self, acfactory, tmpdir):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
dir = tmpdir.mkdir("exportdir")
|
||||
@@ -375,6 +404,7 @@ class TestOnlineAccount:
|
||||
self_addr = ac1.get_config("addr")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
|
||||
assert self_addr in ev[2]
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
|
||||
|
||||
ac1._evlogger.consume_events()
|
||||
lp.sec("send out message without bcc")
|
||||
@@ -384,6 +414,7 @@ class TestOnlineAccount:
|
||||
assert ev[2] == msg_out.id
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
|
||||
assert self_addr not in ev[2]
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
|
||||
|
||||
def test_mvbox_sentbox_threads(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
|
||||
@@ -512,6 +543,14 @@ class TestOnlineAccount:
|
||||
assert msg_back.text == "message-back"
|
||||
assert msg_back.is_encrypted()
|
||||
|
||||
lp.sec("create group chat with two members, one of which has no encrypt state")
|
||||
chat = ac1.create_group_chat("encryption test")
|
||||
chat.add_contact(ac1.create_contact(ac2.get_config("addr")))
|
||||
chat.add_contact(ac1.create_contact("notexisting@testrun.org"))
|
||||
msg = chat.send_text("test not encrypt")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
|
||||
assert not msg.is_encrypted()
|
||||
|
||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
|
||||
@@ -734,45 +773,3 @@ class TestOnlineConfigureFails:
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "could not connect" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
|
||||
class TestThreeAccounts:
|
||||
def test_verified_export_import(self, acfactory, lp, tmpdir):
|
||||
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()
|
||||
assert msg.chat.is_verified()
|
||||
|
||||
lp.sec("export ac1")
|
||||
backupdir = tmpdir.mkdir("backup")
|
||||
path = ac1.export_all(backupdir.strpath)
|
||||
assert os.path.exists(path)
|
||||
|
||||
lp.sec("ac3: import ac1-state")
|
||||
ac3 = acfactory.get_unconfigured_account()
|
||||
ac3.import_all(path)
|
||||
ch3 = ac3.get_chat_by_id(chat1.id)
|
||||
assert ch3.is_verified()
|
||||
ac3.start_threads()
|
||||
|
||||
lp.sec("ac3: send message")
|
||||
msg_out = ch3.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.is_encrypted()
|
||||
assert msg.chat.is_verified()
|
||||
|
||||
|
||||
@@ -79,16 +79,13 @@ impl Aheader {
|
||||
let optional_field = unsafe { (*field).fld_data.fld_optional_field };
|
||||
if !optional_field.is_null()
|
||||
&& unsafe { !(*optional_field).fld_name.is_null() }
|
||||
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_str().unwrap() }
|
||||
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_string_lossy() }
|
||||
== "Autocrypt"
|
||||
{
|
||||
let value = unsafe {
|
||||
CStr::from_ptr((*optional_field).fld_value)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
};
|
||||
let value =
|
||||
unsafe { CStr::from_ptr((*optional_field).fld_value).to_string_lossy() };
|
||||
|
||||
if let Ok(test) = Self::from_str(value) {
|
||||
if let Ok(test) = Self::from_str(&value) {
|
||||
if addr_cmp(&test.addr, wanted_from) {
|
||||
if fine_header.is_none() {
|
||||
fine_header = Some(test);
|
||||
|
||||
81
src/chat.rs
81
src/chat.rs
@@ -162,9 +162,13 @@ impl Chat {
|
||||
let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?));
|
||||
let params = params![self.id as i32, DC_CONTACT_ID_SELF as i32];
|
||||
let sql = &context.sql;
|
||||
|
||||
// use the last messsage of another user in the group as the parent
|
||||
let main_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
|
||||
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
|
||||
FROM msgs WHERE chat_id=?1 AND from_id!=?2);";
|
||||
|
||||
// there are no messages of other users - use the first message if SELF as parent
|
||||
let fallback_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
|
||||
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
|
||||
FROM msgs WHERE chat_id=?1 AND from_id==?2);";
|
||||
@@ -287,7 +291,7 @@ impl Chat {
|
||||
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
|
||||
if self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
|
||||
self.param.remove(Param::Unpromoted);
|
||||
self.update_param(context).unwrap();
|
||||
self.update_param(context)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,10 +303,13 @@ impl Chat {
|
||||
do_guarantee_e2ee = false;
|
||||
e2ee_enabled = context.get_config_bool(Config::E2eeEnabled);
|
||||
if e2ee_enabled && msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0 {
|
||||
let mut can_encrypt = 1;
|
||||
let mut all_mutual = 1;
|
||||
let mut can_encrypt = true;
|
||||
let mut all_mutual = true;
|
||||
|
||||
let res = context.sql.query_row(
|
||||
// take care that this statement returns NULL rows
|
||||
// if there is no peerstates for a chat member!
|
||||
// for DC_PARAM_SELFTALK this statement does not return any row
|
||||
let res = context.sql.query_map(
|
||||
"SELECT ps.prefer_encrypted, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
@@ -310,29 +317,32 @@ impl Chat {
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![self.id],
|
||||
|row| {
|
||||
let state: String = row.get(1)?;
|
||||
let addr: String = row.get(1)?;
|
||||
|
||||
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
|
||||
// the peerstate exist, so we have either public_key or gossip_key
|
||||
// and can encrypt potentially
|
||||
if prefer_encrypted != 1 {
|
||||
info!(
|
||||
context,
|
||||
"[autocrypt] peerstate for {} is {}",
|
||||
state,
|
||||
addr,
|
||||
if prefer_encrypted == 0 {
|
||||
"NOPREFERENCE"
|
||||
} else {
|
||||
"RESET"
|
||||
},
|
||||
);
|
||||
all_mutual = 0;
|
||||
all_mutual = false;
|
||||
}
|
||||
} else {
|
||||
info!(context, "[autocrypt] no peerstate for {}", state,);
|
||||
can_encrypt = 0;
|
||||
all_mutual = 0;
|
||||
info!(context, "[autocrypt] no peerstate for {}", addr,);
|
||||
can_encrypt = false;
|
||||
all_mutual = false;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
);
|
||||
match res {
|
||||
Ok(_) => {}
|
||||
@@ -341,8 +351,8 @@ impl Chat {
|
||||
}
|
||||
}
|
||||
|
||||
if 0 != can_encrypt {
|
||||
if 0 != all_mutual {
|
||||
if can_encrypt {
|
||||
if all_mutual {
|
||||
do_guarantee_e2ee = true;
|
||||
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
|
||||
do_guarantee_e2ee = true;
|
||||
@@ -352,7 +362,15 @@ impl Chat {
|
||||
if do_guarantee_e2ee {
|
||||
msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
}
|
||||
// reset eg. for forwarding
|
||||
msg.param.remove(Param::ErroneousE2ee);
|
||||
|
||||
// set "In-Reply-To:" to identify the message to which the composed message is a reply;
|
||||
// set "References:" to identify the "thread" of the conversation;
|
||||
// both according to RFC 5322 3.6.4, page 25
|
||||
//
|
||||
// as self-talks are mainly used to transfer data between devices,
|
||||
// we do not set In-Reply-To/References in this case.
|
||||
if !self.is_self_talk() {
|
||||
if let Some((parent_rfc724_mid, parent_in_reply_to, parent_references)) =
|
||||
self.get_parent_mime_headers(context)
|
||||
@@ -360,6 +378,9 @@ impl Chat {
|
||||
if !parent_rfc724_mid.is_empty() {
|
||||
new_in_reply_to = parent_rfc724_mid.clone();
|
||||
}
|
||||
|
||||
// the whole list of messages referenced may be huge;
|
||||
// only use the oldest and and the parent message
|
||||
let parent_references = if let Some(n) = parent_references.find(' ') {
|
||||
&parent_references[0..n]
|
||||
} else {
|
||||
@@ -367,6 +388,7 @@ impl Chat {
|
||||
};
|
||||
|
||||
if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
|
||||
// angle brackets are added by the mimefactory later
|
||||
new_references = format!("{} {}", parent_references, parent_rfc724_mid);
|
||||
} else if !parent_references.is_empty() {
|
||||
new_references = parent_references.to_string();
|
||||
@@ -951,10 +973,7 @@ pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before:
|
||||
};
|
||||
|
||||
let success = if chat_id == 1 {
|
||||
let show_emails = context
|
||||
.sql
|
||||
.get_config_int(context, "show_emails")
|
||||
.unwrap_or_default();
|
||||
let show_emails = context.get_config_int(Config::ShowEmails);
|
||||
context.sql.query_map(
|
||||
"SELECT m.id, m.timestamp FROM msgs m \
|
||||
LEFT JOIN chats ON m.chat_id=chats.id \
|
||||
@@ -1370,11 +1389,10 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
}
|
||||
if from_handshake && chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
|
||||
chat.param.remove(Param::Unpromoted);
|
||||
chat.update_param(context).unwrap();
|
||||
chat.update_param(context)?;
|
||||
}
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
if contact.get_addr() == &self_addr {
|
||||
bail!("invalid attempt to add self e-mail address to group");
|
||||
@@ -1506,7 +1524,7 @@ pub fn remove_contact_from_chat(
|
||||
if chat.is_promoted() {
|
||||
msg.type_0 = Viewtype::Text;
|
||||
if contact.id == DC_CONTACT_ID_SELF {
|
||||
set_group_explicitly_left(context, chat.grpid).unwrap();
|
||||
set_group_explicitly_left(context, chat.grpid)?;
|
||||
msg.text = Some(context.stock_system_msg(
|
||||
StockMessage::MsgGroupLeft,
|
||||
"",
|
||||
@@ -1715,7 +1733,7 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) -> Result<
|
||||
let mut created_db_entries = Vec::new();
|
||||
let mut curr_timestamp: i64;
|
||||
|
||||
unarchive(context, chat_id).unwrap();
|
||||
unarchive(context, chat_id)?;
|
||||
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
|
||||
@@ -1725,18 +1743,15 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) -> Result<
|
||||
(if i == 0 { acc } else { acc + "," }) + &n.to_string()
|
||||
});
|
||||
|
||||
let ids = context
|
||||
.sql
|
||||
.query_map(
|
||||
format!(
|
||||
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
||||
idsstr
|
||||
),
|
||||
params![],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)
|
||||
.unwrap(); // TODO: better error handling
|
||||
let ids = context.sql.query_map(
|
||||
format!(
|
||||
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
||||
idsstr
|
||||
),
|
||||
params![],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)?;
|
||||
|
||||
for id in ids {
|
||||
let src_msg_id = id;
|
||||
|
||||
@@ -78,13 +78,13 @@ impl Context {
|
||||
pub fn get_config(&self, key: Config) -> Option<String> {
|
||||
let value = match key {
|
||||
Config::Selfavatar => {
|
||||
let rel_path = self.sql.get_config(self, key);
|
||||
rel_path.map(|p| dc_get_abs_path(self, &p).to_str().unwrap().to_string())
|
||||
let rel_path = self.sql.get_raw_config(self, key);
|
||||
rel_path.map(|p| dc_get_abs_path(self, &p).to_string_lossy().into_owned())
|
||||
}
|
||||
Config::SysVersion => Some((&*DC_VERSION_STR).clone()),
|
||||
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
|
||||
Config::SysConfigKeys => Some(get_config_keys_string()),
|
||||
_ => self.sql.get_config(self, key),
|
||||
_ => self.sql.get_raw_config(self, key),
|
||||
};
|
||||
|
||||
if value.is_some() {
|
||||
@@ -99,7 +99,9 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn get_config_int(&self, key: Config) -> i32 {
|
||||
self.get_config(key).and_then(|s| s.parse().ok()).unwrap()
|
||||
self.get_config(key)
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn get_config_bool(&self, key: Config) -> bool {
|
||||
@@ -113,20 +115,20 @@ impl Context {
|
||||
Config::Selfavatar if value.is_some() => {
|
||||
let rel_path = std::fs::canonicalize(value.unwrap())?;
|
||||
self.sql
|
||||
.set_config(self, key, Some(&rel_path.to_string_lossy()))
|
||||
.set_raw_config(self, key, Some(&rel_path.to_string_lossy()))
|
||||
}
|
||||
Config::InboxWatch => {
|
||||
let ret = self.sql.set_config(self, key, value);
|
||||
let ret = self.sql.set_raw_config(self, key, value);
|
||||
interrupt_imap_idle(self);
|
||||
ret
|
||||
}
|
||||
Config::SentboxWatch => {
|
||||
let ret = self.sql.set_config(self, key, value);
|
||||
let ret = self.sql.set_raw_config(self, key, value);
|
||||
interrupt_sentbox_idle(self);
|
||||
ret
|
||||
}
|
||||
Config::MvboxWatch => {
|
||||
let ret = self.sql.set_config(self, key, value);
|
||||
let ret = self.sql.set_raw_config(self, key, value);
|
||||
interrupt_mvbox_idle(self);
|
||||
ret
|
||||
}
|
||||
@@ -138,9 +140,9 @@ impl Context {
|
||||
value
|
||||
};
|
||||
|
||||
self.sql.set_config(self, key, val)
|
||||
self.sql.set_raw_config(self, key, val)
|
||||
}
|
||||
_ => self.sql.set_config(self, key, value),
|
||||
_ => self.sql.set_raw_config(self, key, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
@@ -12,51 +10,57 @@ use super::read_autoconf_file;
|
||||
* Thunderbird's Autoconfigure
|
||||
******************************************************************************/
|
||||
/* documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */
|
||||
#[repr(C)]
|
||||
struct moz_autoconfigure_t<'a> {
|
||||
struct MozAutoconfigure<'a> {
|
||||
pub in_0: &'a LoginParam,
|
||||
pub in_emaildomain: &'a str,
|
||||
pub in_emaillocalpart: &'a str,
|
||||
pub out: LoginParam,
|
||||
pub out_imap_set: libc::c_int,
|
||||
pub out_smtp_set: libc::c_int,
|
||||
pub tag_server: libc::c_int,
|
||||
pub tag_config: libc::c_int,
|
||||
pub out_imap_set: bool,
|
||||
pub out_smtp_set: bool,
|
||||
pub tag_server: MozServer,
|
||||
pub tag_config: MozConfigTag,
|
||||
}
|
||||
|
||||
pub unsafe fn moz_autoconfigure(
|
||||
enum MozServer {
|
||||
Undefined,
|
||||
Imap,
|
||||
Smtp,
|
||||
}
|
||||
|
||||
enum MozConfigTag {
|
||||
Undefined,
|
||||
Hostname,
|
||||
Port,
|
||||
Sockettype,
|
||||
Username,
|
||||
}
|
||||
|
||||
pub fn moz_autoconfigure(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
param_in: &LoginParam,
|
||||
) -> Option<LoginParam> {
|
||||
let xml_raw = read_autoconf_file(context, url);
|
||||
if xml_raw.is_null() {
|
||||
return None;
|
||||
}
|
||||
let xml_raw = read_autoconf_file(context, url)?;
|
||||
|
||||
// Split address into local part and domain part.
|
||||
let p = param_in.addr.find("@");
|
||||
if p.is_none() {
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
return None;
|
||||
}
|
||||
let (in_emaillocalpart, in_emaildomain) = param_in.addr.split_at(p.unwrap());
|
||||
let p = param_in.addr.find('@')?;
|
||||
let (in_emaillocalpart, in_emaildomain) = param_in.addr.split_at(p);
|
||||
let in_emaildomain = &in_emaildomain[1..];
|
||||
|
||||
let mut reader = quick_xml::Reader::from_str(as_str(xml_raw));
|
||||
let mut reader = quick_xml::Reader::from_str(&xml_raw);
|
||||
reader.trim_text(true);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
let mut moz_ac = moz_autoconfigure_t {
|
||||
let mut moz_ac = MozAutoconfigure {
|
||||
in_0: param_in,
|
||||
in_emaildomain,
|
||||
in_emaillocalpart,
|
||||
out: LoginParam::new(),
|
||||
out_imap_set: 0,
|
||||
out_smtp_set: 0,
|
||||
tag_server: 0,
|
||||
tag_config: 0,
|
||||
out_imap_set: false,
|
||||
out_smtp_set: false,
|
||||
tag_server: MozServer::Undefined,
|
||||
tag_config: MozConfigTag::Undefined,
|
||||
};
|
||||
loop {
|
||||
match reader.read_event(&mut buf) {
|
||||
@@ -68,7 +72,7 @@ pub unsafe fn moz_autoconfigure(
|
||||
moz_autoconfigure_text_cb(e, &mut moz_ac, &reader)
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
warn!(
|
||||
context,
|
||||
"Configure xml: Error at position {}: {:?}",
|
||||
reader.buffer_position(),
|
||||
@@ -88,17 +92,15 @@ pub unsafe fn moz_autoconfigure(
|
||||
{
|
||||
let r = moz_ac.out.to_string();
|
||||
warn!(context, "Bad or incomplete autoconfig: {}", r,);
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
return None;
|
||||
}
|
||||
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
Some(moz_ac.out)
|
||||
}
|
||||
|
||||
fn moz_autoconfigure_text_cb<B: std::io::BufRead>(
|
||||
event: &BytesText,
|
||||
moz_ac: &mut moz_autoconfigure_t,
|
||||
moz_ac: &mut MozAutoconfigure,
|
||||
reader: &quick_xml::Reader<B>,
|
||||
) {
|
||||
let val = event.unescape_and_decode(reader).unwrap_or_default();
|
||||
@@ -113,12 +115,12 @@ fn moz_autoconfigure_text_cb<B: std::io::BufRead>(
|
||||
.replace("%EMAILLOCALPART%", email_local)
|
||||
.replace("%EMAILDOMAIN%", email_domain);
|
||||
|
||||
if moz_ac.tag_server == 1 {
|
||||
match moz_ac.tag_config {
|
||||
10 => moz_ac.out.mail_server = val,
|
||||
11 => moz_ac.out.mail_port = val.parse().unwrap_or_default(),
|
||||
12 => moz_ac.out.mail_user = val,
|
||||
13 => {
|
||||
match moz_ac.tag_server {
|
||||
MozServer::Imap => match moz_ac.tag_config {
|
||||
MozConfigTag::Hostname => moz_ac.out.mail_server = val,
|
||||
MozConfigTag::Port => moz_ac.out.mail_port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.mail_user = val,
|
||||
MozConfigTag::Sockettype => {
|
||||
let val_lower = val.to_lowercase();
|
||||
if val_lower == "ssl" {
|
||||
moz_ac.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
|
||||
@@ -131,13 +133,12 @@ fn moz_autoconfigure_text_cb<B: std::io::BufRead>(
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if moz_ac.tag_server == 2 {
|
||||
match moz_ac.tag_config {
|
||||
10 => moz_ac.out.send_server = val,
|
||||
11 => moz_ac.out.send_port = val.parse().unwrap_or_default(),
|
||||
12 => moz_ac.out.send_user = val,
|
||||
13 => {
|
||||
},
|
||||
MozServer::Smtp => match moz_ac.tag_config {
|
||||
MozConfigTag::Hostname => moz_ac.out.send_server = val,
|
||||
MozConfigTag::Port => moz_ac.out.send_port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.send_user = val,
|
||||
MozConfigTag::Sockettype => {
|
||||
let val_lower = val.to_lowercase();
|
||||
if val_lower == "ssl" {
|
||||
moz_ac.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
|
||||
@@ -150,29 +151,30 @@ fn moz_autoconfigure_text_cb<B: std::io::BufRead>(
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
MozServer::Undefined => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn moz_autoconfigure_endtag_cb(event: &BytesEnd, moz_ac: &mut moz_autoconfigure_t) {
|
||||
fn moz_autoconfigure_endtag_cb(event: &BytesEnd, moz_ac: &mut MozAutoconfigure) {
|
||||
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
|
||||
|
||||
if tag == "incomingserver" {
|
||||
moz_ac.tag_server = 0;
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.out_imap_set = 1;
|
||||
moz_ac.tag_server = MozServer::Undefined;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
moz_ac.out_imap_set = true;
|
||||
} else if tag == "outgoingserver" {
|
||||
moz_ac.tag_server = 0;
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.out_smtp_set = 1;
|
||||
moz_ac.tag_server = MozServer::Undefined;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
moz_ac.out_smtp_set = true;
|
||||
} else {
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
fn moz_autoconfigure_starttag_cb<B: std::io::BufRead>(
|
||||
event: &BytesStart,
|
||||
moz_ac: &mut moz_autoconfigure_t,
|
||||
moz_ac: &mut MozAutoconfigure,
|
||||
reader: &quick_xml::Reader<B>,
|
||||
) {
|
||||
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
|
||||
@@ -189,25 +191,29 @@ fn moz_autoconfigure_starttag_cb<B: std::io::BufRead>(
|
||||
.unwrap_or_default()
|
||||
.to_lowercase();
|
||||
|
||||
if typ == "imap" && moz_ac.out_imap_set == 0 {
|
||||
1
|
||||
if typ == "imap" && !moz_ac.out_imap_set {
|
||||
MozServer::Imap
|
||||
} else {
|
||||
0
|
||||
MozServer::Undefined
|
||||
}
|
||||
} else {
|
||||
0
|
||||
MozServer::Undefined
|
||||
};
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
} else if tag == "outgoingserver" {
|
||||
moz_ac.tag_server = if moz_ac.out_smtp_set == 0 { 2 } else { 0 };
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.tag_server = if !moz_ac.out_smtp_set {
|
||||
MozServer::Smtp
|
||||
} else {
|
||||
MozServer::Undefined
|
||||
};
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
} else if tag == "hostname" {
|
||||
moz_ac.tag_config = 10;
|
||||
moz_ac.tag_config = MozConfigTag::Hostname;
|
||||
} else if tag == "port" {
|
||||
moz_ac.tag_config = 11;
|
||||
moz_ac.tag_config = MozConfigTag::Port;
|
||||
} else if tag == "sockettype" {
|
||||
moz_ac.tag_config = 13;
|
||||
moz_ac.tag_config = MozConfigTag::Sockettype;
|
||||
} else if tag == "username" {
|
||||
moz_ac.tag_config = 12;
|
||||
moz_ac.tag_config = MozConfigTag::Username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,212 +1,157 @@
|
||||
use std::ptr;
|
||||
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
use quick_xml::events::BytesEnd;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
/* ******************************************************************************
|
||||
* Outlook's Autodiscover
|
||||
******************************************************************************/
|
||||
#[repr(C)]
|
||||
struct outlk_autodiscover_t<'a> {
|
||||
pub in_0: &'a LoginParam,
|
||||
|
||||
/// Outlook's Autodiscover
|
||||
struct OutlookAutodiscover {
|
||||
pub out: LoginParam,
|
||||
pub out_imap_set: libc::c_int,
|
||||
pub out_smtp_set: libc::c_int,
|
||||
pub tag_config: libc::c_int,
|
||||
pub config: [*mut libc::c_char; 6],
|
||||
pub out_imap_set: bool,
|
||||
pub out_smtp_set: bool,
|
||||
pub config_type: Option<String>,
|
||||
pub config_server: String,
|
||||
pub config_port: i32,
|
||||
pub config_ssl: String,
|
||||
pub config_redirecturl: Option<String>,
|
||||
}
|
||||
|
||||
pub unsafe fn outlk_autodiscover(
|
||||
pub fn outlk_autodiscover(
|
||||
context: &Context,
|
||||
url__: &str,
|
||||
param_in: &LoginParam,
|
||||
url: &str,
|
||||
_param_in: &LoginParam,
|
||||
) -> Option<LoginParam> {
|
||||
let mut xml_raw: *mut libc::c_char = ptr::null_mut();
|
||||
let mut url = url__.strdup();
|
||||
let mut outlk_ad = outlk_autodiscover_t {
|
||||
in_0: param_in,
|
||||
out: LoginParam::new(),
|
||||
out_imap_set: 0,
|
||||
out_smtp_set: 0,
|
||||
tag_config: 0,
|
||||
config: [ptr::null_mut(); 6],
|
||||
};
|
||||
let ok_to_continue;
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if i >= 10 {
|
||||
ok_to_continue = true;
|
||||
break;
|
||||
}
|
||||
libc::memset(
|
||||
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
|
||||
0,
|
||||
::std::mem::size_of::<outlk_autodiscover_t>(),
|
||||
);
|
||||
xml_raw = read_autoconf_file(context, as_str(url));
|
||||
if xml_raw.is_null() {
|
||||
ok_to_continue = false;
|
||||
break;
|
||||
}
|
||||
let mut url = url.to_string();
|
||||
/* Follow up to 10 xml-redirects (http-redirects are followed in read_autoconf_file() */
|
||||
for _i in 0..10 {
|
||||
let mut outlk_ad = OutlookAutodiscover {
|
||||
out: LoginParam::new(),
|
||||
out_imap_set: false,
|
||||
out_smtp_set: false,
|
||||
config_type: None,
|
||||
config_server: String::new(),
|
||||
config_port: 0,
|
||||
config_ssl: String::new(),
|
||||
config_redirecturl: None,
|
||||
};
|
||||
|
||||
let mut reader = quick_xml::Reader::from_str(as_str(xml_raw));
|
||||
reader.trim_text(true);
|
||||
if let Some(xml_raw) = read_autoconf_file(context, &url) {
|
||||
let mut reader = quick_xml::Reader::from_str(&xml_raw);
|
||||
reader.trim_text(true);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
loop {
|
||||
match reader.read_event(&mut buf) {
|
||||
Ok(quick_xml::events::Event::Start(ref e)) => {
|
||||
outlk_autodiscover_starttag_cb(e, &mut outlk_ad)
|
||||
let mut current_tag: Option<String> = None;
|
||||
|
||||
loop {
|
||||
match reader.read_event(&mut buf) {
|
||||
Ok(quick_xml::events::Event::Start(ref e)) => {
|
||||
let tag = String::from_utf8_lossy(e.name()).trim().to_lowercase();
|
||||
|
||||
if tag == "protocol" {
|
||||
outlk_ad.config_type = None;
|
||||
outlk_ad.config_server = String::new();
|
||||
outlk_ad.config_port = 0;
|
||||
outlk_ad.config_ssl = String::new();
|
||||
outlk_ad.config_redirecturl = None;
|
||||
|
||||
current_tag = None;
|
||||
} else {
|
||||
current_tag = Some(tag);
|
||||
}
|
||||
}
|
||||
Ok(quick_xml::events::Event::End(ref e)) => {
|
||||
outlk_autodiscover_endtag_cb(e, &mut outlk_ad);
|
||||
current_tag = None;
|
||||
}
|
||||
Ok(quick_xml::events::Event::Text(ref e)) => {
|
||||
let val = e.unescape_and_decode(&reader).unwrap_or_default();
|
||||
|
||||
if let Some(ref tag) = current_tag {
|
||||
match tag.as_str() {
|
||||
"type" => outlk_ad.config_type = Some(val.trim().to_string()),
|
||||
"server" => outlk_ad.config_server = val.trim().to_string(),
|
||||
"port" => {
|
||||
outlk_ad.config_port = val.trim().parse().unwrap_or_default()
|
||||
}
|
||||
"ssl" => outlk_ad.config_ssl = val.trim().to_string(),
|
||||
"redirecturl" => {
|
||||
outlk_ad.config_redirecturl = Some(val.trim().to_string())
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
context,
|
||||
"Configure xml: Error at position {}: {:?}",
|
||||
reader.buffer_position(),
|
||||
e
|
||||
);
|
||||
}
|
||||
Ok(quick_xml::events::Event::Eof) => break,
|
||||
_ => (),
|
||||
}
|
||||
Ok(quick_xml::events::Event::End(ref e)) => {
|
||||
outlk_autodiscover_endtag_cb(e, &mut outlk_ad)
|
||||
}
|
||||
Ok(quick_xml::events::Event::Text(ref e)) => {
|
||||
outlk_autodiscover_text_cb(e, &mut outlk_ad, &reader)
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
context,
|
||||
"Configure xml: Error at position {}: {:?}",
|
||||
reader.buffer_position(),
|
||||
e
|
||||
);
|
||||
}
|
||||
Ok(quick_xml::events::Event::Eof) => break,
|
||||
_ => (),
|
||||
buf.clear();
|
||||
}
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
if !(!outlk_ad.config[5].is_null()
|
||||
&& 0 != *outlk_ad.config[5usize].offset(0isize) as libc::c_int)
|
||||
{
|
||||
ok_to_continue = true;
|
||||
break;
|
||||
}
|
||||
free(url as *mut libc::c_void);
|
||||
url = dc_strdup(outlk_ad.config[5usize]);
|
||||
|
||||
outlk_clean_config(&mut outlk_ad);
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
xml_raw = ptr::null_mut();
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if ok_to_continue {
|
||||
if outlk_ad.out.mail_server.is_empty()
|
||||
|| outlk_ad.out.mail_port == 0
|
||||
|| outlk_ad.out.send_server.is_empty()
|
||||
|| outlk_ad.out.send_port == 0
|
||||
{
|
||||
let r = outlk_ad.out.to_string();
|
||||
warn!(context, "Bad or incomplete autoconfig: {}", r,);
|
||||
free(url as *mut libc::c_void);
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
outlk_clean_config(&mut outlk_ad);
|
||||
|
||||
// XML redirect via redirecturl
|
||||
if outlk_ad.config_redirecturl.is_none()
|
||||
|| outlk_ad.config_redirecturl.as_ref().unwrap().is_empty()
|
||||
{
|
||||
if outlk_ad.out.mail_server.is_empty()
|
||||
|| outlk_ad.out.mail_port == 0
|
||||
|| outlk_ad.out.send_server.is_empty()
|
||||
|| outlk_ad.out.send_port == 0
|
||||
{
|
||||
let r = outlk_ad.out.to_string();
|
||||
warn!(context, "Bad or incomplete autoconfig: {}", r,);
|
||||
return None;
|
||||
}
|
||||
return Some(outlk_ad.out);
|
||||
} else {
|
||||
url = outlk_ad.config_redirecturl.unwrap();
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
free(url as *mut libc::c_void);
|
||||
free(xml_raw as *mut libc::c_void);
|
||||
outlk_clean_config(&mut outlk_ad);
|
||||
Some(outlk_ad.out)
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn outlk_clean_config(mut outlk_ad: *mut outlk_autodiscover_t) {
|
||||
for i in 0..6 {
|
||||
free((*outlk_ad).config[i] as *mut libc::c_void);
|
||||
(*outlk_ad).config[i] = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
fn outlk_autodiscover_text_cb<B: std::io::BufRead>(
|
||||
event: &BytesText,
|
||||
outlk_ad: &mut outlk_autodiscover_t,
|
||||
reader: &quick_xml::Reader<B>,
|
||||
) {
|
||||
let val = event.unescape_and_decode(reader).unwrap_or_default();
|
||||
|
||||
unsafe {
|
||||
free(outlk_ad.config[outlk_ad.tag_config as usize].cast());
|
||||
outlk_ad.config[outlk_ad.tag_config as usize] = val.trim().strdup();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut outlk_autodiscover_t) {
|
||||
fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut OutlookAutodiscover) {
|
||||
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
|
||||
|
||||
if tag == "protocol" {
|
||||
if !outlk_ad.config[1].is_null() {
|
||||
let port = dc_atoi_null_is_0(outlk_ad.config[3]);
|
||||
let ssl_on = (!outlk_ad.config[4].is_null()
|
||||
&& strcasecmp(
|
||||
outlk_ad.config[4],
|
||||
b"on\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0) as libc::c_int;
|
||||
let ssl_off = (!outlk_ad.config[4].is_null()
|
||||
&& strcasecmp(
|
||||
outlk_ad.config[4],
|
||||
b"off\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0) as libc::c_int;
|
||||
if strcasecmp(
|
||||
outlk_ad.config[1],
|
||||
b"imap\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
&& outlk_ad.out_imap_set == 0
|
||||
{
|
||||
outlk_ad.out.mail_server = to_string(outlk_ad.config[2]);
|
||||
if let Some(type_) = &outlk_ad.config_type {
|
||||
let port = outlk_ad.config_port;
|
||||
let ssl_on = outlk_ad.config_ssl == "on";
|
||||
let ssl_off = outlk_ad.config_ssl == "off";
|
||||
if type_ == "imap" && !outlk_ad.out_imap_set {
|
||||
outlk_ad.out.mail_server =
|
||||
std::mem::replace(&mut outlk_ad.config_server, String::new());
|
||||
outlk_ad.out.mail_port = port;
|
||||
if 0 != ssl_on {
|
||||
if ssl_on {
|
||||
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
|
||||
} else if 0 != ssl_off {
|
||||
} else if ssl_off {
|
||||
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32
|
||||
}
|
||||
outlk_ad.out_imap_set = 1
|
||||
} else if strcasecmp(
|
||||
outlk_ad.config[1usize],
|
||||
b"smtp\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
&& outlk_ad.out_smtp_set == 0
|
||||
{
|
||||
outlk_ad.out.send_server = to_string(outlk_ad.config[2]);
|
||||
outlk_ad.out.send_port = port;
|
||||
if 0 != ssl_on {
|
||||
outlk_ad.out_imap_set = true
|
||||
} else if type_ == "smtp" && !outlk_ad.out_smtp_set {
|
||||
outlk_ad.out.send_server =
|
||||
std::mem::replace(&mut outlk_ad.config_server, String::new());
|
||||
outlk_ad.out.send_port = outlk_ad.config_port;
|
||||
if ssl_on {
|
||||
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
|
||||
} else if 0 != ssl_off {
|
||||
} else if ssl_off {
|
||||
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
}
|
||||
outlk_ad.out_smtp_set = 1
|
||||
outlk_ad.out_smtp_set = true
|
||||
}
|
||||
}
|
||||
outlk_clean_config(outlk_ad);
|
||||
}
|
||||
outlk_ad.tag_config = 0;
|
||||
}
|
||||
|
||||
fn outlk_autodiscover_starttag_cb(event: &BytesStart, outlk_ad: &mut outlk_autodiscover_t) {
|
||||
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
|
||||
|
||||
if tag == "protocol" {
|
||||
unsafe { outlk_clean_config(outlk_ad) };
|
||||
} else if tag == "type" {
|
||||
outlk_ad.tag_config = 1
|
||||
} else if tag == "server" {
|
||||
outlk_ad.tag_config = 2
|
||||
} else if tag == "port" {
|
||||
outlk_ad.tag_config = 3
|
||||
} else if tag == "ssl" {
|
||||
outlk_ad.tag_config = 4
|
||||
} else if tag == "redirecturl" {
|
||||
outlk_ad.tag_config = 5
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -129,23 +129,23 @@ pub const DC_CREATE_MVBOX: usize = 1;
|
||||
/// Force OAuth2 authorization. This flag does not skip automatic configuration.
|
||||
/// Before calling configure() with DC_LP_AUTH_OAUTH2 set,
|
||||
/// the user has to confirm access at the URL returned by dc_get_oauth2_url().
|
||||
pub const DC_LP_AUTH_OAUTH2: usize = 0x2;
|
||||
pub const DC_LP_AUTH_OAUTH2: i32 = 0x2;
|
||||
|
||||
/// Force NORMAL authorization, this is the default.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_AUTH_NORMAL: usize = 0x4;
|
||||
pub const DC_LP_AUTH_NORMAL: i32 = 0x4;
|
||||
|
||||
/// Connect to IMAP via STARTTLS.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_STARTTLS: usize = 0x100;
|
||||
pub const DC_LP_IMAP_SOCKET_STARTTLS: i32 = 0x100;
|
||||
|
||||
/// Connect to IMAP via SSL.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_SSL: usize = 0x200;
|
||||
pub const DC_LP_IMAP_SOCKET_SSL: i32 = 0x200;
|
||||
|
||||
/// Connect to IMAP unencrypted, this should not be used.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_PLAIN: usize = 0x400;
|
||||
pub const DC_LP_IMAP_SOCKET_PLAIN: i32 = 0x400;
|
||||
|
||||
/// Connect to SMTP via STARTTLS.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
@@ -160,9 +160,9 @@ pub const DC_LP_SMTP_SOCKET_SSL: usize = 0x20000;
|
||||
pub const DC_LP_SMTP_SOCKET_PLAIN: usize = 0x40000;
|
||||
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_AUTH_FLAGS: usize = (DC_LP_AUTH_OAUTH2 | DC_LP_AUTH_NORMAL);
|
||||
pub const DC_LP_AUTH_FLAGS: i32 = (DC_LP_AUTH_OAUTH2 | DC_LP_AUTH_NORMAL);
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
|
||||
pub const DC_LP_IMAP_SOCKET_FLAGS: i32 =
|
||||
(DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_SSL | DC_LP_IMAP_SOCKET_PLAIN);
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||
@@ -257,7 +257,7 @@ const DC_SHOW_EMAILS_ACCEPTED_CONTACTS: usize = 1;
|
||||
const DC_SHOW_EMAILS_ALL: usize = 2;
|
||||
|
||||
// TODO: Strings need some doumentation about used placeholders.
|
||||
// These constants are used to request strings using #DC_EVENT_GET_STRING.
|
||||
// These constants are used to set stock translation strings
|
||||
|
||||
const DC_STR_NOMESSAGES: usize = 1;
|
||||
const DC_STR_SELF: usize = 2;
|
||||
|
||||
@@ -63,12 +63,13 @@ pub struct Context {
|
||||
pub running_state: Arc<RwLock<RunningState>>,
|
||||
/// Mutex to avoid generating the key for the user more than once.
|
||||
pub generating_key_mutex: Mutex<()>,
|
||||
pub translated_stockstrings: RwLock<HashMap<usize, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct RunningState {
|
||||
pub ongoing_running: bool,
|
||||
pub shall_stop_ongoing: bool,
|
||||
shall_stop_ongoing: bool,
|
||||
}
|
||||
|
||||
/// Return some info about deltachat-core
|
||||
@@ -145,6 +146,7 @@ impl Context {
|
||||
probe_imap_network: Arc::new(RwLock::new(false)),
|
||||
perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
|
||||
generating_key_mutex: Mutex::new(()),
|
||||
translated_stockstrings: RwLock::new(HashMap::new()),
|
||||
};
|
||||
|
||||
ensure!(
|
||||
@@ -208,7 +210,9 @@ impl Context {
|
||||
.open(&path)
|
||||
{
|
||||
file.write_all(data)?;
|
||||
return Ok(format!("$BLOBDIR/{}", candidate_basename));
|
||||
let db_entry = format!("$BLOBDIR/{}", candidate_basename);
|
||||
self.call_cb(Event::NewBlobFile(db_entry.clone()));
|
||||
return Ok(db_entry);
|
||||
}
|
||||
}
|
||||
bail!("out of luck to create new blob file");
|
||||
@@ -218,22 +222,79 @@ impl Context {
|
||||
(*self.cb)(self, event)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Ongoing process allocation/free/check
|
||||
******************************************************************************/
|
||||
|
||||
pub fn alloc_ongoing(&self) -> bool {
|
||||
if self.has_ongoing() {
|
||||
warn!(self, "There is already another ongoing process running.",);
|
||||
|
||||
false
|
||||
} else {
|
||||
let s_a = self.running_state.clone();
|
||||
let mut s = s_a.write().unwrap();
|
||||
|
||||
s.ongoing_running = true;
|
||||
s.shall_stop_ongoing = false;
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free_ongoing(&self) {
|
||||
let s_a = self.running_state.clone();
|
||||
let mut s = s_a.write().unwrap();
|
||||
|
||||
s.ongoing_running = false;
|
||||
s.shall_stop_ongoing = true;
|
||||
}
|
||||
|
||||
pub fn has_ongoing(&self) -> bool {
|
||||
let s_a = self.running_state.clone();
|
||||
let s = s_a.read().unwrap();
|
||||
|
||||
s.ongoing_running || !s.shall_stop_ongoing
|
||||
}
|
||||
|
||||
/// Signal an ongoing process to stop.
|
||||
pub fn stop_ongoing(&self) {
|
||||
let s_a = self.running_state.clone();
|
||||
let mut s = s_a.write().unwrap();
|
||||
|
||||
if s.ongoing_running && !s.shall_stop_ongoing {
|
||||
info!(self, "Signaling the ongoing process to stop ASAP.",);
|
||||
s.shall_stop_ongoing = true;
|
||||
} else {
|
||||
info!(self, "No ongoing process to stop.",);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn shall_stop_ongoing(&self) -> bool {
|
||||
self.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* UI chat/message related API
|
||||
******************************************************************************/
|
||||
|
||||
pub fn get_info(&self) -> HashMap<&'static str, String> {
|
||||
let unset = "0";
|
||||
let l = LoginParam::from_database(self, "");
|
||||
let l2 = LoginParam::from_database(self, "configured_");
|
||||
let displayname = self.sql.get_config(self, "displayname");
|
||||
let displayname = self.get_config(Config::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 contacts = Contact::get_real_cnt(self) as usize;
|
||||
let is_configured = self
|
||||
.sql
|
||||
.get_config_int(self, "configured")
|
||||
.unwrap_or_default();
|
||||
let is_configured = self.get_config_int(Config::Configured);
|
||||
let dbversion = self
|
||||
.sql
|
||||
.get_config_int(self, "dbversion")
|
||||
.get_raw_config_int(self, "dbversion")
|
||||
.unwrap_or_default();
|
||||
|
||||
let e2ee_enabled = self.get_config_int(Config::E2eeEnabled);
|
||||
@@ -262,16 +323,16 @@ impl Context {
|
||||
let mvbox_move = self.get_config_int(Config::MvboxMove);
|
||||
let folders_configured = self
|
||||
.sql
|
||||
.get_config_int(self, "folders_configured")
|
||||
.get_raw_config_int(self, "folders_configured")
|
||||
.unwrap_or_default();
|
||||
|
||||
let configured_sentbox_folder = self
|
||||
.sql
|
||||
.get_config(self, "configured_sentbox_folder")
|
||||
.get_raw_config(self, "configured_sentbox_folder")
|
||||
.unwrap_or_else(|| "<unset>".to_string());
|
||||
let configured_mvbox_folder = self
|
||||
.sql
|
||||
.get_config(self, "configured_mvbox_folder")
|
||||
.get_raw_config(self, "configured_mvbox_folder")
|
||||
.unwrap_or_else(|| "<unset>".to_string());
|
||||
|
||||
let mut res = get_info();
|
||||
@@ -331,7 +392,7 @@ impl Context {
|
||||
Ok(ret)
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -375,7 +436,7 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn is_sentbox(&self, folder_name: impl AsRef<str>) -> bool {
|
||||
let sentbox_name = self.sql.get_config(self, "configured_sentbox_folder");
|
||||
let sentbox_name = self.sql.get_raw_config(self, "configured_sentbox_folder");
|
||||
if let Some(name) = sentbox_name {
|
||||
name == folder_name.as_ref()
|
||||
} else {
|
||||
@@ -384,7 +445,7 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn is_mvbox(&self, folder_name: impl AsRef<str>) -> bool {
|
||||
let mvbox_name = self.sql.get_config(self, "configured_mvbox_folder");
|
||||
let mvbox_name = self.sql.get_raw_config(self, "configured_mvbox_folder");
|
||||
|
||||
if let Some(name) = mvbox_name {
|
||||
name == folder_name.as_ref()
|
||||
@@ -394,12 +455,7 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn do_heuristics_moves(&self, folder: &str, msg_id: u32) {
|
||||
if self
|
||||
.sql
|
||||
.get_config_int(self, "mvbox_move")
|
||||
.unwrap_or_else(|| 1)
|
||||
== 0
|
||||
{
|
||||
if !self.get_config_bool(Config::MvboxMove) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ impl<'a> MimeParser<'a> {
|
||||
if self.get_last_nonmeta().is_some() {
|
||||
let mut mb_list: *mut mailimf_mailbox_list = ptr::null_mut();
|
||||
let mut index_0 = 0;
|
||||
let dn_field_c = CString::new(dn_field).unwrap();
|
||||
let dn_field_c = CString::new(dn_field).unwrap_or_default();
|
||||
|
||||
if mailimf_mailbox_list_parse(
|
||||
dn_field_c.as_ptr(),
|
||||
@@ -606,7 +606,6 @@ impl<'a> MimeParser<'a> {
|
||||
let old_part_count = self.parts.len();
|
||||
|
||||
/* regard `Content-Transfer-Encoding:` */
|
||||
let mut ok_to_continue = true;
|
||||
let mut desired_filename = String::default();
|
||||
let mut simplifier: Option<Simplify> = None;
|
||||
match mime_type {
|
||||
@@ -621,15 +620,14 @@ impl<'a> MimeParser<'a> {
|
||||
&& strcmp(charset, b"UTF-8\x00" as *const u8 as *const libc::c_char) != 0i32
|
||||
{
|
||||
if let Some(encoding) =
|
||||
Charset::for_label(CStr::from_ptr(charset).to_str().unwrap().as_bytes())
|
||||
Charset::for_label(CStr::from_ptr(charset).to_string_lossy().as_bytes())
|
||||
{
|
||||
let (res, _, _) = encoding.decode(&decoded_data);
|
||||
if res.is_empty() {
|
||||
/* no error - but nothing to add */
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
decoded_data = res.as_bytes().to_vec()
|
||||
return false;
|
||||
}
|
||||
decoded_data = res.as_bytes().to_vec()
|
||||
} else {
|
||||
warn!(
|
||||
self.context,
|
||||
@@ -639,31 +637,29 @@ impl<'a> MimeParser<'a> {
|
||||
);
|
||||
}
|
||||
}
|
||||
if ok_to_continue {
|
||||
/* check header directly as is_send_by_messenger is not yet set up */
|
||||
let is_msgrmsg = self.lookup_optional_field("Chat-Version").is_some();
|
||||
/* check header directly as is_send_by_messenger is not yet set up */
|
||||
let is_msgrmsg = self.lookup_optional_field("Chat-Version").is_some();
|
||||
|
||||
let simplified_txt = if decoded_data.is_empty() {
|
||||
"".into()
|
||||
} else {
|
||||
let input = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
let is_html = mime_type == 70;
|
||||
let simplified_txt = if decoded_data.is_empty() {
|
||||
"".into()
|
||||
} else {
|
||||
let input = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
let is_html = mime_type == 70;
|
||||
|
||||
simplifier.unwrap().simplify(&input, is_html, is_msgrmsg)
|
||||
};
|
||||
if !simplified_txt.is_empty() {
|
||||
let mut part = Part::default();
|
||||
part.typ = Viewtype::Text;
|
||||
part.mimetype = mime_type;
|
||||
part.msg = Some(simplified_txt);
|
||||
part.msg_raw =
|
||||
Some(std::string::String::from_utf8_lossy(&decoded_data).to_string());
|
||||
self.do_add_single_part(part);
|
||||
}
|
||||
simplifier.unwrap().simplify(&input, is_html, is_msgrmsg)
|
||||
};
|
||||
if !simplified_txt.is_empty() {
|
||||
let mut part = Part::default();
|
||||
part.typ = Viewtype::Text;
|
||||
part.mimetype = mime_type;
|
||||
part.msg = Some(simplified_txt);
|
||||
part.msg_raw =
|
||||
Some(std::string::String::from_utf8_lossy(&decoded_data).to_string());
|
||||
self.do_add_single_part(part);
|
||||
}
|
||||
|
||||
if simplifier.unwrap().is_forwarded {
|
||||
self.is_forwarded = true;
|
||||
}
|
||||
if simplifier.unwrap().is_forwarded {
|
||||
self.is_forwarded = true;
|
||||
}
|
||||
}
|
||||
DC_MIMETYPE_IMAGE
|
||||
@@ -738,33 +734,29 @@ impl<'a> MimeParser<'a> {
|
||||
desired_filename =
|
||||
format!("file.{}", as_str((*(*mime).mm_content_type).ct_subtype));
|
||||
} else {
|
||||
ok_to_continue = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ok_to_continue {
|
||||
if desired_filename.starts_with("location")
|
||||
&& desired_filename.ends_with(".kml")
|
||||
{
|
||||
if !decoded_data.is_empty() {
|
||||
let d = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
self.location_kml = location::Kml::parse(self.context, &d).ok();
|
||||
}
|
||||
} else if desired_filename.starts_with("message")
|
||||
&& desired_filename.ends_with(".kml")
|
||||
{
|
||||
if !decoded_data.is_empty() {
|
||||
let d = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
self.message_kml = location::Kml::parse(self.context, &d).ok();
|
||||
}
|
||||
} else if !decoded_data.is_empty() {
|
||||
self.do_add_single_file_part(
|
||||
msg_type,
|
||||
mime_type,
|
||||
raw_mime.as_ref(),
|
||||
&decoded_data,
|
||||
&desired_filename,
|
||||
);
|
||||
if desired_filename.starts_with("location") && desired_filename.ends_with(".kml") {
|
||||
if !decoded_data.is_empty() {
|
||||
let d = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
self.location_kml = location::Kml::parse(self.context, &d).ok();
|
||||
}
|
||||
} else if desired_filename.starts_with("message")
|
||||
&& desired_filename.ends_with(".kml")
|
||||
{
|
||||
if !decoded_data.is_empty() {
|
||||
let d = std::string::String::from_utf8_lossy(&decoded_data);
|
||||
self.message_kml = location::Kml::parse(self.context, &d).ok();
|
||||
}
|
||||
} else if !decoded_data.is_empty() {
|
||||
self.do_add_single_file_part(
|
||||
msg_type,
|
||||
mime_type,
|
||||
raw_mime.as_ref(),
|
||||
&decoded_data,
|
||||
&desired_filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -890,7 +882,7 @@ impl<'a> MimeParser<'a> {
|
||||
unsafe {
|
||||
let fld_message_id = (*field).fld_data.fld_message_id;
|
||||
if !fld_message_id.is_null() {
|
||||
return Some(to_string((*fld_message_id).mid_value));
|
||||
return Some(to_string_lossy((*fld_message_id).mid_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use itertools::join;
|
||||
@@ -436,7 +435,7 @@ unsafe fn add_parts(
|
||||
to_ids,
|
||||
chat_id,
|
||||
&mut chat_id_blocked,
|
||||
);
|
||||
)?;
|
||||
if 0 != *chat_id && Blocked::Not != chat_id_blocked && create_blocked == Blocked::Not {
|
||||
chat::unblock(context, *chat_id);
|
||||
chat_id_blocked = Blocked::Not;
|
||||
@@ -521,7 +520,7 @@ unsafe fn add_parts(
|
||||
to_ids,
|
||||
chat_id,
|
||||
&mut chat_id_blocked,
|
||||
);
|
||||
)?;
|
||||
if 0 != *chat_id && Blocked::Not != chat_id_blocked {
|
||||
chat::unblock(context, *chat_id);
|
||||
chat_id_blocked = Blocked::Not;
|
||||
@@ -581,11 +580,11 @@ unsafe fn add_parts(
|
||||
);
|
||||
|
||||
// unarchive chat
|
||||
chat::unarchive(context, *chat_id).unwrap();
|
||||
chat::unarchive(context, *chat_id)?;
|
||||
|
||||
// if the mime-headers should be saved, find out its size
|
||||
// (the mime-header ends with an empty line)
|
||||
let save_mime_headers = context.sql.get_config_bool(context, "save_mime_headers");
|
||||
let save_mime_headers = context.get_config_bool(Config::SaveMimeHeaders);
|
||||
if let Some(field) = mime_parser.lookup_field_typ("In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO) {
|
||||
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
|
||||
if !fld_in_reply_to.is_null() {
|
||||
@@ -688,8 +687,8 @@ unsafe fn add_parts(
|
||||
} else {
|
||||
None
|
||||
},
|
||||
to_string(mime_in_reply_to),
|
||||
to_string(mime_references),
|
||||
to_string_lossy(mime_in_reply_to),
|
||||
to_string_lossy(mime_references),
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
@@ -852,12 +851,7 @@ unsafe fn handle_reports(
|
||||
let mut param = Params::new();
|
||||
param.set(Param::ServerFolder, server_folder.as_ref());
|
||||
param.set_int(Param::ServerUid, server_uid as i32);
|
||||
if mime_parser.is_send_by_messenger
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mvbox_move")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
if mime_parser.is_send_by_messenger && context.get_config_bool(Config::MvboxMove) {
|
||||
param.set_int(Param::AlsoMove, 1);
|
||||
}
|
||||
job_add(context, Action::MarkseenMdnOnImap, 0, param, 0);
|
||||
@@ -973,7 +967,7 @@ unsafe fn create_or_lookup_group(
|
||||
to_ids: &mut Vec<u32>,
|
||||
ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
let group_explicitly_left: bool;
|
||||
let mut chat_id = 0;
|
||||
let mut chat_id_blocked = Blocked::Not;
|
||||
@@ -1031,7 +1025,7 @@ unsafe fn create_or_lookup_group(
|
||||
{
|
||||
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
|
||||
if !fld_in_reply_to.is_null() {
|
||||
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
|
||||
grpid = to_string_lossy(dc_extract_grpid_from_rfc724_mid_list(
|
||||
(*fld_in_reply_to).mid_list,
|
||||
));
|
||||
}
|
||||
@@ -1042,7 +1036,7 @@ unsafe fn create_or_lookup_group(
|
||||
{
|
||||
let fld_references = (*field).fld_data.fld_references;
|
||||
if !fld_references.is_null() {
|
||||
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
|
||||
grpid = to_string_lossy(dc_extract_grpid_from_rfc724_mid_list(
|
||||
(*fld_references).mid_list,
|
||||
));
|
||||
}
|
||||
@@ -1058,9 +1052,9 @@ unsafe fn create_or_lookup_group(
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
);
|
||||
)?;
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1159,8 +1153,7 @@ unsafe fn create_or_lookup_group(
|
||||
group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
|
||||
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
if chat_id == 0
|
||||
&& !mime_parser.is_mailinglist_message()
|
||||
@@ -1186,7 +1179,7 @@ unsafe fn create_or_lookup_group(
|
||||
}
|
||||
if 0 == allow_creation {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
chat_id = create_group_record(
|
||||
context,
|
||||
@@ -1214,10 +1207,10 @@ unsafe fn create_or_lookup_group(
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// execute group commands
|
||||
@@ -1270,7 +1263,7 @@ unsafe fn create_or_lookup_group(
|
||||
} else {
|
||||
chat.param.set(Param::ProfileImage, grpimage);
|
||||
}
|
||||
chat.update_param(context).unwrap();
|
||||
chat.update_param(context)?;
|
||||
send_EVENT_CHAT_MODIFIED = 1;
|
||||
}
|
||||
}
|
||||
@@ -1334,11 +1327,12 @@ unsafe fn create_or_lookup_group(
|
||||
to_ids,
|
||||
&mut chat_id,
|
||||
&mut chat_id_blocked,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// Handle groups for received messages
|
||||
@@ -1351,7 +1345,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
to_ids: &mut Vec<u32>,
|
||||
ret_chat_id: *mut u32,
|
||||
ret_chat_id_blocked: &mut Blocked,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
// if we're here, no grpid was found, check there is an existing ad-hoc
|
||||
// group matching the to-list or if we can create one
|
||||
let mut chat_id = 0;
|
||||
@@ -1371,7 +1365,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
if to_ids.is_empty() || mime_parser.is_mailinglist_message() {
|
||||
// too few contacts or a mailinglist
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut member_ids = to_ids.clone();
|
||||
@@ -1384,10 +1378,10 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
if member_ids.len() < 3 {
|
||||
// too few contacts given
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let chat_ids = search_chat_ids_by_contact_ids(context, &member_ids);
|
||||
let chat_ids = search_chat_ids_by_contact_ids(context, &member_ids)?;
|
||||
if !chat_ids.is_empty() {
|
||||
let chat_ids_str = join(chat_ids.iter().map(|x| x.to_string()), ",");
|
||||
let res = context.sql.query_row(
|
||||
@@ -1407,13 +1401,13 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
chat_id_blocked = id_blocked;
|
||||
/* success, chat found */
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if 0 == allow_creation {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
// we do not check if the message is a reply to another group, this may result in
|
||||
// chats with unclear member list. instead we create a new group in the following lines ...
|
||||
@@ -1423,7 +1417,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
let grpid = create_adhoc_grp_id(context, &member_ids);
|
||||
if grpid.is_empty() {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// use subject as initial chat name
|
||||
@@ -1449,6 +1443,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
context.call_cb(Event::ChatModified(chat_id));
|
||||
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn create_group_record(
|
||||
@@ -1490,8 +1485,7 @@ fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> String {
|
||||
*/
|
||||
let member_ids_str = join(member_ids.iter().map(|x| x.to_string()), ",");
|
||||
let member_cs = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_else(|| "no-self".to_string())
|
||||
.to_lowercase();
|
||||
|
||||
@@ -1527,7 +1521,10 @@ fn hex_hash(s: impl AsRef<str>) -> String {
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<u32>) -> Vec<u32> {
|
||||
fn search_chat_ids_by_contact_ids(
|
||||
context: &Context,
|
||||
unsorted_contact_ids: &Vec<u32>,
|
||||
) -> Result<Vec<u32>> {
|
||||
/* searches chat_id's by the given contact IDs, may return zero, one or more chat_id's */
|
||||
let mut contact_ids = Vec::with_capacity(23);
|
||||
let mut chat_ids = Vec::with_capacity(23);
|
||||
@@ -1582,11 +1579,11 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
).unwrap(); // TODO: better error handling
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
chat_ids
|
||||
Ok(chat_ids)
|
||||
}
|
||||
|
||||
fn check_verified_properties(
|
||||
@@ -1688,13 +1685,7 @@ fn set_better_msg(mime_parser: &mut MimeParser, better_msg: impl AsRef<str>) {
|
||||
|
||||
unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimeParser) -> libc::c_int {
|
||||
/* check if the message is a reply to a known message; the replies are identified by the Message-ID from
|
||||
`In-Reply-To`/`References:` (to support non-Delta-Clients) or from `Chat-Predecessor:` (Delta clients, see comment in dc_chat.c) */
|
||||
if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Predecessor") {
|
||||
let optional_field_c = CString::new(optional_field).unwrap();
|
||||
if 0 != is_known_rfc724_mid(context, optional_field_c.as_ptr()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
`In-Reply-To`/`References:` (to support non-Delta-Clients) */
|
||||
|
||||
if let Some(field) = mime_parser.lookup_field("In-Reply-To") {
|
||||
if (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int {
|
||||
@@ -1942,8 +1933,7 @@ unsafe fn add_or_lookup_contact_by_addr(
|
||||
}
|
||||
*check_self = 0;
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
if addr_cmp(self_addr, as_str(addr_spec)) {
|
||||
|
||||
@@ -86,7 +86,7 @@ pub(crate) fn dc_decode_header_words(input: &str) -> String {
|
||||
if r as u32 != MAILIMF_NO_ERROR || out.is_null() {
|
||||
input.to_string()
|
||||
} else {
|
||||
let res = to_string(out);
|
||||
let res = to_string_lossy(out);
|
||||
free(out.cast());
|
||||
res
|
||||
}
|
||||
|
||||
220
src/dc_tools.rs
220
src/dc_tools.rs
@@ -17,6 +17,7 @@ use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
|
||||
pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||
0 != v && 0 == v & (v - 1)
|
||||
@@ -29,11 +30,11 @@ pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string};
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string_lossy};
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup(str_a);
|
||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
||||
/// assert_eq!(to_string_lossy(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
@@ -50,83 +51,6 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
|
||||
if !s.is_null() {
|
||||
as_str(s).parse().unwrap_or_default()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dc_ltrim(buf: *mut libc::c_char) {
|
||||
let mut len: libc::size_t;
|
||||
let mut cur: *const libc::c_uchar;
|
||||
if !buf.is_null() && 0 != *buf as libc::c_int {
|
||||
len = strlen(buf);
|
||||
cur = buf as *const libc::c_uchar;
|
||||
while 0 != *cur as libc::c_int && 0 != libc::isspace(*cur as libc::c_int) {
|
||||
cur = cur.offset(1isize);
|
||||
len = len.wrapping_sub(1)
|
||||
}
|
||||
if buf as *const libc::c_uchar != cur {
|
||||
libc::memmove(
|
||||
buf as *mut libc::c_void,
|
||||
cur as *const libc::c_void,
|
||||
len.wrapping_add(1),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn dc_rtrim(buf: *mut libc::c_char) {
|
||||
let mut len: libc::size_t;
|
||||
let mut cur: *mut libc::c_uchar;
|
||||
if !buf.is_null() && 0 != *buf as libc::c_int {
|
||||
len = strlen(buf);
|
||||
cur = (buf as *mut libc::c_uchar)
|
||||
.offset(len as isize)
|
||||
.offset(-1isize);
|
||||
while cur != buf as *mut libc::c_uchar && 0 != libc::isspace(*cur as libc::c_int) {
|
||||
cur = cur.offset(-1isize);
|
||||
len = len.wrapping_sub(1)
|
||||
}
|
||||
*cur.offset(
|
||||
(if 0 != libc::isspace(*cur as libc::c_int) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}) as isize,
|
||||
) = '\u{0}' as i32 as libc::c_uchar
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn dc_trim(buf: *mut libc::c_char) {
|
||||
dc_ltrim(buf);
|
||||
dc_rtrim(buf);
|
||||
}
|
||||
|
||||
/* remove all \r characters from string */
|
||||
pub(crate) unsafe fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
||||
/* search for first `\r` */
|
||||
let mut p1: *const libc::c_char = buf;
|
||||
while 0 != *p1 {
|
||||
if *p1 as libc::c_int == '\r' as i32 {
|
||||
break;
|
||||
}
|
||||
p1 = p1.offset(1isize)
|
||||
}
|
||||
/* p1 is `\r` or null-byte; start removing `\r` */
|
||||
let mut p2: *mut libc::c_char = p1 as *mut libc::c_char;
|
||||
while 0 != *p1 {
|
||||
if *p1 as libc::c_int != '\r' as i32 {
|
||||
*p2 = *p1;
|
||||
p2 = p2.offset(1isize)
|
||||
}
|
||||
p1 = p1.offset(1isize)
|
||||
}
|
||||
*p2 = 0 as libc::c_char;
|
||||
}
|
||||
|
||||
/// Shortens a string to a specified length and adds "..." or "[...]" to the end of
|
||||
/// the shortened string.
|
||||
pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Cow<str> {
|
||||
@@ -512,10 +436,14 @@ pub(crate) fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path
|
||||
return false;
|
||||
}
|
||||
|
||||
let dpath = format!("{}", path.as_ref().to_string_lossy());
|
||||
match fs::remove_file(path_abs) {
|
||||
Ok(_) => true,
|
||||
Ok(_) => {
|
||||
context.call_cb(Event::DeletedBlobFile(dpath));
|
||||
true
|
||||
}
|
||||
Err(_err) => {
|
||||
warn!(context, "Cannot delete \"{}\".", path.as_ref().display());
|
||||
warn!(context, "Cannot delete \"{}\".", dpath);
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -596,6 +524,25 @@ pub fn dc_read_file<P: AsRef<std::path::Path>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_open_file<P: AsRef<std::path::Path>>(
|
||||
context: &Context,
|
||||
path: P,
|
||||
) -> Result<std::fs::File, Error> {
|
||||
let path_abs = dc_get_abs_path(context, &path);
|
||||
|
||||
match fs::File::open(&path_abs) {
|
||||
Ok(bytes) => Ok(bytes),
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot read \"{}\" or file is empty.",
|
||||
path.as_ref().display()
|
||||
);
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dc_get_next_backup_path(
|
||||
folder: impl AsRef<Path>,
|
||||
backup_time: i64,
|
||||
@@ -632,7 +579,10 @@ fn dc_make_rel_path(context: &Context, path: &mut String) {
|
||||
.map(|s| path.starts_with(s))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
*path = path.replace(context.get_blobdir().to_str().unwrap(), "$BLOBDIR");
|
||||
*path = path.replace(
|
||||
context.get_blobdir().to_str().unwrap_or_default(),
|
||||
"$BLOBDIR",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,22 +743,6 @@ impl<T: AsRef<str>> StrExt for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_str().map(|s| s.to_string()).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Non utf8 string: '{:?}' ({:?})",
|
||||
cstr.to_string_lossy(),
|
||||
err
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_string_lossy(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
@@ -816,9 +750,7 @@ pub fn to_string_lossy(s: *const libc::c_char) -> String {
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|_| cstr.to_string_lossy().to_string())
|
||||
cstr.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
pub fn as_str<'a>(s: *const libc::c_char) -> &'a str {
|
||||
@@ -1023,54 +955,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_ltrim() {
|
||||
unsafe {
|
||||
let html: *const libc::c_char =
|
||||
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
|
||||
let out: *mut libc::c_char = strndup(html, strlen(html) as libc::c_ulong);
|
||||
|
||||
dc_ltrim(out);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(out as *const libc::c_char).to_str().unwrap(),
|
||||
"line1<br>\r\n\r\n\r\rline2\n\r"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_rtrim() {
|
||||
unsafe {
|
||||
let html: *const libc::c_char =
|
||||
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
|
||||
let out: *mut libc::c_char = strndup(html, strlen(html) as libc::c_ulong);
|
||||
|
||||
dc_rtrim(out);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(out as *const libc::c_char).to_str().unwrap(),
|
||||
"\r\r\nline1<br>\r\n\r\n\r\rline2"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_trim() {
|
||||
unsafe {
|
||||
let html: *const libc::c_char =
|
||||
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
|
||||
let out: *mut libc::c_char = strndup(html, strlen(html) as libc::c_ulong);
|
||||
|
||||
dc_trim(out);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(out as *const libc::c_char).to_str().unwrap(),
|
||||
"line1<br>\r\n\r\n\r\rline2"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rust_ftoa() {
|
||||
assert_eq!("1.22", format!("{}", 1.22));
|
||||
@@ -1347,6 +1231,25 @@ mod tests {
|
||||
assert_eq!(grpid, Some("1234567890123456"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_create_outgoing_rfc724_mid() {
|
||||
// create a normal message-id
|
||||
let mid = dc_create_outgoing_rfc724_mid(None, "foo@bar.de");
|
||||
assert!(mid.starts_with("Mr."));
|
||||
assert!(mid.ends_with("bar.de"));
|
||||
assert!(dc_extract_grpid_from_rfc724_mid(mid.as_str()).is_none());
|
||||
|
||||
// create a message-id containing a group-id
|
||||
let grpid = dc_create_id();
|
||||
let mid = dc_create_outgoing_rfc724_mid(Some(&grpid), "foo@bar.de");
|
||||
assert!(mid.starts_with("Gr."));
|
||||
assert!(mid.ends_with("bar.de"));
|
||||
assert_eq!(
|
||||
dc_extract_grpid_from_rfc724_mid(mid.as_str()),
|
||||
Some(grpid.as_str())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_emailaddress_parse() {
|
||||
assert_eq!(EmailAddress::new("").is_ok(), false);
|
||||
@@ -1431,8 +1334,8 @@ mod tests {
|
||||
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)
|
||||
to_string_lossy(res),
|
||||
to_string_lossy(b"hell\x00" as *const u8 as *const libc::c_char)
|
||||
);
|
||||
assert_eq!(strlen(res), 4);
|
||||
free(res as *mut _);
|
||||
@@ -1520,19 +1423,4 @@ mod tests {
|
||||
let listflags: u32 = DC_GCL_VERIFIED_ONLY.try_into().unwrap();
|
||||
assert!(listflags_has(listflags, DC_GCL_ADD_SELF) == false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_remove_cr_chars() {
|
||||
unsafe {
|
||||
let input = "foo\r\nbar".strdup();
|
||||
dc_remove_cr_chars(input);
|
||||
assert_eq!("foo\nbar", to_string(input));
|
||||
free(input.cast());
|
||||
|
||||
let input = "\rfoo\r\rbar\r".strdup();
|
||||
dc_remove_cr_chars(input);
|
||||
assert_eq!("foobar", to_string(input));
|
||||
free(input.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
src/e2ee.rs
13
src/e2ee.rs
@@ -28,7 +28,7 @@ use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::mimefactory::MimeFactory;
|
||||
use crate::peerstate::*;
|
||||
use crate::pgp::*;
|
||||
use crate::pgp;
|
||||
use crate::securejoin::handle_degrade_event;
|
||||
use crate::wrapmime;
|
||||
use crate::wrapmime::*;
|
||||
@@ -47,7 +47,8 @@ pub struct EncryptHelper {
|
||||
impl EncryptHelper {
|
||||
pub fn new(context: &Context) -> Result<EncryptHelper> {
|
||||
let prefer_encrypt =
|
||||
EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled)).unwrap();
|
||||
EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled))
|
||||
.unwrap_or_default();
|
||||
let addr = match context.get_config(Config::ConfiguredAddr) {
|
||||
None => {
|
||||
bail!("addr not configured!");
|
||||
@@ -210,7 +211,7 @@ impl EncryptHelper {
|
||||
"could not write/allocate"
|
||||
);
|
||||
|
||||
let ctext = dc_pgp_pk_encrypt(
|
||||
let ctext = pgp::pk_encrypt(
|
||||
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
|
||||
&keyring,
|
||||
sign_key.as_ref(),
|
||||
@@ -262,7 +263,7 @@ pub fn try_decrypt(
|
||||
in_out_message: *mut Mailmime,
|
||||
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
|
||||
// just a pointer into mailmime structure, must not be freed
|
||||
let imffields = unsafe { mailmime_find_mailimf_fields(in_out_message) };
|
||||
let imffields = mailmime_find_mailimf_fields(in_out_message);
|
||||
ensure!(
|
||||
!in_out_message.is_null() && !imffields.is_null(),
|
||||
"corrupt invalid mime inputs"
|
||||
@@ -397,7 +398,7 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
|
||||
context,
|
||||
"Generating keypair with {} bits, e={} ...", 2048, 65537,
|
||||
);
|
||||
match dc_pgp_create_keypair(&self_addr) {
|
||||
match pgp::create_keypair(&self_addr) {
|
||||
Some((public_key, private_key)) => {
|
||||
match dc_key_save_self_keypair(
|
||||
context,
|
||||
@@ -580,7 +581,7 @@ fn decrypt_part(
|
||||
// we should only have one decryption happening
|
||||
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
|
||||
|
||||
let plain = match dc_pgp_pk_decrypt(
|
||||
let plain = match pgp::pk_decrypt(
|
||||
&data,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
|
||||
12
src/error.rs
12
src/error.rs
@@ -70,12 +70,6 @@ impl From<std::str::Utf8Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::FromUtf8Error> for Error {
|
||||
fn from(err: std::string::FromUtf8Error) -> Error {
|
||||
Error::FromUtf8(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<image_meta::ImageError> for Error {
|
||||
fn from(err: image_meta::ImageError) -> Error {
|
||||
Error::Image(err)
|
||||
@@ -94,6 +88,12 @@ impl From<pgp::errors::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::FromUtf8Error> for Error {
|
||||
fn from(err: std::string::FromUtf8Error) -> Error {
|
||||
Error::FromUtf8(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bail {
|
||||
($e:expr) => {
|
||||
|
||||
@@ -2,8 +2,6 @@ use std::path::PathBuf;
|
||||
|
||||
use strum::EnumProperty;
|
||||
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
impl Event {
|
||||
/// Returns the corresponding Event id.
|
||||
pub fn as_id(&self) -> i32 {
|
||||
@@ -54,6 +52,18 @@ pub enum Event {
|
||||
#[strum(props(id = "105"))]
|
||||
ImapMessageMoved(String),
|
||||
|
||||
/// Emitted when an new file in the $BLOBDIR was created
|
||||
///
|
||||
/// @return 0
|
||||
#[strum(props(id = "150"))]
|
||||
NewBlobFile(String),
|
||||
|
||||
/// Emitted when an new file in the $BLOBDIR was created
|
||||
///
|
||||
/// @return 0
|
||||
#[strum(props(id = "151"))]
|
||||
DeletedBlobFile(String),
|
||||
|
||||
/// The library-user should write a warning string to the log.
|
||||
/// Passed to the callback given to dc_context_new().
|
||||
///
|
||||
@@ -225,17 +235,4 @@ pub enum Event {
|
||||
/// @return 0
|
||||
#[strum(props(id = "2061"))]
|
||||
SecurejoinJoinerProgress { contact_id: u32, progress: usize },
|
||||
|
||||
// the following events are functions that should be provided by the frontends
|
||||
/// Requeste a localized string from the frontend.
|
||||
/// @param data1 (int) ID of the string to request, one of the DC_STR_/// constants.
|
||||
/// @param data2 (int) The count. If the requested string contains a placeholder for a numeric value,
|
||||
/// the ui may use this value to return different strings on different plural forms.
|
||||
/// @return (const char*) Null-terminated UTF-8 string.
|
||||
/// The string will be free()'d by the core,
|
||||
/// so it must be allocated using malloc() or a compatible function.
|
||||
/// Return 0 if the ui cannot provide the requested string
|
||||
/// the core will use a default string in english language then.
|
||||
#[strum(props(id = "2091"))]
|
||||
GetString { id: StockMessage, count: usize },
|
||||
}
|
||||
|
||||
52
src/imap.rs
52
src/imap.rs
@@ -384,7 +384,7 @@ impl Imap {
|
||||
return true;
|
||||
}
|
||||
|
||||
let server_flags = self.config.read().unwrap().server_flags;
|
||||
let server_flags = self.config.read().unwrap().server_flags as i32;
|
||||
|
||||
let connection_res: imap::error::Result<Client> =
|
||||
if (server_flags & (DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_PLAIN)) != 0 {
|
||||
@@ -693,12 +693,20 @@ impl Imap {
|
||||
|
||||
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
|
||||
let key = format!("imap.mailbox.{}", folder.as_ref());
|
||||
if let Some(entry) = context.sql.get_config(context, &key) {
|
||||
if let Some(entry) = context.sql.get_raw_config(context, &key) {
|
||||
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
|
||||
let mut parts = entry.split(':');
|
||||
(
|
||||
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
|
||||
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
|
||||
parts
|
||||
.next()
|
||||
.unwrap_or_default()
|
||||
.parse()
|
||||
.unwrap_or_else(|_| 0),
|
||||
parts
|
||||
.next()
|
||||
.unwrap_or_default()
|
||||
.parse()
|
||||
.unwrap_or_else(|_| 0),
|
||||
)
|
||||
} else {
|
||||
(0, 0)
|
||||
@@ -742,7 +750,7 @@ impl Imap {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if mailbox.uid_validity.unwrap() != uid_validity {
|
||||
if mailbox.uid_validity.unwrap_or_default() != uid_validity {
|
||||
// first time this folder is selected or UIDVALIDITY has changed, init lastseenuid and save it to config
|
||||
|
||||
if mailbox.exists == 0 {
|
||||
@@ -752,7 +760,12 @@ impl Imap {
|
||||
// id we do not do this here, we'll miss the first message
|
||||
// as we will get in here again and fetch from lastseenuid+1 then
|
||||
|
||||
self.set_config_last_seen_uid(context, &folder, mailbox.uid_validity.unwrap(), 0);
|
||||
self.set_config_last_seen_uid(
|
||||
context,
|
||||
&folder,
|
||||
mailbox.uid_validity.unwrap_or_default(),
|
||||
0,
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -783,7 +796,7 @@ impl Imap {
|
||||
last_seen_uid -= 1;
|
||||
}
|
||||
|
||||
uid_validity = mailbox.uid_validity.unwrap();
|
||||
uid_validity = mailbox.uid_validity.unwrap_or_default();
|
||||
self.set_config_last_seen_uid(context, &folder, uid_validity, last_seen_uid);
|
||||
info!(
|
||||
context,
|
||||
@@ -884,7 +897,7 @@ impl Imap {
|
||||
let key = format!("imap.mailbox.{}", folder.as_ref());
|
||||
let val = format!("{}:{}", uidvalidity, lastseenuid);
|
||||
|
||||
context.sql.set_config(context, &key, Some(&val)).ok();
|
||||
context.sql.set_raw_config(context, &key, Some(&val)).ok();
|
||||
}
|
||||
|
||||
fn fetch_single_msg<S: AsRef<str>>(
|
||||
@@ -945,7 +958,7 @@ impl Imap {
|
||||
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
|
||||
|
||||
if !is_deleted && msg.body().is_some() {
|
||||
let body = msg.body().unwrap();
|
||||
let body = msg.body().unwrap_or_default();
|
||||
unsafe {
|
||||
dc_receive_imf(context, &body, folder.as_ref(), server_uid, flags as u32);
|
||||
}
|
||||
@@ -1056,13 +1069,14 @@ impl Imap {
|
||||
let mut do_fake_idle = true;
|
||||
while do_fake_idle {
|
||||
// wait a moment: every 5 seconds in the first 3 minutes after a new message, after that every 60 seconds.
|
||||
let seconds_to_wait =
|
||||
if fake_idle_start_time.elapsed().unwrap() < Duration::new(3 * 60, 0) && !wait_long
|
||||
{
|
||||
Duration::new(5, 0)
|
||||
} else {
|
||||
Duration::new(60, 0)
|
||||
};
|
||||
let seconds_to_wait = if fake_idle_start_time.elapsed().unwrap_or_default()
|
||||
< Duration::new(3 * 60, 0)
|
||||
&& !wait_long
|
||||
{
|
||||
Duration::new(5, 0)
|
||||
} else {
|
||||
Duration::new(60, 0)
|
||||
};
|
||||
|
||||
let &(ref lock, ref cvar) = &*self.watch.clone();
|
||||
let mut watch = lock.lock().unwrap();
|
||||
@@ -1396,18 +1410,18 @@ impl Imap {
|
||||
|
||||
context
|
||||
.sql
|
||||
.set_config_int(context, "folders_configured", 3)
|
||||
.set_raw_config_int(context, "folders_configured", 3)
|
||||
.ok();
|
||||
if let Some(ref mvbox_folder) = mvbox_folder {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "configured_mvbox_folder", Some(mvbox_folder))
|
||||
.set_raw_config(context, "configured_mvbox_folder", Some(mvbox_folder))
|
||||
.ok();
|
||||
}
|
||||
if let Some(ref sentbox_folder) = sentbox_folder {
|
||||
context
|
||||
.sql
|
||||
.set_config(
|
||||
.set_raw_config(
|
||||
context,
|
||||
"configured_sentbox_folder",
|
||||
Some(sentbox_folder.name()),
|
||||
|
||||
563
src/imex.rs
563
src/imex.rs
@@ -1,6 +1,5 @@
|
||||
use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use core::cmp::{max, min};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
use rand::{thread_rng, Rng};
|
||||
@@ -18,7 +17,7 @@ use crate::job::*;
|
||||
use crate::key::*;
|
||||
use crate::message::Message;
|
||||
use crate::param::*;
|
||||
use crate::pgp::*;
|
||||
use crate::pgp;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
@@ -90,7 +89,7 @@ pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<Strin
|
||||
let sql = Sql::new();
|
||||
if sql.open(context, &path, 0x1) {
|
||||
let curr_backup_time =
|
||||
sql.get_config_int(context, "backup_time")
|
||||
sql.get_raw_config_int(context, "backup_time")
|
||||
.unwrap_or_default() as u64;
|
||||
if curr_backup_time > newest_backup_time {
|
||||
newest_backup_path = Some(path);
|
||||
@@ -109,78 +108,48 @@ pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<Strin
|
||||
}
|
||||
|
||||
pub fn initiate_key_transfer(context: &Context) -> Result<String> {
|
||||
ensure!(context.alloc_ongoing(), "could not allocate ongoing");
|
||||
let res = do_initiate_key_transfer(context);
|
||||
context.free_ongoing();
|
||||
res
|
||||
}
|
||||
|
||||
fn do_initiate_key_transfer(context: &Context) -> Result<String> {
|
||||
let mut msg: Message;
|
||||
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing");
|
||||
let setup_code = create_setup_code(context);
|
||||
/* this may require a keypair to be created. this may take a second ... */
|
||||
if !context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
if let Ok(ref setup_file_content) = render_setup_file(context, &setup_code) {
|
||||
/* encrypting may also take a while ... */
|
||||
if !context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
let setup_file_name = context.new_blob_file(
|
||||
"autocrypt-setup-message.html",
|
||||
setup_file_content.as_bytes(),
|
||||
)?;
|
||||
{
|
||||
if let Ok(chat_id) = chat::create_by_contact_id(context, 1) {
|
||||
msg = Message::default();
|
||||
msg.type_0 = Viewtype::File;
|
||||
msg.param.set(Param::File, setup_file_name);
|
||||
ensure!(!context.shall_stop_ongoing(), "canceled");
|
||||
let setup_file_content = render_setup_file(context, &setup_code)?;
|
||||
/* encrypting may also take a while ... */
|
||||
ensure!(!context.shall_stop_ongoing(), "canceled");
|
||||
let setup_file_name = context.new_blob_file(
|
||||
"autocrypt-setup-message.html",
|
||||
setup_file_content.as_bytes(),
|
||||
)?;
|
||||
|
||||
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);
|
||||
let chat_id = chat::create_by_contact_id(context, 1)?;
|
||||
msg = Message::default();
|
||||
msg.type_0 = Viewtype::File;
|
||||
msg.param.set(Param::File, setup_file_name);
|
||||
|
||||
if !context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
if let Ok(msg_id) = chat::send_msg(context, chat_id, &mut msg) {
|
||||
info!(context, "Wait for setup message being sent ...",);
|
||||
loop {
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
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() {
|
||||
info!(context, "... setup message sent.",);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
ensure!(!context.shall_stop_ongoing(), "canceled");
|
||||
let msg_id = chat::send_msg(context, chat_id, &mut msg)?;
|
||||
info!(context, "Wait for setup message being sent ...",);
|
||||
while !context.shall_stop_ongoing() {
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
if let Ok(msg) = Message::load_from_db(context, msg_id) {
|
||||
if msg.is_sent() {
|
||||
info!(context, "... setup message sent.",);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dc_free_ongoing(context);
|
||||
|
||||
Ok(setup_code)
|
||||
}
|
||||
|
||||
@@ -200,7 +169,7 @@ pub fn render_setup_file(context: &Context, passphrase: &str) -> Result<String>
|
||||
true => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
|
||||
};
|
||||
let private_key_asc = private_key.to_asc(ac_headers);
|
||||
let encr = dc_pgp_symm_encrypt(&passphrase, private_key_asc.as_bytes())?;
|
||||
let encr = pgp::symm_encrypt(&passphrase, private_key_asc.as_bytes())?;
|
||||
|
||||
let replacement = format!(
|
||||
concat!(
|
||||
@@ -263,25 +232,19 @@ pub fn continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) -
|
||||
if msg.is_err() {
|
||||
bail!("Message is no Autocrypt Setup Message.");
|
||||
}
|
||||
let msg = msg.unwrap();
|
||||
let msg = msg.unwrap_or_default();
|
||||
ensure!(
|
||||
msg.is_setupmessage(),
|
||||
"Message is no Autocrypt Setup Message."
|
||||
);
|
||||
|
||||
if let Some(filename) = msg.get_file(context) {
|
||||
if let Ok(ref mut buf) = dc_read_file(context, filename) {
|
||||
let sc = normalize_setup_code(setup_code);
|
||||
if let Ok(armored_key) = decrypt_setup_file(context, sc, buf) {
|
||||
set_self_key(context, &armored_key, true, true)?;
|
||||
} else {
|
||||
bail!("Bad setup code.")
|
||||
}
|
||||
let file = dc_open_file(context, filename)?;
|
||||
let sc = normalize_setup_code(setup_code);
|
||||
let armored_key = decrypt_setup_file(context, &sc, file)?;
|
||||
set_self_key(context, &armored_key, true, true)?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Cannot read Autocrypt Setup Message file.");
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Message is no Autocrypt Setup Message.");
|
||||
}
|
||||
@@ -313,7 +276,7 @@ fn set_self_key(
|
||||
};
|
||||
context
|
||||
.sql
|
||||
.set_config_int(context, "e2ee_enabled", e2ee_enabled)?;
|
||||
.set_raw_config_int(context, "e2ee_enabled", e2ee_enabled)?;
|
||||
}
|
||||
None => {
|
||||
if prefer_encrypt_required {
|
||||
@@ -346,7 +309,7 @@ fn set_self_key(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr.unwrap(),
|
||||
self_addr.unwrap_or_default(),
|
||||
set_default,
|
||||
&context.sql,
|
||||
) {
|
||||
@@ -355,53 +318,15 @@ fn set_self_key(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt_setup_file(
|
||||
fn decrypt_setup_file<T: std::io::Read + std::io::Seek>(
|
||||
_context: &Context,
|
||||
passphrase: impl AsRef<str>,
|
||||
filecontent: &mut [u8],
|
||||
passphrase: &str,
|
||||
file: T,
|
||||
) -> Result<String> {
|
||||
let mut fc_headerline = String::default();
|
||||
let mut fc_base64: *const libc::c_char = ptr::null();
|
||||
let plain_bytes = pgp::symm_decrypt(passphrase, file)?;
|
||||
let plain_text = std::string::String::from_utf8(plain_bytes)?;
|
||||
|
||||
let split_result = unsafe {
|
||||
dc_split_armored_data(
|
||||
filecontent.as_mut_ptr().cast(),
|
||||
&mut fc_headerline,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
&mut fc_base64,
|
||||
)
|
||||
};
|
||||
|
||||
if !split_result || fc_headerline != "-----BEGIN PGP MESSAGE-----" || fc_base64.is_null() {
|
||||
bail!("Invalid armored data");
|
||||
}
|
||||
|
||||
// convert base64 to binary
|
||||
let base64_encoded =
|
||||
unsafe { std::slice::from_raw_parts(fc_base64 as *const u8, libc::strlen(fc_base64)) };
|
||||
|
||||
let data = base64_decode(&base64_encoded)?;
|
||||
|
||||
// decrypt symmetrically
|
||||
let payload = dc_pgp_symm_decrypt(passphrase.as_ref(), &data)?;
|
||||
let payload_str = String::from_utf8(payload)?;
|
||||
|
||||
Ok(payload_str)
|
||||
}
|
||||
|
||||
/// Decode the base64 encoded slice. Handles line breaks.
|
||||
fn base64_decode(input: &[u8]) -> Result<Vec<u8>> {
|
||||
use std::io::Read;
|
||||
let c = std::io::Cursor::new(input);
|
||||
let lr = pgp::line_reader::LineReader::new(c);
|
||||
let br = pgp::base64_reader::Base64Reader::new(lr);
|
||||
let mut reader = pgp::base64_decoder::Base64Decoder::new(br);
|
||||
|
||||
let mut data = Vec::new();
|
||||
reader.read_to_end(&mut data)?;
|
||||
|
||||
Ok(data)
|
||||
Ok(plain_text)
|
||||
}
|
||||
|
||||
pub fn normalize_setup_code(s: &str) -> String {
|
||||
@@ -419,7 +344,7 @@ pub fn normalize_setup_code(s: &str) -> String {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
|
||||
ensure!(dc_alloc_ongoing(context), "could not allocate ongoing");
|
||||
ensure!(context.alloc_ongoing(), "could not allocate ongoing");
|
||||
let what: Option<ImexMode> = job.param.get_int(Param::Cmd).and_then(ImexMode::from_i32);
|
||||
let param = job.param.get(Param::Arg).unwrap_or_default();
|
||||
|
||||
@@ -431,7 +356,7 @@ pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
|
||||
if what == Some(ImexMode::ExportBackup) || what == Some(ImexMode::ExportSelfKeys) {
|
||||
// before we export anything, make sure the private key exists
|
||||
if e2ee::ensure_secret_key_exists(context).is_err() {
|
||||
dc_free_ongoing(context);
|
||||
context.free_ongoing();
|
||||
bail!("Cannot create private key or private key not available.");
|
||||
} else {
|
||||
dc_create_folder(context, ¶m);
|
||||
@@ -447,7 +372,7 @@ pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
|
||||
bail!("unknown IMEX type");
|
||||
}
|
||||
};
|
||||
dc_free_ongoing(context);
|
||||
context.free_ongoing();
|
||||
match success {
|
||||
Ok(()) => {
|
||||
info!(context, "IMEX successfully completed");
|
||||
@@ -513,15 +438,7 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
|
||||
|files| {
|
||||
for (processed_files_cnt, file) in files.enumerate() {
|
||||
let (file_name, file_blob) = file?;
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
bail!("received stop signal");
|
||||
}
|
||||
ensure!(!context.shall_stop_ongoing(), "received stop signal");
|
||||
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
|
||||
if permille < 10 {
|
||||
permille = 10
|
||||
@@ -562,10 +479,6 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
|
||||
/* the FILE_PROGRESS macro calls the callback with the permille of files processed.
|
||||
The macro avoids weird values of 0% or 100% while still working. */
|
||||
fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
let mut ok_to_continue = true;
|
||||
let mut success = false;
|
||||
|
||||
let mut delete_dest_file: libc::c_int = 0;
|
||||
// get a fine backup file name (the name includes the date so that multiple backup instances are possible)
|
||||
// FIXME: we should write to a temporary file first and rename it on success. this would guarantee the backup is complete.
|
||||
// let dest_path_filename = dc_get_next_backup_file(context, dir, res);
|
||||
@@ -592,130 +505,79 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
s
|
||||
);
|
||||
}
|
||||
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
|
||||
/*for logging only*/
|
||||
match add_files_to_export(context, &dest_path_filename) {
|
||||
Err(err) => {
|
||||
dc_delete_file(context, &dest_path_filename);
|
||||
error!(context, "backup failed: {}", err);
|
||||
Err(err)
|
||||
}
|
||||
Ok(()) => {
|
||||
context
|
||||
.sql
|
||||
.set_raw_config_int(context, "backup_time", now as i32)?;
|
||||
context.call_cb(Event::ImexFileWritten(dest_path_filename.clone()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_files_to_export(context: &Context, dest_path_filename: &PathBuf) -> Result<()> {
|
||||
// add all files as blobs to the database copy (this does not require
|
||||
// the source to be locked, neigher the destination as it is used only here)
|
||||
let sql = Sql::new();
|
||||
if sql.open(context, &dest_path_filename, 0) {
|
||||
if !sql.table_exists("backup_blobs") {
|
||||
if sql::execute(
|
||||
context,
|
||||
&sql,
|
||||
"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);",
|
||||
params![],
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
/* error already logged */
|
||||
ok_to_continue = false;
|
||||
}
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mut total_files_cnt = 0;
|
||||
let dir = context.get_blobdir();
|
||||
if let Ok(dir_handle) = std::fs::read_dir(&dir) {
|
||||
total_files_cnt += dir_handle.filter(|r| r.is_ok()).count();
|
||||
ensure!(
|
||||
sql.open(context, &dest_path_filename, 0),
|
||||
"could not open db"
|
||||
);
|
||||
if !sql.table_exists("backup_blobs") {
|
||||
sql::execute(
|
||||
context,
|
||||
&sql,
|
||||
"CREATE TABLE backup_blobs (id INTEGER PRIMARY KEY, file_name, file_content);",
|
||||
params![],
|
||||
)?
|
||||
}
|
||||
// copy all files from BLOBDIR into backup-db
|
||||
let mut total_files_cnt = 0;
|
||||
let dir = context.get_blobdir();
|
||||
let dir_handle = std::fs::read_dir(&dir)?;
|
||||
total_files_cnt += dir_handle.filter(|r| r.is_ok()).count();
|
||||
|
||||
info!(context, "EXPORT: total_files_cnt={}", total_files_cnt);
|
||||
if total_files_cnt > 0 {
|
||||
// scan directory, pass 2: copy files
|
||||
if let Ok(dir_handle) = std::fs::read_dir(&dir) {
|
||||
sql.prepare(
|
||||
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|
||||
move |mut stmt, _| {
|
||||
let mut processed_files_cnt = 0;
|
||||
for entry in dir_handle {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
delete_dest_file = 1;
|
||||
ok_to_continue = false;
|
||||
break;
|
||||
} else {
|
||||
processed_files_cnt += 1;
|
||||
let mut permille =
|
||||
processed_files_cnt * 1000 / total_files_cnt;
|
||||
if permille < 10 {
|
||||
permille = 10;
|
||||
}
|
||||
if permille > 990 {
|
||||
permille = 990;
|
||||
}
|
||||
context.call_cb(Event::ImexProgress(permille));
|
||||
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.starts_with("delta-chat") && name.ends_with(".bak")
|
||||
{
|
||||
continue;
|
||||
} else {
|
||||
info!(context, "EXPORTing filename={}", name);
|
||||
let curr_path_filename = context.get_blobdir().join(entry.file_name());
|
||||
if let Ok(buf) =
|
||||
dc_read_file(context, &curr_path_filename)
|
||||
{
|
||||
if buf.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if stmt.execute(params![name, buf]).is_err() {
|
||||
error!(
|
||||
context,
|
||||
"Disk full? Cannot add file \"{}\" to backup.",
|
||||
curr_path_filename.display(),
|
||||
);
|
||||
/* this is not recoverable! writing to the sqlite database should work! */
|
||||
ok_to_continue = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
).unwrap();
|
||||
} else {
|
||||
error!(
|
||||
context,
|
||||
"Backup: Cannot copy from blob-directory \"{}\".",
|
||||
context.get_blobdir().display(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
info!(context, "Backup: No files to copy.",);
|
||||
}
|
||||
if ok_to_continue {
|
||||
if sql
|
||||
.set_config_int(context, "backup_time", now as i32)
|
||||
.is_ok()
|
||||
{
|
||||
context.call_cb(Event::ImexFileWritten(dest_path_filename.clone()));
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
context,
|
||||
"Backup: Cannot get info for blob-directory \"{}\".",
|
||||
context.get_blobdir().display(),
|
||||
info!(context, "EXPORT: total_files_cnt={}", total_files_cnt);
|
||||
// scan directory, pass 2: copy files
|
||||
let dir_handle = std::fs::read_dir(&dir)?;
|
||||
sql.prepare(
|
||||
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|
||||
|mut stmt, _| {
|
||||
let mut processed_files_cnt = 0;
|
||||
for entry in dir_handle {
|
||||
let entry = entry?;
|
||||
ensure!(
|
||||
!context.shall_stop_ongoing(),
|
||||
"canceled during export-files"
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
if 0 != delete_dest_file {
|
||||
dc_delete_file(context, &dest_path_filename);
|
||||
}
|
||||
processed_files_cnt += 1;
|
||||
let permille = max(min(processed_files_cnt * 1000 / total_files_cnt, 990), 10);
|
||||
context.call_cb(Event::ImexProgress(permille));
|
||||
|
||||
ensure!(success, "failed");
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.starts_with("delta-chat") && name.ends_with(".bak") {
|
||||
continue;
|
||||
}
|
||||
info!(context, "EXPORT: copying filename={}", name);
|
||||
let curr_path_filename = context.get_blobdir().join(entry.file_name());
|
||||
if let Ok(buf) = dc_read_file(context, &curr_path_filename) {
|
||||
if buf.is_empty() {
|
||||
continue;
|
||||
}
|
||||
// bail out if we can't insert
|
||||
stmt.execute(params![name, buf])?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -730,81 +592,48 @@ fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
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 set_default: bool;
|
||||
let mut key: String;
|
||||
let mut imported_cnt = 0;
|
||||
|
||||
let dir_name = dir.as_ref().to_string_lossy();
|
||||
if let Ok(dir_handle) = std::fs::read_dir(&dir) {
|
||||
for entry in dir_handle {
|
||||
let entry_fn = match entry {
|
||||
Err(err) => {
|
||||
info!(context, "file-dir error: {}", err);
|
||||
break;
|
||||
let dir_handle = std::fs::read_dir(&dir)?;
|
||||
for entry in dir_handle {
|
||||
let entry_fn = entry?.file_name();
|
||||
let name_f = entry_fn.to_string_lossy();
|
||||
let path_plus_name = dir.as_ref().join(&entry_fn);
|
||||
match dc_get_filesuffix_lc(&name_f) {
|
||||
Some(suffix) => {
|
||||
if suffix != "asc" {
|
||||
continue;
|
||||
}
|
||||
Ok(res) => res.file_name(),
|
||||
};
|
||||
let name_f = entry_fn.to_string_lossy();
|
||||
let path_plus_name = dir.as_ref().join(&entry_fn);
|
||||
match dc_get_filesuffix_lc(&name_f) {
|
||||
Some(suffix) => {
|
||||
if suffix != "asc" {
|
||||
continue;
|
||||
}
|
||||
set_default = if name_f.contains("legacy") {
|
||||
info!(context, "found legacy key '{}'", path_plus_name.display());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
set_default = if name_f.contains("legacy") {
|
||||
info!(context, "found legacy key '{}'", path_plus_name.display());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
None => {
|
||||
}
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match dc_read_file(context, &path_plus_name) {
|
||||
Ok(buf) => {
|
||||
let armored = std::string::String::from_utf8_lossy(&buf);
|
||||
if let Err(err) = set_self_key(context, &armored, set_default, false) {
|
||||
error!(context, "set_self_key: {}", err);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let ccontent = if let Ok(content) = dc_read_file(context, &path_plus_name) {
|
||||
key = String::from_utf8_lossy(&content).to_string();
|
||||
CString::new(content).unwrap()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
/* only import if we have a private key */
|
||||
let mut buf2_headerline = String::default();
|
||||
let split_res: bool;
|
||||
unsafe {
|
||||
let buf2 = dc_strdup(ccontent.as_ptr());
|
||||
split_res = dc_split_armored_data(
|
||||
buf2,
|
||||
&mut buf2_headerline,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
libc::free(buf2 as *mut libc::c_void);
|
||||
}
|
||||
if split_res
|
||||
&& buf2_headerline.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
|
||||
&& !key.contains("-----BEGIN PGP PRIVATE KEY BLOCK")
|
||||
{
|
||||
info!(context, "ignoring public key file '{}", name_f);
|
||||
// it's fine: DC exports public with private
|
||||
continue;
|
||||
}
|
||||
if let Err(err) = set_self_key(context, &key, set_default, false) {
|
||||
error!(context, "set_self_key: {}", err);
|
||||
continue;
|
||||
}
|
||||
imported_cnt += 1
|
||||
Err(_) => continue,
|
||||
}
|
||||
ensure!(
|
||||
imported_cnt > 0,
|
||||
"No private keys found in \"{}\".",
|
||||
dir_name
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Import: Cannot open directory \"{}\".", dir_name);
|
||||
imported_cnt += 1;
|
||||
}
|
||||
ensure!(
|
||||
imported_cnt > 0,
|
||||
"No private keys found in \"{}\".",
|
||||
dir_name
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
@@ -847,7 +676,7 @@ fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
},
|
||||
)?;
|
||||
|
||||
ensure!(export_errors == 0, "errors while importing");
|
||||
ensure!(export_errors == 0, "errors while exporting keys");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -884,7 +713,9 @@ fn export_key_to_asc_file(
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::pgp::{split_armored_data, HEADER_AUTOCRYPT, HEADER_SETUPCODE};
|
||||
use crate::test_utils::*;
|
||||
use ::pgp::armor::BlockType;
|
||||
|
||||
#[test]
|
||||
fn test_render_setup_file() {
|
||||
@@ -906,19 +737,12 @@ mod tests {
|
||||
assert!(msg.contains("-----END PGP MESSAGE-----\n"));
|
||||
}
|
||||
|
||||
fn ac_setup_msg_cb(ctx: &Context, evt: Event) -> libc::uintptr_t {
|
||||
match evt {
|
||||
Event::GetString {
|
||||
id: StockMessage::AcSetupMsgBody,
|
||||
..
|
||||
} => unsafe { "hello\r\nthere".strdup() as usize },
|
||||
_ => logging_cb(ctx, evt),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn otest_render_setup_file_newline_replace() {
|
||||
let t = test_context(Some(Box::new(ac_setup_msg_cb)));
|
||||
fn test_render_setup_file_newline_replace() {
|
||||
let t = dummy_context();
|
||||
t.ctx
|
||||
.set_stock_translation(StockMessage::AcSetupMsgBody, "hello\r\nthere".to_string())
|
||||
.unwrap();
|
||||
configure_alice_keypair(&t.ctx);
|
||||
let msg = render_setup_file(&t.ctx, "pw").unwrap();
|
||||
println!("{}", &msg);
|
||||
@@ -974,47 +798,26 @@ mod tests {
|
||||
let ctx = dummy_context();
|
||||
let context = &ctx.ctx;
|
||||
|
||||
let mut headerline = String::default();
|
||||
let mut setupcodebegin = ptr::null();
|
||||
let mut preferencrypt = ptr::null();
|
||||
let buf_1 = S_EM_SETUPFILE.as_bytes().to_vec();
|
||||
let (typ, headers, base64) = split_armored_data(&buf_1).unwrap();
|
||||
assert_eq!(typ, BlockType::Message);
|
||||
assert!(S_EM_SETUPCODE.starts_with(headers.get(HEADER_SETUPCODE).unwrap()));
|
||||
assert!(headers.get(HEADER_AUTOCRYPT).is_none());
|
||||
|
||||
let mut buf_1 = S_EM_SETUPFILE.to_string();
|
||||
assert!(!base64.is_empty());
|
||||
|
||||
unsafe {
|
||||
assert!(dc_split_armored_data(
|
||||
buf_1.as_mut_ptr().cast(),
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
&mut preferencrypt,
|
||||
ptr::null_mut(),
|
||||
));
|
||||
}
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
assert!(!setupcodebegin.is_null());
|
||||
let setup_file = S_EM_SETUPFILE.to_string();
|
||||
let decrypted = decrypt_setup_file(
|
||||
context,
|
||||
S_EM_SETUPCODE,
|
||||
std::io::Cursor::new(setup_file.as_bytes()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// TODO: verify that this is the right check
|
||||
assert!(S_EM_SETUPCODE.starts_with(as_str(setupcodebegin)));
|
||||
let (typ, headers, _base64) = split_armored_data(decrypted.as_bytes()).unwrap();
|
||||
|
||||
assert!(preferencrypt.is_null());
|
||||
|
||||
let mut setup_file = S_EM_SETUPFILE.to_string();
|
||||
let mut decrypted = unsafe {
|
||||
decrypt_setup_file(context, S_EM_SETUPCODE, setup_file.as_bytes_mut()).unwrap()
|
||||
};
|
||||
|
||||
unsafe {
|
||||
assert!(dc_split_armored_data(
|
||||
decrypted.as_mut_ptr().cast(),
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
&mut preferencrypt,
|
||||
ptr::null_mut(),
|
||||
));
|
||||
}
|
||||
|
||||
assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----");
|
||||
assert!(setupcodebegin.is_null());
|
||||
assert!(!preferencrypt.is_null());
|
||||
assert_eq!(as_str(preferencrypt), "mutual",);
|
||||
assert_eq!(typ, BlockType::PrivateKey);
|
||||
assert_eq!(headers.get(HEADER_AUTOCRYPT), Some(&"mutual".to_string()));
|
||||
assert!(headers.get(HEADER_SETUPCODE).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
50
src/job.rs
50
src/job.rs
@@ -219,13 +219,15 @@ impl Job {
|
||||
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.get_raw_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
let dest_folder = context
|
||||
.sql
|
||||
.get_raw_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
@@ -327,13 +329,15 @@ impl Job {
|
||||
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.get_raw_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
let dest_folder = context
|
||||
.sql
|
||||
.get_raw_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let mut dest_uid = 0;
|
||||
if ImapResult::RetryLater
|
||||
@@ -364,12 +368,7 @@ pub fn perform_imap_fetch(context: &Context) {
|
||||
if 0 == connect_to_inbox(context, &inbox) {
|
||||
return;
|
||||
}
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "inbox_watch")
|
||||
.unwrap_or_else(|| 1)
|
||||
== 0
|
||||
{
|
||||
if !context.get_config_bool(Config::InboxWatch) {
|
||||
info!(context, "INBOX-watch disabled.",);
|
||||
return;
|
||||
}
|
||||
@@ -404,29 +403,23 @@ pub fn perform_imap_idle(context: &Context) {
|
||||
}
|
||||
|
||||
pub fn perform_mvbox_fetch(context: &Context) {
|
||||
let use_network = context
|
||||
.sql
|
||||
.get_config_int(context, "mvbox_watch")
|
||||
.unwrap_or_else(|| 1);
|
||||
let use_network = context.get_config_bool(Config::MvboxWatch);
|
||||
|
||||
context
|
||||
.mvbox_thread
|
||||
.write()
|
||||
.unwrap()
|
||||
.fetch(context, use_network == 1);
|
||||
.fetch(context, use_network);
|
||||
}
|
||||
|
||||
pub fn perform_mvbox_idle(context: &Context) {
|
||||
let use_network = context
|
||||
.sql
|
||||
.get_config_int(context, "mvbox_watch")
|
||||
.unwrap_or_else(|| 1);
|
||||
let use_network = context.get_config_bool(Config::MvboxWatch);
|
||||
|
||||
context
|
||||
.mvbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.idle(context, use_network == 1);
|
||||
.idle(context, use_network);
|
||||
}
|
||||
|
||||
pub fn interrupt_mvbox_idle(context: &Context) {
|
||||
@@ -434,29 +427,23 @@ pub fn interrupt_mvbox_idle(context: &Context) {
|
||||
}
|
||||
|
||||
pub fn perform_sentbox_fetch(context: &Context) {
|
||||
let use_network = context
|
||||
.sql
|
||||
.get_config_int(context, "sentbox_watch")
|
||||
.unwrap_or_else(|| 1);
|
||||
let use_network = context.get_config_bool(Config::SentboxWatch);
|
||||
|
||||
context
|
||||
.sentbox_thread
|
||||
.write()
|
||||
.unwrap()
|
||||
.fetch(context, use_network == 1);
|
||||
.fetch(context, use_network);
|
||||
}
|
||||
|
||||
pub fn perform_sentbox_idle(context: &Context) {
|
||||
let use_network = context
|
||||
.sql
|
||||
.get_config_int(context, "sentbox_watch")
|
||||
.unwrap_or_else(|| 1);
|
||||
let use_network = context.get_config_bool(Config::SentboxWatch);
|
||||
|
||||
context
|
||||
.sentbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.idle(context, use_network == 1);
|
||||
.idle(context, use_network);
|
||||
}
|
||||
|
||||
pub fn interrupt_sentbox_idle(context: &Context) {
|
||||
@@ -794,7 +781,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
Action::MarkseenMdnOnImap => job.do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context),
|
||||
Action::MoveMsg => job.do_DC_JOB_MOVE_MSG(context),
|
||||
Action::SendMdn => job.do_DC_JOB_SEND(context),
|
||||
Action::ConfigureImap => unsafe { dc_job_do_DC_JOB_CONFIGURE_IMAP(context) },
|
||||
Action::ConfigureImap => dc_job_do_DC_JOB_CONFIGURE_IMAP(context),
|
||||
Action::ImexImap => match job_do_DC_JOB_IMEX_IMAP(context, &job) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
@@ -947,7 +934,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
|
||||
)
|
||||
};
|
||||
let bpath = context.new_blob_file(&mimefactory.rfc724_mid, bytes)?;
|
||||
info!(context, "add_smtp_job file written: {:?}", bpath);
|
||||
let recipients = mimefactory.recipients_addr.join("\x1e");
|
||||
param.set(Param::File, &bpath);
|
||||
param.set(Param::Recipients, &recipients);
|
||||
|
||||
@@ -116,14 +116,14 @@ impl JobThread {
|
||||
if ret_connected {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.get_raw_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
self.imap.configure_folders(context, 0x1);
|
||||
}
|
||||
|
||||
if let Some(mvbox_name) = context.sql.get_config(context, self.folder_config_name) {
|
||||
if let Some(mvbox_name) = context.sql.get_raw_config(context, self.folder_config_name) {
|
||||
self.imap.set_watch_folder(mvbox_name);
|
||||
} else {
|
||||
self.imap.disconnect(context);
|
||||
|
||||
@@ -163,8 +163,8 @@ impl Key {
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Key::Public(k) => k.to_bytes().unwrap(),
|
||||
Key::Secret(k) => k.to_bytes().unwrap(),
|
||||
Key::Public(k) => k.to_bytes().unwrap_or_default(),
|
||||
Key::Secret(k) => k.to_bytes().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
|
||||
#[test]
|
||||
#[ignore] // is too expensive
|
||||
fn test_from_slice_roundtrip() {
|
||||
let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
|
||||
let (public_key, private_key) = crate::pgp::create_keypair("hello").unwrap();
|
||||
|
||||
let binary = public_key.to_bytes();
|
||||
let public_key2 = Key::from_slice(&binary, KeyType::Public).expect("invalid public key");
|
||||
@@ -416,7 +416,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
|
||||
#[test]
|
||||
#[ignore] // is too expensive
|
||||
fn test_ascii_roundtrip() {
|
||||
let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
|
||||
let (public_key, private_key) = crate::pgp::create_keypair("hello").unwrap();
|
||||
|
||||
let s = public_key.to_armored_string(None).unwrap();
|
||||
let (public_key2, _) =
|
||||
|
||||
@@ -57,7 +57,7 @@ pub mod qr;
|
||||
pub mod securejoin;
|
||||
mod smtp;
|
||||
pub mod sql;
|
||||
mod stock;
|
||||
pub mod stock;
|
||||
mod token;
|
||||
#[macro_use]
|
||||
mod wrapmime;
|
||||
|
||||
@@ -3,6 +3,7 @@ use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
use crate::chat;
|
||||
use crate::config::Config;
|
||||
use crate::constants::*;
|
||||
use crate::context::*;
|
||||
use crate::dc_tools::*;
|
||||
@@ -218,7 +219,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
|
||||
msg.text =
|
||||
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
|
||||
msg.param.set_int(Param::Cmd, 8);
|
||||
chat::send_msg(context, chat_id, &mut msg).unwrap();
|
||||
chat::send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
||||
} else if 0 == seconds && is_sending_locations_before {
|
||||
let stock_str =
|
||||
context.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0);
|
||||
@@ -375,8 +376,7 @@ pub fn get_kml(context: &Context, chat_id: u32) -> Result<(String, u32), Error>
|
||||
let mut last_added_location_id = 0;
|
||||
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
let (locations_send_begin, locations_send_until, locations_last_sent) = context.sql.query_row(
|
||||
@@ -615,7 +615,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
|
||||
|
||||
for (chat_id, mut msg) in msgs.into_iter() {
|
||||
// TODO: better error handling
|
||||
chat::send_msg(context, chat_id as u32, &mut msg).unwrap();
|
||||
chat::send_msg(context, chat_id as u32, &mut msg).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
if 0 != continue_streaming {
|
||||
|
||||
@@ -51,53 +51,53 @@ impl LoginParam {
|
||||
|
||||
let key = format!("{}addr", prefix);
|
||||
let addr = sql
|
||||
.get_config(context, key)
|
||||
.get_raw_config(context, key)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
let key = format!("{}mail_server", prefix);
|
||||
let mail_server = sql.get_config(context, key).unwrap_or_default();
|
||||
let mail_server = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
let mail_port = sql.get_config_int(context, key).unwrap_or_default();
|
||||
let mail_port = sql.get_raw_config_int(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
let mail_user = sql.get_config(context, key).unwrap_or_default();
|
||||
let mail_user = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
let mail_pw = sql.get_config(context, key).unwrap_or_default();
|
||||
let mail_pw = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}imap_certificate_checks", prefix);
|
||||
let imap_certificate_checks =
|
||||
if let Some(certificate_checks) = sql.get_config_int(context, key) {
|
||||
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
|
||||
if let Some(certificate_checks) = sql.get_raw_config_int(context, key) {
|
||||
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
let send_server = sql.get_config(context, key).unwrap_or_default();
|
||||
let send_server = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
let send_port = sql.get_config_int(context, key).unwrap_or_default();
|
||||
let send_port = sql.get_raw_config_int(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
let send_user = sql.get_config(context, key).unwrap_or_default();
|
||||
let send_user = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
let send_pw = sql.get_config(context, key).unwrap_or_default();
|
||||
let send_pw = sql.get_raw_config(context, key).unwrap_or_default();
|
||||
|
||||
let key = format!("{}smtp_certificate_checks", prefix);
|
||||
let smtp_certificate_checks =
|
||||
if let Some(certificate_checks) = sql.get_config_int(context, key) {
|
||||
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
|
||||
if let Some(certificate_checks) = sql.get_raw_config_int(context, key) {
|
||||
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
let server_flags = sql.get_config_int(context, key).unwrap_or_default();
|
||||
let server_flags = sql.get_raw_config_int(context, key).unwrap_or_default();
|
||||
|
||||
LoginParam {
|
||||
addr: addr.to_string(),
|
||||
@@ -129,40 +129,40 @@ impl LoginParam {
|
||||
let sql = &context.sql;
|
||||
|
||||
let key = format!("{}addr", prefix);
|
||||
sql.set_config(context, key, Some(&self.addr))?;
|
||||
sql.set_raw_config(context, key, Some(&self.addr))?;
|
||||
|
||||
let key = format!("{}mail_server", prefix);
|
||||
sql.set_config(context, key, Some(&self.mail_server))?;
|
||||
sql.set_raw_config(context, key, Some(&self.mail_server))?;
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
sql.set_config_int(context, key, self.mail_port)?;
|
||||
sql.set_raw_config_int(context, key, self.mail_port)?;
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
sql.set_config(context, key, Some(&self.mail_user))?;
|
||||
sql.set_raw_config(context, key, Some(&self.mail_user))?;
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
sql.set_config(context, key, Some(&self.mail_pw))?;
|
||||
sql.set_raw_config(context, key, Some(&self.mail_pw))?;
|
||||
|
||||
let key = format!("{}imap_certificate_checks", prefix);
|
||||
sql.set_config_int(context, key, self.imap_certificate_checks as i32)?;
|
||||
sql.set_raw_config_int(context, key, self.imap_certificate_checks as i32)?;
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
sql.set_config(context, key, Some(&self.send_server))?;
|
||||
sql.set_raw_config(context, key, Some(&self.send_server))?;
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
sql.set_config_int(context, key, self.send_port)?;
|
||||
sql.set_raw_config_int(context, key, self.send_port)?;
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
sql.set_config(context, key, Some(&self.send_user))?;
|
||||
sql.set_raw_config(context, key, Some(&self.send_user))?;
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
sql.set_config(context, key, Some(&self.send_pw))?;
|
||||
sql.set_raw_config(context, key, Some(&self.send_pw))?;
|
||||
|
||||
let key = format!("{}smtp_certificate_checks", prefix);
|
||||
sql.set_config_int(context, key, self.smtp_certificate_checks as i32)?;
|
||||
sql.set_raw_config_int(context, key, self.smtp_certificate_checks as i32)?;
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
sql.set_config_int(context, key, self.server_flags)?;
|
||||
sql.set_raw_config_int(context, key, self.server_flags)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
|
||||
@@ -107,6 +106,7 @@ impl Message {
|
||||
msg.hidden = row.get(18)?;
|
||||
msg.location_id = row.get(19)?;
|
||||
msg.chat_blocked = row.get::<_, Option<Blocked>>(20)?.unwrap_or_default();
|
||||
|
||||
Ok(msg)
|
||||
})
|
||||
}
|
||||
@@ -339,23 +339,10 @@ impl Message {
|
||||
}
|
||||
|
||||
if let Some(filename) = self.get_file(context) {
|
||||
if let Ok(mut buf) = dc_read_file(context, filename) {
|
||||
unsafe {
|
||||
// just a pointer inside buf, MUST NOT be free()'d
|
||||
let mut buf_headerline = String::default();
|
||||
// just a pointer inside buf, MUST NOT be free()'d
|
||||
let mut buf_setupcodebegin = ptr::null();
|
||||
|
||||
if dc_split_armored_data(
|
||||
buf.as_mut_ptr().cast(),
|
||||
&mut buf_headerline,
|
||||
&mut buf_setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
) && buf_headerline == "-----BEGIN PGP MESSAGE-----"
|
||||
&& !buf_setupcodebegin.is_null()
|
||||
{
|
||||
return Some(to_string(buf_setupcodebegin));
|
||||
if let Ok(ref buf) = dc_read_file(context, filename) {
|
||||
if let Ok((typ, headers, _)) = split_armored_data(buf) {
|
||||
if typ == pgp::armor::BlockType::Message {
|
||||
return headers.get(crate::pgp::HEADER_SETUPCODE).cloned();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,7 +511,7 @@ pub fn get_msg_info(context: &Context, msg_id: u32) -> String {
|
||||
return ret;
|
||||
}
|
||||
|
||||
let msg = msg.unwrap();
|
||||
let msg = msg.unwrap_or_default();
|
||||
|
||||
let rawtxt: Option<String> = context.sql.query_get_value(
|
||||
context,
|
||||
@@ -536,7 +523,7 @@ pub fn get_msg_info(context: &Context, msg_id: u32) -> String {
|
||||
ret += &format!("Cannot load message #{}.", msg_id as usize);
|
||||
return ret;
|
||||
}
|
||||
let rawtxt = rawtxt.unwrap();
|
||||
let rawtxt = rawtxt.unwrap_or_default();
|
||||
let rawtxt = dc_truncate(rawtxt.trim(), 100000, false);
|
||||
|
||||
let fts = dc_timestamp_to_str(msg.get_timestamp());
|
||||
@@ -745,7 +732,7 @@ pub fn markseen_msgs(context: &Context, msg_ids: &[u32]) -> bool {
|
||||
return false;
|
||||
}
|
||||
let mut send_event = false;
|
||||
let msgs = msgs.unwrap();
|
||||
let msgs = msgs.unwrap_or_default();
|
||||
|
||||
for (id, curr_state, curr_blocked) in msgs.into_iter() {
|
||||
if curr_blocked == Blocked::Not {
|
||||
@@ -982,7 +969,7 @@ pub fn mdn_from_ext(
|
||||
context.sql.execute(
|
||||
"INSERT INTO msgs_mdns (msg_id, contact_id, timestamp_sent) VALUES (?, ?, ?);",
|
||||
params![*ret_msg_id as i32, from_id as i32, timestamp_sent],
|
||||
).unwrap(); // TODO: better error handling
|
||||
).unwrap_or_default(); // TODO: better error handling
|
||||
}
|
||||
|
||||
// Normal chat? that's quite easy.
|
||||
|
||||
@@ -60,11 +60,13 @@ pub struct MimeFactory<'a> {
|
||||
|
||||
impl<'a> MimeFactory<'a> {
|
||||
fn new(context: &'a Context, msg: Message) -> Self {
|
||||
let cget = |context: &Context, name: &str| context.sql.get_config(context, name);
|
||||
MimeFactory {
|
||||
from_addr: cget(&context, "configured_addr").unwrap_or_default(),
|
||||
from_displayname: cget(&context, "displayname").unwrap_or_default(),
|
||||
selfstatus: cget(&context, "selfstatus")
|
||||
from_addr: context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default(),
|
||||
from_displayname: context.get_config(Config::Displayname).unwrap_or_default(),
|
||||
selfstatus: context
|
||||
.get_config(Config::Selfstatus)
|
||||
.unwrap_or_else(|| context.stock_str(StockMessage::StatusLine).to_string()),
|
||||
recipients_names: Vec::with_capacity(5),
|
||||
recipients_addr: Vec::with_capacity(5),
|
||||
@@ -669,31 +671,28 @@ impl<'a> MimeFactory<'a> {
|
||||
.push(factory.from_displayname.to_string());
|
||||
factory.recipients_addr.push(factory.from_addr.to_string());
|
||||
} else {
|
||||
context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT c.authname, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![factory.msg.chat_id as i32],
|
||||
|row| {
|
||||
let authname: String = row.get(0)?;
|
||||
let addr: String = row.get(1)?;
|
||||
Ok((authname, addr))
|
||||
},
|
||||
|rows| {
|
||||
for row in rows {
|
||||
let (authname, addr) = row?;
|
||||
if !vec_contains_lowercase(&factory.recipients_addr, &addr) {
|
||||
factory.recipients_addr.push(addr);
|
||||
factory.recipients_names.push(authname);
|
||||
}
|
||||
context.sql.query_map(
|
||||
"SELECT c.authname, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![factory.msg.chat_id as i32],
|
||||
|row| {
|
||||
let authname: String = row.get(0)?;
|
||||
let addr: String = row.get(1)?;
|
||||
Ok((authname, addr))
|
||||
},
|
||||
|rows| {
|
||||
for row in rows {
|
||||
let (authname, addr) = row?;
|
||||
if !vec_contains_lowercase(&factory.recipients_addr, &addr) {
|
||||
factory.recipients_addr.push(addr);
|
||||
factory.recipients_names.push(authname);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
let command = factory.msg.param.get_cmd();
|
||||
let msg = &factory.msg;
|
||||
@@ -703,8 +702,7 @@ impl<'a> MimeFactory<'a> {
|
||||
let email_to_remove = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
if !email_to_remove.is_empty() && email_to_remove != self_addr {
|
||||
@@ -897,9 +895,7 @@ fn build_body_file(
|
||||
wrapmime::append_ct_param(content, "name", &filename_encoded)?;
|
||||
|
||||
let mime_sub = mailmime_new_empty(content, mime_fields);
|
||||
let abs_path = dc_get_abs_path(context, path_filename)
|
||||
.to_c_string()
|
||||
.unwrap();
|
||||
let abs_path = dc_get_abs_path(context, path_filename).to_c_string()?;
|
||||
mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr()));
|
||||
Ok((mime_sub, filename_to_send))
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ pub fn dc_get_oauth2_url(
|
||||
if let Some(oauth2) = Oauth2::from_address(addr) {
|
||||
if context
|
||||
.sql
|
||||
.set_config(
|
||||
.set_raw_config(
|
||||
context,
|
||||
"oauth2_pending_redirect_uri",
|
||||
Some(redirect_uri.as_ref()),
|
||||
@@ -82,17 +82,17 @@ pub fn dc_get_oauth2_access_token(
|
||||
|
||||
// read generated token
|
||||
if !regenerate && !is_expired(context) {
|
||||
let access_token = context.sql.get_config(context, "oauth2_access_token");
|
||||
let access_token = context.sql.get_raw_config(context, "oauth2_access_token");
|
||||
if access_token.is_some() {
|
||||
// success
|
||||
return access_token;
|
||||
}
|
||||
}
|
||||
|
||||
let refresh_token = context.sql.get_config(context, "oauth2_refresh_token");
|
||||
let refresh_token = context.sql.get_raw_config(context, "oauth2_refresh_token");
|
||||
let refresh_token_for = context
|
||||
.sql
|
||||
.get_config(context, "oauth2_refresh_token_for")
|
||||
.get_raw_config(context, "oauth2_refresh_token_for")
|
||||
.unwrap_or_else(|| "unset".into());
|
||||
|
||||
let (redirect_uri, token_url, update_redirect_uri_on_success) =
|
||||
@@ -101,7 +101,7 @@ pub fn dc_get_oauth2_access_token(
|
||||
(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "oauth2_pending_redirect_uri")
|
||||
.get_raw_config(context, "oauth2_pending_redirect_uri")
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.init_token,
|
||||
true,
|
||||
@@ -114,7 +114,7 @@ pub fn dc_get_oauth2_access_token(
|
||||
(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "oauth2_redirect_uri")
|
||||
.get_raw_config(context, "oauth2_redirect_uri")
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.refresh_token,
|
||||
false,
|
||||
@@ -159,11 +159,11 @@ pub fn dc_get_oauth2_access_token(
|
||||
if let Some(ref token) = response.refresh_token {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_refresh_token", Some(token))
|
||||
.set_raw_config(context, "oauth2_refresh_token", Some(token))
|
||||
.ok();
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_refresh_token_for", Some(code.as_ref()))
|
||||
.set_raw_config(context, "oauth2_refresh_token_for", Some(code.as_ref()))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ pub fn dc_get_oauth2_access_token(
|
||||
if let Some(ref token) = response.access_token {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_access_token", Some(token))
|
||||
.set_raw_config(context, "oauth2_access_token", Some(token))
|
||||
.ok();
|
||||
let expires_in = response
|
||||
.expires_in
|
||||
@@ -181,13 +181,13 @@ pub fn dc_get_oauth2_access_token(
|
||||
.unwrap_or_else(|| 0);
|
||||
context
|
||||
.sql
|
||||
.set_config_int64(context, "oauth2_timestamp_expires", expires_in)
|
||||
.set_raw_config_int64(context, "oauth2_timestamp_expires", expires_in)
|
||||
.ok();
|
||||
|
||||
if update_redirect_uri_on_success {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()))
|
||||
.set_raw_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()))
|
||||
.ok();
|
||||
}
|
||||
} else {
|
||||
@@ -293,7 +293,7 @@ impl Oauth2 {
|
||||
fn is_expired(context: &Context) -> bool {
|
||||
let expire_timestamp = context
|
||||
.sql
|
||||
.get_config_int64(context, "oauth2_timestamp_expires")
|
||||
.get_raw_config_int64(context, "oauth2_timestamp_expires")
|
||||
.unwrap_or_default();
|
||||
|
||||
if expire_timestamp <= 0 {
|
||||
|
||||
@@ -122,8 +122,8 @@ impl str::FromStr for Params {
|
||||
ensure!(key.is_some(), "Missing key");
|
||||
ensure!(value.is_some(), "Missing value");
|
||||
|
||||
let key = key.unwrap().trim();
|
||||
let value = value.unwrap().trim();
|
||||
let key = key.unwrap_or_default().trim();
|
||||
let value = value.unwrap_or_default().trim();
|
||||
|
||||
if let Some(key) = Param::from_u8(key.as_bytes()[0]) {
|
||||
inner.insert(key, value.to_string());
|
||||
|
||||
191
src/pgp.rs
191
src/pgp.rs
@@ -1,9 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::convert::TryInto;
|
||||
use std::io::Cursor;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{strchr, strlen, strncmp, strspn, strstr};
|
||||
use pgp::armor::BlockType;
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||
SignedSecretKey, SubkeyParamsBuilder,
|
||||
@@ -12,126 +11,43 @@ use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm};
|
||||
use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait, StringToKey};
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
|
||||
pub unsafe fn dc_split_armored_data(
|
||||
buf: *mut libc::c_char,
|
||||
ret_headerline: *mut String,
|
||||
ret_setupcodebegin: *mut *const libc::c_char,
|
||||
ret_preferencrypt: *mut *const libc::c_char,
|
||||
ret_base64: *mut *const libc::c_char,
|
||||
) -> bool {
|
||||
let mut success = false;
|
||||
let mut line_chars: libc::size_t = 0;
|
||||
let mut line: *mut libc::c_char = buf;
|
||||
let mut p1: *mut libc::c_char = buf;
|
||||
let mut p2: *mut libc::c_char;
|
||||
let mut headerline: *mut libc::c_char = ptr::null_mut();
|
||||
let mut base64: *mut libc::c_char = ptr::null_mut();
|
||||
if !ret_setupcodebegin.is_null() {
|
||||
*ret_setupcodebegin = ptr::null_mut();
|
||||
}
|
||||
if !ret_preferencrypt.is_null() {
|
||||
*ret_preferencrypt = ptr::null();
|
||||
}
|
||||
if !ret_base64.is_null() {
|
||||
*ret_base64 = ptr::null();
|
||||
}
|
||||
if !buf.is_null() {
|
||||
dc_remove_cr_chars(buf);
|
||||
while 0 != *p1 {
|
||||
if i32::from(*p1) == '\n' as i32 {
|
||||
*line.offset(line_chars as isize) = 0i32 as libc::c_char;
|
||||
if headerline.is_null() {
|
||||
dc_trim(line);
|
||||
if strncmp(
|
||||
line,
|
||||
b"-----BEGIN \x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
) == 0i32
|
||||
&& strncmp(
|
||||
&mut *line.offset(strlen(line).wrapping_sub(5) as isize),
|
||||
b"-----\x00" as *const u8 as *const libc::c_char,
|
||||
5,
|
||||
) == 0i32
|
||||
{
|
||||
headerline = line;
|
||||
*ret_headerline = as_str(headerline).to_string();
|
||||
}
|
||||
} else if strspn(line, b"\t\r\n \x00" as *const u8 as *const libc::c_char)
|
||||
== strlen(line)
|
||||
{
|
||||
base64 = p1.offset(1isize);
|
||||
break;
|
||||
} else {
|
||||
p2 = strchr(line, ':' as i32);
|
||||
if p2.is_null() {
|
||||
*line.add(line_chars) = '\n' as i32 as libc::c_char;
|
||||
base64 = line;
|
||||
break;
|
||||
} else {
|
||||
*p2 = 0i32 as libc::c_char;
|
||||
dc_trim(line);
|
||||
if strcasecmp(
|
||||
line,
|
||||
b"Passphrase-Begin\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
p2 = p2.offset(1isize);
|
||||
dc_trim(p2);
|
||||
if !ret_setupcodebegin.is_null() {
|
||||
*ret_setupcodebegin = p2
|
||||
}
|
||||
} else if strcasecmp(
|
||||
line,
|
||||
b"Autocrypt-Prefer-Encrypt\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
p2 = p2.offset(1isize);
|
||||
dc_trim(p2);
|
||||
if !ret_preferencrypt.is_null() {
|
||||
*ret_preferencrypt = p2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p1 = p1.offset(1isize);
|
||||
line = p1;
|
||||
line_chars = 0;
|
||||
} else {
|
||||
p1 = p1.offset(1isize);
|
||||
line_chars = line_chars.wrapping_add(1)
|
||||
}
|
||||
}
|
||||
if !(headerline.is_null() || base64.is_null()) {
|
||||
/* now, line points to beginning of base64 data, search end */
|
||||
/*the trailing space makes sure, this is not a normal base64 sequence*/
|
||||
p1 = strstr(base64, b"-----END \x00" as *const u8 as *const libc::c_char);
|
||||
if !(p1.is_null()
|
||||
|| strncmp(
|
||||
p1.offset(9isize),
|
||||
headerline.offset(11isize),
|
||||
strlen(headerline.offset(11isize)),
|
||||
) != 0i32)
|
||||
{
|
||||
*p1 = 0i32 as libc::c_char;
|
||||
dc_trim(base64);
|
||||
if !ret_base64.is_null() {
|
||||
*ret_base64 = base64
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt";
|
||||
pub const HEADER_SETUPCODE: &str = "passphrase-begin";
|
||||
|
||||
success
|
||||
/// Split data from PGP Armored Data as defined in https://tools.ietf.org/html/rfc4880#section-6.2.
|
||||
///
|
||||
/// Returns (type, headers, base64 encoded body).
|
||||
pub fn split_armored_data(
|
||||
buf: &[u8],
|
||||
) -> Result<(BlockType, BTreeMap<String, String>, Vec<u8>), Error> {
|
||||
use std::io::Read;
|
||||
|
||||
let cursor = Cursor::new(buf);
|
||||
let mut dearmor = pgp::armor::Dearmor::new(cursor);
|
||||
|
||||
let mut bytes = Vec::with_capacity(buf.len());
|
||||
|
||||
dearmor.read_to_end(&mut bytes)?;
|
||||
ensure!(dearmor.typ.is_some(), "Failed to parse type");
|
||||
|
||||
let typ = dearmor.typ.unwrap();
|
||||
|
||||
// normalize headers
|
||||
let headers = dearmor
|
||||
.headers
|
||||
.into_iter()
|
||||
.map(|(key, value)| (key.trim().to_lowercase(), value.trim().to_string()))
|
||||
.collect();
|
||||
|
||||
Ok((typ, headers, bytes))
|
||||
}
|
||||
|
||||
/// Create a new key pair.
|
||||
pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
|
||||
pub fn create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
|
||||
let user_id = format!("<{}>", addr.as_ref());
|
||||
|
||||
let key_params = SecretKeyParamsBuilder::default()
|
||||
@@ -181,7 +97,7 @@ pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
|
||||
Some((Key::Public(public_key), Key::Secret(private_key)))
|
||||
}
|
||||
|
||||
pub fn dc_pgp_pk_encrypt(
|
||||
pub fn pk_encrypt(
|
||||
plain: &[u8],
|
||||
public_keys_for_encryption: &Keyring,
|
||||
private_key_for_signing: Option<&Key>,
|
||||
@@ -218,7 +134,7 @@ pub fn dc_pgp_pk_encrypt(
|
||||
Ok(encoded_msg)
|
||||
}
|
||||
|
||||
pub fn dc_pgp_pk_decrypt(
|
||||
pub fn pk_decrypt(
|
||||
ctext: &[u8],
|
||||
private_keys_for_decryption: &Keyring,
|
||||
public_keys_for_validation: &Keyring,
|
||||
@@ -267,7 +183,7 @@ pub fn dc_pgp_pk_decrypt(
|
||||
}
|
||||
|
||||
/// Symmetric encryption.
|
||||
pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Error> {
|
||||
pub fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Error> {
|
||||
let mut rng = thread_rng();
|
||||
let lit_msg = Message::new_literal_bytes("", plain);
|
||||
|
||||
@@ -281,8 +197,11 @@ pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Err
|
||||
}
|
||||
|
||||
/// Symmetric decryption.
|
||||
pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Result<Vec<u8>, Error> {
|
||||
let enc_msg = Message::from_bytes(Cursor::new(ctext))?;
|
||||
pub fn symm_decrypt<T: std::io::Read + std::io::Seek>(
|
||||
passphrase: &str,
|
||||
ctext: T,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let (enc_msg, _) = Message::from_armor_single(ctext)?;
|
||||
let decryptor = enc_msg.decrypt_with_password(|| passphrase.into())?;
|
||||
|
||||
let msgs = decryptor.collect::<Result<Vec<_>, _>>()?;
|
||||
@@ -293,3 +212,35 @@ pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Result<Vec<u8>, Er
|
||||
None => bail!("Decrypted message is empty"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_split_armored_data_1() {
|
||||
let (typ, _headers, base64) = split_armored_data(
|
||||
b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\naGVsbG8gd29ybGQ=\n-----END PGP MESSAGE----",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(typ, BlockType::Message);
|
||||
assert!(!base64.is_empty());
|
||||
assert_eq!(
|
||||
std::string::String::from_utf8(base64).unwrap(),
|
||||
"hello world"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_armored_data_2() {
|
||||
let (typ, headers, base64) = split_armored_data(
|
||||
b"-----BEGIN PGP PRIVATE KEY BLOCK-----\nAutocrypt-Prefer-Encrypt: mutual \n\naGVsbG8gd29ybGQ=\n-----END PGP PRIVATE KEY BLOCK-----"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(typ, BlockType::PrivateKey);
|
||||
assert!(!base64.is_empty());
|
||||
assert_eq!(headers.get(HEADER_AUTOCRYPT), Some(&"mutual".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
|
||||
use crate::aheader::EncryptPreference;
|
||||
use crate::chat::{self, Chat};
|
||||
use crate::config::*;
|
||||
use crate::configure::*;
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
@@ -82,10 +81,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: u32) -> Option<Str
|
||||
}
|
||||
};
|
||||
|
||||
let self_name = context
|
||||
.sql
|
||||
.get_config(context, "displayname")
|
||||
.unwrap_or_default();
|
||||
let self_name = context.get_config(Config::Displayname).unwrap_or_default();
|
||||
|
||||
fingerprint = match get_self_fingerprint(context) {
|
||||
Some(fp) => fp,
|
||||
@@ -160,7 +156,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
|
||||
bob.qr_scan = None;
|
||||
|
||||
if ongoing_allocated {
|
||||
dc_free_ongoing(context);
|
||||
context.free_ongoing();
|
||||
}
|
||||
ret_chat_id as u32
|
||||
};
|
||||
@@ -173,7 +169,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
|
||||
|
||||
info!(context, "Requesting secure-join ...",);
|
||||
ensure_secret_key_exists(context).ok();
|
||||
if !dc_alloc_ongoing(context) {
|
||||
if !context.alloc_ongoing() {
|
||||
return cleanup(&context, contact_chat_id, false, join_vg);
|
||||
}
|
||||
let qr_scan = check_qr(context, &qr);
|
||||
@@ -187,7 +183,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
|
||||
error!(context, "Unknown contact.",);
|
||||
return cleanup(&context, contact_chat_id, true, join_vg);
|
||||
}
|
||||
if check_exit(context) {
|
||||
if context.shall_stop_ongoing() {
|
||||
return cleanup(&context, contact_chat_id, true, join_vg);
|
||||
}
|
||||
join_vg = qr_scan.get_state() == LotState::QrAskVerifyGroup;
|
||||
@@ -213,7 +209,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
|
||||
info!(context, "Taking protocol shortcut.");
|
||||
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
|
||||
joiner_progress!(context, chat_id_2_contact_id(context, contact_chat_id), 400);
|
||||
let own_fingerprint = get_self_fingerprint(context).unwrap();
|
||||
let own_fingerprint = get_self_fingerprint(context).unwrap_or_default();
|
||||
send_handshake_msg(
|
||||
context,
|
||||
contact_chat_id,
|
||||
@@ -243,21 +239,12 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
|
||||
}
|
||||
|
||||
// Bob -> Alice
|
||||
while !check_exit(&context) {
|
||||
while !context.shall_stop_ongoing() {
|
||||
std::thread::sleep(std::time::Duration::new(0, 3_000_000));
|
||||
}
|
||||
cleanup(&context, contact_chat_id, true, join_vg)
|
||||
}
|
||||
|
||||
fn check_exit(context: &Context) -> bool {
|
||||
context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
}
|
||||
|
||||
fn send_handshake_msg(
|
||||
context: &Context,
|
||||
contact_chat_id: u32,
|
||||
@@ -294,7 +281,7 @@ fn send_handshake_msg(
|
||||
msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
}
|
||||
// TODO. handle cleanup on error
|
||||
chat::send_msg(context, contact_chat_id, &mut msg).unwrap();
|
||||
chat::send_msg(context, contact_chat_id, &mut msg).unwrap_or_default();
|
||||
}
|
||||
|
||||
fn chat_id_2_contact_id(context: &Context, contact_chat_id: u32) -> u32 {
|
||||
@@ -639,7 +626,7 @@ pub fn handle_securejoin_handshake(
|
||||
|
||||
fn end_bobs_joining(context: &Context, status: libc::c_int) {
|
||||
context.bob.write().unwrap().status = status;
|
||||
dc_stop_ongoing_process(context);
|
||||
context.stop_ongoing();
|
||||
}
|
||||
|
||||
fn secure_connection_established(context: &Context, contact_chat_id: u32) {
|
||||
@@ -678,7 +665,9 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
|
||||
if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
|
||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||
peerstate.to_save = Some(ToSave::All);
|
||||
peerstate.save_to_db(&context.sql, false).unwrap();
|
||||
peerstate
|
||||
.save_to_db(&context.sql, false)
|
||||
.unwrap_or_default();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,10 @@ impl Smtp {
|
||||
}
|
||||
let user = &lp.send_user;
|
||||
|
||||
lettre::smtp::authentication::Credentials::new(user.to_string(), access_token.unwrap())
|
||||
lettre::smtp::authentication::Credentials::new(
|
||||
user.to_string(),
|
||||
access_token.unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
// plain
|
||||
let user = lp.send_user.clone();
|
||||
|
||||
90
src/sql.rs
90
src/sql.rs
@@ -193,14 +193,14 @@ impl Sql {
|
||||
///
|
||||
/// Setting `None` deletes the value. On failure an error message
|
||||
/// will already have been logged.
|
||||
pub fn set_config(
|
||||
pub fn set_raw_config(
|
||||
&self,
|
||||
context: &Context,
|
||||
key: impl AsRef<str>,
|
||||
value: Option<&str>,
|
||||
) -> Result<()> {
|
||||
if !self.is_open() {
|
||||
error!(context, "set_config(): Database not ready.");
|
||||
error!(context, "set_raw_config(): Database not ready.");
|
||||
return Err(Error::SqlNoConnection);
|
||||
}
|
||||
|
||||
@@ -234,14 +234,14 @@ impl Sql {
|
||||
match res {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
error!(context, "set_config(): Cannot change value. {:?}", &err);
|
||||
error!(context, "set_raw_config(): Cannot change value. {:?}", &err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get configuration options from the database.
|
||||
pub fn get_config(&self, context: &Context, key: impl AsRef<str>) -> Option<String> {
|
||||
pub fn get_raw_config(&self, context: &Context, key: impl AsRef<str>) -> Option<String> {
|
||||
if !self.is_open() || key.as_ref().is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -252,44 +252,46 @@ impl Sql {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_config_int(
|
||||
pub fn set_raw_config_int(
|
||||
&self,
|
||||
context: &Context,
|
||||
key: impl AsRef<str>,
|
||||
value: i32,
|
||||
) -> Result<()> {
|
||||
self.set_config(context, key, Some(&format!("{}", value)))
|
||||
self.set_raw_config(context, key, Some(&format!("{}", value)))
|
||||
}
|
||||
|
||||
pub fn get_config_int(&self, context: &Context, key: impl AsRef<str>) -> Option<i32> {
|
||||
self.get_config(context, key).and_then(|s| s.parse().ok())
|
||||
pub fn get_raw_config_int(&self, context: &Context, key: impl AsRef<str>) -> Option<i32> {
|
||||
self.get_raw_config(context, key)
|
||||
.and_then(|s| s.parse().ok())
|
||||
}
|
||||
|
||||
pub fn get_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
|
||||
pub fn get_raw_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
|
||||
// Not the most obvious way to encode bool as string, but it is matter
|
||||
// of backward compatibility.
|
||||
self.get_config_int(context, key).unwrap_or_default() > 0
|
||||
self.get_raw_config_int(context, key).unwrap_or_default() > 0
|
||||
}
|
||||
|
||||
pub fn set_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
|
||||
pub fn set_raw_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
let value = if value { Some("1") } else { None };
|
||||
self.set_config(context, key, value)
|
||||
self.set_raw_config(context, key, value)
|
||||
}
|
||||
|
||||
pub fn set_config_int64(
|
||||
pub fn set_raw_config_int64(
|
||||
&self,
|
||||
context: &Context,
|
||||
key: impl AsRef<str>,
|
||||
value: i64,
|
||||
) -> Result<()> {
|
||||
self.set_config(context, key, Some(&format!("{}", value)))
|
||||
self.set_raw_config(context, key, Some(&format!("{}", value)))
|
||||
}
|
||||
|
||||
pub fn get_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
|
||||
self.get_config(context, key).and_then(|r| r.parse().ok())
|
||||
pub fn get_raw_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
|
||||
self.get_raw_config(context, key)
|
||||
.and_then(|r| r.parse().ok())
|
||||
}
|
||||
|
||||
fn start_stmt(&self, stmt: impl AsRef<str>) {
|
||||
@@ -477,11 +479,13 @@ fn open(
|
||||
// cannot create the tables - maybe we cannot write?
|
||||
return Err(Error::SqlFailedToOpen);
|
||||
} else {
|
||||
sql.set_config_int(context, "dbversion", 0)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 0)?;
|
||||
}
|
||||
} else {
|
||||
exists_before_update = 1;
|
||||
dbversion_before_update = sql.get_config_int(context, "dbversion").unwrap_or_default();
|
||||
dbversion_before_update = sql
|
||||
.get_raw_config_int(context, "dbversion")
|
||||
.unwrap_or_default();
|
||||
}
|
||||
|
||||
// (1) update low-level database structure.
|
||||
@@ -503,7 +507,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 1;
|
||||
sql.set_config_int(context, "dbversion", 1)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 1)?;
|
||||
}
|
||||
if dbversion < 2 {
|
||||
info!(context, "[migration] v2");
|
||||
@@ -512,7 +516,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 2;
|
||||
sql.set_config_int(context, "dbversion", 2)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 2)?;
|
||||
}
|
||||
if dbversion < 7 {
|
||||
info!(context, "[migration] v7");
|
||||
@@ -527,7 +531,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 7;
|
||||
sql.set_config_int(context, "dbversion", 7)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 7)?;
|
||||
}
|
||||
if dbversion < 10 {
|
||||
info!(context, "[migration] v10");
|
||||
@@ -546,7 +550,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 10;
|
||||
sql.set_config_int(context, "dbversion", 10)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 10)?;
|
||||
}
|
||||
if dbversion < 12 {
|
||||
info!(context, "[migration] v12");
|
||||
@@ -559,7 +563,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 12;
|
||||
sql.set_config_int(context, "dbversion", 12)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 12)?;
|
||||
}
|
||||
if dbversion < 17 {
|
||||
info!(context, "[migration] v17");
|
||||
@@ -574,7 +578,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("CREATE INDEX msgs_index5 ON msgs (starred);", params![])?;
|
||||
dbversion = 17;
|
||||
sql.set_config_int(context, "dbversion", 17)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 17)?;
|
||||
}
|
||||
if dbversion < 18 {
|
||||
info!(context, "[migration] v18");
|
||||
@@ -584,7 +588,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("ALTER TABLE acpeerstates ADD COLUMN gossip_key;", params![])?;
|
||||
dbversion = 18;
|
||||
sql.set_config_int(context, "dbversion", 18)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 18)?;
|
||||
}
|
||||
if dbversion < 27 {
|
||||
info!(context, "[migration] v27");
|
||||
@@ -602,7 +606,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 27;
|
||||
sql.set_config_int(context, "dbversion", 27)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 27)?;
|
||||
}
|
||||
if dbversion < 34 {
|
||||
info!(context, "[migration] v34");
|
||||
@@ -632,7 +636,7 @@ fn open(
|
||||
)?;
|
||||
recalc_fingerprints = 1;
|
||||
dbversion = 34;
|
||||
sql.set_config_int(context, "dbversion", 34)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 34)?;
|
||||
}
|
||||
if dbversion < 39 {
|
||||
info!(context, "[migration] v39");
|
||||
@@ -663,7 +667,7 @@ fn open(
|
||||
)?;
|
||||
}
|
||||
dbversion = 39;
|
||||
sql.set_config_int(context, "dbversion", 39)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 39)?;
|
||||
}
|
||||
if dbversion < 40 {
|
||||
info!(context, "[migration] v40");
|
||||
@@ -672,25 +676,25 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 40;
|
||||
sql.set_config_int(context, "dbversion", 40)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 40)?;
|
||||
}
|
||||
if dbversion < 41 {
|
||||
info!(context, "[migration] v41");
|
||||
update_file_paths = 1;
|
||||
dbversion = 41;
|
||||
sql.set_config_int(context, "dbversion", 41)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 41)?;
|
||||
}
|
||||
if dbversion < 42 {
|
||||
info!(context, "[migration] v42");
|
||||
sql.execute("UPDATE msgs SET txt='' WHERE type!=10", params![])?;
|
||||
dbversion = 42;
|
||||
sql.set_config_int(context, "dbversion", 42)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 42)?;
|
||||
}
|
||||
if dbversion < 44 {
|
||||
info!(context, "[migration] v44");
|
||||
sql.execute("ALTER TABLE msgs ADD COLUMN mime_headers TEXT;", params![])?;
|
||||
dbversion = 44;
|
||||
sql.set_config_int(context, "dbversion", 44)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 44)?;
|
||||
}
|
||||
if dbversion < 46 {
|
||||
info!(context, "[migration] v46");
|
||||
@@ -703,7 +707,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 46;
|
||||
sql.set_config_int(context, "dbversion", 46)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 46)?;
|
||||
}
|
||||
if dbversion < 47 {
|
||||
info!(context, "[migration] v47");
|
||||
@@ -712,7 +716,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 47;
|
||||
sql.set_config_int(context, "dbversion", 47)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 47)?;
|
||||
}
|
||||
if dbversion < 48 {
|
||||
info!(context, "[migration] v48");
|
||||
@@ -722,7 +726,7 @@ fn open(
|
||||
)?;
|
||||
|
||||
dbversion = 48;
|
||||
sql.set_config_int(context, "dbversion", 48)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 48)?;
|
||||
}
|
||||
if dbversion < 49 {
|
||||
info!(context, "[migration] v49");
|
||||
@@ -731,15 +735,15 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 49;
|
||||
sql.set_config_int(context, "dbversion", 49)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 49)?;
|
||||
}
|
||||
if dbversion < 50 {
|
||||
info!(context, "[migration] v50");
|
||||
if 0 != exists_before_update {
|
||||
sql.set_config_int(context, "show_emails", 2)?;
|
||||
sql.set_raw_config_int(context, "show_emails", 2)?;
|
||||
}
|
||||
dbversion = 50;
|
||||
sql.set_config_int(context, "dbversion", 50)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 50)?;
|
||||
}
|
||||
if dbversion < 53 {
|
||||
info!(context, "[migration] v53");
|
||||
@@ -772,7 +776,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 53;
|
||||
sql.set_config_int(context, "dbversion", 53)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 53)?;
|
||||
}
|
||||
if dbversion < 54 {
|
||||
info!(context, "[migration] v54");
|
||||
@@ -782,7 +786,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("CREATE INDEX msgs_index6 ON msgs (location_id);", params![])?;
|
||||
dbversion = 54;
|
||||
sql.set_config_int(context, "dbversion", 54)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 54)?;
|
||||
}
|
||||
if dbversion < 55 {
|
||||
info!(context, "[migration] v55");
|
||||
@@ -791,7 +795,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
|
||||
sql.set_config_int(context, "dbversion", 55)?;
|
||||
sql.set_raw_config_int(context, "dbversion", 55)?;
|
||||
}
|
||||
|
||||
if 0 != recalc_fingerprints {
|
||||
@@ -818,7 +822,7 @@ fn open(
|
||||
// this snippet converts older databases and can be removed after some time.
|
||||
info!(context, "[migration] update file paths");
|
||||
let repl_from = sql
|
||||
.get_config(context, "backup_for")
|
||||
.get_raw_config(context, "backup_for")
|
||||
.unwrap_or_else(|| context.get_blobdir().to_string_lossy().into());
|
||||
|
||||
let repl_from = dc_ensure_no_slash_safe(&repl_from);
|
||||
@@ -838,7 +842,7 @@ fn open(
|
||||
NO_PARAMS,
|
||||
)?;
|
||||
|
||||
sql.set_config(context, "backup_for", None)?;
|
||||
sql.set_raw_config(context, "backup_for", None)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
90
src/stock.rs
90
src/stock.rs
@@ -5,8 +5,7 @@ use strum_macros::EnumProperty;
|
||||
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use crate::error::Error;
|
||||
|
||||
/// Stock strings
|
||||
///
|
||||
@@ -118,24 +117,52 @@ impl StockMessage {
|
||||
///
|
||||
/// These could be used in logging calls, so no logging here.
|
||||
fn fallback(&self) -> &'static str {
|
||||
self.get_str("fallback").unwrap()
|
||||
self.get_str("fallback").unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Set the stock string for the [StockMessage].
|
||||
///
|
||||
pub fn set_stock_translation(
|
||||
&self,
|
||||
id: StockMessage,
|
||||
stockstring: String,
|
||||
) -> Result<(), Error> {
|
||||
if stockstring.contains("%1") && !id.fallback().contains("%1") {
|
||||
bail!(
|
||||
"translation {} contains invalid %1 placeholder, default is {}",
|
||||
stockstring,
|
||||
id.fallback()
|
||||
);
|
||||
}
|
||||
if stockstring.contains("%2") && !id.fallback().contains("%2") {
|
||||
bail!(
|
||||
"translation {} contains invalid %2 placeholder, default is {}",
|
||||
stockstring,
|
||||
id.fallback()
|
||||
);
|
||||
}
|
||||
self.translated_stockstrings
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(id as usize, stockstring);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the stock string for the [StockMessage].
|
||||
///
|
||||
/// If the context callback responds with a string to use, e.g. a
|
||||
/// translation, then this string will be returned. Otherwise a
|
||||
/// default (English) string is returned.
|
||||
/// Return a translation (if it was set with set_stock_translation before)
|
||||
/// or a default (English) string.
|
||||
pub fn stock_str(&self, id: StockMessage) -> Cow<str> {
|
||||
let ptr = self.call_cb(Event::GetString { id, count: 0 }) as *mut libc::c_char;
|
||||
if ptr.is_null() {
|
||||
Cow::Borrowed(id.fallback())
|
||||
} else {
|
||||
let ret = to_string(ptr);
|
||||
unsafe { libc::free(ptr as *mut libc::c_void) };
|
||||
Cow::Owned(ret)
|
||||
match self
|
||||
.translated_stockstrings
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&(id as usize))
|
||||
{
|
||||
Some(ref x) => Cow::Owned(x.to_string()),
|
||||
None => Cow::Borrowed(id.fallback()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +266,6 @@ mod tests {
|
||||
use crate::test_utils::*;
|
||||
|
||||
use crate::constants::DC_CONTACT_ID_SELF;
|
||||
use libc::uintptr_t;
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
@@ -255,25 +281,31 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stock_str() {
|
||||
fn test_set_stock_translation() {
|
||||
let t = dummy_context();
|
||||
assert_eq!(t.ctx.stock_str(StockMessage::NoMessages), "No messages.");
|
||||
}
|
||||
|
||||
fn test_stock_str_no_fallback_cb(_ctx: &Context, evt: Event) -> uintptr_t {
|
||||
match evt {
|
||||
Event::GetString {
|
||||
id: StockMessage::NoMessages,
|
||||
..
|
||||
} => unsafe { "Hello there".strdup() as usize },
|
||||
_ => 0,
|
||||
}
|
||||
t.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz".to_string())
|
||||
.unwrap();
|
||||
assert_eq!(t.ctx.stock_str(StockMessage::NoMessages), "xyz")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stock_str_no_fallback() {
|
||||
let t = test_context(Some(Box::new(test_stock_str_no_fallback_cb)));
|
||||
assert_eq!(t.ctx.stock_str(StockMessage::NoMessages), "Hello there");
|
||||
fn test_set_stock_translation_wrong_replacements() {
|
||||
let t = dummy_context();
|
||||
assert!(t
|
||||
.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %1$s ".to_string())
|
||||
.is_err());
|
||||
assert!(t
|
||||
.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %2$s ".to_string())
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stock_str() {
|
||||
let t = dummy_context();
|
||||
assert_eq!(t.ctx.stock_str(StockMessage::NoMessages), "No messages.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,24 +14,24 @@ if __name__ == "__main__":
|
||||
s = re.sub(r"(?m)///.*$", "", s) # remove comments
|
||||
unsafe = s.count("unsafe")
|
||||
free = s.count("free(")
|
||||
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
|
||||
unsafe_fn = s.count("unsafe fn")
|
||||
chars = s.count("c_char") + s.count("CStr")
|
||||
filestats.append((fn, unsafe, free, gotoblocks, chars))
|
||||
filestats.append((fn, unsafe, free, unsafe_fn, chars))
|
||||
|
||||
sum_unsafe, sum_free, sum_gotoblocks, sum_chars = 0, 0, 0, 0
|
||||
sum_unsafe, sum_free, sum_unsafe_fn, sum_chars = 0, 0, 0, 0
|
||||
|
||||
for fn, unsafe, free, gotoblocks, chars in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
if unsafe + free + gotoblocks + chars == 0:
|
||||
for fn, unsafe, free, unsafe_fn, chars in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
if unsafe + free + unsafe_fn + chars == 0:
|
||||
continue
|
||||
print("{0: <25} unsafe: {1: >3} free: {2: >3} ok_to_cont: {3: >3} chars: {4: >3}".format(str(fn), unsafe, free, gotoblocks, chars))
|
||||
print("{0: <25} unsafe: {1: >3} free: {2: >3} unsafe-fn: {3: >3} chars: {4: >3}".format(str(fn), unsafe, free, unsafe_fn, chars))
|
||||
sum_unsafe += unsafe
|
||||
sum_free += free
|
||||
sum_gotoblocks += gotoblocks
|
||||
sum_unsafe_fn += unsafe_fn
|
||||
sum_chars += chars
|
||||
|
||||
|
||||
print()
|
||||
print("total unsafe:", sum_unsafe)
|
||||
print("total free:", sum_free)
|
||||
print("total ok_to_continue:", sum_gotoblocks)
|
||||
print("total unsafe-fn:", sum_unsafe_fn)
|
||||
print("total c_chars:", sum_chars)
|
||||
|
||||
@@ -42,7 +42,7 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
|
||||
let ct: *mut mailmime_content = (*mime).mm_content_type;
|
||||
|
||||
if !ct.is_null() && !(*ct).ct_subtype.is_null() {
|
||||
Some(to_string((*ct).ct_subtype))
|
||||
Some(to_string_lossy((*ct).ct_subtype))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -51,7 +51,7 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
|
||||
|
||||
pub fn parse_message_id(message_id: &str) -> Result<String, Error> {
|
||||
let mut dummy = 0;
|
||||
let c_message_id = CString::new(message_id).unwrap();
|
||||
let c_message_id = CString::new(message_id).unwrap_or_default();
|
||||
let c_ptr = c_message_id.as_ptr();
|
||||
let mut rfc724_mid_c = std::ptr::null_mut();
|
||||
if unsafe { mailimf_msg_id_parse(c_ptr, libc::strlen(c_ptr), &mut dummy, &mut rfc724_mid_c) }
|
||||
@@ -175,21 +175,21 @@ pub fn mailimf_find_field(
|
||||
}
|
||||
|
||||
/*the result is a pointer to mime, must not be freed*/
|
||||
pub unsafe fn mailmime_find_mailimf_fields(mime: *mut Mailmime) -> *mut mailimf_fields {
|
||||
pub fn mailmime_find_mailimf_fields(mime: *mut Mailmime) -> *mut mailimf_fields {
|
||||
if mime.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
match (*mime).mm_type as _ {
|
||||
match unsafe { (*mime).mm_type as _ } {
|
||||
MAILMIME_MULTIPLE => {
|
||||
for cur_data in (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() {
|
||||
for cur_data in unsafe { (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() } {
|
||||
let header = mailmime_find_mailimf_fields(cur_data as *mut _);
|
||||
if !header.is_null() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
MAILMIME_MESSAGE => return (*mime).mm_data.mm_message.mm_fields,
|
||||
MAILMIME_MESSAGE => return unsafe { (*mime).mm_data.mm_message.mm_fields },
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -448,8 +448,8 @@ pub fn append_ct_param(
|
||||
value: &str,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let name_c = CString::new(name).unwrap();
|
||||
let value_c = CString::new(value).unwrap();
|
||||
let name_c = CString::new(name).unwrap_or_default();
|
||||
let value_c = CString::new(value).unwrap_or_default();
|
||||
|
||||
clist_append!(
|
||||
(*content).ct_parameters,
|
||||
@@ -463,7 +463,7 @@ pub fn append_ct_param(
|
||||
}
|
||||
|
||||
pub fn new_content_type(content_type: &str) -> Result<*mut mailmime_content, Error> {
|
||||
let ct = CString::new(content_type).unwrap();
|
||||
let ct = CString::new(content_type).unwrap_or_default();
|
||||
let content: *mut mailmime_content;
|
||||
// mailmime_content_new_with_str only parses but does not retain/own ct
|
||||
unsafe {
|
||||
|
||||
155
tests/stress.rs
155
tests/stress.rs
@@ -1,18 +1,15 @@
|
||||
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::ptr;
|
||||
|
||||
use deltachat::chat::{self, Chat};
|
||||
use deltachat::config;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::keyring::*;
|
||||
use deltachat::oauth2::*;
|
||||
use deltachat::pgp::*;
|
||||
use deltachat::pgp;
|
||||
use deltachat::Event;
|
||||
use libc::{free, strcmp, strdup};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
/* some data used for testing
|
||||
@@ -50,135 +47,6 @@ unsafe fn stress_functions(context: &Context) {
|
||||
assert!(res.contains(" configured_send_port "));
|
||||
assert!(res.contains(" configured_server_flags "));
|
||||
|
||||
let mut buf_0: *mut libc::c_char;
|
||||
let mut headerline = String::default();
|
||||
let mut setupcodebegin: *const libc::c_char = ptr::null();
|
||||
let mut preferencrypt: *const libc::c_char = ptr::null();
|
||||
let mut base64: *const libc::c_char = ptr::null();
|
||||
buf_0 = strdup(
|
||||
b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\ndata\n-----END PGP MESSAGE-----\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
&mut base64,
|
||||
);
|
||||
assert!(ok);
|
||||
assert!(!headerline.is_empty());
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
|
||||
assert!(!base64.is_null());
|
||||
assert_eq!(as_str(base64 as *const libc::c_char), "data",);
|
||||
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
|
||||
buf_0 =
|
||||
strdup(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
&mut base64,
|
||||
);
|
||||
|
||||
assert!(ok);
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
|
||||
assert!(!base64.is_null());
|
||||
assert_eq!(as_str(base64 as *const libc::c_char), "dat1",);
|
||||
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
|
||||
buf_0 = strdup(
|
||||
b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
&mut base64,
|
||||
);
|
||||
|
||||
assert!(ok);
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
assert!(setupcodebegin.is_null());
|
||||
|
||||
assert!(!base64.is_null());
|
||||
assert_eq!(as_str(base64 as *const libc::c_char), "base64-123",);
|
||||
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
|
||||
buf_0 = strdup(b"foo-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
&mut base64,
|
||||
);
|
||||
|
||||
assert!(!ok);
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
buf_0 =
|
||||
strdup(b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
&mut base64,
|
||||
);
|
||||
assert!(ok);
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
|
||||
assert!(!setupcodebegin.is_null());
|
||||
assert_eq!(
|
||||
strcmp(
|
||||
setupcodebegin,
|
||||
b"23\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
assert!(!base64.is_null());
|
||||
assert_eq!(as_str(base64 as *const libc::c_char), "base64-567 \n abc",);
|
||||
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
|
||||
buf_0 =
|
||||
strdup(b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
let ok = dc_split_armored_data(
|
||||
buf_0,
|
||||
&mut headerline,
|
||||
ptr::null_mut(),
|
||||
&mut preferencrypt,
|
||||
&mut base64,
|
||||
);
|
||||
assert!(ok);
|
||||
assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----");
|
||||
assert!(!preferencrypt.is_null());
|
||||
assert_eq!(
|
||||
strcmp(
|
||||
preferencrypt,
|
||||
b"mutual\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
assert!(!base64.is_null());
|
||||
assert_eq!(as_str(base64 as *const libc::c_char), "base64",);
|
||||
|
||||
free(buf_0 as *mut libc::c_void);
|
||||
|
||||
// Cant check, no configured context
|
||||
// assert!(dc_is_configured(context) != 0, "Missing configured context");
|
||||
|
||||
@@ -232,11 +100,11 @@ unsafe fn stress_functions(context: &Context) {
|
||||
#[test]
|
||||
#[ignore] // is too expensive
|
||||
fn test_encryption_decryption() {
|
||||
let (public_key, private_key) = dc_pgp_create_keypair("foo@bar.de").unwrap();
|
||||
let (public_key, private_key) = pgp::create_keypair("foo@bar.de").unwrap();
|
||||
|
||||
private_key.split_key().unwrap();
|
||||
|
||||
let (public_key2, private_key2) = dc_pgp_create_keypair("two@zwo.de").unwrap();
|
||||
let (public_key2, private_key2) = pgp::create_keypair("two@zwo.de").unwrap();
|
||||
|
||||
assert_ne!(public_key, public_key2);
|
||||
|
||||
@@ -245,11 +113,11 @@ fn test_encryption_decryption() {
|
||||
keyring.add_owned(public_key.clone());
|
||||
keyring.add_ref(&public_key2);
|
||||
|
||||
let ctext_signed = dc_pgp_pk_encrypt(original_text, &keyring, Some(&private_key)).unwrap();
|
||||
let ctext_signed = pgp::pk_encrypt(original_text, &keyring, Some(&private_key)).unwrap();
|
||||
assert!(!ctext_signed.is_empty());
|
||||
assert!(ctext_signed.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
let ctext_unsigned = dc_pgp_pk_encrypt(original_text, &keyring, None).unwrap();
|
||||
let ctext_unsigned = pgp::pk_encrypt(original_text, &keyring, None).unwrap();
|
||||
assert!(!ctext_unsigned.is_empty());
|
||||
assert!(ctext_unsigned.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
@@ -264,7 +132,7 @@ fn test_encryption_decryption() {
|
||||
|
||||
let mut valid_signatures: HashSet<String> = Default::default();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
ctext_signed.as_bytes(),
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
@@ -278,7 +146,7 @@ fn test_encryption_decryption() {
|
||||
valid_signatures.clear();
|
||||
|
||||
let empty_keyring = Keyring::default();
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
ctext_signed.as_bytes(),
|
||||
&keyring,
|
||||
&empty_keyring,
|
||||
@@ -290,7 +158,7 @@ fn test_encryption_decryption() {
|
||||
|
||||
valid_signatures.clear();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
ctext_signed.as_bytes(),
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
@@ -304,7 +172,7 @@ fn test_encryption_decryption() {
|
||||
|
||||
public_keyring2.add_ref(&public_key);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
ctext_signed.as_bytes(),
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
@@ -316,7 +184,7 @@ fn test_encryption_decryption() {
|
||||
|
||||
valid_signatures.clear();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
ctext_unsigned.as_bytes(),
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
@@ -333,8 +201,7 @@ fn test_encryption_decryption() {
|
||||
let mut public_keyring = Keyring::default();
|
||||
public_keyring.add_ref(&public_key);
|
||||
|
||||
let plain =
|
||||
dc_pgp_pk_decrypt(ctext_signed.as_bytes(), &keyring, &public_keyring, None).unwrap();
|
||||
let plain = pgp::pk_decrypt(ctext_signed.as_bytes(), &keyring, &public_keyring, None).unwrap();
|
||||
|
||||
assert_eq!(plain, original_text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user