mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 22:06:33 +03:00
Compare commits
60 Commits
hpk-unsafe
...
crystal-cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e365a6666b | ||
|
|
6f92ce0fa8 | ||
|
|
cde2c9137f | ||
|
|
120524ae00 | ||
|
|
7bb73f45a5 | ||
|
|
2d0f563dfe | ||
|
|
cfe3c69f00 | ||
|
|
c266d2ca0d | ||
|
|
85fc696975 | ||
|
|
9bf8bed0c3 | ||
|
|
c4d55f6ba4 | ||
|
|
766d7cbd3a | ||
|
|
8e0e1bd58d | ||
|
|
a471ccc95a | ||
|
|
daac8c4824 | ||
|
|
59c22a5626 | ||
|
|
5154f27f72 | ||
|
|
5f7279eb85 | ||
|
|
ce67f593f6 | ||
|
|
556ea57f37 | ||
|
|
a4257b619a | ||
|
|
8479c8afbf | ||
|
|
eba012b965 | ||
|
|
66e53e6804 | ||
|
|
c8aa8b55f6 | ||
|
|
900e3905c0 | ||
|
|
088490721d | ||
|
|
a40b99aae0 | ||
|
|
b9646446f8 | ||
|
|
4e36b35039 | ||
|
|
d412ee6042 | ||
|
|
67848e3333 | ||
|
|
4d79c6e235 | ||
|
|
bc99d9d196 | ||
|
|
e1fc5863c2 | ||
|
|
f0791149e6 | ||
|
|
297b032bdc | ||
|
|
98180c175d | ||
|
|
46e8a436cb | ||
|
|
dc2cf8ecfc | ||
|
|
fd69ebfd1f | ||
|
|
03979fdc51 | ||
|
|
2c98e91276 | ||
|
|
3270120d16 | ||
|
|
77a7efc920 | ||
|
|
de604e744e | ||
|
|
24c0a833bd | ||
|
|
45f011c63c | ||
|
|
bc86201b44 | ||
|
|
b82af9fff3 | ||
|
|
3a1e74a306 | ||
|
|
e4cca92910 | ||
|
|
102220834c | ||
|
|
24d744b94c | ||
|
|
1df6229e99 | ||
|
|
c23e98ff83 | ||
|
|
b7c81f37c0 | ||
|
|
5c3a7e4119 | ||
|
|
a94acef49b | ||
|
|
7f5b362eda |
@@ -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:
|
||||
|
||||
24
CHANGELOG.md
Normal file
24
CHANGELOG.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# API changes
|
||||
|
||||
## 1.0.0-beta1
|
||||
|
||||
- first beta of the Delta Chat Rust core library. many fixes of crashes
|
||||
and other issues compared to 1.0.0-alpha.5.
|
||||
|
||||
- Most code is now "rustified" and does not do manual memory allocation anymore.
|
||||
|
||||
- The `DC_EVENT_GET_STRING` event is not used anymore, removing the last
|
||||
event where the core requested a return value from the event callback.
|
||||
|
||||
Please now use `dc_set_stock_translation()` API for core messages
|
||||
to be properly localized.
|
||||
|
||||
- Deltachat FFI docs are automatically generated and available here:
|
||||
https://c.delta.chat
|
||||
|
||||
- New events ImapMessageMoved and ImapMessageDeleted
|
||||
|
||||
For a full list of changes, please see our closed Pull Requests:
|
||||
|
||||
https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed
|
||||
|
||||
265
Cargo.lock
generated
265
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]]
|
||||
@@ -481,7 +481,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.5"
|
||||
version = "1.0.0-beta.1"
|
||||
dependencies = [
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -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.22 (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)",
|
||||
@@ -550,9 +550,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.5"
|
||||
version = "1.0.0-beta.1"
|
||||
dependencies = [
|
||||
"deltachat 1.0.0-alpha.5",
|
||||
"deltachat 1.0.0-beta.1",
|
||||
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -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.51 (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.51 (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.51"
|
||||
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.22"
|
||||
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.51 (registry+https://github.com/rust-lang/crates.io-index)" = "ba24190c8f0805d3bd2ce028f439fe5af1d55882bbe6261bed1dbc93b50dd6b1"
|
||||
"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.22 (registry+https://github.com/rust-lang/crates.io-index)" = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
|
||||
"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"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.5"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
version = "1.0.0-beta.1"
|
||||
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
||||
edition = "2018"
|
||||
license = "MPL"
|
||||
|
||||
@@ -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 = { version = "0.2.3", default-features = false }
|
||||
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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.5"
|
||||
version = "1.0.0-beta.1"
|
||||
description = "Deltachat FFI"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -78,8 +78,7 @@ typedef struct _dc_provider dc_provider_t;
|
||||
*
|
||||
* The example above uses "pthreads",
|
||||
* however, you can also use anything else for thread handling.
|
||||
* NB: The deltachat-core library itself does not create any threads on its own,
|
||||
* however, functions, unless stated otherwise, are thread-safe.
|
||||
* All deltachat-core-functions, unless stated otherwise, are thread-safe.
|
||||
*
|
||||
* After that you can **define and open a database.**
|
||||
* The database is a normal sqlite-file and is created as needed:
|
||||
@@ -135,7 +134,7 @@ typedef struct _dc_provider dc_provider_t;
|
||||
*
|
||||
* printf("Message %i: %s\n", i+1, text);
|
||||
*
|
||||
* free(text);
|
||||
* dc_str_unref(text);
|
||||
* dc_msg_unref(msg);
|
||||
* }
|
||||
* dc_array_unref(msglist);
|
||||
@@ -321,7 +320,7 @@ int dc_is_open (const dc_context_t* context);
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as created by dc_context_new().
|
||||
* @return Blob directory associated with the context object, empty string if unset or on errors. NULL is never returned.
|
||||
* The returned string must be free()'d.
|
||||
* The returned string must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_get_blobdir (const dc_context_t* context);
|
||||
|
||||
@@ -397,11 +396,24 @@ int dc_set_config (dc_context_t* context, const char*
|
||||
* @param context The context object as created by dc_context_new(). For querying system values, this can be NULL.
|
||||
* @param key The key to query.
|
||||
* @return Returns current value of "key", if "key" is unset, the default
|
||||
* value is returned. The returned value must be free()'d, NULL is never
|
||||
* value is returned. The returned value must be released using dc_str_unref(), NULL is never
|
||||
* returned. If there is an error an empty string will be returned.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @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 stock_id, const char* stock_msg);
|
||||
|
||||
|
||||
/**
|
||||
* Get information about the context.
|
||||
@@ -415,7 +427,7 @@ char* dc_get_config (dc_context_t* context, const char*
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return String which must be free()'d after usage. Never returns NULL.
|
||||
* @return String which must be released using dc_str_unref() after usage. Never returns NULL.
|
||||
*/
|
||||
char* dc_get_info (dc_context_t* context);
|
||||
|
||||
@@ -446,6 +458,7 @@ char* dc_get_info (dc_context_t* context);
|
||||
* `https://localhost:PORT/PATH`, `urn:ietf:wg:oauth:2.0:oob`
|
||||
* (the latter just displays the code the user can copy+paste then)
|
||||
* @return URL that can be opened in the browser to start OAuth2.
|
||||
* Returned strings must be released using dc_str_unref().
|
||||
* If OAuth2 is not possible for the given e-mail-address, NULL is returned.
|
||||
*/
|
||||
char* dc_get_oauth2_url (dc_context_t* context, const char* addr, const char* redirect_uri);
|
||||
@@ -694,6 +707,7 @@ void dc_perform_mvbox_idle (dc_context_t* context);
|
||||
*/
|
||||
void dc_interrupt_mvbox_idle (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Execute pending sentbox-jobs.
|
||||
* This function and dc_perform_sentbox_fetch() and dc_perform_sentbox_idle()
|
||||
@@ -1465,7 +1479,7 @@ int dc_set_chat_profile_image (dc_context_t* context, uint32_t ch
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as created by dc_context_new().
|
||||
* @param msg_id The message id for which information should be generated
|
||||
* @return Text string, must be free()'d after usage
|
||||
* @return Text string, must be released using dc_str_unref() after usage
|
||||
*/
|
||||
char* dc_get_msg_info (dc_context_t* context, uint32_t msg_id);
|
||||
|
||||
@@ -1479,7 +1493,7 @@ char* dc_get_msg_info (dc_context_t* context, uint32_t ms
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as created by dc_context_new().
|
||||
* @param msg_id The message id, must be the id of an incoming message.
|
||||
* @return Raw headers as a multi-line string, must be free()'d after usage.
|
||||
* @return Raw headers as a multi-line string, must be released using dc_str_unref() after usage.
|
||||
* Returns NULL if there are no headers saved for the given message,
|
||||
* eg. because of save_mime_headers is not set
|
||||
* or the message is not incoming.
|
||||
@@ -1720,7 +1734,7 @@ void dc_block_contact (dc_context_t* context, uint32_t co
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as created by dc_context_new().
|
||||
* @param contact_id ID of the contact to get the encryption info for.
|
||||
* @return Multi-line text, must be free()'d after usage.
|
||||
* @return Multi-line text, must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_get_contact_encrinfo (dc_context_t* context, uint32_t contact_id);
|
||||
|
||||
@@ -1856,7 +1870,8 @@ void dc_imex (dc_context_t* context, int what, c
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @param dir Directory to search backups in.
|
||||
* @return String with the backup file, typically given to dc_imex(), returned strings must be free()'d.
|
||||
* @return String with the backup file, typically given to dc_imex(),
|
||||
* returned strings must be released using dc_str_unref().
|
||||
* The function returns NULL if no backup was found.
|
||||
*/
|
||||
char* dc_imex_has_backup (dc_context_t* context, const char* dir);
|
||||
@@ -1904,7 +1919,7 @@ char* dc_imex_has_backup (dc_context_t* context, const char*
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object.
|
||||
* @return The setup code. Must be free()'d after usage.
|
||||
* @return The setup code. Must be released using dc_str_unref() after usage.
|
||||
* On errors, eg. if the message could not be sent, NULL is returned.
|
||||
*/
|
||||
char* dc_initiate_key_transfer (dc_context_t* context);
|
||||
@@ -2009,7 +2024,7 @@ dc_lot_t* dc_check_qr (dc_context_t* context, const char*
|
||||
* If set to 0, the setup-Verified-contact-protocol is offered in the QR code.
|
||||
* @return Text that should go to the QR code,
|
||||
* On errors, an empty QR code is returned, NULL is never returned.
|
||||
* The returned string must be free()'d after usage.
|
||||
* The returned string must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_get_securejoin_qr (dc_context_t* context, uint32_t chat_id);
|
||||
|
||||
@@ -2179,6 +2194,21 @@ dc_array_t* dc_get_locations (dc_context_t* context, uint32_t cha
|
||||
void dc_delete_all_locations (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Release a string returned by another deltachat-core function.
|
||||
* - Strings returned by any deltachat-core-function
|
||||
* MUST NOT be released by the standard free() function;
|
||||
* always use dc_str_unref() for this purpose.
|
||||
* - dc_str_unref() MUST NOT be called for strings not returned by deltachat-core.
|
||||
* - dc_str_unref() MUST NOT be called for other objectes returned by deltachat-core.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param str The string to release.
|
||||
* @return None.
|
||||
*/
|
||||
void dc_str_unref (char* str);
|
||||
|
||||
|
||||
/**
|
||||
* @class dc_array_t
|
||||
*
|
||||
@@ -2319,7 +2349,7 @@ uint32_t dc_array_get_msg_id (const dc_array_t* array, size_t in
|
||||
* @param index Index of the item. Must be between 0 and dc_array_get_cnt()-1.
|
||||
* @return Marker-character of the item at the given index.
|
||||
* NULL if there is no marker-character bound to the given item.
|
||||
* The returned value must be free()'d after usage.
|
||||
* The returned value must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_array_get_marker (const dc_array_t* array, size_t index);
|
||||
|
||||
@@ -2574,7 +2604,7 @@ int dc_chat_get_type (const dc_chat_t* chat);
|
||||
*
|
||||
* @memberof dc_chat_t
|
||||
* @param chat The chat object.
|
||||
* @return Chat name as a string. Must be free()'d after usage. Never NULL.
|
||||
* @return Chat name as a string. Must be released using dc_str_unref() after usage. Never NULL.
|
||||
*/
|
||||
char* dc_chat_get_name (const dc_chat_t* chat);
|
||||
|
||||
@@ -2587,7 +2617,7 @@ char* dc_chat_get_name (const dc_chat_t* chat);
|
||||
*
|
||||
* @memberof dc_chat_t
|
||||
* @param chat The chat object to calulate the subtitle for.
|
||||
* @return Subtitle as a string. Must be free()'d after usage. Never NULL.
|
||||
* @return Subtitle as a string. Must be released using dc_str_unref() after usage. Never NULL.
|
||||
*/
|
||||
char* dc_chat_get_subtitle (const dc_chat_t* chat);
|
||||
|
||||
@@ -2603,7 +2633,7 @@ char* dc_chat_get_subtitle (const dc_chat_t* chat);
|
||||
* @param chat The chat object.
|
||||
* @return Path and file if the profile image, if any.
|
||||
* NULL otherwise.
|
||||
* Must be free()'d after usage.
|
||||
* Must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_chat_get_profile_image (const dc_chat_t* chat);
|
||||
|
||||
@@ -2907,7 +2937,7 @@ int64_t dc_msg_get_sort_timestamp (const dc_msg_t* msg);
|
||||
*
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The message object.
|
||||
* @return Message text. The result must be free()'d. Never returns NULL.
|
||||
* @return Message text. The result must be released using dc_str_unref(). Never returns NULL.
|
||||
*/
|
||||
char* dc_msg_get_text (const dc_msg_t* msg);
|
||||
|
||||
@@ -2921,9 +2951,9 @@ char* dc_msg_get_text (const dc_msg_t* msg);
|
||||
*
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The message object.
|
||||
* @return Full path, file name and extension of the file associated with the
|
||||
* message. If there is no file associated with the message, an emtpy
|
||||
* string is returned. NULL is never returned and the returned value must be free()'d.
|
||||
* @return Full path, file name and extension of the file associated with the message.
|
||||
* If there is no file associated with the message, an emtpy string is returned.
|
||||
* NULL is never returned and the returned value must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_msg_get_file (const dc_msg_t* msg);
|
||||
|
||||
@@ -2936,7 +2966,7 @@ char* dc_msg_get_file (const dc_msg_t* msg);
|
||||
* @param msg The message object.
|
||||
* @return Base file name plus extension without part. If there is no file
|
||||
* associated with the message, an empty string is returned. The returned
|
||||
* value must be free()'d.
|
||||
* value must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_msg_get_filename (const dc_msg_t* msg);
|
||||
|
||||
@@ -2948,7 +2978,8 @@ char* dc_msg_get_filename (const dc_msg_t* msg);
|
||||
*
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The message object.
|
||||
* @return String containing the mime type. Must be free()'d after usage. NULL is never returned.
|
||||
* @return String containing the mime type.
|
||||
* Must be released using dc_str_unref() after usage. NULL is never returned.
|
||||
*/
|
||||
char* dc_msg_get_filemime (const dc_msg_t* msg);
|
||||
|
||||
@@ -3056,7 +3087,8 @@ dc_lot_t* dc_msg_get_summary (const dc_msg_t* msg, const dc_cha
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The message object.
|
||||
* @param approx_characters Rough length of the expected string.
|
||||
* @return A summary for the given messages. The returned string must be free()'d.
|
||||
* @return A summary for the given messages.
|
||||
* The returned string must be released using dc_str_unref().
|
||||
* Returns an empty string on errors, never returns NULL.
|
||||
*/
|
||||
char* dc_msg_get_summarytext (const dc_msg_t* msg, int approx_characters);
|
||||
@@ -3201,7 +3233,7 @@ int dc_msg_is_setupmessage (const dc_msg_t* msg);
|
||||
* @memberof dc_msg_t
|
||||
* @param msg The message object.
|
||||
* @return Typically, the first two digits of the setup code or an empty string if unknown.
|
||||
* NULL is never returned. Must be free()'d when done.
|
||||
* NULL is never returned. Must be released using dc_str_unref() when done.
|
||||
*/
|
||||
char* dc_msg_get_setupcodebegin (const dc_msg_t* msg);
|
||||
|
||||
@@ -3358,7 +3390,8 @@ uint32_t dc_contact_get_id (const dc_contact_t* contact);
|
||||
*
|
||||
* @memberof dc_contact_t
|
||||
* @param contact The contact object.
|
||||
* @return String with the email address, must be free()'d. Never returns NULL.
|
||||
* @return String with the email address,
|
||||
* must be released using dc_str_unref(). Never returns NULL.
|
||||
*/
|
||||
char* dc_contact_get_addr (const dc_contact_t* contact);
|
||||
|
||||
@@ -3372,7 +3405,8 @@ char* dc_contact_get_addr (const dc_contact_t* contact);
|
||||
*
|
||||
* @memberof dc_contact_t
|
||||
* @param contact The contact object.
|
||||
* @return String with the name to display, must be free()'d. Empty string if unset, never returns NULL.
|
||||
* @return String with the name to display, must be released using dc_str_unref().
|
||||
* Empty string if unset, never returns NULL.
|
||||
*/
|
||||
char* dc_contact_get_name (const dc_contact_t* contact);
|
||||
|
||||
@@ -3386,7 +3420,8 @@ char* dc_contact_get_name (const dc_contact_t* contact);
|
||||
*
|
||||
* @memberof dc_contact_t
|
||||
* @param contact The contact object.
|
||||
* @return String with the name to display, must be free()'d. Never returns NULL.
|
||||
* @return String with the name to display, must be released using dc_str_unref().
|
||||
* Never returns NULL.
|
||||
*/
|
||||
char* dc_contact_get_display_name (const dc_contact_t* contact);
|
||||
|
||||
@@ -3402,7 +3437,8 @@ char* dc_contact_get_display_name (const dc_contact_t* contact);
|
||||
*
|
||||
* @memberof dc_contact_t
|
||||
* @param contact The contact object.
|
||||
* @return Summary string, must be free()'d. Never returns NULL.
|
||||
* @return Summary string, must be released using dc_str_unref().
|
||||
* Never returns NULL.
|
||||
*/
|
||||
char* dc_contact_get_name_n_addr (const dc_contact_t* contact);
|
||||
|
||||
@@ -3414,7 +3450,8 @@ char* dc_contact_get_name_n_addr (const dc_contact_t* contact);
|
||||
*
|
||||
* @memberof dc_contact_t
|
||||
* @param contact The contact object.
|
||||
* @return String with the name to display, must be free()'d. Never returns NULL.
|
||||
* @return String with the name to display, must be released using dc_str_unref().
|
||||
* Never returns NULL.
|
||||
*/
|
||||
char* dc_contact_get_first_name (const dc_contact_t* contact);
|
||||
|
||||
@@ -3428,7 +3465,7 @@ char* dc_contact_get_first_name (const dc_contact_t* contact);
|
||||
* @param contact The contact object.
|
||||
* @return Path and file if the profile image, if any.
|
||||
* NULL otherwise.
|
||||
* Must be free()'d after usage.
|
||||
* Must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_contact_get_profile_image (const dc_contact_t* contact);
|
||||
|
||||
@@ -3509,7 +3546,7 @@ dc_provider_t* dc_provider_new_from_email (const char* email);
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
@@ -3521,7 +3558,7 @@ char* dc_provider_get_overview_page (const dc_provider_t* prov
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
@@ -3534,7 +3571,7 @@ char* dc_provider_get_name (const dc_provider_t* prov
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
@@ -3546,7 +3583,7 @@ char* dc_provider_get_markdown (const dc_provider_t* prov
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
|
||||
@@ -3608,7 +3645,9 @@ void dc_lot_unref (dc_lot_t* lot);
|
||||
*
|
||||
* @memberof dc_lot_t
|
||||
* @param lot The lot object.
|
||||
* @return A string, the string may be empty and the returned value must be free()'d. NULL if there is no such string.
|
||||
* @return A string, the string may be empty
|
||||
* and the returned value must be released using dc_str_unref().
|
||||
* NULL if there is no such string.
|
||||
*/
|
||||
char* dc_lot_get_text1 (const dc_lot_t* lot);
|
||||
|
||||
@@ -3617,10 +3656,10 @@ char* dc_lot_get_text1 (const dc_lot_t* lot);
|
||||
* Get second string. The meaning of the string is defined by the creator of the object.
|
||||
*
|
||||
* @memberof dc_lot_t
|
||||
*
|
||||
* @param lot The lot object.
|
||||
*
|
||||
* @return A string, the string may be empty and the returned value must be free()'d . NULL if there is no such string.
|
||||
* @return A string, the string may be empty
|
||||
* and the returned value must be released using dc_str_unref().
|
||||
* NULL if there is no such string.
|
||||
*/
|
||||
char* dc_lot_get_text2 (const dc_lot_t* lot);
|
||||
|
||||
@@ -3641,9 +3680,7 @@ int dc_lot_get_text1_meaning (const dc_lot_t* lot);
|
||||
* Get the associated state. The meaning of the state is defined by the creator of the object.
|
||||
*
|
||||
* @memberof dc_lot_t
|
||||
*
|
||||
* @param lot The lot object.
|
||||
*
|
||||
* @return The state as defined by the creator of the object. 0 if there is not state or on errors.
|
||||
*/
|
||||
int dc_lot_get_state (const dc_lot_t* lot);
|
||||
@@ -3665,9 +3702,7 @@ uint32_t dc_lot_get_id (const dc_lot_t* lot);
|
||||
* The meaning of the timestamp is defined by the creator of the object.
|
||||
*
|
||||
* @memberof dc_lot_t
|
||||
*
|
||||
* @param lot The lot object.
|
||||
*
|
||||
* @return The timestamp as defined by the creator of the object. 0 if there is not timestamp or on errors.
|
||||
*/
|
||||
int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
@@ -3867,7 +3902,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_INFO 100
|
||||
@@ -3878,7 +3913,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_SMTP_CONNECTED 101
|
||||
@@ -3889,7 +3924,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_IMAP_CONNECTED 102
|
||||
@@ -3899,7 +3934,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_SMTP_MESSAGE_SENT 103
|
||||
@@ -3909,7 +3944,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_IMAP_MESSAGE_DELETED 104
|
||||
@@ -3919,7 +3954,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_IMAP_MESSAGE_MOVED 105
|
||||
@@ -3929,7 +3964,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) path name
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_NEW_BLOB_FILE 150
|
||||
@@ -3939,7 +3974,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) path name
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_DELETED_BLOB_FILE 151
|
||||
@@ -3952,7 +3987,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Warning string in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_WARNING 300
|
||||
@@ -3972,9 +4007,10 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
* in a messasge box then.
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Error string, always set, never NULL. Frequent error strings are
|
||||
* localized using #DC_EVENT_GET_STRING, however, most error strings will be in english language.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* @param data2 (const char*) Error string, always set, never NULL.
|
||||
* Some error strings are taken from dc_set_stock_translation(),
|
||||
* however, most error strings will be in english language.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_ERROR 400
|
||||
@@ -3998,7 +4034,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
* @param data1 (int) 1=first/new network error, should be reported the user;
|
||||
* 0=subsequent network error, should be logged only
|
||||
* @param data2 (const char*) Error string, always set, never NULL.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_ERROR_NETWORK 401
|
||||
@@ -4013,7 +4049,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*
|
||||
* @param data1 0
|
||||
* @param data2 (const char*) Info string in english language.
|
||||
* Must not be free()'d or modified
|
||||
* Must not be unref'd or modified
|
||||
* and is valid only until the callback returns.
|
||||
* @return 0
|
||||
*/
|
||||
@@ -4144,7 +4180,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
* services.
|
||||
*
|
||||
* @param data1 (const char*) Path and file name.
|
||||
* Must not be free()'d or modified and is valid only until the callback returns.
|
||||
* Must not be unref'd or modified and is valid only until the callback returns.
|
||||
* @param data2 0
|
||||
* @return 0
|
||||
*/
|
||||
@@ -4185,36 +4221,21 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
#define DC_EVENT_SECUREJOIN_JOINER_PROGRESS 2061
|
||||
|
||||
|
||||
// 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.
|
||||
*/
|
||||
#define DC_EVENT_GET_STRING 2091
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define DC_EVENT_FILE_COPIED 2055 // deprecated
|
||||
#define DC_EVENT_IS_OFFLINE 2081 // deprecated
|
||||
#define DC_ERROR_SEE_STRING 0 // deprecated
|
||||
#define DC_ERROR_SELF_NOT_IN_GROUP 1 // deprecated
|
||||
#define DC_STR_SELFNOTINGRP 21 // deprecated
|
||||
|
||||
#define DC_EVENT_FILE_COPIED 2055 // not used anymore
|
||||
#define DC_EVENT_IS_OFFLINE 2081 // not used anymore
|
||||
#define DC_EVENT_GET_STRING 2091 // not used anymore, use dc_set_stock_translation()
|
||||
#define DC_ERROR_SEE_STRING 0 // not used anymore
|
||||
#define DC_ERROR_SELF_NOT_IN_GROUP 1 // not used anymore
|
||||
#define DC_STR_SELFNOTINGRP 21 // not used anymore
|
||||
#define DC_EVENT_DATA1_IS_STRING(e) ((e)==DC_EVENT_IMEX_FILE_WRITTEN || (e)==DC_EVENT_FILE_COPIED)
|
||||
#define DC_EVENT_DATA2_IS_STRING(e) ((e)>=100 && (e)<=499)
|
||||
#define DC_EVENT_RETURNS_INT(e) ((e)==DC_EVENT_IS_OFFLINE)
|
||||
#define DC_EVENT_RETURNS_STRING(e) ((e)==DC_EVENT_GET_STRING)
|
||||
#define DC_EVENT_RETURNS_INT(e) ((e)==DC_EVENT_IS_OFFLINE) // not used anymore
|
||||
#define DC_EVENT_RETURNS_STRING(e) ((e)==DC_EVENT_GET_STRING) // not used anymore
|
||||
char* dc_get_version_str (void); // deprecated
|
||||
void dc_array_add_id (dc_array_t*, uint32_t); // deprecated
|
||||
|
||||
@@ -4316,10 +4337,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
|
||||
|
||||
void dc_str_unref (char*);
|
||||
|
||||
#define DC_STR_STICKER 67
|
||||
#define DC_STR_COUNT 67
|
||||
|
||||
/*
|
||||
* @}
|
||||
|
||||
@@ -25,6 +25,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use deltachat::contact::Contact;
|
||||
use deltachat::context::Context;
|
||||
use deltachat::dc_tools::{as_path, as_str, dc_strdup, to_string_lossy, OsStrExt, StrExt};
|
||||
use deltachat::stock::StockMessage;
|
||||
use deltachat::*;
|
||||
|
||||
// as C lacks a good and portable error handling,
|
||||
@@ -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() {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ use crate::mailmime::types_helper::*;
|
||||
|
||||
pub(crate) use libc::{
|
||||
calloc, close, free, isalpha, isdigit, malloc, memcmp, memcpy, memmove, memset, realloc,
|
||||
strcpy, strlen, strncmp, strncpy,
|
||||
strcpy, strlen, strncmp, strncpy, strnlen,
|
||||
};
|
||||
|
||||
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,25 @@ 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, strnlen(s1 as *const libc::c_char, n));
|
||||
let s2_slice =
|
||||
std::slice::from_raw_parts(s2 as *const u8, strnlen(s2 as *const libc::c_char, 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
|
||||
@@ -1682,6 +1695,14 @@ mod tests {
|
||||
4,
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(0, unsafe {
|
||||
strncasecmp(
|
||||
CString::new("hell").unwrap().as_ptr(),
|
||||
CString::new("Hell").unwrap().as_ptr(),
|
||||
100_000_000,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
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
|
||||
|
||||
@@ -71,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.
|
||||
|
||||
|
||||
@@ -57,6 +57,14 @@ DC_MSG_AUDIO = 40
|
||||
DC_MSG_VOICE = 41
|
||||
DC_MSG_VIDEO = 50
|
||||
DC_MSG_FILE = 60
|
||||
DC_LP_AUTH_OAUTH2 = 0x2
|
||||
DC_LP_AUTH_NORMAL = 0x4
|
||||
DC_LP_IMAP_SOCKET_STARTTLS = 0x100
|
||||
DC_LP_IMAP_SOCKET_SSL = 0x200
|
||||
DC_LP_IMAP_SOCKET_PLAIN = 0x400
|
||||
DC_LP_SMTP_SOCKET_STARTTLS = 0x10000
|
||||
DC_LP_SMTP_SOCKET_SSL = 0x20000
|
||||
DC_LP_SMTP_SOCKET_PLAIN = 0x40000
|
||||
DC_EVENT_INFO = 100
|
||||
DC_EVENT_SMTP_CONNECTED = 101
|
||||
DC_EVENT_IMAP_CONNECTED = 102
|
||||
@@ -82,17 +90,64 @@ DC_EVENT_IMEX_PROGRESS = 2051
|
||||
DC_EVENT_IMEX_FILE_WRITTEN = 2052
|
||||
DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
|
||||
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
||||
DC_EVENT_GET_STRING = 2091
|
||||
DC_EVENT_FILE_COPIED = 2055
|
||||
DC_EVENT_IS_OFFLINE = 2081
|
||||
DC_EVENT_GET_STRING = 2091
|
||||
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_LP|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)
|
||||
|
||||
@@ -150,6 +150,11 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
lib.dc_set_config(ac._dc_context, b"configured", b"1")
|
||||
return ac
|
||||
|
||||
def peek_online_config(self):
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
return session_liveconfig.get(self.live_count)
|
||||
|
||||
def get_online_config(self):
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
|
||||
@@ -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()
|
||||
@@ -368,7 +389,8 @@ class TestOnlineAccount:
|
||||
|
||||
def test_one_account_send_bcc_setting(self, acfactory, lp):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
c2 = ac1.create_contact(email="notexists@testrun.org")
|
||||
ac2_config = acfactory.peek_online_config()
|
||||
c2 = ac1.create_contact(email=ac2_config["addr"])
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
wait_successful_IMAP_SMTP_connection(ac1)
|
||||
|
||||
@@ -1761,9 +1761,12 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) -> Result<
|
||||
}
|
||||
let mut msg = msg.unwrap();
|
||||
let original_param = msg.param.clone();
|
||||
if msg.from_id != DC_CONTACT_ID_SELF {
|
||||
msg.param.set_int(Param::Forwarded, 1);
|
||||
}
|
||||
|
||||
// we tested a sort of broadcast
|
||||
// by not marking own forwarded messages as such,
|
||||
// however, this turned out to be to confusing and unclear.
|
||||
msg.param.set_int(Param::Forwarded, 1);
|
||||
|
||||
msg.param.remove(Param::GuranteeE2ee);
|
||||
msg.param.remove(Param::ForcePlaintext);
|
||||
msg.param.remove(Param::Cmd);
|
||||
|
||||
@@ -270,7 +270,7 @@ impl Chatlist {
|
||||
|
||||
let lastmsg = if 0 != lastmsg_id {
|
||||
if let Ok(lastmsg) = Message::load_from_db(context, lastmsg_id) {
|
||||
if lastmsg.from_id != 1 as libc::c_uint
|
||||
if lastmsg.from_id != 1
|
||||
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
|
||||
{
|
||||
lastcontact = Contact::load_from_db(context, lastmsg.from_id).ok();
|
||||
|
||||
@@ -3,6 +3,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::login_param::LoginParam;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
@@ -10,48 +11,56 @@ 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> {
|
||||
pub in_0: &'a LoginParam,
|
||||
struct MozAutoconfigure<'a> {
|
||||
pub in_emailaddr: &'a str,
|
||||
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 fn moz_autoconfigure(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
param_in: &LoginParam,
|
||||
) -> Option<LoginParam> {
|
||||
let xml_raw = read_autoconf_file(context, url)?;
|
||||
#[derive(PartialEq)]
|
||||
enum MozServer {
|
||||
Undefined,
|
||||
Imap,
|
||||
Smtp,
|
||||
}
|
||||
|
||||
// Split address into local part and domain part.
|
||||
let p = param_in.addr.find("@");
|
||||
if p.is_none() {
|
||||
return None;
|
||||
}
|
||||
let (in_emaillocalpart, in_emaildomain) = param_in.addr.split_at(p.unwrap());
|
||||
let in_emaildomain = &in_emaildomain[1..];
|
||||
enum MozConfigTag {
|
||||
Undefined,
|
||||
Hostname,
|
||||
Port,
|
||||
Sockettype,
|
||||
Username,
|
||||
}
|
||||
|
||||
let mut reader = quick_xml::Reader::from_str(&xml_raw);
|
||||
pub fn moz_parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Error> {
|
||||
let mut reader = quick_xml::Reader::from_str(xml_raw);
|
||||
reader.trim_text(true);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
// Split address into local part and domain part.
|
||||
let p = match in_emailaddr.find('@') {
|
||||
Some(i) => i,
|
||||
None => bail!("Email address {} does not contain @", in_emailaddr),
|
||||
};
|
||||
let (in_emaillocalpart, in_emaildomain) = in_emailaddr.split_at(p);
|
||||
let in_emaildomain = &in_emaildomain[1..];
|
||||
|
||||
let mut moz_ac = moz_autoconfigure_t {
|
||||
in_0: param_in,
|
||||
let mut moz_ac = MozAutoconfigure {
|
||||
in_emailaddr,
|
||||
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,
|
||||
};
|
||||
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
match reader.read_event(&mut buf) {
|
||||
Ok(quick_xml::events::Event::Start(ref e)) => {
|
||||
@@ -62,8 +71,7 @@ pub fn moz_autoconfigure(
|
||||
moz_autoconfigure_text_cb(e, &mut moz_ac, &reader)
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
context,
|
||||
bail!(
|
||||
"Configure xml: Error at position {}: {:?}",
|
||||
reader.buffer_position(),
|
||||
e
|
||||
@@ -81,21 +89,36 @@ pub fn moz_autoconfigure(
|
||||
|| moz_ac.out.send_port == 0
|
||||
{
|
||||
let r = moz_ac.out.to_string();
|
||||
warn!(context, "Bad or incomplete autoconfig: {}", r,);
|
||||
return None;
|
||||
bail!("Bad or incomplete autoconfig: {}", r,);
|
||||
}
|
||||
|
||||
Some(moz_ac.out)
|
||||
Ok(moz_ac.out)
|
||||
}
|
||||
|
||||
pub fn moz_autoconfigure(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
param_in: &LoginParam,
|
||||
) -> Option<LoginParam> {
|
||||
let xml_raw = read_autoconf_file(context, url)?;
|
||||
|
||||
match moz_parse_xml(¶m_in.addr, &xml_raw) {
|
||||
Err(err) => {
|
||||
warn!(context, "{}", err);
|
||||
None
|
||||
}
|
||||
Ok(lp) => Some(lp),
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let addr = &moz_ac.in_0.addr;
|
||||
let addr = moz_ac.in_emailaddr;
|
||||
let email_local = moz_ac.in_emaillocalpart;
|
||||
let email_domain = moz_ac.in_emaildomain;
|
||||
|
||||
@@ -105,12 +128,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
|
||||
@@ -123,13 +146,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
|
||||
@@ -142,29 +164,34 @@ 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;
|
||||
if moz_ac.tag_server == MozServer::Imap {
|
||||
moz_ac.out_imap_set = true;
|
||||
}
|
||||
moz_ac.tag_server = MozServer::Undefined;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
} else if tag == "outgoingserver" {
|
||||
moz_ac.tag_server = 0;
|
||||
moz_ac.tag_config = 0;
|
||||
moz_ac.out_smtp_set = 1;
|
||||
if moz_ac.tag_server == MozServer::Smtp {
|
||||
moz_ac.out_smtp_set = true;
|
||||
}
|
||||
moz_ac.tag_server = MozServer::Undefined;
|
||||
moz_ac.tag_config = MozConfigTag::Undefined;
|
||||
} 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();
|
||||
@@ -181,25 +208,115 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_outlook_autoconfig() {
|
||||
// Copied from https://autoconfig.thunderbird.net/v1.1/outlook.com on 2019-10-11
|
||||
let xml_raw =
|
||||
"<clientConfig version=\"1.1\">
|
||||
<emailProvider id=\"outlook.com\">
|
||||
<domain>hotmail.com</domain>
|
||||
<domain>hotmail.co.uk</domain>
|
||||
<domain>hotmail.co.jp</domain>
|
||||
<domain>hotmail.com.br</domain>
|
||||
<domain>hotmail.de</domain>
|
||||
<domain>hotmail.fr</domain>
|
||||
<domain>hotmail.it</domain>
|
||||
<domain>hotmail.es</domain>
|
||||
<domain>live.com</domain>
|
||||
<domain>live.co.uk</domain>
|
||||
<domain>live.co.jp</domain>
|
||||
<domain>live.de</domain>
|
||||
<domain>live.fr</domain>
|
||||
<domain>live.it</domain>
|
||||
<domain>live.jp</domain>
|
||||
<domain>msn.com</domain>
|
||||
<domain>outlook.com</domain>
|
||||
<displayName>Outlook.com (Microsoft)</displayName>
|
||||
<displayShortName>Outlook</displayShortName>
|
||||
<incomingServer type=\"exchange\">
|
||||
<hostname>outlook.office365.com</hostname>
|
||||
<port>443</port>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<socketType>SSL</socketType>
|
||||
<authentication>OAuth2</authentication>
|
||||
<owaURL>https://outlook.office365.com/owa/</owaURL>
|
||||
<ewsURL>https://outlook.office365.com/ews/exchange.asmx</ewsURL>
|
||||
<useGlobalPreferredServer>true</useGlobalPreferredServer>
|
||||
</incomingServer>
|
||||
<incomingServer type=\"imap\">
|
||||
<hostname>outlook.office365.com</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
</incomingServer>
|
||||
<incomingServer type=\"pop3\">
|
||||
<hostname>outlook.office365.com</hostname>
|
||||
<port>995</port>
|
||||
<socketType>SSL</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<pop3>
|
||||
<leaveMessagesOnServer>true</leaveMessagesOnServer>
|
||||
<!-- Outlook.com docs specifically mention that POP3 deletes have effect on the main inbox on webmail and IMAP -->
|
||||
</pop3>
|
||||
</incomingServer>
|
||||
<outgoingServer type=\"smtp\">
|
||||
<hostname>smtp.office365.com</hostname>
|
||||
<port>587</port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
</outgoingServer>
|
||||
<documentation url=\"http://windows.microsoft.com/en-US/windows/outlook/send-receive-from-app\">
|
||||
<descr lang=\"en\">Set up an email app with Outlook.com</descr>
|
||||
</documentation>
|
||||
</emailProvider>
|
||||
<webMail>
|
||||
<loginPage url=\"https://www.outlook.com/\"/>
|
||||
<loginPageInfo url=\"https://www.outlook.com/\">
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<usernameField id=\"i0116\" name=\"login\"/>
|
||||
<passwordField id=\"i0118\" name=\"passwd\"/>
|
||||
<loginButton id=\"idSIButton9\" name=\"SI\"/>
|
||||
</loginPageInfo>
|
||||
</webMail>
|
||||
</clientConfig>";
|
||||
let res = moz_parse_xml("example@outlook.com", xml_raw).expect("XML parsing failed");
|
||||
assert_eq!(res.mail_server, "outlook.office365.com");
|
||||
assert_eq!(res.mail_port, 993);
|
||||
assert_eq!(res.send_server, "smtp.office365.com");
|
||||
assert_eq!(res.send_port, 587);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use quick_xml::events::BytesEnd;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::login_param::LoginParam;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
@@ -19,6 +20,100 @@ struct OutlookAutodiscover {
|
||||
pub config_redirecturl: Option<String>,
|
||||
}
|
||||
|
||||
enum ParsingResult {
|
||||
LoginParam(LoginParam),
|
||||
RedirectUrl(String),
|
||||
}
|
||||
|
||||
fn outlk_parse_xml(xml_raw: &str) -> Result<ParsingResult, Error> {
|
||||
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(&xml_raw);
|
||||
reader.trim_text(true);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
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_lowercase().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) => {
|
||||
bail!(
|
||||
"Configure xml: Error at position {}: {:?}",
|
||||
reader.buffer_position(),
|
||||
e
|
||||
);
|
||||
}
|
||||
Ok(quick_xml::events::Event::Eof) => break,
|
||||
_ => (),
|
||||
}
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
// 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();
|
||||
bail!("Bad or incomplete autoconfig: {}", r,);
|
||||
}
|
||||
Ok(ParsingResult::LoginParam(outlk_ad.out))
|
||||
} else {
|
||||
Ok(ParsingResult::RedirectUrl(
|
||||
outlk_ad.config_redirecturl.unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn outlk_autodiscover(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
@@ -27,94 +122,16 @@ pub fn outlk_autodiscover(
|
||||
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,
|
||||
};
|
||||
|
||||
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 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,
|
||||
_ => (),
|
||||
}
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
// 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,);
|
||||
match outlk_parse_xml(&xml_raw) {
|
||||
Err(err) => {
|
||||
warn!(context, "{}", err);
|
||||
return None;
|
||||
}
|
||||
return Some(outlk_ad.out);
|
||||
} else {
|
||||
url = outlk_ad.config_redirecturl.unwrap();
|
||||
Ok(res) => match res {
|
||||
ParsingResult::RedirectUrl(redirect_url) => url = redirect_url,
|
||||
ParsingResult::LoginParam(login_param) => return Some(login_param),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
@@ -155,3 +172,78 @@ fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut OutlookAutodisc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_redirect() {
|
||||
let res = outlk_parse_xml("
|
||||
<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
||||
<Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006\">
|
||||
<Response xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a\">
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>redirectUrl</Action>
|
||||
<RedirectUrl>https://mail.example.com/autodiscover/autodiscover.xml</RedirectUrl>
|
||||
</Account>
|
||||
</Response>
|
||||
</Autodiscover>
|
||||
").expect("XML is not parsed successfully");
|
||||
match res {
|
||||
ParsingResult::LoginParam(_lp) => {
|
||||
panic!("redirecturl is not found");
|
||||
}
|
||||
ParsingResult::RedirectUrl(url) => {
|
||||
assert_eq!(
|
||||
url,
|
||||
"https://mail.example.com/autodiscover/autodiscover.xml"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_loginparam() {
|
||||
let res = outlk_parse_xml(
|
||||
"\
|
||||
<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
||||
<Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006\">
|
||||
<Response xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a\">
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>settings</Action>
|
||||
<Protocol>
|
||||
<Type>IMAP</Type>
|
||||
<Server>example.com</Server>
|
||||
<Port>993</Port>
|
||||
<SSL>on</SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>SMTP</Type>
|
||||
<Server>smtp.example.com</Server>
|
||||
<Port>25</Port>
|
||||
<SSL>off</SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
</Protocol>
|
||||
</Account>
|
||||
</Response>
|
||||
</Autodiscover>",
|
||||
)
|
||||
.expect("XML is not parsed successfully");
|
||||
|
||||
match res {
|
||||
ParsingResult::LoginParam(lp) => {
|
||||
assert_eq!(lp.mail_server, "example.com");
|
||||
assert_eq!(lp.mail_port, 993);
|
||||
assert_eq!(lp.send_server, "smtp.example.com");
|
||||
assert_eq!(lp.send_port, 25);
|
||||
}
|
||||
ParsingResult::RedirectUrl(_) => {
|
||||
panic!("RedirectUrl is not expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ macro_rules! progress {
|
||||
}
|
||||
|
||||
// connect
|
||||
pub unsafe fn configure(context: &Context) {
|
||||
pub fn configure(context: &Context) {
|
||||
if context.has_ongoing() {
|
||||
warn!(context, "There is already another ongoing process running.",);
|
||||
return;
|
||||
@@ -46,94 +46,99 @@ pub fn dc_is_configured(context: &Context) -> bool {
|
||||
******************************************************************************/
|
||||
// the other dc_job_do_DC_JOB_*() functions are declared static in the c-file
|
||||
#[allow(non_snake_case, unused_must_use)]
|
||||
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
|
||||
pub fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
|
||||
if !context.sql.is_open() {
|
||||
error!(context, "Cannot configure, database not opened.",);
|
||||
progress!(context, 0);
|
||||
return;
|
||||
}
|
||||
if !context.alloc_ongoing() {
|
||||
progress!(context, 0);
|
||||
return;
|
||||
}
|
||||
let mut success = false;
|
||||
let mut imap_connected_here = false;
|
||||
let mut smtp_connected_here = false;
|
||||
let mut ongoing_allocated_here = false;
|
||||
|
||||
let mut param_autoconfig: Option<LoginParam> = None;
|
||||
if context.alloc_ongoing() {
|
||||
ongoing_allocated_here = true;
|
||||
if !context.sql.is_open() {
|
||||
error!(context, "Cannot configure, database not opened.",);
|
||||
} else {
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
context
|
||||
.sentbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.imap
|
||||
.disconnect(context);
|
||||
context
|
||||
.mvbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.imap
|
||||
.disconnect(context);
|
||||
context.smtp.clone().lock().unwrap().disconnect();
|
||||
info!(context, "Configure ...",);
|
||||
|
||||
// Variables that are shared between steps:
|
||||
let mut param = LoginParam::from_database(context, "");
|
||||
// need all vars here to be mutable because rust thinks the same step could be called multiple times
|
||||
// and also initialize, because otherwise rust thinks it's used while unitilized, even if thats not the case as the loop goes only forward
|
||||
let mut param_domain = "undefined.undefined".to_owned();
|
||||
let mut param_addr_urlencoded: String =
|
||||
"Internal Error: this value should never be used".to_owned();
|
||||
let mut keep_flags = std::i32::MAX;
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
context
|
||||
.sentbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.imap
|
||||
.disconnect(context);
|
||||
context
|
||||
.mvbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.imap
|
||||
.disconnect(context);
|
||||
context.smtp.clone().lock().unwrap().disconnect();
|
||||
info!(context, "Configure ...",);
|
||||
|
||||
const STEP_3_INDEX: u8 = 13;
|
||||
let mut step_counter: u8 = 0;
|
||||
while !context.shall_stop_ongoing() {
|
||||
step_counter = step_counter + 1;
|
||||
// Variables that are shared between steps:
|
||||
let mut param = LoginParam::from_database(context, "");
|
||||
// need all vars here to be mutable because rust thinks the same step could be called multiple times
|
||||
// and also initialize, because otherwise rust thinks it's used while unitilized, even if thats not the case as the loop goes only forward
|
||||
let mut param_domain = "undefined.undefined".to_owned();
|
||||
let mut param_addr_urlencoded: String =
|
||||
"Internal Error: this value should never be used".to_owned();
|
||||
let mut keep_flags = std::i32::MAX;
|
||||
|
||||
let success = match step_counter {
|
||||
// Read login parameters from the database
|
||||
1 => {
|
||||
progress!(context, 1);
|
||||
if param.addr.is_empty() {
|
||||
error!(context, "Please enter an email address.",);
|
||||
}
|
||||
!param.addr.is_empty()
|
||||
const STEP_3_INDEX: u8 = 13;
|
||||
let mut step_counter: u8 = 0;
|
||||
while !context.shall_stop_ongoing() {
|
||||
step_counter = step_counter + 1;
|
||||
|
||||
let success = match step_counter {
|
||||
// Read login parameters from the database
|
||||
1 => {
|
||||
progress!(context, 1);
|
||||
if param.addr.is_empty() {
|
||||
error!(context, "Please enter an email address.",);
|
||||
}
|
||||
!param.addr.is_empty()
|
||||
}
|
||||
// Step 1: Load the parameters and check email-address and password
|
||||
2 => {
|
||||
if 0 != param.server_flags & 0x2 {
|
||||
// the used oauth2 addr may differ, check this.
|
||||
// if dc_get_oauth2_addr() is not available in the oauth2 implementation,
|
||||
// just use the given one.
|
||||
progress!(context, 10);
|
||||
if let Some(oauth2_addr) =
|
||||
dc_get_oauth2_addr(context, ¶m.addr, ¶m.mail_pw)
|
||||
.and_then(|e| e.parse().ok())
|
||||
{
|
||||
info!(context, "Authorized address is {}", oauth2_addr);
|
||||
param.addr = oauth2_addr;
|
||||
context
|
||||
.sql
|
||||
.set_raw_config(context, "addr", Some(param.addr.as_str()))
|
||||
.ok();
|
||||
}
|
||||
// Step 1: Load the parameters and check email-address and password
|
||||
2 => {
|
||||
if 0 != param.server_flags & 0x2 {
|
||||
// the used oauth2 addr may differ, check this.
|
||||
// if dc_get_oauth2_addr() is not available in the oauth2 implementation,
|
||||
// just use the given one.
|
||||
progress!(context, 10);
|
||||
if let Some(oauth2_addr) =
|
||||
dc_get_oauth2_addr(context, ¶m.addr, ¶m.mail_pw)
|
||||
.and_then(|e| e.parse().ok())
|
||||
{
|
||||
param.addr = oauth2_addr;
|
||||
context
|
||||
.sql
|
||||
.set_raw_config(context, "addr", Some(param.addr.as_str()))
|
||||
.ok();
|
||||
}
|
||||
progress!(context, 20);
|
||||
}
|
||||
true // no oauth? - just continue it's no error
|
||||
}
|
||||
3 => {
|
||||
if let Ok(parsed) = param.addr.parse() {
|
||||
let parsed: EmailAddress = parsed;
|
||||
param_domain = parsed.domain;
|
||||
param_addr_urlencoded =
|
||||
utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string();
|
||||
true
|
||||
} else {
|
||||
error!(context, "Bad email-address.");
|
||||
false
|
||||
}
|
||||
}
|
||||
// Step 2: Autoconfig
|
||||
4 => {
|
||||
progress!(context, 200);
|
||||
if param.mail_server.is_empty()
|
||||
progress!(context, 20);
|
||||
}
|
||||
true // no oauth? - just continue it's no error
|
||||
}
|
||||
3 => {
|
||||
if let Ok(parsed) = param.addr.parse() {
|
||||
let parsed: EmailAddress = parsed;
|
||||
param_domain = parsed.domain;
|
||||
param_addr_urlencoded =
|
||||
utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string();
|
||||
true
|
||||
} else {
|
||||
error!(context, "Bad email-address.");
|
||||
false
|
||||
}
|
||||
}
|
||||
// Step 2: Autoconfig
|
||||
4 => {
|
||||
progress!(context, 200);
|
||||
if param.mail_server.is_empty()
|
||||
&& param.mail_port == 0
|
||||
/*&¶m.mail_user.is_empty() -- the user can enter a loginname which is used by autoconfig then */
|
||||
&& param.send_server.is_empty()
|
||||
@@ -141,388 +146,255 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
|
||||
&& param.send_user.is_empty()
|
||||
/*&¶m.send_pw.is_empty() -- the password cannot be auto-configured and is no criterion for autoconfig or not */
|
||||
&& param.server_flags & !0x2 == 0
|
||||
{
|
||||
keep_flags = param.server_flags & 0x2;
|
||||
} else {
|
||||
// Autoconfig is not needed so skip it.
|
||||
step_counter = STEP_3_INDEX - 1;
|
||||
}
|
||||
true
|
||||
{
|
||||
keep_flags = param.server_flags & 0x2;
|
||||
} else {
|
||||
// Autoconfig is not needed so skip it.
|
||||
step_counter = STEP_3_INDEX - 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
|
||||
5 => {
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
6 => {
|
||||
progress!(context, 300);
|
||||
if param_autoconfig.is_none() {
|
||||
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
|
||||
let url = format!(
|
||||
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* Outlook section start ------------- */
|
||||
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
|
||||
7 => {
|
||||
progress!(context, 310);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://{}{}/autodiscover/autodiscover.xml",
|
||||
"", param_domain
|
||||
);
|
||||
param_autoconfig = outlk_autodiscover(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
8 => {
|
||||
progress!(context, 320);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://{}{}/autodiscover/autodiscover.xml",
|
||||
"autodiscover.", param_domain
|
||||
);
|
||||
param_autoconfig = outlk_autodiscover(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* ----------- Outlook section end */
|
||||
9 => {
|
||||
progress!(context, 330);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
10 => {
|
||||
progress!(context, 340);
|
||||
if param_autoconfig.is_none() {
|
||||
// do not transfer the email-address unencrypted
|
||||
let url = format!(
|
||||
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
|
||||
param_domain
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
|
||||
11 => {
|
||||
progress!(context, 350);
|
||||
if param_autoconfig.is_none() {
|
||||
/* always SSL for Thunderbird's database */
|
||||
let url = format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* C. Do we have any result? */
|
||||
12 => {
|
||||
progress!(context, 500);
|
||||
if let Some(ref cfg) = param_autoconfig {
|
||||
info!(context, "Got autoconfig: {}", &cfg);
|
||||
if !cfg.mail_user.is_empty() {
|
||||
param.mail_user = cfg.mail_user.clone();
|
||||
}
|
||||
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
|
||||
5 => {
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
param.mail_server = cfg.mail_server.clone(); /* all other values are always NULL when entering autoconfig */
|
||||
param.mail_port = cfg.mail_port;
|
||||
param.send_server = cfg.send_server.clone();
|
||||
param.send_port = cfg.send_port;
|
||||
param.send_user = cfg.send_user.clone();
|
||||
param.server_flags = cfg.server_flags;
|
||||
/* although param_autoconfig's data are no longer needed from, it is important to keep the object as
|
||||
we may enter "deep guessing" if we could not read a configuration */
|
||||
}
|
||||
param.server_flags |= keep_flags;
|
||||
true
|
||||
}
|
||||
// Step 3: Fill missing fields with defaults
|
||||
13 => {
|
||||
// if you move this, don't forget to update STEP_3_INDEX, too
|
||||
if param.mail_server.is_empty() {
|
||||
param.mail_server = format!("imap.{}", param_domain,)
|
||||
}
|
||||
if param.mail_port == 0 {
|
||||
param.mail_port = if 0 != param.server_flags & (0x100 | 0x400) {
|
||||
143
|
||||
} else {
|
||||
993
|
||||
}
|
||||
6 => {
|
||||
progress!(context, 300);
|
||||
if param_autoconfig.is_none() {
|
||||
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
|
||||
let url = format!(
|
||||
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain,
|
||||
param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
if param.mail_user.is_empty() {
|
||||
param.mail_user = param.addr.clone();
|
||||
}
|
||||
if param.send_server.is_empty() && !param.mail_server.is_empty() {
|
||||
param.send_server = param.mail_server.clone();
|
||||
if param.send_server.starts_with("imap.") {
|
||||
param.send_server = param.send_server.replacen("imap", "smtp", 1);
|
||||
}
|
||||
/* Outlook section start ------------- */
|
||||
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
|
||||
7 => {
|
||||
progress!(context, 310);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://{}{}/autodiscover/autodiscover.xml",
|
||||
"", param_domain
|
||||
);
|
||||
param_autoconfig = outlk_autodiscover(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
if param.send_port == 0 {
|
||||
param.send_port = if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32
|
||||
{
|
||||
587
|
||||
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
|
||||
25
|
||||
} else {
|
||||
465
|
||||
}
|
||||
8 => {
|
||||
progress!(context, 320);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"https://{}{}/autodiscover/autodiscover.xml",
|
||||
"autodiscover.", param_domain
|
||||
);
|
||||
param_autoconfig = outlk_autodiscover(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
if param.send_user.is_empty() && !param.mail_user.is_empty() {
|
||||
param.send_user = param.mail_user.clone();
|
||||
}
|
||||
if param.send_pw.is_empty() && !param.mail_pw.is_empty() {
|
||||
param.send_pw = param.mail_pw.clone()
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & DC_LP_AUTH_FLAGS as i32) {
|
||||
param.server_flags &= !(DC_LP_AUTH_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_AUTH_NORMAL as i32
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & DC_LP_IMAP_SOCKET_FLAGS as i32) {
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= if param.send_port == 143 {
|
||||
DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||
} else {
|
||||
DC_LP_IMAP_SOCKET_SSL as i32
|
||||
}
|
||||
/* ----------- Outlook section end */
|
||||
9 => {
|
||||
progress!(context, 330);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!(
|
||||
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & (DC_LP_SMTP_SOCKET_FLAGS as i32)) {
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= if param.send_port == 587 {
|
||||
DC_LP_SMTP_SOCKET_STARTTLS as i32
|
||||
} else if param.send_port == 25 {
|
||||
DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
} else {
|
||||
DC_LP_SMTP_SOCKET_SSL as i32
|
||||
}
|
||||
10 => {
|
||||
progress!(context, 340);
|
||||
if param_autoconfig.is_none() {
|
||||
// do not transfer the email-address unencrypted
|
||||
let url = format!(
|
||||
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
|
||||
param_domain
|
||||
);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
|
||||
11 => {
|
||||
progress!(context, 350);
|
||||
if param_autoconfig.is_none() {
|
||||
/* always SSL for Thunderbird's database */
|
||||
let url =
|
||||
format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
|
||||
param_autoconfig = moz_autoconfigure(context, &url, ¶m);
|
||||
}
|
||||
true
|
||||
}
|
||||
/* C. Do we have any result? */
|
||||
12 => {
|
||||
progress!(context, 500);
|
||||
if let Some(ref cfg) = param_autoconfig {
|
||||
info!(context, "Got autoconfig: {}", &cfg);
|
||||
if !cfg.mail_user.is_empty() {
|
||||
param.mail_user = cfg.mail_user.clone();
|
||||
}
|
||||
param.mail_server = cfg.mail_server.clone(); /* all other values are always NULL when entering autoconfig */
|
||||
param.mail_port = cfg.mail_port;
|
||||
param.send_server = cfg.send_server.clone();
|
||||
param.send_port = cfg.send_port;
|
||||
param.send_user = cfg.send_user.clone();
|
||||
param.server_flags = cfg.server_flags;
|
||||
/* although param_autoconfig's data are no longer needed from, it is important to keep the object as
|
||||
we may enter "deep guessing" if we could not read a configuration */
|
||||
}
|
||||
param.server_flags |= keep_flags;
|
||||
true
|
||||
}
|
||||
// Step 3: Fill missing fields with defaults
|
||||
13 => {
|
||||
// if you move this, don't forget to update STEP_3_INDEX, too
|
||||
if param.mail_server.is_empty() {
|
||||
param.mail_server = format!("imap.{}", param_domain,)
|
||||
}
|
||||
if param.mail_port == 0 {
|
||||
param.mail_port = if 0 != param.server_flags & (0x100 | 0x400) {
|
||||
143
|
||||
} else {
|
||||
993
|
||||
}
|
||||
}
|
||||
if param.mail_user.is_empty() {
|
||||
param.mail_user = param.addr.clone();
|
||||
}
|
||||
if param.send_server.is_empty() && !param.mail_server.is_empty() {
|
||||
param.send_server = param.mail_server.clone();
|
||||
if param.send_server.starts_with("imap.") {
|
||||
param.send_server = param.send_server.replacen("imap", "smtp", 1);
|
||||
}
|
||||
}
|
||||
if param.send_port == 0 {
|
||||
param.send_port =
|
||||
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
|
||||
587
|
||||
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
|
||||
25
|
||||
} else {
|
||||
465
|
||||
}
|
||||
}
|
||||
if param.send_user.is_empty() && !param.mail_user.is_empty() {
|
||||
param.send_user = param.mail_user.clone();
|
||||
}
|
||||
if param.send_pw.is_empty() && !param.mail_pw.is_empty() {
|
||||
param.send_pw = param.mail_pw.clone()
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & DC_LP_AUTH_FLAGS as i32) {
|
||||
param.server_flags &= !(DC_LP_AUTH_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_AUTH_NORMAL as i32
|
||||
}
|
||||
if !dc_exactly_one_bit_set(
|
||||
param.server_flags & DC_LP_IMAP_SOCKET_FLAGS as i32,
|
||||
) {
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= if param.send_port == 143 {
|
||||
DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||
} else {
|
||||
DC_LP_IMAP_SOCKET_SSL as i32
|
||||
}
|
||||
}
|
||||
if !dc_exactly_one_bit_set(
|
||||
param.server_flags & (DC_LP_SMTP_SOCKET_FLAGS as i32),
|
||||
) {
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= if param.send_port == 587 {
|
||||
DC_LP_SMTP_SOCKET_STARTTLS as i32
|
||||
} else if param.send_port == 25 {
|
||||
DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
} else {
|
||||
DC_LP_SMTP_SOCKET_SSL as i32
|
||||
}
|
||||
}
|
||||
/* do we have a complete configuration? */
|
||||
if param.mail_server.is_empty()
|
||||
|| param.mail_port == 0
|
||||
|| param.mail_user.is_empty()
|
||||
|| param.mail_pw.is_empty()
|
||||
|| param.send_server.is_empty()
|
||||
|| param.send_port == 0
|
||||
|| param.send_user.is_empty()
|
||||
|| param.send_pw.is_empty()
|
||||
|| param.server_flags == 0
|
||||
{
|
||||
error!(context, "Account settings incomplete.");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
14 => {
|
||||
progress!(context, 600);
|
||||
/* try to connect to IMAP - if we did not got an autoconfig,
|
||||
do some further tries with different settings and username variations */
|
||||
let ok_to_continue8;
|
||||
let mut username_variation = 0;
|
||||
loop {
|
||||
if !(username_variation <= 1) {
|
||||
ok_to_continue8 = true;
|
||||
break;
|
||||
}
|
||||
info!(context, "Trying: {}", ¶m);
|
||||
|
||||
if context.inbox.read().unwrap().connect(context, ¶m) {
|
||||
ok_to_continue8 = true;
|
||||
break;
|
||||
}
|
||||
if param_autoconfig.is_some() {
|
||||
ok_to_continue8 = false;
|
||||
break;
|
||||
}
|
||||
// probe STARTTLS/993
|
||||
if context.shall_stop_ongoing() {
|
||||
ok_to_continue8 = false;
|
||||
break;
|
||||
}
|
||||
progress!(context, 650 + username_variation * 30);
|
||||
param.server_flags &= !(0x100 | 0x200 | 0x400);
|
||||
param.server_flags |= 0x100;
|
||||
info!(context, "Trying: {}", ¶m);
|
||||
|
||||
if context.inbox.read().unwrap().connect(context, ¶m) {
|
||||
ok_to_continue8 = true;
|
||||
break;
|
||||
}
|
||||
// probe STARTTLS/143
|
||||
if context.shall_stop_ongoing() {
|
||||
ok_to_continue8 = false;
|
||||
break;
|
||||
}
|
||||
progress!(context, 660 + username_variation * 30);
|
||||
param.mail_port = 143;
|
||||
info!(context, "Trying: {}", ¶m);
|
||||
|
||||
if context.inbox.read().unwrap().connect(context, ¶m) {
|
||||
ok_to_continue8 = true;
|
||||
break;
|
||||
}
|
||||
if 0 != username_variation {
|
||||
ok_to_continue8 = false;
|
||||
break;
|
||||
}
|
||||
// next probe round with only the localpart of the email-address as the loginname
|
||||
if context.shall_stop_ongoing() {
|
||||
ok_to_continue8 = false;
|
||||
break;
|
||||
}
|
||||
progress!(context, 670 + username_variation * 30);
|
||||
param.server_flags &= !(0x100 | 0x200 | 0x400);
|
||||
param.server_flags |= 0x200;
|
||||
param.mail_port = 993;
|
||||
|
||||
if let Some(at) = param.mail_user.find('@') {
|
||||
param.mail_user = param.mail_user.split_at(at).0.to_string();
|
||||
}
|
||||
if let Some(at) = param.send_user.find('@') {
|
||||
param.send_user = param.send_user.split_at(at).0.to_string();
|
||||
}
|
||||
|
||||
username_variation += 1
|
||||
}
|
||||
if ok_to_continue8 {
|
||||
// success, so we are connected and should disconnect in cleanup
|
||||
imap_connected_here = true;
|
||||
}
|
||||
ok_to_continue8
|
||||
}
|
||||
15 => {
|
||||
progress!(context, 800);
|
||||
let success;
|
||||
/* try to connect to SMTP - if we did not got an autoconfig, the first try was SSL-465 and we do a second try with STARTTLS-587 */
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect(context, ¶m)
|
||||
{
|
||||
if param_autoconfig.is_some() {
|
||||
success = false;
|
||||
} else if context.shall_stop_ongoing() {
|
||||
success = false;
|
||||
} else {
|
||||
progress!(context, 850);
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.send_port = 587;
|
||||
info!(context, "Trying: {}", ¶m);
|
||||
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect(context, ¶m)
|
||||
{
|
||||
if context.shall_stop_ongoing() {
|
||||
success = false;
|
||||
} else {
|
||||
progress!(context, 860);
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.send_port = 25;
|
||||
info!(context, "Trying: {}", ¶m);
|
||||
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect(context, ¶m)
|
||||
{
|
||||
success = false;
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
if success {
|
||||
smtp_connected_here = true;
|
||||
}
|
||||
success
|
||||
}
|
||||
16 => {
|
||||
progress!(context, 900);
|
||||
let flags: libc::c_int = if context.get_config_bool(Config::MvboxWatch)
|
||||
|| context.get_config_bool(Config::MvboxMove)
|
||||
{
|
||||
DC_CREATE_MVBOX as i32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
context
|
||||
.inbox
|
||||
.read()
|
||||
.unwrap()
|
||||
.configure_folders(context, flags);
|
||||
true
|
||||
}
|
||||
17 => {
|
||||
progress!(context, 910);
|
||||
/* configuration success - write back the configured parameters with the "configured_" prefix; also write the "configured"-flag */
|
||||
param
|
||||
.save_to_database(
|
||||
context,
|
||||
"configured_", /*the trailing underscore is correct*/
|
||||
)
|
||||
.ok();
|
||||
|
||||
context.sql.set_raw_config_bool(context, "configured", true);
|
||||
true
|
||||
}
|
||||
18 => {
|
||||
progress!(context, 920);
|
||||
// we generate the keypair just now - we could also postpone this until the first message is sent, however,
|
||||
// this may result in a unexpected and annoying delay when the user sends his very first message
|
||||
// (~30 seconds on a Moto G4 play) and might looks as if message sending is always that slow.
|
||||
e2ee::ensure_secret_key_exists(context);
|
||||
success = true;
|
||||
info!(context, "Configure completed.");
|
||||
progress!(context, 940);
|
||||
break; // We are done here
|
||||
}
|
||||
|
||||
_ => {
|
||||
error!(context, "Internal error: step counter out of bound",);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if !success {
|
||||
break;
|
||||
}
|
||||
/* do we have a complete configuration? */
|
||||
if param.mail_server.is_empty()
|
||||
|| param.mail_port == 0
|
||||
|| param.mail_user.is_empty()
|
||||
|| param.mail_pw.is_empty()
|
||||
|| param.send_server.is_empty()
|
||||
|| param.send_port == 0
|
||||
|| param.send_user.is_empty()
|
||||
|| param.send_pw.is_empty()
|
||||
|| param.server_flags == 0
|
||||
{
|
||||
error!(context, "Account settings incomplete.");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
14 => {
|
||||
progress!(context, 600);
|
||||
/* try to connect to IMAP - if we did not got an autoconfig,
|
||||
do some further tries with different settings and username variations */
|
||||
imap_connected_here =
|
||||
try_imap_connections(context, &mut param, param_autoconfig.is_some());
|
||||
imap_connected_here
|
||||
}
|
||||
15 => {
|
||||
progress!(context, 800);
|
||||
smtp_connected_here =
|
||||
try_smtp_connections(context, &mut param, param_autoconfig.is_some());
|
||||
smtp_connected_here
|
||||
}
|
||||
16 => {
|
||||
progress!(context, 900);
|
||||
let flags: libc::c_int = if context.get_config_bool(Config::MvboxWatch)
|
||||
|| context.get_config_bool(Config::MvboxMove)
|
||||
{
|
||||
DC_CREATE_MVBOX as i32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
context
|
||||
.inbox
|
||||
.read()
|
||||
.unwrap()
|
||||
.configure_folders(context, flags);
|
||||
true
|
||||
}
|
||||
17 => {
|
||||
progress!(context, 910);
|
||||
/* configuration success - write back the configured parameters with the "configured_" prefix; also write the "configured"-flag */
|
||||
param
|
||||
.save_to_database(
|
||||
context,
|
||||
"configured_", /*the trailing underscore is correct*/
|
||||
)
|
||||
.ok();
|
||||
|
||||
context.sql.set_raw_config_bool(context, "configured", true);
|
||||
true
|
||||
}
|
||||
18 => {
|
||||
progress!(context, 920);
|
||||
// we generate the keypair just now - we could also postpone this until the first message is sent, however,
|
||||
// this may result in a unexpected and annoying delay when the user sends his very first message
|
||||
// (~30 seconds on a Moto G4 play) and might looks as if message sending is always that slow.
|
||||
e2ee::ensure_secret_key_exists(context);
|
||||
success = true;
|
||||
info!(context, "Configure completed.");
|
||||
progress!(context, 940);
|
||||
break; // We are done here
|
||||
}
|
||||
|
||||
_ => {
|
||||
error!(context, "Internal error: step counter out of bound",);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if !success {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if imap_connected_here {
|
||||
@@ -549,11 +421,131 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
|
||||
);
|
||||
}
|
||||
*/
|
||||
if ongoing_allocated_here {
|
||||
context.free_ongoing();
|
||||
context.free_ongoing();
|
||||
progress!(context, if success { 1000 } else { 0 });
|
||||
}
|
||||
|
||||
fn try_imap_connections(
|
||||
context: &Context,
|
||||
mut param: &mut LoginParam,
|
||||
was_autoconfig: bool,
|
||||
) -> bool {
|
||||
// progress 650 and 660
|
||||
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 0) {
|
||||
return res;
|
||||
}
|
||||
progress!(context, 670);
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_SSL;
|
||||
param.mail_port = 993;
|
||||
|
||||
if let Some(at) = param.mail_user.find('@') {
|
||||
param.mail_user = param.mail_user.split_at(at).0.to_string();
|
||||
}
|
||||
if let Some(at) = param.send_user.find('@') {
|
||||
param.send_user = param.send_user.split_at(at).0.to_string();
|
||||
}
|
||||
// progress 680 and 690
|
||||
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 1) {
|
||||
res
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn try_imap_connection(
|
||||
context: &Context,
|
||||
param: &mut LoginParam,
|
||||
was_autoconfig: bool,
|
||||
variation: usize,
|
||||
) -> Option<bool> {
|
||||
if let Some(res) = try_imap_one_param(context, ¶m) {
|
||||
return Some(res);
|
||||
}
|
||||
if was_autoconfig {
|
||||
return Some(false);
|
||||
}
|
||||
progress!(context, 650 + variation * 30);
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS;
|
||||
if let Some(res) = try_imap_one_param(context, ¶m) {
|
||||
return Some(res);
|
||||
}
|
||||
|
||||
progress!(context, if success { 1000 } else { 0 });
|
||||
progress!(context, 660 + variation * 30);
|
||||
param.mail_port = 143;
|
||||
|
||||
try_imap_one_param(context, ¶m)
|
||||
}
|
||||
|
||||
fn try_imap_one_param(context: &Context, param: &LoginParam) -> Option<bool> {
|
||||
let inf = format!(
|
||||
"imap: {}@{}:{} flags=0x{:x}",
|
||||
param.mail_user, param.mail_server, param.mail_port, param.server_flags
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
if context.inbox.read().unwrap().connect(context, ¶m) {
|
||||
info!(context, "success: {}", inf);
|
||||
return Some(true);
|
||||
}
|
||||
if context.shall_stop_ongoing() {
|
||||
return Some(false);
|
||||
}
|
||||
info!(context, "Could not connect: {}", inf);
|
||||
None
|
||||
}
|
||||
|
||||
fn try_smtp_connections(
|
||||
context: &Context,
|
||||
mut param: &mut LoginParam,
|
||||
was_autoconfig: bool,
|
||||
) -> bool {
|
||||
/* try to connect to SMTP - if we did not got an autoconfig, the first try was SSL-465 and we do a second try with STARTTLS-587 */
|
||||
if let Some(res) = try_smtp_one_param(context, ¶m) {
|
||||
return res;
|
||||
}
|
||||
if was_autoconfig {
|
||||
return false;
|
||||
}
|
||||
progress!(context, 850);
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.send_port = 587;
|
||||
|
||||
if let Some(res) = try_smtp_one_param(context, ¶m) {
|
||||
return res;
|
||||
}
|
||||
progress!(context, 860);
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.send_port = 25;
|
||||
if let Some(res) = try_smtp_one_param(context, ¶m) {
|
||||
return res;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn try_smtp_one_param(context: &Context, param: &LoginParam) -> Option<bool> {
|
||||
let inf = format!(
|
||||
"smtp: {}@{}:{} flags: 0x{:x}",
|
||||
param.send_user, param.send_server, param.send_port, param.server_flags
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
if context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.connect(context, ¶m)
|
||||
{
|
||||
info!(context, "success: {}", inf);
|
||||
return Some(true);
|
||||
}
|
||||
if context.shall_stop_ongoing() {
|
||||
return Some(false);
|
||||
}
|
||||
info!(context, "could not connect: {}", inf);
|
||||
None
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -613,8 +605,6 @@ mod tests {
|
||||
.set_config(Config::Addr, Some("probably@unexistant.addr"))
|
||||
.unwrap();
|
||||
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
|
||||
unsafe {
|
||||
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
|
||||
}
|
||||
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,6 +63,7 @@ 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)]
|
||||
@@ -145,10 +146,11 @@ 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!(
|
||||
ctx.sql.open(&ctx, &ctx.dbfile, 0),
|
||||
ctx.sql.open(&ctx, &ctx.dbfile, false),
|
||||
"Failed opening sqlite database"
|
||||
);
|
||||
|
||||
|
||||
@@ -105,15 +105,15 @@ impl<'a> MimeParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self, body: &[u8]) -> Result<(), Error> {
|
||||
pub unsafe fn parse(&mut self, body: &[u8]) -> Result<(), Error> {
|
||||
let mut index = 0;
|
||||
|
||||
let r = unsafe { mailmime_parse(
|
||||
let r = mailmime_parse(
|
||||
body.as_ptr() as *const libc::c_char,
|
||||
body.len(),
|
||||
&mut index,
|
||||
&mut self.mimeroot,
|
||||
) };
|
||||
);
|
||||
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() {
|
||||
let (encrypted, signatures, gossipped_addr) =
|
||||
@@ -121,11 +121,11 @@ impl<'a> MimeParser<'a> {
|
||||
self.encrypted = encrypted;
|
||||
self.signatures = signatures;
|
||||
self.gossipped_addr = gossipped_addr;
|
||||
unsafe { self.parse_mime_recursive(self.mimeroot) } ;
|
||||
self.parse_mime_recursive(self.mimeroot);
|
||||
|
||||
if let Some(field) = self.lookup_field("Subject") {
|
||||
if unsafe { (*field).fld_type } == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
let subj = unsafe { (*(*field).fld_data.fld_subject).sbj_value };
|
||||
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
let subj = (*(*field).fld_data.fld_subject).sbj_value;
|
||||
|
||||
self.subject = as_opt_str(subj).map(dc_decode_header_words);
|
||||
}
|
||||
@@ -284,21 +284,21 @@ impl<'a> MimeParser<'a> {
|
||||
let mut index_0 = 0;
|
||||
let dn_field_c = CString::new(dn_field).unwrap_or_default();
|
||||
|
||||
if unsafe { mailimf_mailbox_list_parse(
|
||||
if mailimf_mailbox_list_parse(
|
||||
dn_field_c.as_ptr(),
|
||||
strlen(dn_field_c.as_ptr()),
|
||||
&mut index_0,
|
||||
&mut mb_list,
|
||||
) } == MAILIMF_NO_ERROR as libc::c_int
|
||||
) == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !mb_list.is_null()
|
||||
{
|
||||
if let Some(dn_to_addr) = wrapmime::mailimf_find_first_addr(mb_list) {
|
||||
if let Some(from_field) = self.lookup_field("From") {
|
||||
if unsafe { (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
|
||||
&& !(*from_field).fld_data.fld_from.is_null() }
|
||||
if (*from_field).fld_type == MAILIMF_FIELD_FROM as libc::c_int
|
||||
&& !(*from_field).fld_data.fld_from.is_null()
|
||||
{
|
||||
let from_addr = wrapmime::mailimf_find_first_addr(
|
||||
unsafe { (*(*from_field).fld_data.fld_from).frm_mb_list },
|
||||
(*(*from_field).fld_data.fld_from).frm_mb_list,
|
||||
);
|
||||
if let Some(from_addr) = from_addr {
|
||||
if from_addr == dn_to_addr {
|
||||
@@ -310,7 +310,7 @@ impl<'a> MimeParser<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe { mailimf_mailbox_list_free(mb_list) };
|
||||
mailimf_mailbox_list_free(mb_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ptr;
|
||||
|
||||
use itertools::join;
|
||||
use libc::{free, strcmp};
|
||||
use libc::strcmp;
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailmime::content::*;
|
||||
@@ -319,13 +319,8 @@ unsafe fn add_parts(
|
||||
let mut chat_id_blocked = Blocked::Not;
|
||||
let mut sort_timestamp = 0;
|
||||
let mut rcvd_timestamp = 0;
|
||||
let mut mime_in_reply_to = std::ptr::null_mut();
|
||||
let mut mime_references = std::ptr::null_mut();
|
||||
|
||||
let cleanup = |mime_in_reply_to: *mut libc::c_char, mime_references: *mut libc::c_char| {
|
||||
free(mime_in_reply_to.cast());
|
||||
free(mime_references.cast());
|
||||
};
|
||||
let mut mime_in_reply_to = String::new();
|
||||
let mut mime_references = String::new();
|
||||
|
||||
// collect the rest information, CC: is added to the to-list, BCC: is ignored
|
||||
// (we should not add BCC to groups as this would split groups. We could add them as "known contacts",
|
||||
@@ -359,7 +354,6 @@ unsafe fn add_parts(
|
||||
message::update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
}
|
||||
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Message already in DB");
|
||||
}
|
||||
|
||||
@@ -588,20 +582,14 @@ unsafe fn add_parts(
|
||||
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() {
|
||||
mime_in_reply_to = dc_str_from_clist(
|
||||
(*(*field).fld_data.fld_in_reply_to).mid_list,
|
||||
b" \x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
mime_in_reply_to = dc_str_from_clist((*(*field).fld_data.fld_in_reply_to).mid_list, " ")
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(field) = mime_parser.lookup_field_typ("References", MAILIMF_FIELD_REFERENCES) {
|
||||
let fld_references = (*field).fld_data.fld_references;
|
||||
if !fld_references.is_null() {
|
||||
mime_references = dc_str_from_clist(
|
||||
(*(*field).fld_data.fld_references).mid_list,
|
||||
b" \x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
mime_references = dc_str_from_clist((*(*field).fld_data.fld_references).mid_list, " ")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,97 +600,91 @@ unsafe fn add_parts(
|
||||
let icnt = mime_parser.parts.len();
|
||||
let mut txt_raw = None;
|
||||
|
||||
context
|
||||
.sql
|
||||
.prepare(
|
||||
"INSERT INTO msgs \
|
||||
(rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \
|
||||
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
|
||||
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
|
||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
||||
|mut stmt, conn| {
|
||||
for i in 0..icnt {
|
||||
let part = &mut mime_parser.parts[i];
|
||||
if part.is_meta {
|
||||
continue;
|
||||
}
|
||||
context.sql.prepare(
|
||||
"INSERT INTO msgs \
|
||||
(rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \
|
||||
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
|
||||
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
|
||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
||||
|mut stmt, conn| {
|
||||
for i in 0..icnt {
|
||||
let part = &mut mime_parser.parts[i];
|
||||
if part.is_meta {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(ref msg) = part.msg {
|
||||
if mime_parser.location_kml.is_some()
|
||||
&& icnt == 1
|
||||
&& (msg == "-location-" || msg.is_empty())
|
||||
{
|
||||
*hidden = 1;
|
||||
if state == MessageState::InFresh {
|
||||
state = MessageState::InNoticed;
|
||||
}
|
||||
if let Some(ref msg) = part.msg {
|
||||
if mime_parser.location_kml.is_some()
|
||||
&& icnt == 1
|
||||
&& (msg == "-location-" || msg.is_empty())
|
||||
{
|
||||
*hidden = 1;
|
||||
if state == MessageState::InFresh {
|
||||
state = MessageState::InNoticed;
|
||||
}
|
||||
}
|
||||
if part.typ == Viewtype::Text {
|
||||
let msg_raw = part.msg_raw.as_ref().cloned().unwrap_or_default();
|
||||
let subject = mime_parser
|
||||
.subject
|
||||
.as_ref()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or("".into());
|
||||
txt_raw = Some(format!("{}\n\n{}", subject, msg_raw));
|
||||
}
|
||||
if mime_parser.is_system_message != SystemMessage::Unknown {
|
||||
part.param
|
||||
.set_int(Param::Cmd, mime_parser.is_system_message as i32);
|
||||
}
|
||||
|
||||
/*
|
||||
info!(
|
||||
context,
|
||||
"received mime message {:?}",
|
||||
String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
imf_raw_not_terminated as *const u8,
|
||||
imf_raw_bytes,
|
||||
))
|
||||
);
|
||||
*/
|
||||
|
||||
stmt.execute(params![
|
||||
rfc724_mid,
|
||||
server_folder.as_ref(),
|
||||
server_uid as libc::c_int,
|
||||
*chat_id as libc::c_int,
|
||||
*from_id as libc::c_int,
|
||||
*to_id as libc::c_int,
|
||||
sort_timestamp,
|
||||
*sent_timestamp,
|
||||
rcvd_timestamp,
|
||||
part.typ,
|
||||
state,
|
||||
msgrmsg,
|
||||
part.msg.as_ref().map_or("", String::as_str),
|
||||
// txt_raw might contain invalid utf8
|
||||
txt_raw.unwrap_or_default(),
|
||||
part.param.to_string(),
|
||||
part.bytes,
|
||||
*hidden,
|
||||
if save_mime_headers {
|
||||
Some(String::from_utf8_lossy(imf_raw))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
to_string_lossy(mime_in_reply_to),
|
||||
to_string_lossy(mime_references),
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
*insert_msg_id =
|
||||
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
created_db_entries.push((*chat_id as usize, *insert_msg_id as usize));
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.map_err(|err| {
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
err
|
||||
})?;
|
||||
if part.typ == Viewtype::Text {
|
||||
let msg_raw = part.msg_raw.as_ref().cloned().unwrap_or_default();
|
||||
let subject = mime_parser
|
||||
.subject
|
||||
.as_ref()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or("".into());
|
||||
txt_raw = Some(format!("{}\n\n{}", subject, msg_raw));
|
||||
}
|
||||
if mime_parser.is_system_message != SystemMessage::Unknown {
|
||||
part.param
|
||||
.set_int(Param::Cmd, mime_parser.is_system_message as i32);
|
||||
}
|
||||
|
||||
/*
|
||||
info!(
|
||||
context,
|
||||
"received mime message {:?}",
|
||||
String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
imf_raw_not_terminated as *const u8,
|
||||
imf_raw_bytes,
|
||||
))
|
||||
);
|
||||
*/
|
||||
|
||||
stmt.execute(params![
|
||||
rfc724_mid,
|
||||
server_folder.as_ref(),
|
||||
server_uid as libc::c_int,
|
||||
*chat_id as libc::c_int,
|
||||
*from_id as libc::c_int,
|
||||
*to_id as libc::c_int,
|
||||
sort_timestamp,
|
||||
*sent_timestamp,
|
||||
rcvd_timestamp,
|
||||
part.typ,
|
||||
state,
|
||||
msgrmsg,
|
||||
part.msg.as_ref().map_or("", String::as_str),
|
||||
// txt_raw might contain invalid utf8
|
||||
txt_raw.unwrap_or_default(),
|
||||
part.param.to_string(),
|
||||
part.bytes,
|
||||
*hidden,
|
||||
if save_mime_headers {
|
||||
Some(String::from_utf8_lossy(imf_raw))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
mime_in_reply_to,
|
||||
mime_references,
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
*insert_msg_id =
|
||||
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
created_db_entries.push((*chat_id as usize, *insert_msg_id as usize));
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
info!(
|
||||
context,
|
||||
@@ -722,8 +704,6 @@ unsafe fn add_parts(
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -142,8 +142,8 @@ impl Simplify {
|
||||
ret += "[...]";
|
||||
}
|
||||
/* we write empty lines only in case and non-empty line follows */
|
||||
let mut pending_linebreaks: libc::c_int = 0i32;
|
||||
let mut content_lines_added: libc::c_int = 0i32;
|
||||
let mut pending_linebreaks = 0;
|
||||
let mut content_lines_added = 0;
|
||||
for l in l_first..l_last {
|
||||
let line = lines[l];
|
||||
if is_empty_line(line) {
|
||||
|
||||
195
src/dc_tools.rs
195
src/dc_tools.rs
@@ -51,75 +51,6 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
ret
|
||||
}
|
||||
|
||||
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> {
|
||||
@@ -143,36 +74,18 @@ pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Co
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn dc_str_from_clist(
|
||||
list: *const clist,
|
||||
delimiter: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
pub(crate) fn dc_str_from_clist(list: *const clist, delimiter: &str) -> String {
|
||||
let mut res = String::new();
|
||||
|
||||
if !list.is_null() {
|
||||
let mut cur: *mut clistiter = (*list).first;
|
||||
while !cur.is_null() {
|
||||
let rfc724_mid = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *const libc::c_char;
|
||||
|
||||
if !rfc724_mid.is_null() {
|
||||
if !res.is_empty() && !delimiter.is_null() {
|
||||
res += as_str(delimiter);
|
||||
}
|
||||
res += as_str(rfc724_mid);
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
for rfc724_mid in unsafe { (*list).into_iter() } {
|
||||
if !res.is_empty() {
|
||||
res += delimiter;
|
||||
}
|
||||
res += as_str(rfc724_mid as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
|
||||
res.strdup()
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn dc_str_to_clist(str: &str, delimiter: &str) -> *mut clist {
|
||||
@@ -593,6 +506,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,
|
||||
@@ -800,9 +732,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 {
|
||||
@@ -1007,54 +937,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));
|
||||
@@ -1160,17 +1042,11 @@ mod tests {
|
||||
unsafe {
|
||||
let list: *mut clist = dc_str_to_clist("foo bar test", " ");
|
||||
assert_eq!((*list).count, 3);
|
||||
let str: *mut libc::c_char =
|
||||
dc_str_from_clist(list, b" \x00" as *const u8 as *const libc::c_char);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"foo bar test"
|
||||
);
|
||||
let str = dc_str_from_clist(list, " ");
|
||||
assert_eq!(str, "foo bar test");
|
||||
|
||||
clist_free_content(list);
|
||||
clist_free(list);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1523,19 +1399,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_lossy(input));
|
||||
free(input.cast());
|
||||
|
||||
let input = "\rfoo\r\rbar\r".strdup();
|
||||
dc_remove_cr_chars(input);
|
||||
assert_eq!("foobar", to_string_lossy(input));
|
||||
free(input.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
src/e2ee.rs
10
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::*;
|
||||
@@ -211,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(),
|
||||
@@ -263,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 = wrapmime::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"
|
||||
@@ -398,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,
|
||||
@@ -581,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 {
|
||||
@@ -237,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 },
|
||||
}
|
||||
|
||||
10
src/imap.rs
10
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 {
|
||||
@@ -598,9 +598,9 @@ impl Imap {
|
||||
self.config.write().unwrap().watch_folder = Some(watch_folder);
|
||||
}
|
||||
|
||||
pub fn fetch(&self, context: &Context) -> libc::c_int {
|
||||
pub fn fetch(&self, context: &Context) -> bool {
|
||||
if !self.is_connected() || !context.sql.is_open() {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
self.setup_handle_if_needed(context);
|
||||
@@ -616,9 +616,9 @@ impl Imap {
|
||||
break;
|
||||
}
|
||||
}
|
||||
1
|
||||
true
|
||||
} else {
|
||||
0
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
201
src/imex.rs
201
src/imex.rs
@@ -1,7 +1,5 @@
|
||||
use core::cmp::{max, min};
|
||||
use std::ffi::CString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
use rand::{thread_rng, Rng};
|
||||
@@ -19,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;
|
||||
|
||||
@@ -89,7 +87,7 @@ pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<Strin
|
||||
let name = name.to_string_lossy();
|
||||
if name.starts_with("delta-chat") && name.ends_with(".bak") {
|
||||
let sql = Sql::new();
|
||||
if sql.open(context, &path, 0x1) {
|
||||
if sql.open(context, &path, true) {
|
||||
let curr_backup_time =
|
||||
sql.get_raw_config_int(context, "backup_time")
|
||||
.unwrap_or_default() as u64;
|
||||
@@ -171,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!(
|
||||
@@ -241,18 +239,12 @@ pub fn continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) -
|
||||
);
|
||||
|
||||
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.");
|
||||
}
|
||||
@@ -326,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 {
|
||||
@@ -459,7 +413,7 @@ fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) -> Resul
|
||||
/* error already logged */
|
||||
/* re-open copied database file */
|
||||
ensure!(
|
||||
context.sql.open(&context, &context.get_dbfile(), 0),
|
||||
context.sql.open(&context, &context.get_dbfile(), false),
|
||||
"could not re-open db"
|
||||
);
|
||||
|
||||
@@ -542,7 +496,7 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
dest_path_filename.display(),
|
||||
);
|
||||
let copied = dc_copy_file(context, context.get_dbfile(), &dest_path_filename);
|
||||
context.sql.open(&context, &context.get_dbfile(), 0);
|
||||
context.sql.open(&context, &context.get_dbfile(), false);
|
||||
if !copied {
|
||||
let s = dest_path_filename.to_string_lossy().to_string();
|
||||
bail!(
|
||||
@@ -572,7 +526,7 @@ fn add_files_to_export(context: &Context, dest_path_filename: &PathBuf) -> Resul
|
||||
// the source to be locked, neigher the destination as it is used only here)
|
||||
let sql = Sql::new();
|
||||
ensure!(
|
||||
sql.open(context, &dest_path_filename, 0),
|
||||
sql.open(context, &dest_path_filename, false),
|
||||
"could not open db"
|
||||
);
|
||||
if !sql.table_exists("backup_blobs") {
|
||||
@@ -638,7 +592,6 @@ 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();
|
||||
@@ -663,40 +616,17 @@ fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
||||
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_or_default()
|
||||
} 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
Err(_) => continue,
|
||||
}
|
||||
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
|
||||
imported_cnt += 1;
|
||||
}
|
||||
ensure!(
|
||||
imported_cnt > 0,
|
||||
@@ -783,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() {
|
||||
@@ -805,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);
|
||||
@@ -873,50 +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());
|
||||
|
||||
unsafe {
|
||||
let buf_1 = S_EM_SETUPFILE.strdup();
|
||||
let res = dc_split_armored_data(
|
||||
buf_1,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
&mut preferencrypt,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
libc::free(buf_1 as *mut libc::c_void);
|
||||
assert!(res);
|
||||
}
|
||||
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
|
||||
assert!(!setupcodebegin.is_null());
|
||||
assert!(!base64.is_empty());
|
||||
|
||||
// TODO: verify that this is the right check
|
||||
assert!(S_EM_SETUPCODE.starts_with(as_str(setupcodebegin)));
|
||||
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();
|
||||
|
||||
assert!(preferencrypt.is_null());
|
||||
let (typ, headers, _base64) = split_armored_data(decrypted.as_bytes()).unwrap();
|
||||
|
||||
let mut setup_file = S_EM_SETUPFILE.to_string();
|
||||
let decrypted = unsafe {
|
||||
decrypt_setup_file(context, S_EM_SETUPCODE, setup_file.as_bytes_mut()).unwrap()
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let buf1 = decrypted.strdup();
|
||||
assert!(dc_split_armored_data(
|
||||
buf1,
|
||||
&mut headerline,
|
||||
&mut setupcodebegin,
|
||||
&mut preferencrypt,
|
||||
ptr::null_mut(),
|
||||
));
|
||||
libc::free(buf1 as *mut libc::c_void);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ impl Job {
|
||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
||||
|
||||
if !connected {
|
||||
self.try_again_later(3i32, None);
|
||||
self.try_again_later(3, None);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ impl Job {
|
||||
Err(err) => {
|
||||
sock.disconnect();
|
||||
warn!(context, "smtp failed: {}", err);
|
||||
self.try_again_later(-1i32, Some(err.to_string()));
|
||||
self.try_again_later(-1, Some(err.to_string()));
|
||||
}
|
||||
Ok(()) => {
|
||||
// smtp success, update db ASAP, then delete smtp file
|
||||
@@ -207,7 +207,7 @@ impl Job {
|
||||
}
|
||||
|
||||
// this value does not increase the number of tries
|
||||
fn try_again_later(&mut self, try_again: libc::c_int, pending_error: Option<String>) {
|
||||
fn try_again_later(&mut self, try_again: i32, pending_error: Option<String>) {
|
||||
self.try_again = try_again;
|
||||
self.pending_error = pending_error;
|
||||
}
|
||||
@@ -781,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) => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -197,7 +197,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
|
||||
let now = time();
|
||||
let mut msg: Message;
|
||||
let is_sending_locations_before: bool;
|
||||
if !(seconds < 0 || chat_id <= 9i32 as libc::c_uint) {
|
||||
if !(seconds < 0 || chat_id <= DC_CHAT_ID_LAST_SPECIAL) {
|
||||
is_sending_locations_before = is_sending_locations_to_chat(context, chat_id);
|
||||
if sql::execute(
|
||||
context,
|
||||
|
||||
@@ -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_lossy(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
|
||||
const OAUTH2_GMAIL: Oauth2 = Oauth2 {
|
||||
// see https://developers.google.com/identity/protocols/OAuth2InstalledApp
|
||||
client_id: "959970109878-4mvtgf6feshskf7695nfln6002mom908.apps.googleusercontent.com",
|
||||
get_code: "https://accounts.google.com/o/oauth2/auth?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&access_type=offline",
|
||||
init_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=authorization_code",
|
||||
@@ -15,6 +16,7 @@ const OAUTH2_GMAIL: Oauth2 = Oauth2 {
|
||||
};
|
||||
|
||||
const OAUTH2_YANDEX: Oauth2 = Oauth2 {
|
||||
// see https://tech.yandex.com/oauth/doc/dg/reference/auto-code-client-docpage/
|
||||
client_id: "c4d0b6735fc8420a816d7e1303469341",
|
||||
get_code: "https://oauth.yandex.com/authorize?client_id=$CLIENT_ID&response_type=code&scope=mail%3Aimap_full%20mail%3Asmtp&force_confirm=true",
|
||||
init_token: "https://oauth.yandex.com/token?grant_type=authorization_code&code=$CODE&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
|
||||
@@ -89,6 +91,7 @@ pub fn dc_get_oauth2_access_token(
|
||||
}
|
||||
}
|
||||
|
||||
// generate new token: build & call auth url
|
||||
let refresh_token = context.sql.get_raw_config(context, "oauth2_refresh_token");
|
||||
let refresh_token_for = context
|
||||
.sql
|
||||
@@ -120,14 +123,37 @@ pub fn dc_get_oauth2_access_token(
|
||||
false,
|
||||
)
|
||||
};
|
||||
let mut token_url = replace_in_uri(&token_url, "$CLIENT_ID", oauth2.client_id);
|
||||
token_url = replace_in_uri(&token_url, "$REDIRECT_URI", &redirect_uri);
|
||||
token_url = replace_in_uri(&token_url, "$CODE", code.as_ref());
|
||||
if let Some(ref token) = refresh_token {
|
||||
token_url = replace_in_uri(&token_url, "$REFRESH_TOKEN", token);
|
||||
|
||||
// to allow easier specification of different configurations,
|
||||
// token_url is in GET-method-format, sth. as https://domain?param1=val1¶m2=val2 -
|
||||
// convert this to POST-format ...
|
||||
let mut parts = token_url.splitn(2, '?');
|
||||
let post_url = parts.next().unwrap_or_default();
|
||||
let post_args = parts.next().unwrap_or_default();
|
||||
let mut post_param = HashMap::new();
|
||||
for key_value_pair in post_args.split('&') {
|
||||
let mut parts = key_value_pair.splitn(2, '=');
|
||||
let key = parts.next().unwrap_or_default();
|
||||
let mut value = parts.next().unwrap_or_default();
|
||||
|
||||
if value == "$CLIENT_ID" {
|
||||
value = oauth2.client_id;
|
||||
} else if value == "$REDIRECT_URI" {
|
||||
value = &redirect_uri;
|
||||
} else if value == "$CODE" {
|
||||
value = code.as_ref();
|
||||
} else if value == "$REFRESH_TOKEN" && refresh_token.is_some() {
|
||||
value = refresh_token.as_ref().unwrap();
|
||||
}
|
||||
|
||||
post_param.insert(key, value);
|
||||
}
|
||||
|
||||
let response = reqwest::Client::new().post(&token_url).send();
|
||||
// ... and POST
|
||||
let response = reqwest::Client::new()
|
||||
.post(post_url)
|
||||
.form(&post_param)
|
||||
.send();
|
||||
if response.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
@@ -139,13 +165,14 @@ pub fn dc_get_oauth2_access_token(
|
||||
if !response.status().is_success() {
|
||||
warn!(
|
||||
context,
|
||||
"Error calling OAuth2 at {}: {:?}",
|
||||
"Unsuccessful response when calling OAuth2 at {}: {:?}",
|
||||
token_url,
|
||||
response.status()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
// generate new token: parse returned json
|
||||
let parsed: reqwest::Result<Response> = response.json();
|
||||
if parsed.is_err() {
|
||||
warn!(
|
||||
@@ -155,6 +182,8 @@ pub fn dc_get_oauth2_access_token(
|
||||
return None;
|
||||
}
|
||||
println!("response: {:?}", &parsed);
|
||||
|
||||
// update refresh_token if given, typically on the first round, but we update it later as well.
|
||||
let response = parsed.unwrap();
|
||||
if let Some(ref token) = response.refresh_token {
|
||||
context
|
||||
@@ -268,7 +297,7 @@ impl Oauth2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let parsed: reqwest::Result<HashMap<String, String>> = response.json();
|
||||
let parsed: reqwest::Result<HashMap<String, serde_json::Value>> = response.json();
|
||||
if parsed.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
@@ -277,11 +306,13 @@ impl Oauth2 {
|
||||
return None;
|
||||
}
|
||||
if let Ok(response) = parsed {
|
||||
// serde_json::Value.as_str() removes the quotes of json-strings
|
||||
let addr = response.get("email");
|
||||
if addr.is_none() {
|
||||
warn!(context, "E-mail missing in userinfo.");
|
||||
return None;
|
||||
}
|
||||
|
||||
let addr = addr.unwrap().as_str();
|
||||
addr.map(|addr| addr.to_string())
|
||||
} else {
|
||||
warn!(context, "Failed to parse userinfo.");
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
12
src/sql.rs
12
src/sql.rs
@@ -11,8 +11,6 @@ use crate::error::{Error, Result};
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
|
||||
const DC_OPEN_READONLY: usize = 0x01;
|
||||
|
||||
/// A wrapper around the underlying Sqlite3 object.
|
||||
#[derive(DebugStub)]
|
||||
pub struct Sql {
|
||||
@@ -42,8 +40,8 @@ impl Sql {
|
||||
}
|
||||
|
||||
// return true on success, false on failure
|
||||
pub fn open(&self, context: &Context, dbfile: &std::path::Path, flags: libc::c_int) -> bool {
|
||||
match open(context, self, dbfile, flags) {
|
||||
pub fn open(&self, context: &Context, dbfile: &std::path::Path, readonly: bool) -> bool {
|
||||
match open(context, self, dbfile, readonly) {
|
||||
Ok(_) => true,
|
||||
Err(Error::SqlAlreadyOpen) => false,
|
||||
Err(_) => {
|
||||
@@ -320,7 +318,7 @@ fn open(
|
||||
context: &Context,
|
||||
sql: &Sql,
|
||||
dbfile: impl AsRef<std::path::Path>,
|
||||
flags: libc::c_int,
|
||||
readonly: bool,
|
||||
) -> Result<()> {
|
||||
if sql.is_open() {
|
||||
error!(
|
||||
@@ -332,7 +330,7 @@ fn open(
|
||||
}
|
||||
|
||||
let mut open_flags = OpenFlags::SQLITE_OPEN_NO_MUTEX;
|
||||
if 0 != (flags & DC_OPEN_READONLY as i32) {
|
||||
if readonly {
|
||||
open_flags.insert(OpenFlags::SQLITE_OPEN_READ_ONLY);
|
||||
} else {
|
||||
open_flags.insert(OpenFlags::SQLITE_OPEN_READ_WRITE);
|
||||
@@ -351,7 +349,7 @@ fn open(
|
||||
*sql.pool.write().unwrap() = Some(pool);
|
||||
}
|
||||
|
||||
if 0 == flags & DC_OPEN_READONLY as i32 {
|
||||
if !readonly {
|
||||
let mut exists_before_update = 0;
|
||||
let mut dbversion_before_update = 0;
|
||||
/* Init tables to dbversion=0 */
|
||||
|
||||
88
src/stock.rs
88
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
|
||||
///
|
||||
@@ -123,19 +122,47 @@ impl StockMessage {
|
||||
}
|
||||
|
||||
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_lossy(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,27 @@ 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))
|
||||
libc = s.count("libc")
|
||||
filestats.append((fn, unsafe, free, unsafe_fn, chars, libc))
|
||||
|
||||
sum_unsafe, sum_free, sum_gotoblocks, sum_chars = 0, 0, 0, 0
|
||||
sum_unsafe, sum_free, sum_unsafe_fn, sum_chars, sum_libc = 0, 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, libc in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
if unsafe + free + unsafe_fn + chars + libc == 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} libc: {5: >3}".format(str(fn), unsafe, free, unsafe_fn, chars, libc))
|
||||
sum_unsafe += unsafe
|
||||
sum_free += free
|
||||
sum_gotoblocks += gotoblocks
|
||||
sum_unsafe_fn += unsafe_fn
|
||||
sum_chars += chars
|
||||
sum_libc += libc
|
||||
|
||||
|
||||
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)
|
||||
print("total libc:", sum_libc)
|
||||
|
||||
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