mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 15:02:11 +03:00
Compare commits
30 Commits
1.0.0-alph
...
qr_remove_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4128aae331 | ||
|
|
c914a0339b | ||
|
|
a1f4849188 | ||
|
|
e5a9761233 | ||
|
|
ff15754c1f | ||
|
|
de2b0059c9 | ||
|
|
6f79800824 | ||
|
|
7a19963879 | ||
|
|
cd7630360f | ||
|
|
4a633169e1 | ||
|
|
ea8d6e8ff0 | ||
|
|
065124b93b | ||
|
|
86d290832b | ||
|
|
56f8717a40 | ||
|
|
4a0b2e68c8 | ||
|
|
2576b78126 | ||
|
|
6a956b6008 | ||
|
|
33575e7aa3 | ||
|
|
8089559958 | ||
|
|
686678c96c | ||
|
|
c116d6f73f | ||
|
|
a7c8ebc089 | ||
|
|
7774052911 | ||
|
|
68888f6d1f | ||
|
|
3dfd623db7 | ||
|
|
31d2bc7401 | ||
|
|
5ee8f8cb59 | ||
|
|
d1825956b2 | ||
|
|
30ca377586 | ||
|
|
f58b1d66c2 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -2,7 +2,7 @@
|
||||
# ensures this even if the user has not set core.autocrlf.
|
||||
* text=auto
|
||||
|
||||
# binary files should be detected by git, however, to be sure, you can add them here explictly
|
||||
# binary files should be detected by git, however, to be sure, you can add them here explicitly
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
|
||||
140
Cargo.lock
generated
140
Cargo.lock
generated
@@ -9,7 +9,7 @@ dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"psl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rental 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -194,12 +194,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "buf_redux"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slice-deque 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -409,7 +409,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -443,7 +443,7 @@ dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -453,7 +453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -461,6 +461,7 @@ name = "deltachat"
|
||||
version = "1.0.0-alpha.3"
|
||||
dependencies = [
|
||||
"addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -484,9 +485,9 @@ dependencies = [
|
||||
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"r2d2_sqlite 0.11.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.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)",
|
||||
"rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -495,6 +496,7 @@ dependencies = [
|
||||
"strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -515,7 +517,7 @@ dependencies = [
|
||||
"derive_builder_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -526,7 +528,7 @@ dependencies = [
|
||||
"darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -608,7 +610,7 @@ dependencies = [
|
||||
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -637,7 +639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -898,7 +900,7 @@ dependencies = [
|
||||
"imap-proto 0.7.0 (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)",
|
||||
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -974,8 +976,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.16.0"
|
||||
source = "git+http://github.com/dignifiedquire/rusqlite?branch=fix/text#d81b8cdb175f7c27a3ace9ad46818e2a01434cdc"
|
||||
dependencies = [
|
||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1158,9 +1160,9 @@ dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.24 (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.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"schannel 0.1.15 (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)",
|
||||
@@ -1225,7 +1227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1278,7 +1280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.23"
|
||||
version = "0.10.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1286,7 +1288,7 @@ dependencies = [
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1304,7 +1306,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.47"
|
||||
version = "0.9.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1320,7 +1322,7 @@ name = "os_type"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1433,7 +1435,7 @@ dependencies = [
|
||||
"block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"buf_redux 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"buf_redux 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
@@ -1583,7 +1585,7 @@ dependencies = [
|
||||
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1616,7 +1618,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1792,22 +1794,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.1.9"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.8"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1834,12 +1836,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.9.18"
|
||||
version = "0.9.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1867,6 +1869,7 @@ dependencies = [
|
||||
"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)",
|
||||
"winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1899,12 +1902,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+http://github.com/dignifiedquire/rusqlite?branch=fix/text#d81b8cdb175f7c27a3ace9ad46818e2a01434cdc"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libsqlite3-sys 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libsqlite3-sys 0.16.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)",
|
||||
"lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2033,7 +2036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2103,7 +2106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slice-deque"
|
||||
version = "0.1.16"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2160,7 +2163,7 @@ dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2180,7 +2183,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.39"
|
||||
version = "0.15.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2195,7 +2198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2237,6 +2240,14 @@ dependencies = [
|
||||
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-local-object"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
@@ -2386,6 +2397,11 @@ dependencies = [
|
||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitobject"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.2"
|
||||
@@ -2416,7 +2432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -2466,6 +2482,14 @@ name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-any"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
@@ -2582,6 +2606,14 @@ dependencies = [
|
||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winutil"
|
||||
version = "0.1.1"
|
||||
@@ -2624,7 +2656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
@@ -2651,7 +2683,7 @@ dependencies = [
|
||||
"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529"
|
||||
"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09"
|
||||
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
||||
"checksum buf_redux 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f25c67abbf523ff8457771622fb731ac4a2391439de33bc60febcdee1749c9"
|
||||
"checksum buf_redux 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cb6b0b3650a857c5f3eb2083d6a51dc86a9967eafdd42919be63e3b3e6599752"
|
||||
"checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||
@@ -2735,7 +2767,7 @@ dependencies = [
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728"
|
||||
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
|
||||
"checksum libsqlite3-sys 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72b1e07fcc60484f42e246f0cf1f133940c98117c81b2cefcdf71be288069680"
|
||||
"checksum libsqlite3-sys 0.16.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)" = "<none>"
|
||||
"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"
|
||||
@@ -2768,10 +2800,10 @@ 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.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
|
||||
"checksum openssl 0.10.23 (registry+https://github.com/rust-lang/crates.io-index)" = "97c140cbb82f3b3468193dd14c1b88def39f341f68257f8a7fe8ed9ed3f628a5"
|
||||
"checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15"
|
||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
"checksum openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)" = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797"
|
||||
"checksum openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)" = "75bdd6dbbb4958d38e47a1d2348847ad1eb4dc205dc5d37473ae504391865acc"
|
||||
"checksum openssl-sys 0.9.48 (registry+https://github.com/rust-lang/crates.io-index)" = "b5ba300217253bcc5dc68bed23d782affa45000193866e025329aa8a7a9f05b8"
|
||||
"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"
|
||||
@@ -2819,15 +2851,15 @@ dependencies = [
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828"
|
||||
"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad"
|
||||
"checksum regex-syntax 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9b01330cce219c1c6b2e209e5ed64ccd587ae5c67bed91c0b49eecf02ae40e21"
|
||||
"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
|
||||
"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum rental 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "01916ebd9fc2e81978a5dc9542a2fa47f5bb2ca3402e14c7cc42d6e3c5123e1f"
|
||||
"checksum rental-impl 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82260d54cf2cbe9608df161f7e7c98e81fae702aa13af9e4d5d39dc2ffb25ab6"
|
||||
"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4"
|
||||
"checksum reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0777154c2c3eb54f5c480db01de845652d941e47191277cc673634c3853939"
|
||||
"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a"
|
||||
"checksum rsa 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6ad8d3632f6745bb671c8637e2aa44015537c5e384789d2ea3235739301ed1e0"
|
||||
"checksum rusqlite 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebca2e7e3deb7241b7fa5929c088548c590728b1b740c479594c23f813eb8a7"
|
||||
"checksum rusqlite 0.19.0 (git+http://github.com/dignifiedquire/rusqlite?branch=fix/text)" = "<none>"
|
||||
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f47ea1ceb347d2deae482d655dc8eef4bd82363d3329baffa3818bd76fea48b"
|
||||
@@ -2852,7 +2884,7 @@ dependencies = [
|
||||
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
|
||||
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum slice-deque 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "d39fca478d10e201944a8e21f4393d6bfe38fa3b16a152050e4d097fe2bbf494"
|
||||
"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 spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
@@ -2863,12 +2895,13 @@ dependencies = [
|
||||
"checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e"
|
||||
"checksum subtle 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01dca13cf6c3b179864ab3292bd794e757618d35a7766b7c46050c614ba00829"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c"
|
||||
"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
|
||||
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||
"checksum thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7da3caa820d0308c84c8654f6cafd81cc3195d45433311cbe22fcf44fc8be071"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
|
||||
@@ -2882,11 +2915,12 @@ dependencies = [
|
||||
"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19"
|
||||
"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"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
|
||||
"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
|
||||
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
|
||||
"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
@@ -2894,6 +2928,7 @@ dependencies = [
|
||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
|
||||
"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
|
||||
@@ -2911,6 +2946,7 @@ dependencies = [
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
|
||||
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
||||
"checksum winreg 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73f1f3c6c4d3cab118551b96c476a2caab920701e28875b64a458f2ecb96ec9d"
|
||||
"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538"
|
||||
|
||||
@@ -41,6 +41,8 @@ r2d2_sqlite = "0.11.0"
|
||||
r2d2 = "0.8.5"
|
||||
strum = "0.15.0"
|
||||
strum_macros = "0.15.0"
|
||||
thread-local-object = "0.1.0"
|
||||
backtrace = "0.3.33"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0"
|
||||
@@ -52,6 +54,10 @@ members = [
|
||||
"deltachat-ffi"
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
rusqlite = { git = "http://github.com/dignifiedquire/rusqlite", branch = "fix/text", features = ["bundled"] }
|
||||
|
||||
|
||||
[[example]]
|
||||
name = "simple"
|
||||
path = "examples/simple.rs"
|
||||
|
||||
@@ -24,3 +24,4 @@ default = ["vendored", "nightly", "ringbuf"]
|
||||
vendored = ["deltachat/vendored"]
|
||||
nightly = ["deltachat/nightly"]
|
||||
ringbuf = ["deltachat/ringbuf"]
|
||||
|
||||
|
||||
33
deltachat-ffi/build.rs
Normal file
33
deltachat-ffi/build.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let target_path = out_path.join("../../..");
|
||||
let target_triple = env::var("TARGET").unwrap();
|
||||
|
||||
// macOS or iOS, inherited from rpgp
|
||||
let libs_priv = if target_triple.contains("apple") || target_triple.contains("darwin") {
|
||||
// needed for OsRng
|
||||
"-framework Security -framework Foundation"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let pkg_config = format!(
|
||||
include_str!("deltachat.pc.in"),
|
||||
name = "deltachat",
|
||||
description = env::var("CARGO_PKG_DESCRIPTION").unwrap(),
|
||||
url = env::var("CARGO_PKG_HOMEPAGE").unwrap_or("".to_string()),
|
||||
version = env::var("CARGO_PKG_VERSION").unwrap(),
|
||||
libs_priv = libs_priv,
|
||||
prefix = env::var("PREFIX").unwrap_or("/usr/local".to_string()),
|
||||
);
|
||||
|
||||
fs::create_dir_all(target_path.join("pkgconfig")).unwrap();
|
||||
fs::File::create(target_path.join("pkgconfig").join("deltachat.pc"))
|
||||
.unwrap()
|
||||
.write_all(&pkg_config.as_bytes())
|
||||
.unwrap();
|
||||
}
|
||||
@@ -503,8 +503,8 @@ int dc_chat_is_sending_locations (const dc_chat_t*);
|
||||
#define DC_STATE_OUT_MDN_RCVD 28
|
||||
|
||||
|
||||
#define DC_MAX_GET_TEXT_LEN 30000 // approx. max. lenght returned by dc_msg_get_text()
|
||||
#define DC_MAX_GET_INFO_LEN 100000 // approx. max. lenght returned by dc_get_msg_info()
|
||||
#define DC_MAX_GET_TEXT_LEN 30000 // approx. max. length returned by dc_msg_get_text()
|
||||
#define DC_MAX_GET_INFO_LEN 100000 // approx. max. length returned by dc_get_msg_info()
|
||||
|
||||
|
||||
dc_msg_t* dc_msg_new (dc_context_t*, int viewtype);
|
||||
@@ -667,7 +667,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
|
||||
* A voice message that was directly recorded by the user.
|
||||
* For all other audio messages, the type #DC_MSG_AUDIO should be used.
|
||||
* File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
|
||||
* and retieved via dc_msg_get_file(), dc_msg_get_duration()
|
||||
* and retrieved via dc_msg_get_file(), dc_msg_get_duration()
|
||||
*/
|
||||
#define DC_MSG_VOICE 41
|
||||
|
||||
@@ -768,9 +768,9 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is choosen
|
||||
#define DC_LP_IMAP_SOCKET_FLAGS (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 choosen
|
||||
#define DC_LP_SMTP_SOCKET_FLAGS (DC_LP_SMTP_SOCKET_STARTTLS|DC_LP_SMTP_SOCKET_SSL|DC_LP_SMTP_SOCKET_PLAIN) // if none of these flags are set, the default is choosen
|
||||
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is chosen
|
||||
#define DC_LP_IMAP_SOCKET_FLAGS (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
|
||||
#define DC_LP_SMTP_SOCKET_FLAGS (DC_LP_SMTP_SOCKET_STARTTLS|DC_LP_SMTP_SOCKET_SSL|DC_LP_SMTP_SOCKET_PLAIN) // if none of these flags are set, the default is chosen
|
||||
|
||||
|
||||
|
||||
@@ -851,7 +851,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
|
||||
* The library-user should report an error to the end-user.
|
||||
* Passed to the callback given to dc_context_new().
|
||||
*
|
||||
* As most things are asynchrounous, things may go wrong at any time and the user
|
||||
* As most things are asynchronous, things may go wrong at any time and the user
|
||||
* should not be disturbed by a dialog or so. Instead, use a bubble or so.
|
||||
*
|
||||
* However, for ongoing processes (eg. dc_configure())
|
||||
@@ -882,7 +882,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t*);
|
||||
*
|
||||
* Moreover, if the UI detects that the device is offline,
|
||||
* it is probably more useful to report this to the user
|
||||
* instread of the string from data2.
|
||||
* instead of the string from data2.
|
||||
*
|
||||
* @param data1 (int) 1=first/new network error, should be reported the user;
|
||||
* 0=subsequent network error, should be logged only
|
||||
|
||||
11
deltachat-ffi/deltachat.pc.in
Normal file
11
deltachat-ffi/deltachat.pc.in
Normal file
@@ -0,0 +1,11 @@
|
||||
prefix={prefix}
|
||||
libdir=${{prefix}}/lib
|
||||
includedir=${{prefix}}/include
|
||||
|
||||
Name: {name}
|
||||
Description: {description}
|
||||
URL: {url}
|
||||
Version: {version}
|
||||
Cflags: -I${{includedir}}
|
||||
Libs: -L${{libdir}} -ldeltachat
|
||||
Libs.private: {libs_priv}
|
||||
@@ -111,7 +111,7 @@ pub unsafe extern "C" fn dc_get_config(
|
||||
match config::Config::from_str(dc_tools::as_str(key)) {
|
||||
Ok(key) => {
|
||||
let value = context.get_config(key).unwrap_or_default();
|
||||
into_cstring(value)
|
||||
dc_tools::to_cstring(value)
|
||||
}
|
||||
Err(_) => std::ptr::null_mut(),
|
||||
}
|
||||
@@ -137,7 +137,7 @@ pub unsafe extern "C" fn dc_get_oauth2_url(
|
||||
let addr = dc_tools::to_string(addr);
|
||||
let redirect = dc_tools::to_string(redirect);
|
||||
match oauth2::dc_get_oauth2_url(context, addr, redirect) {
|
||||
Some(res) => libc::strdup(dc_tools::to_cstring(res).as_ptr()),
|
||||
Some(res) => dc_tools::to_cstring(res),
|
||||
None => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
@@ -481,7 +481,7 @@ pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
// TODO: update to indiciate public api success/failure of deletion
|
||||
// TODO: update to indicate public api success/failure of deletion
|
||||
dc_chat::dc_delete_chat(context, chat_id);
|
||||
}
|
||||
|
||||
@@ -1546,7 +1546,3 @@ fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
|
||||
|
||||
Some(dc_tools::as_str(s))
|
||||
}
|
||||
|
||||
unsafe fn into_cstring(s: impl AsRef<str>) -> *mut libc::c_char {
|
||||
dc_tools::dc_strdup(dc_tools::to_cstring(s).as_ptr())
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use num_traits::FromPrimitive;
|
||||
pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
info!(context, 0, "Resetting tables ({})...", bits);
|
||||
if 0 != bits & 1 {
|
||||
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]);
|
||||
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]).unwrap();
|
||||
info!(context, 0, "(1) Jobs reset.");
|
||||
}
|
||||
if 0 != bits & 2 {
|
||||
@@ -37,11 +37,12 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
&context.sql,
|
||||
"DELETE FROM acpeerstates;",
|
||||
params![],
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
info!(context, 0, "(2) Peerstates reset.");
|
||||
}
|
||||
if 0 != bits & 4 {
|
||||
sql::execute(context, &context.sql, "DELETE FROM keypairs;", params![]);
|
||||
sql::execute(context, &context.sql, "DELETE FROM keypairs;", params![]).unwrap();
|
||||
info!(context, 0, "(4) Private keypairs reset.");
|
||||
}
|
||||
if 0 != bits & 8 {
|
||||
@@ -50,32 +51,37 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
&context.sql,
|
||||
"DELETE FROM contacts WHERE id>9;",
|
||||
params![],
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM chats WHERE id>9;",
|
||||
params![],
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM chats_contacts;",
|
||||
params![],
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM msgs WHERE id>9;",
|
||||
params![],
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';",
|
||||
params![],
|
||||
);
|
||||
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]);
|
||||
)
|
||||
.unwrap();
|
||||
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]).unwrap();
|
||||
info!(context, 0, "(8) Rest but server config reset.");
|
||||
}
|
||||
|
||||
@@ -129,7 +135,8 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
real_spec = dc_strdup(spec);
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)));
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
||||
.unwrap();
|
||||
current_block = 7149356873433890176;
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
@@ -139,7 +146,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
} else {
|
||||
current_block = 7149356873433890176;
|
||||
}
|
||||
real_spec = strdup(to_cstring(rs.unwrap_or_default()).as_ptr());
|
||||
real_spec = to_cstring(rs.unwrap_or_default());
|
||||
}
|
||||
match current_block {
|
||||
8522321847195001863 => {}
|
||||
@@ -177,10 +184,10 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, 0, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = to_cstring(path_plus_name);
|
||||
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c) {
|
||||
read_cnt += 1
|
||||
}
|
||||
free(path_plus_name_c as *mut _);
|
||||
}
|
||||
}
|
||||
current_block = 1622411330066726685;
|
||||
@@ -380,18 +387,16 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
let mut args = line.splitn(3, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
let arg1_c = to_cstring(arg1);
|
||||
let arg1_c_ptr = if arg1.is_empty() {
|
||||
let arg1_c = if arg1.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg1_c.as_ptr()
|
||||
to_cstring(arg1) as *const _
|
||||
};
|
||||
let arg2 = args.next().unwrap_or_default();
|
||||
let arg2_c = to_cstring(arg2);
|
||||
let arg2_c_ptr = if arg2.is_empty() {
|
||||
let arg2_c = if arg2.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg2_c.as_ptr()
|
||||
to_cstring(arg2) as *const _
|
||||
};
|
||||
|
||||
match arg0 {
|
||||
@@ -497,7 +502,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(!arg1.is_empty(), "Argument <file> missing");
|
||||
dc_close(context);
|
||||
ensure!(
|
||||
0 != dc_open(context, arg1_c_ptr, 0 as *const libc::c_char),
|
||||
0 != dc_open(context, arg1_c, 0 as *const libc::c_char),
|
||||
"Open failed"
|
||||
);
|
||||
}
|
||||
@@ -538,7 +543,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
!arg1.is_empty() && !arg2.is_empty(),
|
||||
"Arguments <msg-id> <setup-code> expected"
|
||||
);
|
||||
if 0 == dc_continue_key_transfer(context, arg1.parse().unwrap(), arg2_c_ptr) {
|
||||
if 0 == dc_continue_key_transfer(context, arg1.parse().unwrap(), arg2_c) {
|
||||
bail!("Continue key transfer failed");
|
||||
}
|
||||
}
|
||||
@@ -553,7 +558,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"import-backup" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
|
||||
dc_imex(context, 12, arg1_c_ptr, 0 as *const libc::c_char);
|
||||
dc_imex(context, 12, arg1_c, 0 as *const libc::c_char);
|
||||
}
|
||||
"export-keys" => {
|
||||
dc_imex(context, 1, context.get_blobdir(), 0 as *const libc::c_char);
|
||||
@@ -590,7 +595,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
free(setup_code as *mut libc::c_void);
|
||||
}
|
||||
"poke" => {
|
||||
ensure!(0 != poke_spec(context, arg1_c_ptr), "Poke failed");
|
||||
ensure!(0 != poke_spec(context, arg1_c), "Poke failed");
|
||||
}
|
||||
"reset" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
|
||||
@@ -624,7 +629,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"listchats" | "listarchived" | "chats" => {
|
||||
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
||||
let chatlist = dc_get_chatlist(context, listflags, arg1_c_ptr, 0 as uint32_t);
|
||||
let chatlist = dc_get_chatlist(context, listflags, arg1_c, 0 as uint32_t);
|
||||
ensure!(!chatlist.is_null(), "Failed to retrieve chatlist");
|
||||
|
||||
let mut i: libc::c_int;
|
||||
@@ -782,8 +787,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"creategroup" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||
let chat_id_1: libc::c_int =
|
||||
dc_create_group_chat(context, 0, arg1_c_ptr) as libc::c_int;
|
||||
let chat_id_1: libc::c_int = dc_create_group_chat(context, 0, arg1_c) as libc::c_int;
|
||||
if chat_id_1 != 0 {
|
||||
println!("Group#{} created successfully.", chat_id_1,);
|
||||
} else {
|
||||
@@ -792,8 +796,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"createverified" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||
let chat_id_2: libc::c_int =
|
||||
dc_create_group_chat(context, 1, arg1_c_ptr) as libc::c_int;
|
||||
let chat_id_2: libc::c_int = dc_create_group_chat(context, 1, arg1_c) as libc::c_int;
|
||||
if chat_id_2 != 0 {
|
||||
println!("VerifiedGroup#{} created successfully.", chat_id_2,);
|
||||
} else {
|
||||
@@ -832,7 +835,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"groupname" => {
|
||||
ensure!(!sel_chat.is_null(), "No chat selected.");
|
||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat), arg1_c_ptr) {
|
||||
if 0 != dc_set_chat_name(context, dc_chat_get_id(sel_chat), arg1_c) {
|
||||
println!("Chat name set");
|
||||
} else {
|
||||
bail!("Failed to set chat name");
|
||||
@@ -846,7 +849,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
context,
|
||||
dc_chat_get_id(sel_chat),
|
||||
if !arg1.is_empty() {
|
||||
arg1_c_ptr
|
||||
arg1_c
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
},
|
||||
@@ -937,9 +940,11 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
|
||||
let msg = to_cstring(format!("{} {}", arg1, arg2));
|
||||
|
||||
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg.as_ptr()) {
|
||||
if 0 != dc_send_text_msg(context, dc_chat_get_id(sel_chat), msg) {
|
||||
println!("Message sent.");
|
||||
free(msg as *mut _);
|
||||
} else {
|
||||
free(msg as *mut _);
|
||||
bail!("Sending failed.");
|
||||
}
|
||||
}
|
||||
@@ -960,8 +965,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given.");
|
||||
|
||||
let msg_0 = dc_msg_new(context, if arg0 == "sendimage" { 20 } else { 60 });
|
||||
dc_msg_set_file(msg_0, arg1_c_ptr, 0 as *const libc::c_char);
|
||||
dc_msg_set_text(msg_0, arg2_c_ptr);
|
||||
dc_msg_set_file(msg_0, arg1_c, 0 as *const libc::c_char);
|
||||
dc_msg_set_text(msg_0, arg2_c);
|
||||
dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0);
|
||||
dc_msg_unref(msg_0);
|
||||
}
|
||||
@@ -974,7 +979,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
0 as libc::c_uint
|
||||
};
|
||||
|
||||
let msglist_0 = dc_search_msgs(context, chat, arg1_c_ptr);
|
||||
let msglist_0 = dc_search_msgs(context, chat, arg1_c);
|
||||
|
||||
if !msglist_0.is_null() {
|
||||
log_msglist(context, msglist_0);
|
||||
@@ -987,7 +992,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
|
||||
if !arg1.is_empty() {
|
||||
let draft_0 = dc_msg_new(context, 10);
|
||||
dc_msg_set_text(draft_0, arg1_c_ptr);
|
||||
dc_msg_set_text(draft_0, arg1_c);
|
||||
dc_set_draft(context, dc_chat_get_id(sel_chat), draft_0);
|
||||
dc_msg_unref(draft_0);
|
||||
println!("Draft saved.");
|
||||
@@ -1079,7 +1084,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
} else {
|
||||
0x2
|
||||
},
|
||||
arg1_c_ptr,
|
||||
arg1_c,
|
||||
);
|
||||
if !contacts.is_null() {
|
||||
log_contactlist(context, contacts);
|
||||
@@ -1095,13 +1100,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
if !arg2.is_empty() {
|
||||
let book = dc_mprintf(
|
||||
b"%s\n%s\x00" as *const u8 as *const libc::c_char,
|
||||
arg1_c_ptr,
|
||||
arg2_c_ptr,
|
||||
arg1_c,
|
||||
arg2_c,
|
||||
);
|
||||
dc_add_address_book(context, book);
|
||||
free(book as *mut libc::c_void);
|
||||
} else {
|
||||
if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c_ptr) {
|
||||
if 0 == dc_create_contact(context, 0 as *const libc::c_char, arg1_c) {
|
||||
bail!("Failed to create contact");
|
||||
}
|
||||
}
|
||||
@@ -1148,7 +1153,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"checkqr" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
||||
let res = dc_check_qr(context, arg1_c_ptr);
|
||||
let res = dc_check_qr(context, arg1_c);
|
||||
println!(
|
||||
"state={}, id={}, text1={}, text2={}",
|
||||
(*res).state as libc::c_int,
|
||||
@@ -1176,7 +1181,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
|
||||
if 0 != dc_read_file(
|
||||
context,
|
||||
arg1_c_ptr,
|
||||
arg1_c,
|
||||
&mut buf as *mut *mut libc::c_uchar as *mut *mut libc::c_void,
|
||||
&mut buf_bytes,
|
||||
) {
|
||||
@@ -1194,5 +1199,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
dc_chat_unref(sel_chat);
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
free(arg2_c as *mut _);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -398,11 +398,10 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
||||
|
||||
if args.len() == 2 {
|
||||
if 0 == unsafe {
|
||||
dc_open(
|
||||
&mut context,
|
||||
to_cstring(&args[1]).as_ptr(),
|
||||
0 as *const libc::c_char,
|
||||
)
|
||||
let a = to_cstring(&args[1]);
|
||||
let res = dc_open(&mut context, a, 0 as *const _);
|
||||
free(a as *mut _);
|
||||
res
|
||||
} {
|
||||
println!("Error: Cannot open {}.", args[0],);
|
||||
}
|
||||
@@ -482,11 +481,10 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
let mut args = line.splitn(2, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
let arg1_c = to_cstring(arg1);
|
||||
let arg1_c_ptr = if arg1.is_empty() {
|
||||
let arg1_c = if arg1.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg1_c.as_ptr()
|
||||
to_cstring(arg1)
|
||||
};
|
||||
|
||||
match arg0 {
|
||||
@@ -559,13 +557,15 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
"joinqr" => {
|
||||
start_threads(ctx.clone());
|
||||
if !arg0.is_empty() {
|
||||
dc_join_securejoin(&ctx.read().unwrap(), arg1_c_ptr);
|
||||
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
|
||||
}
|
||||
}
|
||||
"exit" => return Ok(ExitResult::Exit),
|
||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
|
||||
Ok(ExitResult::Continue)
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,9 @@ fn main() {
|
||||
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"));
|
||||
ctx.set_config(config::Config::MailPw, Some(&pw));
|
||||
ctx.set_config(config::Config::Addr, Some("d@testrun.org"))
|
||||
.unwrap();
|
||||
ctx.set_config(config::Config::MailPw, Some(&pw)).unwrap();
|
||||
dc_configure(&ctx);
|
||||
|
||||
thread::sleep(duration);
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
- introduce automatic versioning via setuptools_scm,
|
||||
based on py-X.Y.Z tags
|
||||
|
||||
- integrate latest DCC core-rust with dc_close() fixes
|
||||
|
||||
- provide a account.shutdown() method and improve termination
|
||||
logic also in tests. also fixes output-clubbering during
|
||||
test runs.
|
||||
|
||||
|
||||
0.600.0
|
||||
---------
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
cargo build -p deltachat_ffi --release
|
||||
rm -rf build/ src/deltachat/*.so
|
||||
DCC_RS_DEV=`pwd`/.. pip install -e .
|
||||
36
python/install_python_bindings.py
Executable file
36
python/install_python_bindings.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
setup a python binding development in-place install with cargo debug symbols.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ["DCC_RS_TARGET"] = target = "release"
|
||||
|
||||
toml = os.path.join(os.getcwd(), "..", "Cargo.toml")
|
||||
assert os.path.exists(toml)
|
||||
with open(toml) as f:
|
||||
s = orig = f.read()
|
||||
s += "\n"
|
||||
s += "[profile.release]\n"
|
||||
s += "debug = true\n"
|
||||
with open(toml, "w") as f:
|
||||
f.write(s)
|
||||
print("temporarily modifying Cargo.toml to provide release build with debug symbols ")
|
||||
try:
|
||||
subprocess.check_call([
|
||||
"cargo", "build", "-p", "deltachat_ffi", "--" + target
|
||||
])
|
||||
finally:
|
||||
with open(toml, "w") as f:
|
||||
f.write(orig)
|
||||
print("\nreseted Cargo.toml to previous original state")
|
||||
|
||||
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
|
||||
|
||||
subprocess.check_call([
|
||||
"pip", "install", "-e", "."
|
||||
])
|
||||
@@ -43,6 +43,9 @@ def py_dc_callback(ctx, evt, data1, data2):
|
||||
|
||||
try:
|
||||
ret = callback(ctx, evt_name, data1, data2)
|
||||
if ret is None:
|
||||
ret = 0
|
||||
assert isinstance(ret, int), repr(ret)
|
||||
if event_sig_types & 4:
|
||||
return ffi.cast('uintptr_t', ret)
|
||||
elif event_sig_types & 8:
|
||||
@@ -58,7 +61,10 @@ def set_context_callback(dc_context, func):
|
||||
|
||||
|
||||
def clear_context_callback(dc_context):
|
||||
_DC_CALLBACK_MAP.pop(dc_context, None)
|
||||
try:
|
||||
_DC_CALLBACK_MAP.pop(dc_context, None)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def get_dc_event_name(integer, _DC_EVENTNAME_MAP={}):
|
||||
|
||||
@@ -25,11 +25,13 @@ def ffibuilder():
|
||||
else:
|
||||
raise NotImplementedError("Compilation not supported yet on Windows, can you help?")
|
||||
objs = [os.path.join(projdir, 'target', target, 'libdeltachat.a')]
|
||||
assert os.path.exists(objs[0]), objs
|
||||
incs = [os.path.join(projdir, 'deltachat-ffi')]
|
||||
else:
|
||||
libs = ['deltachat']
|
||||
objs = []
|
||||
incs = []
|
||||
extra_link_args = []
|
||||
builder = cffi.FFI()
|
||||
builder.set_source(
|
||||
'deltachat.capi',
|
||||
@@ -69,8 +71,8 @@ def ffibuilder():
|
||||
distutils.sysconfig.customize_compiler(cc)
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
src_name = os.path.join(tmpdir, "prep.h")
|
||||
dst_name = os.path.join(tmpdir, "prep2.c")
|
||||
src_name = os.path.join(tmpdir, "include.h")
|
||||
dst_name = os.path.join(tmpdir, "expanded.h")
|
||||
with open(src_name, "w") as src_fp:
|
||||
src_fp.write('#include <deltachat.h>')
|
||||
cc.preprocess(source=src_name,
|
||||
|
||||
@@ -23,28 +23,36 @@ class Account(object):
|
||||
by the underlying deltachat c-library. All public Account methods are
|
||||
meant to be memory-safe and return memory-safe objects.
|
||||
"""
|
||||
def __init__(self, db_path, logid=None):
|
||||
def __init__(self, db_path, logid=None, eventlogging=True):
|
||||
""" initialize account object.
|
||||
|
||||
:param db_path: a path to the account database. The database
|
||||
will be created if it doesn't exist.
|
||||
:param logid: an optional logging prefix that should be used with
|
||||
the default internal logging.
|
||||
:param eventlogging: if False no eventlogging and no context callback will be configured
|
||||
"""
|
||||
self._dc_context = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
_destroy_dc_context,
|
||||
)
|
||||
if eventlogging:
|
||||
self._evlogger = EventLogger(self._dc_context, logid)
|
||||
deltachat.set_context_callback(self._dc_context, self._process_event)
|
||||
self._threads = IOThreads(self._dc_context, self._evlogger._log_event)
|
||||
else:
|
||||
self._threads = IOThreads(self._dc_context)
|
||||
|
||||
if hasattr(db_path, "encode"):
|
||||
db_path = db_path.encode("utf8")
|
||||
if not lib.dc_open(self._dc_context, db_path, ffi.NULL):
|
||||
raise ValueError("Could not dc_open: {}".format(db_path))
|
||||
self._evlogger = EventLogger(self._dc_context, logid)
|
||||
deltachat.set_context_callback(self._dc_context, self._process_event)
|
||||
self._threads = IOThreads(self._dc_context)
|
||||
self._configkeys = self.get_config("sys.config_keys").split()
|
||||
self._imex_completed = threading.Event()
|
||||
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
|
||||
def _check_config_key(self, name):
|
||||
if name not in self._configkeys:
|
||||
raise KeyError("{!r} not a valid config key, existing keys: {!r}".format(
|
||||
@@ -333,12 +341,22 @@ class Account(object):
|
||||
lib.dc_stop_ongoing_process(self._dc_context)
|
||||
self._threads.stop(wait=wait)
|
||||
|
||||
def shutdown(self, wait=True):
|
||||
""" stop threads and close and remove underlying dc_context and callbacks. """
|
||||
if hasattr(self, "_dc_context") and hasattr(self, "_threads"):
|
||||
self.stop_threads(wait=False) # to interrupt idle and tell python threads to stop
|
||||
lib.dc_close(self._dc_context)
|
||||
self.stop_threads(wait=wait) # to wait for threads
|
||||
deltachat.clear_context_callback(self._dc_context)
|
||||
del self._dc_context
|
||||
|
||||
def _process_event(self, ctx, evt_name, data1, data2):
|
||||
assert ctx == self._dc_context
|
||||
self._evlogger(evt_name, data1, data2)
|
||||
method = getattr(self, "on_" + evt_name.lower(), None)
|
||||
if method is not None:
|
||||
method(data1, data2)
|
||||
if hasattr(self, "_evlogger"):
|
||||
self._evlogger(evt_name, data1, data2)
|
||||
method = getattr(self, "on_" + evt_name.lower(), None)
|
||||
if method is not None:
|
||||
method(data1, data2)
|
||||
return 0
|
||||
|
||||
def on_dc_event_imex_progress(self, data1, data2):
|
||||
@@ -347,10 +365,11 @@ class Account(object):
|
||||
|
||||
|
||||
class IOThreads:
|
||||
def __init__(self, dc_context):
|
||||
def __init__(self, dc_context, log_event=lambda *args: None):
|
||||
self._dc_context = dc_context
|
||||
self._thread_quitflag = False
|
||||
self._name2thread = {}
|
||||
self._log_event = log_event
|
||||
|
||||
def is_started(self):
|
||||
return len(self._name2thread) > 0
|
||||
@@ -376,15 +395,19 @@ class IOThreads:
|
||||
thread.join()
|
||||
|
||||
def imap_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_imap_jobs(self._dc_context)
|
||||
lib.dc_perform_imap_fetch(self._dc_context)
|
||||
lib.dc_perform_imap_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD FINISHED")
|
||||
|
||||
def smtp_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "SMTP THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_smtp_jobs(self._dc_context)
|
||||
lib.dc_perform_smtp_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "SMTP THREAD FINISHED")
|
||||
|
||||
|
||||
class EventLogger:
|
||||
@@ -414,7 +437,7 @@ class EventLogger:
|
||||
raise ValueError("{}({!r},{!r})".format(*ev))
|
||||
return ev
|
||||
|
||||
def get_matching(self, event_name_regex):
|
||||
def get_matching(self, event_name_regex, check_error=True):
|
||||
self._log("-- waiting for event with regex: {} --".format(event_name_regex))
|
||||
rex = re.compile("(?:{}).*".format(event_name_regex))
|
||||
while 1:
|
||||
|
||||
@@ -16,18 +16,41 @@ def pytest_addoption(parser):
|
||||
)
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
cfg = config.getoption('--liveconfig')
|
||||
if not cfg:
|
||||
cfg = os.getenv('DCC_PY_LIVECONFIG')
|
||||
if cfg:
|
||||
config.option.liveconfig = cfg
|
||||
|
||||
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_runtest_call(item):
|
||||
# perform early finalization because we otherwise get cloberred
|
||||
# output from concurrent threads printing between execution
|
||||
# of the test function and the teardown phase of that test function
|
||||
if "acfactory" in item.funcargs:
|
||||
print("*"*30, "finalizing", "*"*30)
|
||||
acfactory = item.funcargs["acfactory"]
|
||||
acfactory.finalize()
|
||||
|
||||
|
||||
def pytest_report_header(config, startdir):
|
||||
t = tempfile.mktemp()
|
||||
try:
|
||||
ac = Account(t)
|
||||
ac = Account(t, eventlogging=False)
|
||||
info = ac.get_info()
|
||||
del ac
|
||||
ac.shutdown()
|
||||
finally:
|
||||
os.remove(t)
|
||||
return "Deltachat core={} sqlite={}".format(
|
||||
info['deltachat_core_version'],
|
||||
info['sqlite_version'],
|
||||
)
|
||||
summary = ['Deltachat core={} sqlite={}'.format(
|
||||
info['deltachat_core_version'],
|
||||
info['sqlite_version'],
|
||||
)]
|
||||
cfg = config.getoption('--liveconfig')
|
||||
if cfg:
|
||||
summary.append('Liveconfig: {}'.format(os.path.abspath(cfg)))
|
||||
return summary
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -52,7 +75,6 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
self.live_count = 0
|
||||
self.offline_count = 0
|
||||
self._finalizers = []
|
||||
request.addfinalizer(self.finalize)
|
||||
self.init_time = time.time()
|
||||
|
||||
def finalize(self):
|
||||
@@ -64,7 +86,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
def configlist(self):
|
||||
configlist = []
|
||||
for line in open(fn):
|
||||
if line.strip():
|
||||
if line.strip() and not line.strip().startswith('#'):
|
||||
d = {}
|
||||
for part in line.split():
|
||||
name, value = part.split("=")
|
||||
@@ -78,6 +100,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
ac = Account(tmpdb.strpath, logid="ac{}".format(self.offline_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
ac._evlogger.set_timeout(2)
|
||||
self._finalizers.append(ac.shutdown)
|
||||
return ac
|
||||
|
||||
def get_configured_offline_account(self):
|
||||
@@ -103,7 +126,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
ac._evlogger.set_timeout(30)
|
||||
ac.configure(**configdict)
|
||||
ac.start_threads()
|
||||
self._finalizers.append(lambda: ac.stop_threads(wait=False))
|
||||
self._finalizers.append(ac.shutdown)
|
||||
return ac
|
||||
|
||||
def clone_online_account(self, account):
|
||||
@@ -114,7 +137,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
ac._evlogger.set_timeout(30)
|
||||
ac.configure(addr=account.get_config("addr"), mail_pw=account.get_config("mail_pw"))
|
||||
ac.start_threads()
|
||||
self._finalizers.append(lambda: ac.stop_threads(wait=False))
|
||||
self._finalizers.append(ac.shutdown)
|
||||
return ac
|
||||
|
||||
return AccountMaker()
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
import os
|
||||
from deltachat import const
|
||||
from deltachat import const, Account
|
||||
from datetime import datetime, timedelta
|
||||
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
|
||||
|
||||
|
||||
class TestOfflineAccount:
|
||||
def test_wrong_db(self, tmpdir):
|
||||
p = tmpdir.join("hello.db")
|
||||
p.write("123")
|
||||
with pytest.raises(ValueError):
|
||||
Account(p.strpath)
|
||||
|
||||
def test_getinfo(self, acfactory):
|
||||
ac1 = acfactory.get_unconfigured_account()
|
||||
d = ac1.get_info()
|
||||
|
||||
@@ -32,7 +32,11 @@ class TestInCreation:
|
||||
chat2.add_contact(c2)
|
||||
wait_msgs_changed(ac1, 0, 0) # why not chat id?
|
||||
ac1.forward_messages([prepared_original], chat2)
|
||||
# XXX there might be two EVENT_MSGS_CHANGED and only one of them
|
||||
# is the one caused by forwarding
|
||||
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
||||
if forwarded_id == 0:
|
||||
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
||||
forwarded_msg = ac1.get_message_by_id(forwarded_id)
|
||||
assert forwarded_msg.get_state().is_out_preparing()
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
from deltachat import capi, Account, const
|
||||
from deltachat import capi, const, set_context_callback, clear_context_callback
|
||||
from deltachat.capi import ffi
|
||||
from deltachat.capi import lib
|
||||
from deltachat.account import EventLogger
|
||||
|
||||
|
||||
def test_empty_context():
|
||||
@@ -8,10 +10,45 @@ def test_empty_context():
|
||||
capi.lib.dc_close(ctx)
|
||||
|
||||
|
||||
def test_callback_None2int():
|
||||
ctx = capi.lib.dc_context_new(capi.lib.py_dc_callback, ffi.NULL, ffi.NULL)
|
||||
set_context_callback(ctx, lambda *args: None)
|
||||
capi.lib.dc_close(ctx)
|
||||
clear_context_callback(ctx)
|
||||
|
||||
|
||||
def test_dc_close_events():
|
||||
ctx = capi.lib.dc_context_new(capi.lib.py_dc_callback, ffi.NULL, ffi.NULL)
|
||||
evlog = EventLogger(ctx)
|
||||
evlog.set_timeout(5)
|
||||
set_context_callback(ctx, lambda ctx, evt_name, data1, data2: evlog(evt_name, data1, data2))
|
||||
capi.lib.dc_close(ctx)
|
||||
|
||||
def find(info_string):
|
||||
while 1:
|
||||
ev = evlog.get_matching("DC_EVENT_INFO", check_error=False)
|
||||
data2 = ev[2]
|
||||
if info_string in data2:
|
||||
return
|
||||
else:
|
||||
print("skipping event", *ev)
|
||||
|
||||
find("disconnecting INBOX-watch")
|
||||
find("disconnecting sentbox-thread")
|
||||
find("disconnecting mvbox-thread")
|
||||
find("disconnecting SMTP")
|
||||
find("Database closed")
|
||||
|
||||
|
||||
def test_wrong_db(tmpdir):
|
||||
tmpdir.join("hello.db").write("123")
|
||||
with pytest.raises(ValueError):
|
||||
Account(db_path=tmpdir.strpath)
|
||||
dc_context = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
p = tmpdir.join("hello.db")
|
||||
# write an invalid database file
|
||||
p.write("x123" * 10)
|
||||
assert not lib.dc_open(dc_context, p.strpath.encode("ascii"), ffi.NULL)
|
||||
|
||||
|
||||
def test_event_defines():
|
||||
|
||||
@@ -13,6 +13,8 @@ commands =
|
||||
passenv =
|
||||
TRAVIS
|
||||
DCC_RS_DEV
|
||||
DCC_RS_TARGET
|
||||
DCC_PY_LIVECONFIG
|
||||
deps =
|
||||
pytest
|
||||
pytest-faulthandler
|
||||
@@ -52,6 +54,7 @@ commands =
|
||||
python_files = tests/test_*.py
|
||||
norecursedirs = .tox
|
||||
xfail_strict=true
|
||||
timeout = 60
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
|
||||
@@ -23,11 +23,10 @@ if [ $? != 0 ]; then
|
||||
fi
|
||||
|
||||
pushd python
|
||||
toxargs="$@"
|
||||
if [ -e liveconfig ]; then
|
||||
toxargs="--liveconfig liveconfig $@"
|
||||
if [ -e "./liveconfig" ]; then
|
||||
export DCC_PY_LIVECONFIG=liveconfig
|
||||
fi
|
||||
tox $toxargs
|
||||
tox "$@"
|
||||
ret=$?
|
||||
popd
|
||||
exit $ret
|
||||
|
||||
@@ -71,7 +71,12 @@ impl Context {
|
||||
Config::Selfavatar => {
|
||||
let rel_path = self.sql.get_config(self, key);
|
||||
rel_path.map(|p| {
|
||||
let v = unsafe { dc_get_abs_path(self, to_cstring(p).as_ptr()) };
|
||||
let v = unsafe {
|
||||
let n = to_cstring(p);
|
||||
let res = dc_get_abs_path(self, n);
|
||||
free(n as *mut libc::c_void);
|
||||
res
|
||||
};
|
||||
let r = to_string(v);
|
||||
unsafe { free(v as *mut _) };
|
||||
r
|
||||
@@ -100,7 +105,7 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Set the given config key.
|
||||
/// If `None` is passed as a value the value is cleared and set to the deafult if there is one.
|
||||
/// If `None` is passed as a value the value is cleared and set to the default if there is one.
|
||||
pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> {
|
||||
match key {
|
||||
Config::Selfavatar if value.is_some() => {
|
||||
|
||||
@@ -80,9 +80,9 @@ pub const DC_STATE_OUT_FAILED: usize = 24;
|
||||
pub const DC_STATE_OUT_DELIVERED: usize = 26;
|
||||
pub const DC_STATE_OUT_MDN_RCVD: usize = 28;
|
||||
|
||||
/// approx. max. lenght returned by dc_msg_get_text()
|
||||
/// approx. max. length returned by dc_msg_get_text()
|
||||
pub const DC_MAX_GET_TEXT_LEN: usize = 30000;
|
||||
/// approx. max. lenght returned by dc_get_msg_info()
|
||||
/// approx. max. length returned by dc_get_msg_info()
|
||||
pub const DC_MAX_GET_INFO_LEN: usize = 100000;
|
||||
|
||||
pub const DC_CONTACT_ID_SELF: usize = 1;
|
||||
@@ -119,7 +119,7 @@ pub const DC_MSG_AUDIO: usize = 40;
|
||||
/// A voice message that was directly recorded by the user.
|
||||
/// For all other audio messages, the type #DC_MSG_AUDIO should be used.
|
||||
/// File and duration are set via dc_msg_set_file(), dc_msg_set_duration()
|
||||
/// and retieved via dc_msg_get_file(), dc_msg_get_duration()
|
||||
/// and retrieved via dc_msg_get_file(), dc_msg_get_duration()
|
||||
pub const DC_MSG_VOICE: usize = 41;
|
||||
|
||||
/// Video messages.
|
||||
@@ -173,12 +173,12 @@ pub const DC_LP_SMTP_SOCKET_SSL: usize = 0x20000;
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_SMTP_SOCKET_PLAIN: usize = 0x40000;
|
||||
|
||||
/// if none of these flags are set, the default is choosen
|
||||
/// 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);
|
||||
/// if none of these flags are set, the default is choosen
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
|
||||
(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 choosen
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
|
||||
|
||||
@@ -237,7 +237,7 @@ pub enum Event {
|
||||
/// The library-user should report an error to the end-user.
|
||||
/// Passed to the callback given to dc_context_new().
|
||||
///
|
||||
/// As most things are asynchrounous, things may go wrong at any time and the user
|
||||
/// As most things are asynchronous, things may go wrong at any time and the user
|
||||
/// should not be disturbed by a dialog or so. Instead, use a bubble or so.
|
||||
///
|
||||
/// However, for ongoing processes (eg. dc_configure())
|
||||
@@ -265,7 +265,7 @@ pub enum Event {
|
||||
///
|
||||
/// Moreover, if the UI detects that the device is offline,
|
||||
/// it is probably more useful to report this to the user
|
||||
/// instread of the string from data2.
|
||||
/// instead of the string from data2.
|
||||
///
|
||||
/// @param data1 (int) 1=first/new network error, should be reported the user;
|
||||
/// 0=subsequent network error, should be logged only
|
||||
@@ -491,3 +491,12 @@ pub enum KeyType {
|
||||
Public = 0,
|
||||
Private = 1,
|
||||
}
|
||||
|
||||
pub const DC_CMD_GROUPNAME_CHANGED: libc::c_int = 2;
|
||||
pub const DC_CMD_GROUPIMAGE_CHANGED: libc::c_int = 3;
|
||||
pub const DC_CMD_MEMBER_ADDED_TO_GROUP: libc::c_int = 4;
|
||||
pub const DC_CMD_MEMBER_REMOVED_FROM_GROUP: libc::c_int = 5;
|
||||
pub const DC_CMD_AUTOCRYPT_SETUP_MESSAGE: libc::c_int = 6;
|
||||
pub const DC_CMD_SECUREJOIN_MESSAGE: libc::c_int = 7;
|
||||
pub const DC_CMD_LOCATION_STREAMING_ENABLED: libc::c_int = 8;
|
||||
pub const DC_CMD_LOCATION_ONLY: libc::c_int = 9;
|
||||
|
||||
@@ -260,7 +260,7 @@ unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *con
|
||||
} else {
|
||||
Some(as_str(value))
|
||||
};
|
||||
context.sql.set_config(context, as_str(key), v);
|
||||
context.sql.set_config(context, as_str(key), v).ok();
|
||||
}
|
||||
|
||||
/* *
|
||||
@@ -279,7 +279,7 @@ unsafe fn cb_get_config(
|
||||
.sql
|
||||
.get_config(context, as_str(key))
|
||||
.unwrap_or_else(|| to_string(def));
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_context_unref(context: &mut Context) {
|
||||
@@ -291,13 +291,16 @@ pub unsafe fn dc_context_unref(context: &mut Context) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_close(context: &Context) {
|
||||
info!(context, 0, "disconnecting INBOX-watch",);
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
info!(context, 0, "disconnecting sentbox-thread",);
|
||||
context
|
||||
.sentbox_thread
|
||||
.read()
|
||||
.unwrap()
|
||||
.imap
|
||||
.disconnect(context);
|
||||
info!(context, 0, "disconnecting mvbox-thread",);
|
||||
context
|
||||
.mvbox_thread
|
||||
.read()
|
||||
@@ -305,6 +308,7 @@ pub unsafe fn dc_close(context: &Context) {
|
||||
.imap
|
||||
.disconnect(context);
|
||||
|
||||
info!(context, 0, "disconnecting SMTP");
|
||||
context.smtp.clone().lock().unwrap().disconnect();
|
||||
|
||||
context.sql.close(context);
|
||||
@@ -511,7 +515,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
||||
fingerprint_str,
|
||||
);
|
||||
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
|
||||
|
||||
@@ -3,6 +3,8 @@ use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
const DC_ARRAY_MAGIC: uint32_t = 0x000a11aa;
|
||||
|
||||
/* * the structure behind dc_array_t */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
@@ -23,7 +25,7 @@ pub struct dc_array_t {
|
||||
* To free an array object, use dc_array_unref().
|
||||
*/
|
||||
pub unsafe fn dc_array_unref(mut array: *mut dc_array_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return;
|
||||
}
|
||||
if (*array).type_0 == 1i32 {
|
||||
@@ -35,7 +37,7 @@ pub unsafe fn dc_array_unref(mut array: *mut dc_array_t) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_free_ptr(array: *mut dc_array_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return;
|
||||
}
|
||||
let mut i: size_t = 0i32 as size_t;
|
||||
@@ -53,7 +55,7 @@ pub unsafe fn dc_array_free_ptr(array: *mut dc_array_t) {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_uint(mut array: *mut dc_array_t, item: uintptr_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return;
|
||||
}
|
||||
if (*array).count == (*array).allocated {
|
||||
@@ -78,21 +80,21 @@ pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_cnt(array: *const dc_array_t) -> size_t {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return 0i32 as size_t;
|
||||
}
|
||||
(*array).count
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_uint(array: *const dc_array_t, index: size_t) -> uintptr_t {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
|
||||
return 0i32 as uintptr_t;
|
||||
}
|
||||
*(*array).array.offset(index as isize)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
if (*array).type_0 == 1i32 {
|
||||
@@ -102,7 +104,7 @@ pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut libc::c_void {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || index >= (*array).count {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || index >= (*array).count {
|
||||
return 0 as *mut libc::c_void;
|
||||
}
|
||||
*(*array).array.offset(index as isize) as *mut libc::c_void
|
||||
@@ -110,7 +112,7 @@ pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut
|
||||
|
||||
pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -122,7 +124,7 @@ pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) ->
|
||||
|
||||
pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -134,7 +136,7 @@ pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) ->
|
||||
|
||||
pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -146,7 +148,7 @@ pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) ->
|
||||
|
||||
pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) -> i64 {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -158,7 +160,7 @@ pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) ->
|
||||
|
||||
pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -170,7 +172,7 @@ pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> u
|
||||
|
||||
pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -182,7 +184,7 @@ pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -
|
||||
|
||||
pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -194,7 +196,7 @@ pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> ui
|
||||
|
||||
pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *mut libc::c_char {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -216,7 +218,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
|
||||
*/
|
||||
pub unsafe fn dc_array_is_independent(array: *const dc_array_t, index: size_t) -> libc::c_int {
|
||||
if array.is_null()
|
||||
|| (*array).magic != 0xa11aai32 as libc::c_uint
|
||||
|| (*array).magic != DC_ARRAY_MAGIC
|
||||
|| index >= (*array).count
|
||||
|| (*array).type_0 != 1i32
|
||||
|| *(*array).array.offset(index as isize) == 0
|
||||
@@ -232,7 +234,7 @@ pub unsafe fn dc_array_search_id(
|
||||
needle: uint32_t,
|
||||
ret_index: *mut size_t,
|
||||
) -> bool {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return false;
|
||||
}
|
||||
let data: *mut uintptr_t = (*array).array;
|
||||
@@ -251,7 +253,7 @@ pub unsafe fn dc_array_search_id(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_raw(array: *const dc_array_t) -> *const uintptr_t {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return 0 as *const uintptr_t;
|
||||
}
|
||||
(*array).array
|
||||
@@ -266,7 +268,7 @@ pub unsafe fn dc_array_new_typed(type_0: libc::c_int, initsize: size_t) -> *mut
|
||||
array = calloc(1, ::std::mem::size_of::<dc_array_t>()) as *mut dc_array_t;
|
||||
assert!(!array.is_null());
|
||||
|
||||
(*array).magic = 0xa11aai32 as uint32_t;
|
||||
(*array).magic = DC_ARRAY_MAGIC;
|
||||
(*array).count = 0i32 as size_t;
|
||||
(*array).allocated = if initsize < 1 { 1 } else { initsize };
|
||||
(*array).type_0 = type_0;
|
||||
@@ -282,7 +284,7 @@ pub unsafe fn dc_array_new_typed(type_0: libc::c_int, initsize: size_t) -> *mut
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_empty(mut array: *mut dc_array_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return;
|
||||
}
|
||||
(*array).count = 0i32 as size_t;
|
||||
@@ -290,7 +292,7 @@ pub unsafe fn dc_array_empty(mut array: *mut dc_array_t) {
|
||||
|
||||
pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
|
||||
let mut ret: *mut dc_array_t;
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC {
|
||||
return 0 as *mut dc_array_t;
|
||||
}
|
||||
ret = dc_array_new((*array).allocated);
|
||||
@@ -306,7 +308,7 @@ pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_sort_ids(array: *mut dc_array_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || (*array).count <= 1 {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || (*array).count <= 1 {
|
||||
return;
|
||||
}
|
||||
qsort(
|
||||
@@ -330,7 +332,7 @@ unsafe extern "C" fn cmp_intptr_t(p1: *const libc::c_void, p2: *const libc::c_vo
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_sort_strings(array: *mut dc_array_t) {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || (*array).count <= 1 {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || (*array).count <= 1 {
|
||||
return;
|
||||
}
|
||||
qsort(
|
||||
@@ -355,7 +357,7 @@ pub unsafe fn dc_array_get_string(
|
||||
array: *const dc_array_t,
|
||||
sep: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
if array.is_null() || (*array).magic != 0xa11aai32 as libc::c_uint || sep.is_null() {
|
||||
if array.is_null() || (*array).magic != DC_ARRAY_MAGIC || sep.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
let cnt = (*array).count as usize;
|
||||
@@ -374,7 +376,7 @@ pub unsafe fn dc_array_get_string(
|
||||
}
|
||||
res
|
||||
});
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
/// return comma-separated value-string from integer array
|
||||
@@ -396,7 +398,7 @@ pub unsafe fn dc_arr_to_string(arr: *const uint32_t, cnt: libc::c_int) -> *mut l
|
||||
res
|
||||
},
|
||||
);
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -410,22 +412,17 @@ mod tests {
|
||||
let arr = dc_array_new(7 as size_t);
|
||||
assert_eq!(dc_array_get_cnt(arr), 0);
|
||||
|
||||
let mut i: libc::c_int = 0;
|
||||
while i < 1000 {
|
||||
for i in 0..1000 {
|
||||
dc_array_add_id(arr, (i + 2) as uint32_t);
|
||||
i += 1
|
||||
}
|
||||
|
||||
assert_eq!(dc_array_get_cnt(arr), 1000);
|
||||
|
||||
i = 0;
|
||||
|
||||
while i < 1000i32 {
|
||||
for i in 0..1000 {
|
||||
assert_eq!(
|
||||
dc_array_get_id(arr, i as size_t),
|
||||
(i + 1i32 * 2i32) as libc::c_uint
|
||||
);
|
||||
i += 1
|
||||
}
|
||||
|
||||
assert_eq!(dc_array_get_id(arr, -1i32 as size_t), 0);
|
||||
|
||||
319
src/dc_chat.rs
319
src/dc_chat.rs
@@ -130,20 +130,40 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
c.type_0 = row.get(1)?;
|
||||
c.name = {
|
||||
let raw: String = row.get(2)?;
|
||||
unsafe { strdup(to_cstring(raw).as_ptr()) }
|
||||
unsafe { to_cstring(raw) }
|
||||
};
|
||||
c.grpid = {
|
||||
let raw: String = row.get(3)?;
|
||||
unsafe { strdup(to_cstring(raw).as_ptr()) }
|
||||
unsafe { to_cstring(raw) }
|
||||
};
|
||||
|
||||
let packed: String = row.get(4)?;
|
||||
unsafe { dc_param_set_packed((*chat).param, to_cstring(&packed).as_ptr()) };
|
||||
unsafe {
|
||||
let p = to_cstring(&packed);
|
||||
dc_param_set_packed((*chat).param, p);
|
||||
free(p as *mut _);
|
||||
};
|
||||
c.archived = row.get(5)?;
|
||||
c.blocked = row.get(6)?;
|
||||
c.blocked = row.get::<_, Option<i32>>(6)?.unwrap_or_default();
|
||||
c.gossiped_timestamp = row.get(7)?;
|
||||
c.is_sending_locations = row.get(8)?;
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
||||
match res {
|
||||
Err(crate::error::Error::Sql(rusqlite::Error::QueryReturnedNoRows)) => false,
|
||||
Err(err) => match err {
|
||||
_ => {
|
||||
error!(
|
||||
context,
|
||||
0, "chat: failed to load from db {}: {:?}", chat_id, err
|
||||
);
|
||||
false
|
||||
}
|
||||
},
|
||||
Ok(_) => {
|
||||
let c = unsafe { &mut *chat };
|
||||
match c.id {
|
||||
1 => unsafe {
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
@@ -164,7 +184,7 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
(*chat).name = dc_stock_str((*chat).context, 41);
|
||||
},
|
||||
_ => {
|
||||
if 0 != unsafe { dc_param_exists((*chat).param, 'K' as i32) } {
|
||||
if 0 != unsafe { dc_param_exists((*chat).param, DC_PARAM_SELFTALK as i32) } {
|
||||
unsafe {
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
(*chat).name = dc_stock_str((*chat).context, 2);
|
||||
@@ -172,18 +192,7 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(_) => true,
|
||||
Err(err) => {
|
||||
error!(
|
||||
context,
|
||||
0, "chat: failed to load from db {}: {:?}", chat_id, err
|
||||
);
|
||||
false
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,7 +300,7 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
|
||||
&context.sql,
|
||||
format!("INSERT INTO chats_contacts (chat_id, contact_id) VALUES({}, {})", chat_id, contact_id),
|
||||
params![],
|
||||
);
|
||||
).ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +333,7 @@ pub fn dc_lookup_real_nchat_by_contact_id(
|
||||
if let Ok((id, blocked)) = context.sql.query_row(
|
||||
"SELECT c.id, c.blocked FROM chats c INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 AND c.id>9 AND j.contact_id=?;",
|
||||
params![contact_id as i32],
|
||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
|row| Ok((row.get(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default())),
|
||||
) {
|
||||
unsafe { *ret_chat_id = id };
|
||||
unsafe { *ret_chat_blocked = blocked };
|
||||
@@ -379,7 +388,7 @@ unsafe fn prepare_msg_common<'a>(
|
||||
|| (*msg).type_0 == 50i32
|
||||
|| (*msg).type_0 == 60i32
|
||||
{
|
||||
pathNfilename = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
pathNfilename = dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if pathNfilename.is_null() {
|
||||
error!(
|
||||
context,
|
||||
@@ -394,24 +403,24 @@ unsafe fn prepare_msg_common<'a>(
|
||||
} else if 0 == dc_make_rel_and_copy(context, &mut pathNfilename) {
|
||||
current_block = 2171833246886114521;
|
||||
} else {
|
||||
dc_param_set((*msg).param, 'f' as i32, pathNfilename);
|
||||
dc_param_set((*msg).param, DC_PARAM_FILE as i32, pathNfilename);
|
||||
if (*msg).type_0 == 60i32 || (*msg).type_0 == 20i32 {
|
||||
let mut better_type: libc::c_int = 0i32;
|
||||
let mut better_mime: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
dc_msg_guess_msgtype_from_suffix(pathNfilename, &mut better_type, &mut better_mime);
|
||||
if 0 != better_type {
|
||||
(*msg).type_0 = better_type;
|
||||
dc_param_set((*msg).param, 'm' as i32, better_mime);
|
||||
dc_param_set((*msg).param, DC_PARAM_MIMETYPE as i32, better_mime);
|
||||
}
|
||||
free(better_mime as *mut libc::c_void);
|
||||
} else if 0 == dc_param_exists((*msg).param, 'm' as i32) {
|
||||
} else if 0 == dc_param_exists((*msg).param, DC_PARAM_MIMETYPE as i32) {
|
||||
let mut better_mime_0: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
dc_msg_guess_msgtype_from_suffix(
|
||||
pathNfilename,
|
||||
0 as *mut libc::c_int,
|
||||
&mut better_mime_0,
|
||||
);
|
||||
dc_param_set((*msg).param, 'm' as i32, better_mime_0);
|
||||
dc_param_set((*msg).param, DC_PARAM_MIMETYPE as i32, better_mime_0);
|
||||
free(better_mime_0 as *mut libc::c_void);
|
||||
}
|
||||
info!(
|
||||
@@ -496,8 +505,9 @@ unsafe fn prepare_msg_raw(
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
},
|
||||
from_c.as_ptr(),
|
||||
from_c,
|
||||
);
|
||||
free(from_c as *mut _);
|
||||
|
||||
if (*chat).type_0 == 100 {
|
||||
if let Some(id) = context.sql.query_row_col(
|
||||
@@ -519,8 +529,12 @@ unsafe fn prepare_msg_raw(
|
||||
}
|
||||
} else {
|
||||
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
if dc_param_get_int((*chat).param, 'U' as i32, 0) == 1 {
|
||||
dc_param_set((*chat).param, 'U' as i32, 0 as *const libc::c_char);
|
||||
if dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0) == 1 {
|
||||
dc_param_set(
|
||||
(*chat).param,
|
||||
DC_PARAM_UNPROMOTED as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_chat_update_param(chat);
|
||||
}
|
||||
}
|
||||
@@ -538,7 +552,9 @@ unsafe fn prepare_msg_raw(
|
||||
.sql
|
||||
.get_config_int(context, "e2ee_enabled")
|
||||
.unwrap_or_else(|| 1);
|
||||
if 0 != e2ee_enabled && dc_param_get_int((*msg).param, 'u' as i32, 0) == 0 {
|
||||
if 0 != e2ee_enabled
|
||||
&& dc_param_get_int((*msg).param, DC_PARAM_FORCE_PLAINTEXT as i32, 0) == 0
|
||||
{
|
||||
let mut can_encrypt = 1;
|
||||
let mut all_mutual = 1;
|
||||
|
||||
@@ -593,9 +609,13 @@ unsafe fn prepare_msg_raw(
|
||||
}
|
||||
}
|
||||
if 0 != do_guarantee_e2ee {
|
||||
dc_param_set_int((*msg).param, 'c' as i32, 1);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 1);
|
||||
}
|
||||
dc_param_set((*msg).param, 'e' as i32, 0 as *const libc::c_char);
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
DC_PARAM_ERRONEOUS_E2EE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if 0 == dc_chat_is_self_talk(chat)
|
||||
&& 0 != get_parent_mime_headers(
|
||||
chat,
|
||||
@@ -761,9 +781,9 @@ unsafe fn get_parent_mime_headers(
|
||||
FROM msgs WHERE chat_id=? AND from_id!=?);",
|
||||
params![(*chat).id as i32, 1],
|
||||
|row| {
|
||||
*parent_rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
||||
*parent_in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
||||
*parent_references = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
||||
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
|
||||
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
|
||||
*parent_references = to_cstring(row.get::<_, String>(2)?);
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
@@ -779,12 +799,9 @@ unsafe fn get_parent_mime_headers(
|
||||
FROM msgs WHERE chat_id=? AND from_id==?);",
|
||||
params![(*chat).id as i32, 1],
|
||||
|row| {
|
||||
*parent_rfc724_mid =
|
||||
dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
||||
*parent_in_reply_to =
|
||||
dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
||||
*parent_references =
|
||||
dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
||||
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
|
||||
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
|
||||
*parent_references = to_cstring(row.get::<_, String>(2)?);
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
@@ -798,7 +815,7 @@ pub unsafe fn dc_chat_is_self_talk(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
dc_param_exists((*chat).param, 'K' as i32)
|
||||
dc_param_exists((*chat).param, DC_PARAM_SELFTALK as i32)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -823,9 +840,10 @@ unsafe fn last_msg_in_chat_encrypted(
|
||||
if let Some(packed) = packed {
|
||||
let msg_param = dc_param_new();
|
||||
let packed_c = to_cstring(packed);
|
||||
dc_param_set_packed(msg_param, packed_c.as_ptr());
|
||||
dc_param_set_packed(msg_param, packed_c);
|
||||
free(packed_c as *mut _);
|
||||
|
||||
if 0 != dc_param_exists(msg_param, 'c' as i32) {
|
||||
if 0 != dc_param_exists(msg_param, DC_PARAM_GUARANTEE_E2EE as i32) {
|
||||
last_is_encrypted = 1;
|
||||
}
|
||||
dc_param_unref(msg_param);
|
||||
@@ -862,13 +880,15 @@ pub unsafe fn dc_is_contact_in_chat(
|
||||
.unwrap_or_default() as libc::c_int
|
||||
}
|
||||
|
||||
// Should return Result
|
||||
pub fn dc_unarchive_chat(context: &Context, chat_id: u32) {
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"UPDATE chats SET archived=0 WHERE id=?",
|
||||
params![chat_id as i32],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub unsafe fn dc_send_msg<'a>(
|
||||
@@ -903,7 +923,11 @@ pub unsafe fn dc_send_msg<'a>(
|
||||
}
|
||||
|
||||
if 0 == chat_id {
|
||||
let forwards = dc_param_get((*msg).param, 'P' as i32, 0 as *const libc::c_char);
|
||||
let forwards = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_PREP_FORWARDS as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !forwards.is_null() {
|
||||
let mut p = forwards;
|
||||
while 0 != *p {
|
||||
@@ -919,7 +943,11 @@ pub unsafe fn dc_send_msg<'a>(
|
||||
dc_msg_unref(copy);
|
||||
}
|
||||
}
|
||||
dc_param_set((*msg).param, 'P' as i32, 0 as *const libc::c_char);
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
DC_PARAM_PREP_FORWARDS as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_msg_save_param_to_disk(msg);
|
||||
}
|
||||
free(forwards as *mut libc::c_void);
|
||||
@@ -979,7 +1007,8 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
|
||||
|| (*msg).type_0 == 50i32
|
||||
|| (*msg).type_0 == 60i32
|
||||
{
|
||||
pathNfilename = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
pathNfilename =
|
||||
dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if pathNfilename.is_null() {
|
||||
current_block = 14513523936503887211;
|
||||
} else if 0 != dc_msg_is_increation(msg)
|
||||
@@ -989,7 +1018,7 @@ unsafe fn set_draft_raw(context: &Context, chat_id: uint32_t, msg: *mut dc_msg_t
|
||||
} else if 0 == dc_make_rel_and_copy(context, &mut pathNfilename) {
|
||||
current_block = 14513523936503887211;
|
||||
} else {
|
||||
dc_param_set((*msg).param, 'f' as i32, pathNfilename);
|
||||
dc_param_set((*msg).param, DC_PARAM_FILE as i32, pathNfilename);
|
||||
current_block = 4495394744059808450;
|
||||
}
|
||||
} else {
|
||||
@@ -1550,9 +1579,15 @@ pub unsafe fn dc_add_contact_to_chat_ex(
|
||||
"Cannot add contact to group; self not in group.",
|
||||
);
|
||||
} else {
|
||||
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if 0 != flags & 0x1 && dc_param_get_int((*chat).param, 'U' as i32, 0) == 1 {
|
||||
dc_param_set((*chat).param, 'U' as i32, 0 as *const libc::c_char);
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if 0 != flags & 0x1
|
||||
&& dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0) == 1
|
||||
{
|
||||
dc_param_set(
|
||||
(*chat).param,
|
||||
DC_PARAM_UNPROMOTED as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_chat_update_param(chat);
|
||||
}
|
||||
let self_addr = context
|
||||
@@ -1600,7 +1635,7 @@ pub unsafe fn dc_add_contact_to_chat_ex(
|
||||
match current_block {
|
||||
12326129973959287090 => {}
|
||||
_ => {
|
||||
if dc_param_get_int((*chat).param, 'U' as i32, 0) == 0 {
|
||||
if dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0) == 0 {
|
||||
(*msg).type_0 = 10;
|
||||
(*msg).text = dc_stock_system_msg(
|
||||
context,
|
||||
@@ -1609,9 +1644,13 @@ pub unsafe fn dc_add_contact_to_chat_ex(
|
||||
0 as *const libc::c_char,
|
||||
1 as uint32_t,
|
||||
);
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 4);
|
||||
dc_param_set((*msg).param, 'E' as i32, (*contact).addr);
|
||||
dc_param_set_int((*msg).param, 'F' as i32, flags);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 4);
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
(*contact).addr,
|
||||
);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD_ARG2 as i32, flags);
|
||||
(*msg).id = dc_send_msg(context, chat_id, msg);
|
||||
context.call_cb(
|
||||
Event::MSGS_CHANGED,
|
||||
@@ -1658,6 +1697,7 @@ pub fn dc_reset_gossiped_timestamp(context: &Context, chat_id: u32) {
|
||||
dc_set_gossiped_timestamp(context, chat_id, 0);
|
||||
}
|
||||
|
||||
// Should return Result
|
||||
pub fn dc_set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
|
||||
if 0 != chat_id {
|
||||
info!(
|
||||
@@ -1670,7 +1710,8 @@ pub fn dc_set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64
|
||||
&context.sql,
|
||||
"UPDATE chats SET gossiped_timestamp=? WHERE id=?;",
|
||||
params![timestamp, chat_id as i32],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
@@ -1681,7 +1722,8 @@ pub fn dc_set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64
|
||||
&context.sql,
|
||||
"UPDATE chats SET gossiped_timestamp=?;",
|
||||
params![timestamp],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1710,9 +1752,9 @@ pub unsafe fn dc_remove_contact_from_chat(
|
||||
"Cannot remove contact from chat; self not in group.",
|
||||
);
|
||||
} else {
|
||||
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if !contact.is_null() {
|
||||
if dc_param_get_int((*chat).param, 'U' as i32, 0) == 0 {
|
||||
if dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0) == 0 {
|
||||
(*msg).type_0 = 10;
|
||||
if (*contact).id == 1 as libc::c_uint {
|
||||
dc_set_group_explicitly_left(context, (*chat).grpid);
|
||||
@@ -1732,8 +1774,8 @@ pub unsafe fn dc_remove_contact_from_chat(
|
||||
1 as uint32_t,
|
||||
)
|
||||
}
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 5);
|
||||
dc_param_set((*msg).param, 'E' as i32, (*contact).addr);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 5);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG as i32, (*contact).addr);
|
||||
(*msg).id = dc_send_msg(context, chat_id, msg);
|
||||
context.call_cb(
|
||||
Event::MSGS_CHANGED,
|
||||
@@ -1764,6 +1806,7 @@ pub unsafe fn dc_remove_contact_from_chat(
|
||||
success
|
||||
}
|
||||
|
||||
// Should return Result
|
||||
pub fn dc_set_group_explicitly_left(context: &Context, grpid: *const libc::c_char) {
|
||||
if 0 == dc_is_group_explicitly_left(context, grpid) {
|
||||
sql::execute(
|
||||
@@ -1771,7 +1814,8 @@ pub fn dc_set_group_explicitly_left(context: &Context, grpid: *const libc::c_cha
|
||||
&context.sql,
|
||||
"INSERT INTO leftgrps (grpid) VALUES(?);",
|
||||
params![as_str(grpid)],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1812,7 +1856,7 @@ pub unsafe fn dc_set_chat_name(
|
||||
"Cannot set chat name; self not in group",
|
||||
);
|
||||
} else {
|
||||
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
@@ -1825,7 +1869,7 @@ pub unsafe fn dc_set_chat_name(
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
if dc_param_get_int((*chat).param, 'U' as i32, 0i32) == 0i32 {
|
||||
if dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0i32) == 0i32 {
|
||||
(*msg).type_0 = 10i32;
|
||||
(*msg).text = dc_stock_system_msg(
|
||||
context,
|
||||
@@ -1834,8 +1878,8 @@ pub unsafe fn dc_set_chat_name(
|
||||
new_name,
|
||||
1i32 as uint32_t,
|
||||
);
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 2i32);
|
||||
dc_param_set((*msg).param, 'E' as i32, (*chat).name);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 2i32);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG as i32, (*chat).name);
|
||||
(*msg).id = dc_send_msg(context, chat_id, msg);
|
||||
context.call_cb(
|
||||
Event::MSGS_CHANGED,
|
||||
@@ -1881,7 +1925,7 @@ pub unsafe fn dc_set_chat_profile_image(
|
||||
"Cannot set chat profile image; self not in group.",
|
||||
);
|
||||
} else {
|
||||
/* we shoud respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if !new_image.is_null() {
|
||||
new_image_rel = dc_strdup(new_image);
|
||||
if 0 == dc_make_rel_and_copy(context, &mut new_image_rel) {
|
||||
@@ -1895,11 +1939,13 @@ pub unsafe fn dc_set_chat_profile_image(
|
||||
match current_block {
|
||||
14766584022300871387 => {}
|
||||
_ => {
|
||||
dc_param_set((*chat).param, 'i' as i32, new_image_rel);
|
||||
dc_param_set((*chat).param, DC_PARAM_PROFILE_IMAGE as i32, new_image_rel);
|
||||
if !(0 == dc_chat_update_param(chat)) {
|
||||
if dc_param_get_int((*chat).param, 'U' as i32, 0i32) == 0i32 {
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 3i32);
|
||||
dc_param_set((*msg).param, 'E' as i32, new_image_rel);
|
||||
if dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0i32)
|
||||
== 0i32
|
||||
{
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 3i32);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG as i32, new_image_rel);
|
||||
(*msg).type_0 = 10i32;
|
||||
(*msg).text = dc_stock_system_msg(
|
||||
context,
|
||||
@@ -1962,7 +2008,7 @@ pub unsafe fn dc_forward_msgs(
|
||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
|
||||
idsstr = dc_arr_to_string(msg_ids, msg_cnt);
|
||||
|
||||
context
|
||||
let ids = context
|
||||
.sql
|
||||
.query_map(
|
||||
format!(
|
||||
@@ -1971,64 +2017,71 @@ pub unsafe fn dc_forward_msgs(
|
||||
),
|
||||
params![],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
for id in ids {
|
||||
let src_msg_id = id?;
|
||||
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
|
||||
break;
|
||||
}
|
||||
dc_param_set_packed(original_param, (*(*msg).param).packed);
|
||||
if (*msg).from_id != 1i32 as libc::c_uint {
|
||||
dc_param_set_int((*msg).param, 'a' as i32, 1i32);
|
||||
}
|
||||
dc_param_set((*msg).param, 'c' as i32, 0 as *const libc::c_char);
|
||||
dc_param_set((*msg).param, 'u' as i32, 0 as *const libc::c_char);
|
||||
dc_param_set((*msg).param, 'S' as i32, 0 as *const libc::c_char);
|
||||
let new_msg_id: uint32_t;
|
||||
if (*msg).state == 18i32 {
|
||||
let fresh9 = curr_timestamp;
|
||||
curr_timestamp = curr_timestamp + 1;
|
||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
|
||||
let save_param: *mut dc_param_t = (*msg).param;
|
||||
(*msg).param = original_param;
|
||||
(*msg).id = src_msg_id as uint32_t;
|
||||
let old_fwd: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
'P' as i32,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let new_fwd: *mut libc::c_char = dc_mprintf(
|
||||
b"%s %d\x00" as *const u8 as *const libc::c_char,
|
||||
old_fwd,
|
||||
new_msg_id,
|
||||
);
|
||||
dc_param_set((*msg).param, 'P' as i32, new_fwd);
|
||||
dc_msg_save_param_to_disk(msg);
|
||||
free(new_fwd as *mut libc::c_void);
|
||||
free(old_fwd as *mut libc::c_void);
|
||||
(*msg).param = save_param
|
||||
} else {
|
||||
(*msg).state = 20i32;
|
||||
let fresh10 = curr_timestamp;
|
||||
curr_timestamp = curr_timestamp + 1;
|
||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
|
||||
dc_job_send_msg(context, new_msg_id);
|
||||
}
|
||||
carray_add(
|
||||
created_db_entries,
|
||||
chat_id as uintptr_t as *mut libc::c_void,
|
||||
0 as *mut libc::c_uint,
|
||||
);
|
||||
carray_add(
|
||||
created_db_entries,
|
||||
new_msg_id as uintptr_t as *mut libc::c_void,
|
||||
0 as *mut libc::c_uint,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)
|
||||
.unwrap(); // TODO: better error handling
|
||||
|
||||
for id in ids {
|
||||
let src_msg_id = id;
|
||||
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
|
||||
break;
|
||||
}
|
||||
dc_param_set_packed(original_param, (*(*msg).param).packed);
|
||||
if (*msg).from_id != 1i32 as libc::c_uint {
|
||||
dc_param_set_int((*msg).param, DC_PARAM_FORWARDED as i32, 1i32);
|
||||
}
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
DC_PARAM_GUARANTEE_E2EE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
DC_PARAM_FORCE_PLAINTEXT as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD as i32, 0 as *const libc::c_char);
|
||||
let new_msg_id: uint32_t;
|
||||
if (*msg).state == 18i32 {
|
||||
let fresh9 = curr_timestamp;
|
||||
curr_timestamp = curr_timestamp + 1;
|
||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
|
||||
let save_param: *mut dc_param_t = (*msg).param;
|
||||
(*msg).param = original_param;
|
||||
(*msg).id = src_msg_id as uint32_t;
|
||||
let old_fwd: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_PREP_FORWARDS as i32,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let new_fwd: *mut libc::c_char = dc_mprintf(
|
||||
b"%s %d\x00" as *const u8 as *const libc::c_char,
|
||||
old_fwd,
|
||||
new_msg_id,
|
||||
);
|
||||
dc_param_set((*msg).param, DC_PARAM_PREP_FORWARDS as i32, new_fwd);
|
||||
dc_msg_save_param_to_disk(msg);
|
||||
free(new_fwd as *mut libc::c_void);
|
||||
free(old_fwd as *mut libc::c_void);
|
||||
(*msg).param = save_param
|
||||
} else {
|
||||
(*msg).state = 20i32;
|
||||
let fresh10 = curr_timestamp;
|
||||
curr_timestamp = curr_timestamp + 1;
|
||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
|
||||
dc_job_send_msg(context, new_msg_id);
|
||||
}
|
||||
carray_add(
|
||||
created_db_entries,
|
||||
chat_id as uintptr_t as *mut libc::c_void,
|
||||
0 as *mut libc::c_uint,
|
||||
);
|
||||
carray_add(
|
||||
created_db_entries,
|
||||
new_msg_id as uintptr_t as *mut libc::c_void,
|
||||
0 as *mut libc::c_uint,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !created_db_entries.is_null() {
|
||||
@@ -2079,7 +2132,7 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
let mut ret: *mut libc::c_char = std::ptr::null_mut();
|
||||
if (*chat).type_0 == 100 && 0 != dc_param_exists((*chat).param, 'K' as i32) {
|
||||
if (*chat).type_0 == 100 && 0 != dc_param_exists((*chat).param, DC_PARAM_SELFTALK as i32) {
|
||||
ret = dc_stock_str((*chat).context, 50)
|
||||
} else if (*chat).type_0 == 100 {
|
||||
let ret_raw: String = (*chat)
|
||||
@@ -2094,7 +2147,7 @@ pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
|
||||
0,
|
||||
)
|
||||
.unwrap_or_else(|| "Err".into());
|
||||
ret = dc_strdup(to_cstring(ret_raw).as_ptr());
|
||||
ret = to_cstring(ret_raw);
|
||||
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
if (*chat).id == 1 {
|
||||
ret = dc_stock_str((*chat).context, 8)
|
||||
@@ -2128,7 +2181,11 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
|
||||
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
|
||||
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
|
||||
image_rel = dc_param_get((*chat).param, 'i' as i32, 0 as *const libc::c_char);
|
||||
image_rel = dc_param_get(
|
||||
(*chat).param,
|
||||
DC_PARAM_PROFILE_IMAGE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int {
|
||||
image_abs = dc_get_abs_path((*chat).context, image_rel)
|
||||
} else if (*chat).type_0 == 100i32 {
|
||||
@@ -2188,7 +2245,7 @@ pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
return 0i32;
|
||||
}
|
||||
dc_param_get_int((*chat).param, 'U' as i32, 0i32)
|
||||
dc_param_get_int((*chat).param, DC_PARAM_UNPROMOTED as i32, 0i32)
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
|
||||
@@ -102,14 +102,14 @@ pub fn dc_stop_ongoing_process(context: &Context) {
|
||||
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_job_t) {
|
||||
let flags: libc::c_int;
|
||||
let mut current_block: u64;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut imap_connected_here: libc::c_int = 0i32;
|
||||
let mut smtp_connected_here: libc::c_int = 0i32;
|
||||
let mut ongoing_allocated_here: libc::c_int = 0i32;
|
||||
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 = None;
|
||||
if !(0 == dc_alloc_ongoing(context)) {
|
||||
ongoing_allocated_here = 1i32;
|
||||
ongoing_allocated_here = true;
|
||||
if !context.sql.is_open() {
|
||||
error!(context, 0, "Cannot configure, database not opened.",);
|
||||
} else {
|
||||
@@ -174,7 +174,8 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
param.addr = oauth2_addr;
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "addr", Some(param.addr.as_str()));
|
||||
.set_config(context, "addr", Some(param.addr.as_str()))
|
||||
.ok();
|
||||
}
|
||||
if s.shall_stop_ongoing {
|
||||
current_block = 2927484062889439186;
|
||||
@@ -634,7 +635,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
let r_0 = dc_loginparam_get_readable(¶m);
|
||||
info!(context, 0, "Trying: {}", r_0,);
|
||||
|
||||
if 0 != context
|
||||
if context
|
||||
.inbox
|
||||
.read()
|
||||
.unwrap()
|
||||
@@ -671,7 +672,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
let r_1 = dc_loginparam_get_readable(¶m);
|
||||
info!(context, 0, "Trying: {}", r_1,);
|
||||
|
||||
if 0 != context
|
||||
if context
|
||||
.inbox
|
||||
.read()
|
||||
.unwrap()
|
||||
@@ -703,7 +704,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
let r_2 = dc_loginparam_get_readable(¶m);
|
||||
info!(context, 0, "Trying: {}", r_2,);
|
||||
|
||||
if 0 != context
|
||||
if context
|
||||
.inbox
|
||||
.read()
|
||||
.unwrap()
|
||||
@@ -759,7 +760,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
match current_block {
|
||||
2927484062889439186 => {}
|
||||
_ => {
|
||||
imap_connected_here = 1;
|
||||
imap_connected_here = true;
|
||||
if !s.shall_stop_ongoing {
|
||||
context.call_cb(
|
||||
Event::CONFIGURE_PROGRESS,
|
||||
@@ -774,7 +775,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
0 as uintptr_t,
|
||||
);
|
||||
/* 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 0 == context
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
@@ -814,7 +815,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
0, "Trying: {}", r_3,
|
||||
);
|
||||
|
||||
if 0 == context
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
@@ -860,7 +861,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
r_4
|
||||
);
|
||||
|
||||
if 0 == context
|
||||
if !context
|
||||
.smtp
|
||||
.clone()
|
||||
.lock()
|
||||
@@ -887,7 +888,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
match current_block {
|
||||
2927484062889439186 => {}
|
||||
_ => {
|
||||
smtp_connected_here = 1;
|
||||
smtp_connected_here = true;
|
||||
if !s.shall_stop_ongoing {
|
||||
context.call_cb(
|
||||
Event::CONFIGURE_PROGRESS,
|
||||
@@ -966,7 +967,8 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
context,
|
||||
"configured",
|
||||
1,
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
if !s.shall_stop_ongoing
|
||||
{
|
||||
context.call_cb(
|
||||
@@ -991,7 +993,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
uintptr_t
|
||||
);
|
||||
dc_ensure_secret_key_exists(context);
|
||||
success = 1;
|
||||
success = true;
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
@@ -1039,21 +1041,37 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 0 != imap_connected_here {
|
||||
if imap_connected_here {
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
}
|
||||
if 0 != smtp_connected_here {
|
||||
if smtp_connected_here {
|
||||
context.smtp.clone().lock().unwrap().disconnect();
|
||||
}
|
||||
|
||||
if 0 != ongoing_allocated_here {
|
||||
/*
|
||||
if !success {
|
||||
// disconnect if configure did not succeed
|
||||
if imap_connected_here {
|
||||
// context.inbox.read().unwrap().disconnect(context);
|
||||
}
|
||||
if smtp_connected_here {
|
||||
// context.smtp.clone().lock().unwrap().disconnect();
|
||||
}
|
||||
} else {
|
||||
assert!(imap_connected_here && smtp_connected_here);
|
||||
info!(
|
||||
context,
|
||||
0, "Keeping IMAP/SMTP connections open after successful configuration"
|
||||
);
|
||||
}
|
||||
*/
|
||||
if ongoing_allocated_here {
|
||||
dc_free_ongoing(context);
|
||||
}
|
||||
|
||||
context.call_cb(
|
||||
Event::CONFIGURE_PROGRESS,
|
||||
(if 0 != success { 1000 } else { 0 }) as uintptr_t,
|
||||
(if success { 1000 } else { 0 }) as uintptr_t,
|
||||
0 as uintptr_t,
|
||||
);
|
||||
}
|
||||
@@ -1082,12 +1100,14 @@ unsafe fn moz_autoconfigure(
|
||||
tag_config: 0,
|
||||
};
|
||||
|
||||
let xml_raw = read_autoconf_file(context, to_cstring(url).as_ptr());
|
||||
let url_c = to_cstring(url);
|
||||
let xml_raw = read_autoconf_file(context, url_c);
|
||||
free(url_c as *mut libc::c_void);
|
||||
if xml_raw.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
moz_ac.in_emaillocalpart = dc_strdup(to_cstring(¶m_in.addr).as_ptr());
|
||||
moz_ac.in_emaillocalpart = to_cstring(¶m_in.addr);
|
||||
let p = strchr(moz_ac.in_emaillocalpart, '@' as i32);
|
||||
|
||||
if p.is_null() {
|
||||
@@ -1144,11 +1164,13 @@ unsafe fn moz_autoconfigure_text_cb(
|
||||
let mut moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t;
|
||||
let mut val: *mut libc::c_char = dc_strdup(text);
|
||||
dc_trim(val);
|
||||
let addr = to_cstring(&(*moz_ac).in_0.addr);
|
||||
dc_str_replace(
|
||||
&mut val,
|
||||
b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char,
|
||||
to_cstring(&(*moz_ac).in_0.addr).as_ptr(),
|
||||
addr,
|
||||
);
|
||||
free(addr as *mut libc::c_void);
|
||||
dc_str_replace(
|
||||
&mut val,
|
||||
b"%EMAILLOCALPART%\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1282,7 +1304,7 @@ fn read_autoconf_file(context: &Context, url: *const libc::c_char) -> *mut libc:
|
||||
.send()
|
||||
.and_then(|mut res| res.text())
|
||||
{
|
||||
Ok(res) => unsafe { libc::strdup(to_cstring(res).as_ptr()) },
|
||||
Ok(res) => unsafe { to_cstring(res) },
|
||||
Err(_err) => {
|
||||
info!(context, 0, "Can\'t read file.",);
|
||||
|
||||
@@ -1298,7 +1320,7 @@ unsafe fn outlk_autodiscover(
|
||||
) -> Option<dc_loginparam_t> {
|
||||
let current_block: u64;
|
||||
let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut url = dc_strdup(to_cstring(url__).as_ptr());
|
||||
let mut url = to_cstring(url__);
|
||||
let mut outlk_ad = outlk_autodiscover_t {
|
||||
in_0: param_in,
|
||||
out: dc_loginparam_new(),
|
||||
@@ -1502,7 +1524,7 @@ pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_
|
||||
let param = dc_loginparam_read(context, &context.sql, "configured_");
|
||||
// the trailing underscore is correct
|
||||
|
||||
if 0 != imap.connect(context, ¶m) {
|
||||
if imap.connect(context, ¶m) {
|
||||
ret_connected = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ pub unsafe fn dc_contact_empty(mut contact: *mut dc_contact_t) {
|
||||
/* address is in our address book */
|
||||
/* set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */
|
||||
/* set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() ! */
|
||||
/* contact added mannually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names */
|
||||
/* contact added manually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names */
|
||||
/* contacts with at least this origin value are shown in the contact list */
|
||||
/* contacts with at least this origin value are verified and known not to be spam */
|
||||
/* contacts with at least this origin value start a new "normal" chat, defaults to off */
|
||||
@@ -277,15 +277,12 @@ pub unsafe fn dc_contact_load_from_db(
|
||||
if contact_id == 1 as libc::c_uint {
|
||||
(*contact).id = contact_id;
|
||||
(*contact).name = dc_stock_str((*contact).context, 2);
|
||||
(*contact).addr = dc_strdup(
|
||||
to_cstring(
|
||||
(*contact)
|
||||
.context
|
||||
.sql
|
||||
.get_config((*contact).context, "configured_addr")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
(*contact).addr = to_cstring(
|
||||
(*contact)
|
||||
.context
|
||||
.sql
|
||||
.get_config((*contact).context, "configured_addr")
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
@@ -294,11 +291,11 @@ pub unsafe fn dc_contact_load_from_db(
|
||||
params![contact_id as i32],
|
||||
|row| {
|
||||
(*contact).id = contact_id;
|
||||
(*contact).name = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
||||
(*contact).addr = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
||||
(*contact).name = to_cstring(row.get::<_, String>(0)?);
|
||||
(*contact).addr = to_cstring(row.get::<_, String>(1)?);
|
||||
(*contact).origin = row.get(2)?;
|
||||
(*contact).blocked = row.get(3)?;
|
||||
(*contact).authname = dc_strdup(to_cstring(row.get::<_, String>(4)?).as_ptr());
|
||||
(*contact).blocked = row.get::<_, Option<i32>>(3)?.unwrap_or_default();
|
||||
(*contact).authname = to_cstring(row.get::<_, String>(4)?);
|
||||
Ok(())
|
||||
}
|
||||
).is_ok()
|
||||
@@ -421,7 +418,8 @@ pub fn dc_add_or_lookup_contact(
|
||||
},
|
||||
row_id
|
||||
],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
|
||||
if update_name {
|
||||
sql::execute(
|
||||
@@ -429,7 +427,7 @@ pub fn dc_add_or_lookup_contact(
|
||||
&context.sql,
|
||||
"UPDATE chats SET name=? WHERE type=? AND id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?);",
|
||||
params![to_string(name), 100, row_id]
|
||||
);
|
||||
).ok();
|
||||
}
|
||||
unsafe { *sth_modified = 1 };
|
||||
}
|
||||
@@ -735,7 +733,7 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
free(fingerprint_other_verified as *mut libc::c_void);
|
||||
free(fingerprint_other_unverified as *mut libc::c_void);
|
||||
|
||||
strdup(to_cstring(ret).as_ptr())
|
||||
to_cstring(ret)
|
||||
}
|
||||
|
||||
unsafe fn cat_fingerprint(
|
||||
@@ -905,7 +903,7 @@ pub fn dc_contact_get_profile_image(contact: *const dc_contact_t) -> *mut libc::
|
||||
if unsafe { (*contact).id } == 1 {
|
||||
let context = unsafe { (*contact) }.context;
|
||||
if let Some(avatar) = context.get_config(config::Config::Selfavatar) {
|
||||
image_abs = unsafe { dc_strdup(to_cstring(avatar).as_ptr()) };
|
||||
image_abs = unsafe { to_cstring(avatar) };
|
||||
}
|
||||
}
|
||||
// TODO: else get image_abs from contact param
|
||||
|
||||
@@ -53,7 +53,7 @@ pub unsafe fn dc_dehtml(buf_terminated: *mut libc::c_char) -> *mut libc::c_char
|
||||
dc_saxparser_parse(&mut saxparser, buf_terminated);
|
||||
free(dehtml.last_href as *mut libc::c_void);
|
||||
|
||||
strdup(to_cstring(dehtml.strbuilder).as_ptr())
|
||||
to_cstring(dehtml.strbuilder)
|
||||
}
|
||||
|
||||
unsafe fn dehtml_text_cb(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use mmime::clist::*;
|
||||
@@ -31,7 +31,7 @@ use crate::x::*;
|
||||
// attachments of 25 mb brutto should work on the majority of providers
|
||||
// (brutto examples: web.de=50, 1&1=40, t-online.de=32, gmail=25, posteo=50, yahoo=25, all-inkl=100).
|
||||
// as an upper limit, we double the size; the core won't send messages larger than this
|
||||
// to get the netto sizes, we substract 1 mb header-overhead and the base64-overhead.
|
||||
// to get the netto sizes, we subtract 1 mb header-overhead and the base64-overhead.
|
||||
// some defaults
|
||||
#[derive(Clone)]
|
||||
pub struct dc_e2ee_helper_t {
|
||||
@@ -184,7 +184,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
b"Autocrypt-Gossip\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
),
|
||||
strdup(header.as_ptr()),
|
||||
header,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -294,10 +294,8 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
sign_key.as_ref(),
|
||||
) {
|
||||
let ctext_bytes = ctext_v.len();
|
||||
let ctext_c = CString::new(ctext_v).unwrap();
|
||||
let ctext = strdup(ctext_c.as_ptr());
|
||||
|
||||
(*helper).cdata_to_free = ctext as *mut libc::c_void;
|
||||
let ctext = to_cstring(ctext_v);
|
||||
(*helper).cdata_to_free = ctext as *mut _;
|
||||
|
||||
/* create MIME-structure that will contain the encrypted text */
|
||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||
@@ -354,13 +352,13 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
14181132614457621749 => {}
|
||||
_ => {
|
||||
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
|
||||
let rendered = CString::new(aheader.to_string()).unwrap();
|
||||
let rendered = to_cstring(aheader.to_string());
|
||||
|
||||
mailimf_fields_add(
|
||||
imffields_unprotected,
|
||||
mailimf_field_new_custom(
|
||||
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
|
||||
strdup(rendered.as_ptr()),
|
||||
rendered,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -935,13 +933,12 @@ unsafe fn decrypt_part(
|
||||
add_signatures,
|
||||
) {
|
||||
let plain_bytes = plain.len();
|
||||
let plain_c = CString::new(plain).unwrap();
|
||||
let plain_buf = strdup(plain_c.as_ptr());
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
|
||||
let mut index: size_t = 0i32 as size_t;
|
||||
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
||||
if mailmime_parse(
|
||||
plain_buf as *const libc::c_char,
|
||||
plain_buf as *const _,
|
||||
plain_bytes,
|
||||
&mut index,
|
||||
&mut decrypted_mime,
|
||||
@@ -1010,7 +1007,7 @@ unsafe fn has_decrypted_pgp_armor(
|
||||
* that we could use the normal Autocrypt processing.
|
||||
*
|
||||
* @private
|
||||
* @param mime The mime struture to check
|
||||
* @param mime The mime structure to check
|
||||
* @return 1=multipart/report found in MIME, 0=no multipart/report found
|
||||
*/
|
||||
// TODO should return bool /rtn
|
||||
|
||||
181
src/dc_imex.rs
181
src/dc_imex.rs
@@ -34,9 +34,9 @@ pub unsafe fn dc_imex(
|
||||
param2: *const libc::c_char,
|
||||
) {
|
||||
let param: *mut dc_param_t = dc_param_new();
|
||||
dc_param_set_int(param, 'S' as i32, what);
|
||||
dc_param_set(param, 'E' as i32, param1);
|
||||
dc_param_set(param, 'F' as i32, param2);
|
||||
dc_param_set_int(param, DC_PARAM_CMD as i32, what);
|
||||
dc_param_set(param, DC_PARAM_CMD_ARG as i32, param1);
|
||||
dc_param_set(param, DC_PARAM_CMD_ARG2 as i32, param2);
|
||||
dc_job_kill_action(context, 910i32);
|
||||
dc_job_add(context, 910i32, 0i32, (*param).packed, 0i32);
|
||||
dc_param_unref(param);
|
||||
@@ -143,15 +143,15 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
if !(chat_id == 0i32 as libc::c_uint) {
|
||||
msg = dc_msg_new_untyped(context);
|
||||
(*msg).type_0 = 60i32;
|
||||
dc_param_set((*msg).param, 'f' as i32, setup_file_name);
|
||||
dc_param_set((*msg).param, DC_PARAM_FILE as i32, setup_file_name);
|
||||
dc_param_set(
|
||||
(*msg).param,
|
||||
'm' as i32,
|
||||
DC_PARAM_MIMETYPE as i32,
|
||||
b"application/autocrypt-setup\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 6i32);
|
||||
dc_param_set_int((*msg).param, 'u' as i32, 2i32);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 6);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_FORCE_PLAINTEXT as i32, 2);
|
||||
if !context
|
||||
.running_state
|
||||
.clone()
|
||||
@@ -309,7 +309,7 @@ pub unsafe fn dc_create_setup_code(_context: &Context) -> *mut libc::c_char {
|
||||
);
|
||||
}
|
||||
|
||||
strdup(to_cstring(ret).as_ptr())
|
||||
to_cstring(ret)
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
@@ -539,7 +539,7 @@ pub unsafe fn dc_normalize_setup_code(
|
||||
p1 = p1.offset(1);
|
||||
}
|
||||
|
||||
strdup(to_cstring(out).as_ptr())
|
||||
to_cstring(out)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) {
|
||||
@@ -551,9 +551,17 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
let mut param2: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(0 == dc_alloc_ongoing(context)) {
|
||||
ongoing_allocated_here = 1i32;
|
||||
what = dc_param_get_int((*job).param, 'S' as i32, 0i32);
|
||||
param1 = dc_param_get((*job).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
param2 = dc_param_get((*job).param, 'F' as i32, 0 as *const libc::c_char);
|
||||
what = dc_param_get_int((*job).param, DC_PARAM_CMD as i32, 0);
|
||||
param1 = dc_param_get(
|
||||
(*job).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
param2 = dc_param_get(
|
||||
(*job).param,
|
||||
DC_PARAM_CMD_ARG2 as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if param1.is_null() {
|
||||
error!(context, 0, "No Import/export dir/file given.",);
|
||||
} else {
|
||||
@@ -806,77 +814,75 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
|
||||
);
|
||||
|
||||
context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
|
||||
params![],
|
||||
|row| {
|
||||
let name: String = row.get(0)?;
|
||||
let blob: Vec<u8> = row.get(1)?;
|
||||
let res = context.sql.query_map(
|
||||
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
|
||||
params![],
|
||||
|row| {
|
||||
let name: String = row.get(0)?;
|
||||
let blob: Vec<u8> = row.get(1)?;
|
||||
|
||||
Ok((name, blob))
|
||||
},
|
||||
|files| {
|
||||
let mut loop_success = true;
|
||||
let mut processed_files_cnt = 0;
|
||||
Ok((name, blob))
|
||||
},
|
||||
|files| {
|
||||
let mut loop_success = true;
|
||||
let mut processed_files_cnt = 0;
|
||||
|
||||
for file in files {
|
||||
if file.is_err() {
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
let (file_name, file_blob) = file.unwrap();
|
||||
for file in files {
|
||||
let (file_name, file_blob) = file?;
|
||||
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
processed_files_cnt += 1;
|
||||
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
|
||||
if permille < 10 {
|
||||
permille = 10
|
||||
}
|
||||
if permille > 990 {
|
||||
permille = 990
|
||||
}
|
||||
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
|
||||
if file_blob.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
|
||||
if dc_write_file_safe(context, &pathNfilename, &file_blob) {
|
||||
continue;
|
||||
}
|
||||
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Storage full? Cannot write file {} with {} bytes.",
|
||||
&pathNfilename,
|
||||
file_blob.len(),
|
||||
);
|
||||
// otherwise the user may believe the stuff is imported correctly, but there are files missing ...
|
||||
if context
|
||||
.running_state
|
||||
.clone()
|
||||
.read()
|
||||
.unwrap()
|
||||
.shall_stop_ongoing
|
||||
{
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if !loop_success {
|
||||
return Err(format_err!("fail").into());
|
||||
processed_files_cnt += 1;
|
||||
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
|
||||
if permille < 10 {
|
||||
permille = 10
|
||||
}
|
||||
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
|
||||
sql::try_execute(context, &context.sql, "VACUUM;");
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.is_ok() as libc::c_int
|
||||
if permille > 990 {
|
||||
permille = 990
|
||||
}
|
||||
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
|
||||
if file_blob.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pathNfilename = format!("{}/{}", as_str(context.get_blobdir()), file_name);
|
||||
if dc_write_file_safe(context, &pathNfilename, &file_blob) {
|
||||
continue;
|
||||
}
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Storage full? Cannot write file {} with {} bytes.",
|
||||
&pathNfilename,
|
||||
file_blob.len(),
|
||||
);
|
||||
// otherwise the user may believe the stuff is imported correctly, but there are files missing ...
|
||||
loop_success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if !loop_success {
|
||||
return Err(format_err!("fail").into());
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
||||
res.and_then(|_| {
|
||||
// only delete backup_blobs if all files were successfully extracted
|
||||
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
|
||||
sql::try_execute(context, &context.sql, "VACUUM;").ok();
|
||||
Ok(())
|
||||
})
|
||||
.is_ok() as libc::c_int
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -897,7 +903,8 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
.format("delta-chat-%Y-%m-%d.bak")
|
||||
.to_string();
|
||||
let buffer = to_cstring(res);
|
||||
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer.as_ptr());
|
||||
let dest_pathNfilename = dc_get_fine_pathNfilename(context, dir, buffer);
|
||||
free(buffer as *mut _);
|
||||
if dest_pathNfilename.is_null() {
|
||||
error!(context, 0, "Cannot get backup file name.",);
|
||||
|
||||
@@ -906,7 +913,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
|
||||
sql::housekeeping(context);
|
||||
|
||||
sql::try_execute(context, &context.sql, "VACUUM;");
|
||||
sql::try_execute(context, &context.sql, "VACUUM;").ok();
|
||||
context.sql.close(context);
|
||||
let mut closed = true;
|
||||
info!(
|
||||
@@ -973,7 +980,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
|
||||
sql.prepare(
|
||||
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|
||||
move |mut stmt| {
|
||||
move |mut stmt, _| {
|
||||
let mut processed_files_cnt = 0;
|
||||
for entry in dir_handle {
|
||||
if entry.is_err() {
|
||||
@@ -1096,6 +1103,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
let mut imported_cnt: libc::c_int = 0;
|
||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut path_plus_name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut name_c: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut set_default: libc::c_int;
|
||||
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf_bytes: size_t = 0 as size_t;
|
||||
@@ -1123,8 +1131,9 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
let entry = entry.unwrap();
|
||||
free(suffix as *mut libc::c_void);
|
||||
let name_f = entry.file_name();
|
||||
let name_c = to_cstring(name_f.to_string_lossy());
|
||||
suffix = dc_get_filesuffix_lc(name_c.as_ptr());
|
||||
free(name_c as *mut libc::c_void);
|
||||
name_c = to_cstring(name_f.to_string_lossy());
|
||||
suffix = dc_get_filesuffix_lc(name_c);
|
||||
if suffix.is_null()
|
||||
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
|
||||
{
|
||||
@@ -1134,7 +1143,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
path_plus_name = dc_mprintf(
|
||||
b"%s/%s\x00" as *const u8 as *const libc::c_char,
|
||||
dir_name,
|
||||
name_c.as_ptr(),
|
||||
name_c,
|
||||
);
|
||||
info!(context, 0, "Checking: {}", as_str(path_plus_name));
|
||||
free(buf as *mut libc::c_void);
|
||||
@@ -1172,12 +1181,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
}
|
||||
}
|
||||
set_default = 1;
|
||||
if !strstr(
|
||||
name_c.as_ptr(),
|
||||
b"legacy\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
if !strstr(name_c, b"legacy\x00" as *const u8 as *const libc::c_char).is_null() {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
@@ -1202,6 +1206,7 @@ unsafe fn import_self_keys(context: &Context, dir_name: *const libc::c_char) ->
|
||||
}
|
||||
}
|
||||
|
||||
free(name_c as *mut libc::c_void);
|
||||
free(suffix as *mut libc::c_void);
|
||||
free(path_plus_name as *mut libc::c_void);
|
||||
free(buf as *mut libc::c_void);
|
||||
|
||||
133
src/dc_job.rs
133
src/dc_job.rs
@@ -48,14 +48,14 @@ pub struct dc_job_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_perform_imap_jobs(context: &Context) {
|
||||
info!(context, 0, "INBOX-jobs started...",);
|
||||
info!(context, 0, "dc_perform_imap_jobs starting.",);
|
||||
|
||||
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
|
||||
*context.probe_imap_network.write().unwrap() = 0;
|
||||
*context.perform_inbox_jobs_needed.write().unwrap() = 0;
|
||||
|
||||
dc_job_perform(context, 100, probe_imap_network);
|
||||
info!(context, 0, "INBOX-jobs ended.",);
|
||||
info!(context, 0, "dc_perform_imap_jobs ended.",);
|
||||
}
|
||||
|
||||
unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network: libc::c_int) {
|
||||
@@ -80,36 +80,42 @@ unsafe fn dc_job_perform(context: &Context, thread: libc::c_int, probe_network:
|
||||
params_probe
|
||||
};
|
||||
|
||||
let jobs: Vec<dc_job_t> = context
|
||||
.sql
|
||||
.query_map(
|
||||
query,
|
||||
params,
|
||||
|row| {
|
||||
let job = dc_job_t {
|
||||
job_id: row.get(0)?,
|
||||
action: row.get(1)?,
|
||||
foreign_id: row.get(2)?,
|
||||
desired_timestamp: row.get(5)?,
|
||||
added_timestamp: row.get(4)?,
|
||||
tries: row.get(6)?,
|
||||
param: dc_param_new(),
|
||||
try_again: 0,
|
||||
pending_error: 0 as *mut libc::c_char,
|
||||
};
|
||||
let jobs: Result<Vec<dc_job_t>, _> = context.sql.query_map(
|
||||
query,
|
||||
params,
|
||||
|row| {
|
||||
let job = dc_job_t {
|
||||
job_id: row.get(0)?,
|
||||
action: row.get(1)?,
|
||||
foreign_id: row.get(2)?,
|
||||
desired_timestamp: row.get(5)?,
|
||||
added_timestamp: row.get(4)?,
|
||||
tries: row.get(6)?,
|
||||
param: dc_param_new(),
|
||||
try_again: 0,
|
||||
pending_error: 0 as *mut libc::c_char,
|
||||
};
|
||||
|
||||
let packed: String = row.get(3)?;
|
||||
dc_param_set_packed(job.param, to_cstring(packed).as_ptr());
|
||||
Ok(job)
|
||||
},
|
||||
|jobs| {
|
||||
jobs.collect::<Result<Vec<dc_job_t>, _>>()
|
||||
.map_err(Into::into)
|
||||
},
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
for mut job in jobs {
|
||||
let packed: String = row.get(3)?;
|
||||
let packed_c = to_cstring(packed);
|
||||
dc_param_set_packed(job.param, packed_c);
|
||||
free(packed_c as *mut _);
|
||||
Ok(job)
|
||||
},
|
||||
|jobs| {
|
||||
let res = jobs
|
||||
.collect::<Result<Vec<dc_job_t>, _>>()
|
||||
.map_err(Into::into);
|
||||
res
|
||||
},
|
||||
);
|
||||
match jobs {
|
||||
Ok(ref _res) => {}
|
||||
Err(ref err) => {
|
||||
info!(context, 0, "query failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
for mut job in jobs.unwrap_or_default() {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
@@ -285,7 +291,7 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
|
||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
||||
|
||||
if 0 == connected {
|
||||
if !connected {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 14216916617354591294;
|
||||
} else {
|
||||
@@ -296,11 +302,15 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
}
|
||||
match current_block {
|
||||
13109137661213826276 => {
|
||||
filename = dc_param_get(job.param, 'f' as i32, 0 as *const libc::c_char);
|
||||
filename = dc_param_get(job.param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if filename.is_null() {
|
||||
warn!(context, 0, "Missing file name for job {}", job.job_id,);
|
||||
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
|
||||
recipients = dc_param_get(job.param, 'R' as i32, 0 as *const libc::c_char);
|
||||
recipients = dc_param_get(
|
||||
job.param,
|
||||
DC_PARAM_RECIPIENTS as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if recipients.is_null() {
|
||||
warn!(context, 0, "Missing recipients for job {}", job.job_id,);
|
||||
} else {
|
||||
@@ -493,8 +503,12 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let current_block: u64;
|
||||
let folder: *mut libc::c_char = dc_param_get(job.param, 'Z' as i32, 0 as *const libc::c_char);
|
||||
let uid: uint32_t = dc_param_get_int(job.param, 'z' as i32, 0i32) as uint32_t;
|
||||
let folder: *mut libc::c_char = dc_param_get(
|
||||
job.param,
|
||||
DC_PARAM_SERVER_FOLDER as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let uid: uint32_t = dc_param_get_int(job.param, DC_PARAM_SERVER_UID as i32, 0) as uint32_t;
|
||||
let mut dest_uid: uint32_t = 0i32 as uint32_t;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
@@ -515,7 +529,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
if inbox.set_seen(context, folder, uid) as libc::c_uint == 0i32 as libc::c_uint {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
if 0 != dc_param_get_int(job.param, 'M' as i32, 0i32) {
|
||||
if 0 != dc_param_get_int(job.param, DC_PARAM_ALSO_MOVE as i32, 0i32) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
@@ -568,8 +582,12 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != dc_param_get_int((*msg).param, 'r' as i32, 0i32)
|
||||
&& 0 != context
|
||||
if 0 != dc_param_get_int(
|
||||
(*msg).param,
|
||||
DC_PARAM_WANTS_MDN as i32,
|
||||
0i32,
|
||||
) && 0
|
||||
!= context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
@@ -622,7 +640,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != dc_param_get_int((*msg).param, 'r' as i32, 0i32)
|
||||
if 0 != dc_param_get_int((*msg).param, DC_PARAM_WANTS_MDN as i32, 0)
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
@@ -760,8 +778,8 @@ unsafe fn dc_add_smtp_job(
|
||||
(*mimefactory).recipients_addr,
|
||||
b"\x1e\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_param_set(param, 'f' as i32, pathNfilename);
|
||||
dc_param_set(param, 'R' as i32, recipients);
|
||||
dc_param_set(param, DC_PARAM_FILE as i32, pathNfilename);
|
||||
dc_param_set(param, DC_PARAM_RECIPIENTS as i32, recipients);
|
||||
dc_job_add(
|
||||
context,
|
||||
action,
|
||||
@@ -814,7 +832,7 @@ pub unsafe fn dc_job_add(
|
||||
},
|
||||
(timestamp + delay_seconds as i64)
|
||||
]
|
||||
);
|
||||
).ok();
|
||||
|
||||
if thread == 100 {
|
||||
dc_interrupt_imap_idle(context);
|
||||
@@ -1161,19 +1179,19 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
|
||||
{
|
||||
let pathNfilename = dc_param_get(
|
||||
(*mimefactory.msg).param,
|
||||
'f' as i32,
|
||||
DC_PARAM_FILE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !pathNfilename.is_null() {
|
||||
if ((*mimefactory.msg).type_0 == 20i32 || (*mimefactory.msg).type_0 == 21i32)
|
||||
&& 0 == dc_param_exists((*mimefactory.msg).param, 'w' as i32)
|
||||
&& 0 == dc_param_exists((*mimefactory.msg).param, DC_PARAM_WIDTH as i32)
|
||||
{
|
||||
let mut buf: *mut libc::c_uchar = 0 as *mut libc::c_uchar;
|
||||
let mut buf_bytes: size_t = 0;
|
||||
let mut w: uint32_t = 0;
|
||||
let mut h: uint32_t = 0;
|
||||
dc_param_set_int((*mimefactory.msg).param, 'w' as i32, 0i32);
|
||||
dc_param_set_int((*mimefactory.msg).param, 'h' as i32, 0i32);
|
||||
dc_param_set_int((*mimefactory.msg).param, DC_PARAM_WIDTH as i32, 0);
|
||||
dc_param_set_int((*mimefactory.msg).param, DC_PARAM_HEIGHT as i32, 0);
|
||||
if 0 != dc_read_file(
|
||||
context,
|
||||
pathNfilename,
|
||||
@@ -1186,8 +1204,16 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
|
||||
&mut w,
|
||||
&mut h,
|
||||
) {
|
||||
dc_param_set_int((*mimefactory.msg).param, 'w' as i32, w as int32_t);
|
||||
dc_param_set_int((*mimefactory.msg).param, 'h' as i32, h as int32_t);
|
||||
dc_param_set_int(
|
||||
(*mimefactory.msg).param,
|
||||
DC_PARAM_WIDTH as i32,
|
||||
w as int32_t,
|
||||
);
|
||||
dc_param_set_int(
|
||||
(*mimefactory.msg).param,
|
||||
DC_PARAM_HEIGHT as i32,
|
||||
h as int32_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
free(buf as *mut libc::c_void);
|
||||
@@ -1199,7 +1225,7 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
|
||||
/* create message */
|
||||
if 0 == dc_mimefactory_render(&mut mimefactory) {
|
||||
dc_set_msg_failed(context, msg_id, mimefactory.error);
|
||||
} else if 0 != dc_param_get_int((*mimefactory.msg).param, 'c' as i32, 0)
|
||||
} else if 0 != dc_param_get_int((*mimefactory.msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0)
|
||||
&& 0 == mimefactory.out_encrypted
|
||||
{
|
||||
warn!(
|
||||
@@ -1207,7 +1233,7 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
|
||||
0,
|
||||
"e2e encryption unavailable {} - {}",
|
||||
msg_id,
|
||||
dc_param_get_int((*mimefactory.msg).param, 'c' as i32, 0),
|
||||
dc_param_get_int((*mimefactory.msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0),
|
||||
);
|
||||
dc_set_msg_failed(
|
||||
context,
|
||||
@@ -1245,9 +1271,10 @@ pub unsafe fn dc_job_send_msg(context: &Context, msg_id: uint32_t) -> libc::c_in
|
||||
}
|
||||
}
|
||||
if 0 != mimefactory.out_encrypted
|
||||
&& dc_param_get_int((*mimefactory.msg).param, 'c' as i32, 0i32) == 0i32
|
||||
&& dc_param_get_int((*mimefactory.msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0)
|
||||
== 0
|
||||
{
|
||||
dc_param_set_int((*mimefactory.msg).param, 'c' as i32, 1i32);
|
||||
dc_param_set_int((*mimefactory.msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 1);
|
||||
dc_msg_save_param_to_disk(mimefactory.msg);
|
||||
}
|
||||
dc_add_to_keyhistory(
|
||||
|
||||
@@ -76,7 +76,7 @@ pub unsafe fn dc_send_locations_to_chat(
|
||||
0 as *const libc::c_char,
|
||||
0,
|
||||
);
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 8i32);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 8);
|
||||
dc_send_msg(context, chat_id, msg);
|
||||
} else if 0 == seconds && is_sending_locations_before {
|
||||
stock_str = dc_stock_system_msg(
|
||||
@@ -215,8 +215,10 @@ pub fn dc_get_locations(
|
||||
if 0 != (*loc).msg_id {
|
||||
let txt: String = row.get(9)?;
|
||||
let txt_c = to_cstring(txt);
|
||||
if 0 != is_marker(txt_c.as_ptr()) {
|
||||
(*loc).marker = strdup(txt_c.as_ptr());
|
||||
if 0 != is_marker(txt_c) {
|
||||
(*loc).marker = txt_c;
|
||||
} else {
|
||||
free(txt_c as *mut _);
|
||||
}
|
||||
}
|
||||
Ok(loc)
|
||||
@@ -330,9 +332,9 @@ pub fn dc_get_location_kml(
|
||||
}
|
||||
|
||||
if 0 != success {
|
||||
unsafe { strdup(to_cstring(ret).as_ptr()) }
|
||||
unsafe { to_cstring(ret) }
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +346,7 @@ unsafe fn get_kml_timestamp(utc: i64) -> *mut libc::c_char {
|
||||
let res = chrono::NaiveDateTime::from_timestamp(utc, 0)
|
||||
.format("%Y-%m-%dT%H:%M:%SZ")
|
||||
.to_string();
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_message_kml(
|
||||
@@ -661,7 +663,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
|
||||
AND timestamp>? \
|
||||
AND independent=0 \
|
||||
ORDER BY timestamp;",
|
||||
|mut stmt_locations| {
|
||||
|mut stmt_locations, _| {
|
||||
for (chat_id, locations_send_begin, locations_last_sent) in
|
||||
rows.filter_map(|r| match r {
|
||||
Ok(Some(v)) => Some(v),
|
||||
@@ -688,7 +690,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
|
||||
// and dc_set_location() is typically called periodically, this is ok)
|
||||
let mut msg = dc_msg_new(context, 10);
|
||||
(*msg).hidden = 1;
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 9);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 9);
|
||||
dc_send_msg(context, chat_id as u32, msg);
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
|
||||
@@ -91,34 +91,39 @@ pub fn dc_loginparam_write(
|
||||
let prefix = prefix.as_ref();
|
||||
|
||||
let key = format!("{}addr", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.addr));
|
||||
sql.set_config(context, key, Some(&loginparam.addr)).ok();
|
||||
|
||||
let key = format!("{}mail_server", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.mail_server));
|
||||
sql.set_config(context, key, Some(&loginparam.mail_server))
|
||||
.ok();
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
sql.set_config_int(context, key, loginparam.mail_port);
|
||||
sql.set_config_int(context, key, loginparam.mail_port).ok();
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.mail_user));
|
||||
sql.set_config(context, key, Some(&loginparam.mail_user))
|
||||
.ok();
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.mail_pw));
|
||||
sql.set_config(context, key, Some(&loginparam.mail_pw)).ok();
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.send_server));
|
||||
sql.set_config(context, key, Some(&loginparam.send_server))
|
||||
.ok();
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
sql.set_config_int(context, key, loginparam.send_port);
|
||||
sql.set_config_int(context, key, loginparam.send_port).ok();
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.send_user));
|
||||
sql.set_config(context, key, Some(&loginparam.send_user))
|
||||
.ok();
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
sql.set_config(context, key, Some(&loginparam.send_pw));
|
||||
sql.set_config(context, key, Some(&loginparam.send_pw)).ok();
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
sql.set_config_int(context, key, loginparam.server_flags);
|
||||
sql.set_config_int(context, key, loginparam.server_flags)
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn unset_empty(s: &String) -> Cow<String> {
|
||||
|
||||
@@ -8,7 +8,7 @@ use mmime::mailmime_write_mem::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
use crate::constants::DC_VERSION_STR;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_contact::*;
|
||||
@@ -161,24 +161,20 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
for row in rows {
|
||||
let (authname, addr) = row?;
|
||||
let addr_c = to_cstring(addr);
|
||||
if clist_search_string_nocase(
|
||||
(*factory).recipients_addr,
|
||||
addr_c.as_ptr(),
|
||||
) == 0
|
||||
{
|
||||
if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 {
|
||||
clist_insert_after(
|
||||
(*factory).recipients_names,
|
||||
(*(*factory).recipients_names).last,
|
||||
if !authname.is_empty() {
|
||||
dc_strdup(to_cstring(authname).as_ptr())
|
||||
to_cstring(authname)
|
||||
} else {
|
||||
0 as *mut libc::c_char
|
||||
std::ptr::null_mut()
|
||||
} as *mut libc::c_void,
|
||||
);
|
||||
clist_insert_after(
|
||||
(*factory).recipients_addr,
|
||||
(*(*factory).recipients_addr).last,
|
||||
dc_strdup(addr_c.as_ptr()) as *mut libc::c_void,
|
||||
addr_c as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -187,11 +183,11 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0);
|
||||
let command = dc_param_get_int((*(*factory).msg).param, DC_PARAM_CMD as i32, 0);
|
||||
if command == 5 {
|
||||
let email_to_remove_c = dc_param_get(
|
||||
(*(*factory).msg).param,
|
||||
'E' as i32,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let email_to_remove = to_string(email_to_remove_c);
|
||||
@@ -241,8 +237,8 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
);
|
||||
match row {
|
||||
Ok((in_reply_to, references)) => {
|
||||
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
|
||||
(*factory).references = dc_strdup(to_cstring(references).as_ptr());
|
||||
(*factory).in_reply_to = to_cstring(in_reply_to);
|
||||
(*factory).references = to_cstring(references);
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
@@ -266,32 +262,24 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
|
||||
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
|
||||
let context = (*factory).context;
|
||||
(*factory).from_addr = strdup(
|
||||
to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
(*factory).from_addr = to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
(*factory).from_displayname = strdup(
|
||||
to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "displayname")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
|
||||
(*factory).from_displayname = to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "displayname")
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
(*factory).selfstatus = strdup(
|
||||
to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "selfstatus")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.as_ptr(),
|
||||
(*factory).selfstatus = to_cstring(
|
||||
context
|
||||
.sql
|
||||
.get_config(context, "selfstatus")
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
if (*factory).selfstatus.is_null() {
|
||||
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
|
||||
@@ -539,7 +527,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
let msg: *mut dc_msg_t = (*factory).msg;
|
||||
let mut meta_part: *mut mailmime = 0 as *mut mailmime;
|
||||
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if (*chat).type_0 == 130 {
|
||||
if (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -551,9 +539,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
e2ee_guaranteed = 1;
|
||||
min_verified = 2
|
||||
} else {
|
||||
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0);
|
||||
force_plaintext =
|
||||
dc_param_get_int((*(*factory).msg).param, DC_PARAM_FORCE_PLAINTEXT as i32, 0);
|
||||
if force_plaintext == 0 {
|
||||
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0)
|
||||
e2ee_guaranteed =
|
||||
dc_param_get_int((*(*factory).msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0)
|
||||
}
|
||||
}
|
||||
if (*chat).gossiped_timestamp == 0
|
||||
@@ -562,8 +552,10 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
do_gossip = 1
|
||||
}
|
||||
/* build header etc. */
|
||||
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0);
|
||||
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
let command: libc::c_int = dc_param_get_int((*msg).param, DC_PARAM_CMD as i32, 0);
|
||||
if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int
|
||||
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
|
||||
{
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -579,8 +571,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
if command == 5 {
|
||||
let email_to_remove: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
let email_to_remove: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !email_to_remove.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -595,8 +590,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
} else if command == 4 {
|
||||
do_gossip = 1;
|
||||
let email_to_add: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
let email_to_add: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !email_to_add.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -608,9 +606,13 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
email_to_add,
|
||||
),
|
||||
);
|
||||
grpimage = dc_param_get((*chat).param, 'i' as i32, 0 as *const libc::c_char)
|
||||
grpimage = dc_param_get(
|
||||
(*chat).param,
|
||||
DC_PARAM_PROFILE_IMAGE as i32,
|
||||
0 as *const libc::c_char,
|
||||
)
|
||||
}
|
||||
if 0 != dc_param_get_int((*msg).param, 'F' as i32, 0) & 0x1 {
|
||||
if 0 != dc_param_get_int((*msg).param, DC_PARAM_CMD_ARG2 as i32, 0) & 0x1 {
|
||||
info!(
|
||||
(*msg).context,
|
||||
0,
|
||||
@@ -634,13 +636,17 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
dc_param_get(
|
||||
(*msg).param,
|
||||
'E' as i32,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if command == 3 {
|
||||
grpimage = dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
grpimage = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if grpimage.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -674,8 +680,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
placeholdertext = dc_stock_str((*factory).context, 43)
|
||||
}
|
||||
if command == 7 {
|
||||
let step: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
|
||||
let step: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !step.is_null() {
|
||||
info!(
|
||||
(*msg).context,
|
||||
@@ -690,8 +699,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
step,
|
||||
),
|
||||
);
|
||||
let param2: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'F' as i32, 0 as *const libc::c_char);
|
||||
let param2: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG2 as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !param2.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -719,8 +731,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
let fingerprint: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'G' as i32, 0 as *const libc::c_char);
|
||||
let fingerprint: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG3 as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !fingerprint.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -733,8 +748,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
let grpid: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'H' as i32, 0 as *const libc::c_char);
|
||||
let grpid: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_CMD_ARG4 as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !grpid.is_null() {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -750,8 +768,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
if !grpimage.is_null() {
|
||||
let mut meta: *mut dc_msg_t = dc_msg_new_untyped((*factory).context);
|
||||
(*meta).type_0 = 20;
|
||||
dc_param_set((*meta).param, 'f' as i32, grpimage);
|
||||
(*meta).type_0 = DC_MSG_IMAGE as libc::c_int;
|
||||
dc_param_set((*meta).param, DC_PARAM_FILE as i32, grpimage);
|
||||
let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
meta_part = build_body_file(
|
||||
meta,
|
||||
@@ -769,8 +787,11 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
}
|
||||
dc_msg_unref(meta);
|
||||
}
|
||||
if (*msg).type_0 == 41 || (*msg).type_0 == 40 || (*msg).type_0 == 50 {
|
||||
if (*msg).type_0 == 41 {
|
||||
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_AUDIO as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_VIDEO as libc::c_int
|
||||
{
|
||||
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new_custom(
|
||||
@@ -779,7 +800,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
),
|
||||
);
|
||||
}
|
||||
let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0);
|
||||
let duration_ms: libc::c_int =
|
||||
dc_param_get_int((*msg).param, DC_PARAM_DURATION as i32, 0);
|
||||
if duration_ms > 0 {
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
@@ -793,7 +815,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
);
|
||||
}
|
||||
}
|
||||
afwd_email = dc_param_exists((*msg).param, 'a' as i32);
|
||||
afwd_email = dc_param_exists((*msg).param, DC_PARAM_FORWARDED as i32);
|
||||
let mut fwdhint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if 0 != afwd_email {
|
||||
fwdhint = dc_strdup(
|
||||
@@ -845,12 +867,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
free(fwdhint as *mut libc::c_void);
|
||||
free(placeholdertext as *mut libc::c_void);
|
||||
/* add attachment part */
|
||||
if (*msg).type_0 == 20
|
||||
|| (*msg).type_0 == 21
|
||||
|| (*msg).type_0 == 40
|
||||
|| (*msg).type_0 == 41
|
||||
|| (*msg).type_0 == 50
|
||||
|| (*msg).type_0 == 60
|
||||
if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_GIF as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_AUDIO as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_VOICE as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_VIDEO as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_FILE as libc::c_int
|
||||
{
|
||||
if 0 == is_file_size_okay(msg) {
|
||||
let error: *mut libc::c_char = dc_mprintf(
|
||||
@@ -975,7 +997,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
|
||||
mailmime_add_part(message, multipart);
|
||||
let p1: *mut libc::c_char;
|
||||
let p2: *mut libc::c_char;
|
||||
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0) {
|
||||
if 0 != dc_param_get_int((*(*factory).msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0) {
|
||||
p1 = dc_stock_str((*factory).context, 24)
|
||||
} else {
|
||||
p1 = dc_msg_get_summarytext((*factory).msg, 32)
|
||||
@@ -1101,9 +1123,11 @@ unsafe fn get_subject(
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
};
|
||||
if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
|
||||
if dc_param_get_int((*msg).param, DC_PARAM_CMD as i32, 0) == 6 {
|
||||
ret = dc_stock_str(context, 42)
|
||||
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||
} else if (*chat).type_0 == DC_CHAT_TYPE_GROUP as libc::c_int
|
||||
|| (*chat).type_0 == DC_CHAT_TYPE_VERIFIED_GROUP as libc::c_int
|
||||
{
|
||||
ret = dc_mprintf(
|
||||
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
|
||||
(*chat).name,
|
||||
@@ -1160,14 +1184,17 @@ unsafe fn build_body_file(
|
||||
let mut mime_sub: *mut mailmime = 0 as *mut mailmime;
|
||||
let content: *mut mailmime_content;
|
||||
let pathNfilename: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
let mut mimetype: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'm' as i32, 0 as *const libc::c_char);
|
||||
dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
let mut mimetype: *mut libc::c_char = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_MIMETYPE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
let suffix: *mut libc::c_char = dc_get_filesuffix_lc(pathNfilename);
|
||||
let mut filename_to_send: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut filename_encoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !pathNfilename.is_null() {
|
||||
if (*msg).type_0 == 41 {
|
||||
if (*msg).type_0 == DC_MSG_VOICE as libc::c_int {
|
||||
let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
|
||||
|
||||
let suffix = if !suffix.is_null() {
|
||||
@@ -1178,10 +1205,12 @@ unsafe fn build_body_file(
|
||||
let res = ts
|
||||
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
|
||||
.to_string();
|
||||
filename_to_send = strdup(to_cstring(res).as_ptr());
|
||||
} else if (*msg).type_0 == 40 {
|
||||
filename_to_send = to_cstring(res);
|
||||
} else if (*msg).type_0 == DC_MSG_AUDIO as libc::c_int {
|
||||
filename_to_send = dc_get_filename(pathNfilename)
|
||||
} else if (*msg).type_0 == 20 || (*msg).type_0 == 21 {
|
||||
} else if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|
||||
|| (*msg).type_0 == DC_MSG_GIF as libc::c_int
|
||||
{
|
||||
if base_name.is_null() {
|
||||
base_name = b"image\x00" as *const u8 as *const libc::c_char
|
||||
}
|
||||
@@ -1194,7 +1223,7 @@ unsafe fn build_body_file(
|
||||
b"dat\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
)
|
||||
} else if (*msg).type_0 == 50 {
|
||||
} else if (*msg).type_0 == DC_MSG_VIDEO as libc::c_int {
|
||||
filename_to_send = dc_mprintf(
|
||||
b"video.%s\x00" as *const u8 as *const libc::c_char,
|
||||
if !suffix.is_null() {
|
||||
@@ -1319,7 +1348,7 @@ unsafe fn build_body_file(
|
||||
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int {
|
||||
let mut file_size_okay: libc::c_int = 1;
|
||||
let pathNfilename: *mut libc::c_char =
|
||||
dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
let bytes: uint64_t = dc_get_filebytes((*msg).context, pathNfilename);
|
||||
if bytes > (49 * 1024 * 1024 / 4 * 3) as libc::c_ulonglong {
|
||||
file_size_okay = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
|
||||
use charset::Charset;
|
||||
use mmime::mailimf::*;
|
||||
@@ -323,7 +323,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
while i_1 < icnt_0 {
|
||||
let part_2: *mut dc_mimepart_t =
|
||||
carray_get((*mimeparser).parts, i_1 as libc::c_uint) as *mut dc_mimepart_t;
|
||||
dc_param_set_int((*part_2).param, 'a' as i32, 1i32);
|
||||
dc_param_set_int((*part_2).param, DC_PARAM_FORWARDED as i32, 1);
|
||||
i_1 += 1
|
||||
}
|
||||
}
|
||||
@@ -348,7 +348,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
if !field_0.is_null() {
|
||||
let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value);
|
||||
if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 {
|
||||
dc_param_set_int((*part_3).param, 'd' as i32, duration_ms);
|
||||
dc_param_set_int((*part_3).param, DC_PARAM_DURATION as i32, duration_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +385,11 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
let part_4: *mut dc_mimepart_t =
|
||||
dc_mimeparser_get_last_nonmeta(mimeparser);
|
||||
if !part_4.is_null() {
|
||||
dc_param_set_int((*part_4).param, 'r' as i32, 1i32);
|
||||
dc_param_set_int(
|
||||
(*part_4).param,
|
||||
DC_PARAM_WANTS_MDN as i32,
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
free(from_addr as *mut libc::c_void);
|
||||
@@ -833,6 +837,7 @@ unsafe fn hash_header(
|
||||
18 => key = b"References\x00" as *const u8 as *const libc::c_char,
|
||||
19 => key = b"Subject\x00" as *const u8 as *const libc::c_char,
|
||||
22 => {
|
||||
// MAILIMF_FIELD_OPTIONAL_FIELD
|
||||
let optional_field: *const mailimf_optional_field =
|
||||
(*field).fld_data.fld_optional_field;
|
||||
if !optional_field.is_null() {
|
||||
@@ -842,17 +847,16 @@ unsafe fn hash_header(
|
||||
_ => {}
|
||||
}
|
||||
if !key.is_null() {
|
||||
let key_len: libc::c_int = strlen(key) as libc::c_int;
|
||||
if out.contains_key(as_str(key)) {
|
||||
if (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|
||||
|| key_len > 5i32
|
||||
&& strncasecmp(key, b"Chat-\x00" as *const u8 as *const libc::c_char, 5)
|
||||
== 0i32
|
||||
{
|
||||
out.insert(to_string(key), field);
|
||||
}
|
||||
} else {
|
||||
out.insert(to_string(key), field);
|
||||
// XXX the optional field sometimes contains invalid UTF8
|
||||
// which should not happen (according to the mime standard).
|
||||
// This might point to a bug in our mime parsing/processing
|
||||
// logic. As mmime/dc_mimeparser is scheduled fore replacement
|
||||
// anyway we just use a lossy conversion.
|
||||
let key_r = &to_string_lossy(key);
|
||||
if !out.contains_key(key_r) || // key already exists, only overwrite known types (protected headers)
|
||||
(*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key_r.starts_with("Chat-")
|
||||
{
|
||||
out.insert(key_r.to_string(), field);
|
||||
}
|
||||
}
|
||||
cur1 = if !cur1.is_null() {
|
||||
@@ -1204,8 +1208,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
current_block = 8795901732489102124;
|
||||
} else {
|
||||
decoded_data_bytes = res.len();
|
||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
||||
decoded_data = strdup(res_c.as_ptr());
|
||||
decoded_data = res.as_ptr() as *const libc::c_char;
|
||||
current_block = 17788412896529399552;
|
||||
}
|
||||
} else {
|
||||
@@ -1341,8 +1344,9 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
}
|
||||
if !filename_parts.is_empty() {
|
||||
free(desired_filename as *mut libc::c_void);
|
||||
desired_filename =
|
||||
dc_decode_ext_header(to_cstring(filename_parts).as_ptr());
|
||||
let parts_c = to_cstring(filename_parts);
|
||||
desired_filename = dc_decode_ext_header(parts_c);
|
||||
free(parts_c as *mut _);
|
||||
}
|
||||
if desired_filename.is_null() {
|
||||
let param = mailmime_find_ct_parameter(
|
||||
@@ -1440,7 +1444,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
}
|
||||
}
|
||||
}
|
||||
/* add object? (we do not add all objetcs, eg. signatures etc. are ignored) */
|
||||
/* add object? (we do not add all objects, eg. signatures etc. are ignored) */
|
||||
dc_simplify_unref(simplifier);
|
||||
if !transfer_decoding_buffer.is_null() {
|
||||
mmap_string_unref(transfer_decoding_buffer);
|
||||
@@ -1486,8 +1490,8 @@ unsafe fn do_add_single_file_part(
|
||||
(*part).type_0 = msg_type;
|
||||
(*part).int_mimetype = mime_type;
|
||||
(*part).bytes = decoded_data_bytes as libc::c_int;
|
||||
dc_param_set((*part).param, 'f' as i32, pathNfilename);
|
||||
dc_param_set((*part).param, 'm' as i32, raw_mime);
|
||||
dc_param_set((*part).param, DC_PARAM_FILE as i32, pathNfilename);
|
||||
dc_param_set((*part).param, DC_PARAM_MIMETYPE as i32, raw_mime);
|
||||
if mime_type == 80i32 {
|
||||
let mut w: uint32_t = 0i32 as uint32_t;
|
||||
let mut h: uint32_t = 0i32 as uint32_t;
|
||||
@@ -1497,8 +1501,8 @@ unsafe fn do_add_single_file_part(
|
||||
&mut w,
|
||||
&mut h,
|
||||
) {
|
||||
dc_param_set_int((*part).param, 'w' as i32, w as int32_t);
|
||||
dc_param_set_int((*part).param, 'h' as i32, h as int32_t);
|
||||
dc_param_set_int((*part).param, DC_PARAM_WIDTH as i32, w as int32_t);
|
||||
dc_param_set_int((*part).param, DC_PARAM_HEIGHT as i32, h as int32_t);
|
||||
}
|
||||
}
|
||||
do_add_single_part(parser, part);
|
||||
@@ -1511,9 +1515,9 @@ unsafe fn do_add_single_file_part(
|
||||
|
||||
unsafe fn do_add_single_part(parser: &dc_mimeparser_t, part: *mut dc_mimepart_t) {
|
||||
if 0 != (*parser).e2ee_helper.encrypted && (*parser).e2ee_helper.signatures.len() > 0 {
|
||||
dc_param_set_int((*part).param, 'c' as i32, 1i32);
|
||||
dc_param_set_int((*part).param, DC_PARAM_GUARANTEE_E2EE as i32, 1);
|
||||
} else if 0 != (*parser).e2ee_helper.encrypted {
|
||||
dc_param_set_int((*part).param, 'e' as i32, 0x2i32);
|
||||
dc_param_set_int((*part).param, DC_PARAM_ERRONEOUS_E2EE as i32, 0x2);
|
||||
}
|
||||
carray_add(
|
||||
(*parser).parts,
|
||||
|
||||
192
src/dc_msg.rs
192
src/dc_msg.rs
@@ -63,7 +63,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!("Cannot load message #{}.", msg_id as usize);
|
||||
dc_msg_unref(msg);
|
||||
dc_contact_unref(contact_from);
|
||||
return strdup(to_cstring(ret).as_ptr());
|
||||
return to_cstring(ret);
|
||||
}
|
||||
let rawtxt = rawtxt.unwrap();
|
||||
let rawtxt = dc_truncate_str(rawtxt.trim(), 100000);
|
||||
@@ -91,7 +91,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
// device-internal message, no further details needed
|
||||
dc_msg_unref(msg);
|
||||
dc_contact_unref(contact_from);
|
||||
return strdup(to_cstring(ret).as_ptr());
|
||||
return to_cstring(ret);
|
||||
}
|
||||
|
||||
context
|
||||
@@ -142,18 +142,22 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += ", Location sent";
|
||||
}
|
||||
|
||||
let e2ee_errors = dc_param_get_int((*msg).param, 'e' as i32, 0);
|
||||
let e2ee_errors = dc_param_get_int((*msg).param, DC_PARAM_ERRONEOUS_E2EE as i32, 0);
|
||||
|
||||
if 0 != e2ee_errors {
|
||||
if 0 != e2ee_errors & 0x2 {
|
||||
ret += ", Encrypted, no valid signature";
|
||||
}
|
||||
} else if 0 != dc_param_get_int((*msg).param, 'c' as i32, 0) {
|
||||
} else if 0 != dc_param_get_int((*msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0) {
|
||||
ret += ", Encrypted";
|
||||
}
|
||||
|
||||
ret += "\n";
|
||||
p = dc_param_get((*msg).param, 'L' as i32, 0 as *const libc::c_char);
|
||||
p = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_ERROR as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !p.is_null() {
|
||||
ret += &format!("Error: {}", as_str(p));
|
||||
free(p as *mut libc::c_void);
|
||||
@@ -184,12 +188,12 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!("Mimetype: {}\n", as_str(p));
|
||||
free(p as *mut libc::c_void);
|
||||
}
|
||||
let w = dc_param_get_int((*msg).param, 'w' as i32, 0);
|
||||
let h = dc_param_get_int((*msg).param, 'h' as i32, 0);
|
||||
let w = dc_param_get_int((*msg).param, DC_PARAM_WIDTH as i32, 0);
|
||||
let h = dc_param_get_int((*msg).param, DC_PARAM_HEIGHT as i32, 0);
|
||||
if w != 0 || h != 0 {
|
||||
ret += &format!("Dimension: {} x {}\n", w, h,);
|
||||
}
|
||||
let duration = dc_param_get_int((*msg).param, 'd' as i32, 0);
|
||||
let duration = dc_param_get_int((*msg).param, DC_PARAM_DURATION as i32, 0);
|
||||
if duration != 0 {
|
||||
ret += &format!("Duration: {} ms\n", duration,);
|
||||
}
|
||||
@@ -209,7 +213,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
|
||||
dc_msg_unref(msg);
|
||||
dc_contact_unref(contact_from);
|
||||
strdup(to_cstring(ret).as_ptr())
|
||||
to_cstring(ret)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a> {
|
||||
@@ -224,8 +228,8 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a>
|
||||
* If you want an update, you have to recreate the object.
|
||||
*/
|
||||
// to check if a mail was sent, use dc_msg_is_sent()
|
||||
// approx. max. lenght returned by dc_msg_get_text()
|
||||
// approx. max. lenght returned by dc_get_msg_info()
|
||||
// approx. max. length returned by dc_msg_get_text()
|
||||
// approx. max. length returned by dc_get_msg_info()
|
||||
pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: libc::c_int) -> *mut dc_msg_t<'a> {
|
||||
let mut msg: *mut dc_msg_t;
|
||||
msg = calloc(1, ::std::mem::size_of::<dc_msg_t>()) as *mut dc_msg_t;
|
||||
@@ -269,9 +273,13 @@ pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut file: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
ret = dc_param_get((*msg).param, 'm' as i32, 0 as *const libc::c_char);
|
||||
ret = dc_param_get(
|
||||
(*msg).param,
|
||||
DC_PARAM_MIMETYPE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if ret.is_null() {
|
||||
file = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
file = dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if !file.is_null() {
|
||||
dc_msg_guess_msgtype_from_suffix(file, 0 as *mut libc::c_int, &mut ret);
|
||||
if ret.is_null() {
|
||||
@@ -348,7 +356,7 @@ pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut file_rel: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut file_abs: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
file_rel = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
file_rel = dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if !file_rel.is_null() {
|
||||
file_abs = dc_get_abs_path((*msg).context, file_rel)
|
||||
}
|
||||
@@ -445,9 +453,12 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
dc_msg_empty(msg);
|
||||
|
||||
(*msg).id = row.get::<_, i32>(0)? as u32;
|
||||
(*msg).rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
||||
(*msg).in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
||||
(*msg).server_folder = dc_strdup(to_cstring(row.get::<_, String>(3)?).as_ptr());
|
||||
(*msg).rfc724_mid = to_cstring(row.get::<_, String>(1)?);
|
||||
(*msg).in_reply_to = match row.get::<_, Option<String>>(2)? {
|
||||
Some(s) => to_cstring(s),
|
||||
None => std::ptr::null_mut(),
|
||||
};
|
||||
(*msg).server_folder = to_cstring(row.get::<_, String>(3)?);
|
||||
(*msg).server_uid = row.get(4)?;
|
||||
(*msg).move_state = row.get(5)?;
|
||||
(*msg).chat_id = row.get(6)?;
|
||||
@@ -459,15 +470,15 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
(*msg).type_0 = row.get(12)?;
|
||||
(*msg).state = row.get(13)?;
|
||||
(*msg).is_dc_message = row.get(14)?;
|
||||
(*msg).text = dc_strdup(to_cstring(row.get::<_, String>(15).unwrap_or_default()).as_ptr());
|
||||
(*msg).text = to_cstring(row.get::<_, String>(15).unwrap_or_default());
|
||||
dc_param_set_packed(
|
||||
(*msg).param,
|
||||
to_cstring(row.get::<_, String>(16)?).as_ptr()
|
||||
to_cstring(row.get::<_, String>(16)?)
|
||||
);
|
||||
(*msg).starred = row.get(17)?;
|
||||
(*msg).hidden = row.get(18)?;
|
||||
(*msg).location_id = row.get(19)?;
|
||||
(*msg).chat_blocked = row.get(20)?;
|
||||
(*msg).chat_blocked = row.get::<_, Option<i32>>(20)?.unwrap_or_default();
|
||||
if (*msg).chat_blocked == 2 {
|
||||
dc_truncate_n_unwrap_str((*msg).text, 256, 0);
|
||||
}
|
||||
@@ -476,13 +487,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
}
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(_) => true,
|
||||
Err(err) => {
|
||||
error!(context, 0, "msg: load from db failed: {:?}", err);
|
||||
false
|
||||
}
|
||||
}
|
||||
res.is_ok()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut libc::c_char {
|
||||
@@ -494,7 +499,10 @@ pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut l
|
||||
);
|
||||
|
||||
if let Some(headers) = headers {
|
||||
dc_strdup_keep_null(to_cstring(headers).as_ptr())
|
||||
let h = to_cstring(headers);
|
||||
let res = dc_strdup_keep_null(h);
|
||||
free(h as *mut _);
|
||||
res
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
@@ -538,46 +546,48 @@ pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize)
|
||||
if msg_ids.is_null() || msg_cnt <= 0 {
|
||||
return false;
|
||||
}
|
||||
context.sql.prepare(
|
||||
let msgs = context.sql.prepare(
|
||||
"SELECT m.state, c.blocked FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=? AND m.chat_id>9",
|
||||
|mut stmt| {
|
||||
let mut send_event = false;
|
||||
|
||||
|mut stmt, _| {
|
||||
let mut res = Vec::with_capacity(msg_cnt);
|
||||
for i in 0..msg_cnt {
|
||||
// TODO: do I need to reset?
|
||||
let id = unsafe { *msg_ids.offset(i as isize) };
|
||||
if let Ok((curr_state, curr_blocked)) = stmt
|
||||
.query_row(params![id as i32], |row| {
|
||||
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
|
||||
})
|
||||
{
|
||||
if curr_blocked == 0 {
|
||||
if curr_state == 10 || curr_state == 13 {
|
||||
dc_update_msg_state(context, id, 16);
|
||||
info!(context, 0, "Seen message #{}.", id);
|
||||
|
||||
unsafe { dc_job_add(
|
||||
context,
|
||||
130,
|
||||
id as i32,
|
||||
0 as *const libc::c_char,
|
||||
0,
|
||||
) };
|
||||
send_event = true;
|
||||
}
|
||||
} else if curr_state == 10 {
|
||||
dc_update_msg_state(context, id, 13);
|
||||
send_event = true;
|
||||
}
|
||||
}
|
||||
let (state, blocked) = stmt.query_row(params![id as i32], |row| {
|
||||
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default()))
|
||||
})?;
|
||||
res.push((id, state, blocked));
|
||||
}
|
||||
|
||||
if send_event {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0, 0);
|
||||
}
|
||||
Ok(())
|
||||
Ok(res)
|
||||
}
|
||||
).is_ok()
|
||||
);
|
||||
|
||||
if msgs.is_err() {
|
||||
warn!(context, 0, "markseen_msgs failed: {:?}", msgs);
|
||||
return false;
|
||||
}
|
||||
let mut send_event = false;
|
||||
let msgs = msgs.unwrap();
|
||||
|
||||
for (id, curr_state, curr_blocked) in msgs.into_iter() {
|
||||
if curr_blocked == 0 {
|
||||
if curr_state == 10 || curr_state == 13 {
|
||||
dc_update_msg_state(context, id, 16);
|
||||
info!(context, 0, "Seen message #{}.", id);
|
||||
|
||||
unsafe { dc_job_add(context, 130, id as i32, 0 as *const libc::c_char, 0) };
|
||||
send_event = true;
|
||||
}
|
||||
} else if curr_state == 10 {
|
||||
dc_update_msg_state(context, id, 13);
|
||||
send_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
if send_event {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0, 0);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn dc_update_msg_state(context: &Context, msg_id: uint32_t, state: libc::c_int) -> bool {
|
||||
@@ -601,7 +611,7 @@ pub fn dc_star_msgs(
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.prepare("UPDATE msgs SET starred=? WHERE id=?;", |mut stmt| {
|
||||
.prepare("UPDATE msgs SET starred=? WHERE id=?;", |mut stmt, _| {
|
||||
for i in 0..msg_cnt {
|
||||
stmt.execute(params![star, unsafe { *msg_ids.offset(i as isize) as i32 }])?;
|
||||
}
|
||||
@@ -689,14 +699,14 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
let res = dc_truncate_str(as_str((*msg).text), 30000);
|
||||
dc_strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut pathNfilename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
pathNfilename = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
pathNfilename = dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if !pathNfilename.is_null() {
|
||||
ret = dc_get_filename(pathNfilename)
|
||||
}
|
||||
@@ -713,7 +723,7 @@ pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t {
|
||||
let mut ret: uint64_t = 0i32 as uint64_t;
|
||||
let mut file: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
file = dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
|
||||
file = dc_param_get((*msg).param, DC_PARAM_FILE as i32, 0 as *const libc::c_char);
|
||||
if !file.is_null() {
|
||||
ret = dc_get_filebytes((*msg).context, file)
|
||||
}
|
||||
@@ -728,7 +738,7 @@ pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
dc_param_get_int((*msg).param, 'w' as i32, 0i32)
|
||||
dc_param_get_int((*msg).param, DC_PARAM_WIDTH as i32, 0)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
@@ -736,7 +746,7 @@ pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
dc_param_get_int((*msg).param, 'h' as i32, 0i32)
|
||||
dc_param_get_int((*msg).param, DC_PARAM_HEIGHT as i32, 0)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
@@ -744,7 +754,7 @@ pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dc_param_get_int((*msg).param, 'd' as i32, 0i32)
|
||||
dc_param_get_int((*msg).param, DC_PARAM_DURATION as i32, 0)
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
@@ -752,7 +762,7 @@ pub unsafe fn dc_msg_get_showpadlock(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
if dc_param_get_int((*msg).param, 'c' as i32, 0i32) != 0i32 {
|
||||
if dc_param_get_int((*msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 0) != 0i32 {
|
||||
return 1i32;
|
||||
}
|
||||
|
||||
@@ -835,13 +845,13 @@ pub unsafe fn dc_msg_get_summarytext_by_raw(
|
||||
50 => prefix = dc_stock_str(context, 10i32),
|
||||
41 => prefix = dc_stock_str(context, 7i32),
|
||||
40 | 60 => {
|
||||
if dc_param_get_int(param, 'S' as i32, 0i32) == 6i32 {
|
||||
if dc_param_get_int(param, DC_PARAM_CMD as i32, 0) == 6i32 {
|
||||
prefix = dc_stock_str(context, 42i32);
|
||||
append_text = 0i32
|
||||
} else {
|
||||
pathNfilename = dc_param_get(
|
||||
param,
|
||||
'f' as i32,
|
||||
DC_PARAM_FILE as i32,
|
||||
b"ErrFilename\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
value = dc_get_filename(pathNfilename);
|
||||
@@ -861,7 +871,7 @@ pub unsafe fn dc_msg_get_summarytext_by_raw(
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if dc_param_get_int(param, 'S' as i32, 0i32) == 9i32 {
|
||||
if dc_param_get_int(param, DC_PARAM_CMD as i32, 0) == 9i32 {
|
||||
prefix = dc_stock_str(context, 66i32);
|
||||
append_text = 0i32
|
||||
}
|
||||
@@ -925,7 +935,7 @@ pub unsafe fn dc_msg_is_forwarded(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
return if 0 != dc_param_get_int((*msg).param, 'a' as i32, 0i32) {
|
||||
return if 0 != dc_param_get_int((*msg).param, DC_PARAM_FORWARDED as i32, 0) {
|
||||
1i32
|
||||
} else {
|
||||
0i32
|
||||
@@ -937,7 +947,7 @@ pub unsafe fn dc_msg_is_info(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return 0i32;
|
||||
}
|
||||
let cmd: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0i32);
|
||||
let cmd: libc::c_int = dc_param_get_int((*msg).param, DC_PARAM_CMD as i32, 0);
|
||||
if (*msg).from_id == 2i32 as libc::c_uint
|
||||
|| (*msg).to_id == 2i32 as libc::c_uint
|
||||
|| 0 != cmd && cmd != 6i32
|
||||
@@ -971,7 +981,7 @@ pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
|
||||
if dc_param_get_int((*msg).param, DC_PARAM_CMD as i32, 0) == 6 {
|
||||
true
|
||||
} else {
|
||||
true
|
||||
@@ -1045,23 +1055,23 @@ pub unsafe fn dc_msg_set_file(
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
dc_param_set((*msg).param, 'f' as i32, file);
|
||||
dc_param_set((*msg).param, 'm' as i32, filemime);
|
||||
dc_param_set((*msg).param, DC_PARAM_FILE as i32, file);
|
||||
dc_param_set((*msg).param, DC_PARAM_MIMETYPE as i32, filemime);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_dimension(msg: *mut dc_msg_t, width: libc::c_int, height: libc::c_int) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
dc_param_set_int((*msg).param, 'w' as i32, width);
|
||||
dc_param_set_int((*msg).param, 'h' as i32, height);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_WIDTH as i32, width);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_HEIGHT as i32, height);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc::c_int) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
return;
|
||||
}
|
||||
dc_param_set_int((*msg).param, 'd' as i32, duration);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_DURATION as i32, duration);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
@@ -1072,11 +1082,11 @@ pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
) {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if width > 0i32 && height > 0i32 {
|
||||
dc_param_set_int((*msg).param, 'w' as i32, width);
|
||||
dc_param_set_int((*msg).param, 'h' as i32, height);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_WIDTH as i32, width);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_HEIGHT as i32, height);
|
||||
}
|
||||
if duration > 0i32 {
|
||||
dc_param_set_int((*msg).param, 'd' as i32, duration);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_DURATION as i32, duration);
|
||||
}
|
||||
dc_msg_save_param_to_disk(msg);
|
||||
};
|
||||
@@ -1110,13 +1120,15 @@ pub unsafe fn dc_delete_msg_from_db(context: &Context, msg_id: uint32_t) {
|
||||
&context.sql,
|
||||
"DELETE FROM msgs WHERE id=?;",
|
||||
params![(*msg).id as i32],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM msgs_mdns WHERE msg_id=?;",
|
||||
params![(*msg).id as i32],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
@@ -1173,7 +1185,7 @@ pub unsafe fn dc_set_msg_failed(context: &Context, msg_id: uint32_t, error: *con
|
||||
(*msg).state = 24
|
||||
}
|
||||
if !error.is_null() {
|
||||
dc_param_set((*msg).param, 'L' as i32, error);
|
||||
dc_param_set((*msg).param, DC_PARAM_ERROR as i32, error);
|
||||
error!(context, 0, "{}", as_str(error),);
|
||||
}
|
||||
|
||||
@@ -1355,9 +1367,7 @@ pub fn dc_rfc724_mid_exists(
|
||||
&[as_str(rfc724_mid)],
|
||||
|row| {
|
||||
if !ret_server_folder.is_null() {
|
||||
unsafe {
|
||||
*ret_server_folder = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr())
|
||||
};
|
||||
unsafe { *ret_server_folder = to_cstring(row.get::<_, String>(0)?) };
|
||||
}
|
||||
if !ret_server_uid.is_null() {
|
||||
unsafe { *ret_server_uid = row.get(1)? };
|
||||
|
||||
@@ -3,67 +3,69 @@ use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
/// for msgs and jobs
|
||||
pub const DC_PARAM_FILE: char = 'f';
|
||||
pub const DC_PARAM_FILE: char = 'f'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_WIDTH: char = 'w';
|
||||
pub const DC_PARAM_WIDTH: char = 'w'; // int
|
||||
/// for msgs
|
||||
pub const DC_PARAM_HEIGHT: char = 'h';
|
||||
pub const DC_PARAM_HEIGHT: char = 'h'; // int
|
||||
/// for msgs
|
||||
pub const DC_PARAM_DURATION: char = 'd';
|
||||
pub const DC_PARAM_DURATION: char = 'd'; // int
|
||||
/// for msgs
|
||||
pub const DC_PARAM_MIMETYPE: char = 'm';
|
||||
pub const DC_PARAM_MIMETYPE: char = 'm'; // string
|
||||
/// for msgs: incoming: message is encryoted, outgoing: guarantee E2EE or the message is not send
|
||||
pub const DC_PARAM_GUARANTEE_E2EE: char = 'c';
|
||||
pub const DC_PARAM_GUARANTEE_E2EE: char = 'c'; // int (bool?)
|
||||
/// for msgs: decrypted with validation errors or without mutual set, if neither 'c' nor 'e' are preset, the messages is only transport encrypted
|
||||
pub const DC_PARAM_ERRONEOUS_E2EE: char = 'e';
|
||||
pub const DC_PARAM_ERRONEOUS_E2EE: char = 'e'; // int
|
||||
/// for msgs: force unencrypted message, either DC_FP_ADD_AUTOCRYPT_HEADER (1), DC_FP_NO_AUTOCRYPT_HEADER (2) or 0
|
||||
pub const DC_PARAM_FORCE_PLAINTEXT: char = 'u';
|
||||
/// for msgs: an incoming message which requestes a MDN (aka read receipt)
|
||||
pub const DC_PARAM_WANTS_MDN: char = 'r';
|
||||
pub const DC_PARAM_FORCE_PLAINTEXT: char = 'u'; // int (bool?)
|
||||
/// for msgs: an incoming message which requests a MDN (aka read receipt)
|
||||
pub const DC_PARAM_WANTS_MDN: char = 'r'; // int (bool?)
|
||||
/// for msgs
|
||||
pub const DC_PARAM_FORWARDED: char = 'a';
|
||||
pub const DC_PARAM_FORWARDED: char = 'a'; // int (bool?)
|
||||
/// for msgs
|
||||
pub const DC_PARAM_CMD: char = 'S';
|
||||
pub const DC_PARAM_CMD: char = 'S'; // int
|
||||
/// for msgs
|
||||
pub const DC_PARAM_CMD_ARG: char = 'E';
|
||||
pub const DC_PARAM_CMD_ARG: char = 'E'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_CMD_ARG2: char = 'F';
|
||||
pub const DC_PARAM_CMD_ARG2: char = 'F'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_CMD_ARG3: char = 'G';
|
||||
pub const DC_PARAM_CMD_ARG3: char = 'G'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_CMD_ARG4: char = 'H';
|
||||
pub const DC_PARAM_CMD_ARG4: char = 'H'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_ERROR: char = 'L';
|
||||
pub const DC_PARAM_ERROR: char = 'L'; // string
|
||||
/// for msgs in PREPARING: space-separated list of message IDs of forwarded copies
|
||||
pub const DC_PARAM_PREP_FORWARDS: char = 'P';
|
||||
pub const DC_PARAM_PREP_FORWARDS: char = 'P'; // string
|
||||
/// for msgs
|
||||
pub const DC_PARAM_SET_LATITUDE: char = 'l';
|
||||
pub const DC_PARAM_SET_LATITUDE: char = 'l'; // float
|
||||
/// for msgs
|
||||
pub const DC_PARAM_SET_LONGITUDE: char = 'n';
|
||||
pub const DC_PARAM_SET_LONGITUDE: char = 'n'; // float
|
||||
|
||||
/// for jobs
|
||||
pub const DC_PARAM_SERVER_FOLDER: char = 'Z';
|
||||
pub const DC_PARAM_SERVER_FOLDER: char = 'Z'; // string
|
||||
/// for jobs
|
||||
pub const DC_PARAM_SERVER_UID: char = 'z';
|
||||
pub const DC_PARAM_SERVER_UID: char = 'z'; // int
|
||||
/// for jobs
|
||||
pub const DC_PARAM_ALSO_MOVE: char = 'M';
|
||||
pub const DC_PARAM_ALSO_MOVE: char = 'M'; // int (bool?)
|
||||
/// for jobs: space-separated list of message recipients
|
||||
pub const DC_PARAM_RECIPIENTS: char = 'R';
|
||||
pub const DC_PARAM_RECIPIENTS: char = 'R'; // stringap
|
||||
/// for groups
|
||||
pub const DC_PARAM_UNPROMOTED: char = 'U';
|
||||
pub const DC_PARAM_UNPROMOTED: char = 'U'; // int (bool?)
|
||||
/// for groups and contacts
|
||||
pub const DC_PARAM_PROFILE_IMAGE: char = 'i';
|
||||
pub const DC_PARAM_PROFILE_IMAGE: char = 'i'; // string (bytes?)
|
||||
/// for chats
|
||||
pub const DC_PARAM_SELFTALK: char = 'K';
|
||||
|
||||
// missing: 's', 'x', 'g'
|
||||
|
||||
// values for DC_PARAM_FORCE_PLAINTEXT
|
||||
pub const DC_FP_ADD_AUTOCRYPT_HEADER: u8 = 1;
|
||||
pub const DC_FP_NO_AUTOCRYPT_HEADER: u8 = 2;
|
||||
|
||||
/// An object for handling key=value parameter lists; for the key, curently only
|
||||
/// An object for handling key=value parameter lists; for the key, currently only
|
||||
/// a single character is allowed.
|
||||
///
|
||||
/// The object is used eg. by Chat or dc_msg_t, for readable paramter names,
|
||||
/// The object is used eg. by Chat or dc_msg_t, for readable parameter names,
|
||||
/// these classes define some DC_PARAM_* constantats.
|
||||
///
|
||||
/// Only for library-internal use.
|
||||
|
||||
254
src/dc_qr.rs
254
src/dc_qr.rs
@@ -21,7 +21,7 @@ use crate::x::*;
|
||||
// text1=URL
|
||||
// text1=error string
|
||||
pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc_lot_t {
|
||||
let mut current_block: u64;
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
let mut payload: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
// must be normalized, if set
|
||||
let mut addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -56,16 +56,23 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
fragment = fragment.offset(1isize);
|
||||
let param: *mut dc_param_t = dc_param_new();
|
||||
dc_param_set_urlencoded(param, fragment);
|
||||
addr = dc_param_get(param, 'a' as i32, 0 as *const libc::c_char);
|
||||
addr = dc_param_get(param, DC_PARAM_FORWARDED as i32, 0 as *const libc::c_char);
|
||||
if !addr.is_null() {
|
||||
let mut urlencoded: *mut libc::c_char =
|
||||
dc_param_get(param, 'n' as i32, 0 as *const libc::c_char);
|
||||
let mut urlencoded: *mut libc::c_char = dc_param_get(
|
||||
param,
|
||||
DC_PARAM_SET_LONGITUDE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !urlencoded.is_null() {
|
||||
name = dc_urldecode(urlencoded);
|
||||
dc_normalize_name(name);
|
||||
free(urlencoded as *mut libc::c_void);
|
||||
}
|
||||
invitenumber = dc_param_get(param, 'i' as i32, 0 as *const libc::c_char);
|
||||
invitenumber = dc_param_get(
|
||||
param,
|
||||
DC_PARAM_PROFILE_IMAGE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
auth = dc_param_get(param, 's' as i32, 0 as *const libc::c_char);
|
||||
grpid = dc_param_get(param, 'x' as i32, 0 as *const libc::c_char);
|
||||
if !grpid.is_null() {
|
||||
@@ -79,7 +86,6 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
dc_param_unref(param);
|
||||
}
|
||||
fingerprint = dc_normalize_fingerprint_c(payload);
|
||||
current_block = 5023038348526654800;
|
||||
} else if strncasecmp(
|
||||
qr,
|
||||
b"mailto:\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -94,7 +100,6 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
*query = 0i32 as libc::c_char
|
||||
}
|
||||
addr = dc_strdup(payload);
|
||||
current_block = 5023038348526654800;
|
||||
} else if strncasecmp(
|
||||
qr,
|
||||
b"SMTP:\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -109,7 +114,6 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
*colon = 0i32 as libc::c_char
|
||||
}
|
||||
addr = dc_strdup(payload);
|
||||
current_block = 5023038348526654800;
|
||||
} else if strncasecmp(
|
||||
qr,
|
||||
b"MATMSG:\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -125,12 +129,11 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
if !semicolon.is_null() {
|
||||
*semicolon = 0i32 as libc::c_char
|
||||
}
|
||||
current_block = 5023038348526654800;
|
||||
} else {
|
||||
(*qr_parsed).state = 400i32;
|
||||
(*qr_parsed).text1 =
|
||||
dc_strdup(b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char);
|
||||
current_block = 16562876845594826114;
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
} else {
|
||||
if strncasecmp(
|
||||
@@ -183,146 +186,111 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
}
|
||||
dc_free_splitted_lines(lines);
|
||||
}
|
||||
current_block = 5023038348526654800;
|
||||
}
|
||||
match current_block {
|
||||
16562876845594826114 => {}
|
||||
_ => {
|
||||
/* check the paramters
|
||||
---------------------- */
|
||||
if !addr.is_null() {
|
||||
/* urldecoding is needed at least for OPENPGP4FPR but should not hurt in the other cases */
|
||||
let mut temp: *mut libc::c_char = dc_urldecode(addr);
|
||||
free(addr as *mut libc::c_void);
|
||||
addr = temp;
|
||||
temp = dc_addr_normalize(addr);
|
||||
free(addr as *mut libc::c_void);
|
||||
addr = temp;
|
||||
if !dc_may_be_valid_addr(addr) {
|
||||
(*qr_parsed).state = 400i32;
|
||||
(*qr_parsed).text1 = dc_strdup(
|
||||
b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char,
|
||||
if OK_TO_CONTINUE {
|
||||
/* check the parameters
|
||||
---------------------- */
|
||||
if !addr.is_null() {
|
||||
/* urldecoding is needed at least for OPENPGP4FPR but should not hurt in the other cases */
|
||||
let mut temp: *mut libc::c_char = dc_urldecode(addr);
|
||||
free(addr as *mut libc::c_void);
|
||||
addr = temp;
|
||||
temp = dc_addr_normalize(addr);
|
||||
free(addr as *mut libc::c_void);
|
||||
addr = temp;
|
||||
if !dc_may_be_valid_addr(addr) {
|
||||
(*qr_parsed).state = 400i32;
|
||||
(*qr_parsed).text1 =
|
||||
dc_strdup(b"Bad e-mail address.\x00" as *const u8 as *const libc::c_char);
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if OK_TO_CONTINUE {
|
||||
if !fingerprint.is_null() {
|
||||
if strlen(fingerprint) != 40 {
|
||||
(*qr_parsed).state = 400i32;
|
||||
(*qr_parsed).text1 = dc_strdup(
|
||||
b"Bad fingerprint length in QR code.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if OK_TO_CONTINUE {
|
||||
if !fingerprint.is_null() {
|
||||
let peerstate =
|
||||
Peerstate::from_fingerprint(context, &context.sql, as_str(fingerprint));
|
||||
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||
if let Some(peerstate) = peerstate {
|
||||
(*qr_parsed).state = 210i32;
|
||||
let addr_ptr = if let Some(ref addr) = peerstate.addr {
|
||||
to_cstring(addr)
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
0 as *const libc::c_char,
|
||||
addr_ptr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
current_block = 16562876845594826114;
|
||||
free(addr_ptr as *mut _);
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
(*qr_parsed).id,
|
||||
2i32,
|
||||
&mut chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
device_msg = dc_mprintf(
|
||||
b"%s verified.\x00" as *const u8 as *const libc::c_char,
|
||||
peerstate.addr,
|
||||
)
|
||||
} else {
|
||||
current_block = 14116432890150942211;
|
||||
(*qr_parsed).text1 = dc_format_fingerprint_c(fingerprint);
|
||||
(*qr_parsed).state = 230i32
|
||||
}
|
||||
} else {
|
||||
current_block = 14116432890150942211;
|
||||
}
|
||||
match current_block {
|
||||
16562876845594826114 => {}
|
||||
_ => {
|
||||
if !fingerprint.is_null() {
|
||||
if strlen(fingerprint) != 40 {
|
||||
(*qr_parsed).state = 400i32;
|
||||
(*qr_parsed).text1 = dc_strdup(
|
||||
b"Bad fingerprint length in QR code.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
current_block = 16562876845594826114;
|
||||
} else {
|
||||
current_block = 5409161009579131794;
|
||||
}
|
||||
} else {
|
||||
current_block = 5409161009579131794;
|
||||
}
|
||||
match current_block {
|
||||
16562876845594826114 => {}
|
||||
_ => {
|
||||
if !fingerprint.is_null() {
|
||||
let peerstate = Peerstate::from_fingerprint(
|
||||
context,
|
||||
&context.sql,
|
||||
as_str(fingerprint),
|
||||
);
|
||||
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||
if let Some(peerstate) = peerstate {
|
||||
(*qr_parsed).state = 210i32;
|
||||
let c_addr = peerstate
|
||||
.addr
|
||||
.as_ref()
|
||||
.map(to_cstring)
|
||||
.unwrap_or_default();
|
||||
let addr_ptr = if peerstate.addr.is_some() {
|
||||
c_addr.as_ptr()
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
0 as *const libc::c_char,
|
||||
addr_ptr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
(*qr_parsed).id,
|
||||
2i32,
|
||||
&mut chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
device_msg = dc_mprintf(
|
||||
b"%s verified.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
peerstate.addr,
|
||||
)
|
||||
} else {
|
||||
(*qr_parsed).text1 =
|
||||
dc_format_fingerprint_c(fingerprint);
|
||||
(*qr_parsed).state = 230i32
|
||||
}
|
||||
} else {
|
||||
if !grpid.is_null() && !grpname.is_null() {
|
||||
(*qr_parsed).state = 202i32;
|
||||
(*qr_parsed).text1 = dc_strdup(grpname);
|
||||
(*qr_parsed).text2 = dc_strdup(grpid)
|
||||
} else {
|
||||
(*qr_parsed).state = 200i32
|
||||
}
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
name,
|
||||
addr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
(*qr_parsed).fingerprint = dc_strdup(fingerprint);
|
||||
(*qr_parsed).invitenumber = dc_strdup(invitenumber);
|
||||
(*qr_parsed).auth = dc_strdup(auth)
|
||||
}
|
||||
} else if !addr.is_null() {
|
||||
(*qr_parsed).state = 320i32;
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
name,
|
||||
addr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
)
|
||||
} else if strstr(
|
||||
qr,
|
||||
b"http://\x00" as *const u8 as *const libc::c_char,
|
||||
) == qr as *mut libc::c_char
|
||||
|| strstr(
|
||||
qr,
|
||||
b"https://\x00" as *const u8 as *const libc::c_char,
|
||||
) == qr as *mut libc::c_char
|
||||
{
|
||||
(*qr_parsed).state = 332i32;
|
||||
(*qr_parsed).text1 = dc_strdup(qr)
|
||||
} else {
|
||||
(*qr_parsed).state = 330i32;
|
||||
(*qr_parsed).text1 = dc_strdup(qr)
|
||||
}
|
||||
if !device_msg.is_null() {
|
||||
dc_add_device_msg(context, chat_id, device_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !grpid.is_null() && !grpname.is_null() {
|
||||
(*qr_parsed).state = 202i32;
|
||||
(*qr_parsed).text1 = dc_strdup(grpname);
|
||||
(*qr_parsed).text2 = dc_strdup(grpid)
|
||||
} else {
|
||||
(*qr_parsed).state = 200i32
|
||||
}
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
name,
|
||||
addr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
(*qr_parsed).fingerprint = dc_strdup(fingerprint);
|
||||
(*qr_parsed).invitenumber = dc_strdup(invitenumber);
|
||||
(*qr_parsed).auth = dc_strdup(auth)
|
||||
}
|
||||
} else if !addr.is_null() {
|
||||
(*qr_parsed).state = 320i32;
|
||||
(*qr_parsed).id =
|
||||
dc_add_or_lookup_contact(context, name, addr, 0x80i32, 0 as *mut libc::c_int)
|
||||
} else if strstr(qr, b"http://\x00" as *const u8 as *const libc::c_char)
|
||||
== qr as *mut libc::c_char
|
||||
|| strstr(qr, b"https://\x00" as *const u8 as *const libc::c_char)
|
||||
== qr as *mut libc::c_char
|
||||
{
|
||||
(*qr_parsed).state = 332i32;
|
||||
(*qr_parsed).text1 = dc_strdup(qr)
|
||||
} else {
|
||||
(*qr_parsed).state = 330i32;
|
||||
(*qr_parsed).text1 = dc_strdup(qr)
|
||||
}
|
||||
if !device_msg.is_null() {
|
||||
dc_add_device_msg(context, chat_id, device_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,9 @@ pub unsafe fn dc_receive_imf(
|
||||
maybe this can be optimized later,
|
||||
by checking the state before the message body is downloaded */
|
||||
let mut allow_creation: libc::c_int = 1;
|
||||
if msgrmsg == 0 {
|
||||
if mime_parser.is_system_message != DC_CMD_AUTOCRYPT_SETUP_MESSAGE
|
||||
&& msgrmsg == 0
|
||||
{
|
||||
let show_emails = context
|
||||
.sql
|
||||
.get_config_int(context, "show_emails")
|
||||
@@ -443,7 +445,7 @@ pub unsafe fn dc_receive_imf(
|
||||
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
|
||||
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
|
||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
||||
|mut stmt| {
|
||||
|mut stmt, conn| {
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if !(i < icnt) {
|
||||
@@ -503,16 +505,19 @@ pub unsafe fn dc_receive_imf(
|
||||
} else {
|
||||
""
|
||||
},
|
||||
// txt_raw might contain invalid utf8
|
||||
if !txt_raw.is_null() {
|
||||
as_str(txt_raw)
|
||||
to_string_lossy(txt_raw)
|
||||
} else {
|
||||
""
|
||||
String::new()
|
||||
},
|
||||
as_str((*(*part).param).packed),
|
||||
(*part).bytes,
|
||||
hidden,
|
||||
if 0 != save_mime_headers {
|
||||
Some(to_string(imf_raw_not_terminated))
|
||||
let body_string = std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap();
|
||||
|
||||
Some(body_string)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@@ -528,9 +533,9 @@ pub unsafe fn dc_receive_imf(
|
||||
} else {
|
||||
free(txt_raw as *mut libc::c_void);
|
||||
txt_raw = 0 as *mut libc::c_char;
|
||||
insert_msg_id = sql::get_rowid(
|
||||
insert_msg_id = sql::get_rowid_with_conn(
|
||||
context,
|
||||
&context.sql,
|
||||
conn,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
@@ -739,19 +744,25 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed {
|
||||
let param = dc_param_new();
|
||||
let server_folder_c = to_cstring(server_folder.as_ref());
|
||||
dc_param_set(
|
||||
param,
|
||||
'Z' as i32,
|
||||
to_cstring(server_folder.as_ref()).as_ptr(),
|
||||
DC_PARAM_SERVER_FOLDER as i32,
|
||||
server_folder_c,
|
||||
);
|
||||
free(server_folder_c as *mut _);
|
||||
dc_param_set_int(
|
||||
param,
|
||||
DC_PARAM_SERVER_UID as i32,
|
||||
server_uid as i32,
|
||||
);
|
||||
dc_param_set_int(param, 'z' as i32, server_uid as i32);
|
||||
if 0 != mime_parser.is_send_by_messenger
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mvbox_move")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
dc_param_set_int(param, 'M' as i32, 1);
|
||||
dc_param_set_int(param, DC_PARAM_ALSO_MOVE as i32, 1);
|
||||
}
|
||||
dc_job_add(context, 120, 0, (*param).packed, 0);
|
||||
dc_param_unref(param);
|
||||
@@ -827,6 +838,14 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"received message {} has Message-Id: {}",
|
||||
server_uid,
|
||||
to_string(rfc724_mid)
|
||||
);
|
||||
|
||||
free(rfc724_mid as *mut libc::c_void);
|
||||
free(mime_in_reply_to as *mut libc::c_void);
|
||||
free(mime_references as *mut libc::c_void);
|
||||
@@ -884,7 +903,7 @@ unsafe fn calc_timestamps(
|
||||
}
|
||||
|
||||
/* the function tries extracts the group-id from the message and returns the
|
||||
corresponding chat_id. If the chat_id is not existant, it is created.
|
||||
corresponding chat_id. If the chat_id is not existent, it is created.
|
||||
If the message contains groups commands (name, profile image, changed members),
|
||||
they are executed as well.
|
||||
|
||||
@@ -1210,7 +1229,7 @@ unsafe fn create_or_lookup_group(
|
||||
if (*part).type_0 == 20 {
|
||||
grpimage = dc_param_get(
|
||||
(*part).param,
|
||||
'f' as i32,
|
||||
DC_PARAM_FILE as i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
ok = 1
|
||||
@@ -1231,7 +1250,11 @@ unsafe fn create_or_lookup_group(
|
||||
},
|
||||
);
|
||||
dc_chat_load_from_db(chat, chat_id);
|
||||
dc_param_set((*chat).param, 'i' as i32, grpimage);
|
||||
dc_param_set(
|
||||
(*chat).param,
|
||||
DC_PARAM_PROFILE_IMAGE as i32,
|
||||
grpimage,
|
||||
);
|
||||
dc_chat_update_param(chat);
|
||||
dc_chat_unref(chat);
|
||||
free(grpimage as *mut libc::c_void);
|
||||
@@ -1249,7 +1272,8 @@ unsafe fn create_or_lookup_group(
|
||||
&context.sql,
|
||||
"DELETE FROM chats_contacts WHERE chat_id=?;",
|
||||
params![chat_id as i32],
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
if skip.is_null() || !dc_addr_cmp(&self_addr, as_str(skip)) {
|
||||
dc_add_to_chat_contacts_table(context, chat_id, 1);
|
||||
}
|
||||
@@ -1375,7 +1399,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
),
|
||||
params![],
|
||||
|row| {
|
||||
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
|
||||
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default()))
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1397,7 +1421,7 @@ unsafe fn create_or_lookup_adhoc_group(
|
||||
/* we do not check if the message is a reply to another group, this may result in
|
||||
chats with unclear member list. instead we create a new group in the following lines ... */
|
||||
/* create a new ad-hoc group
|
||||
- there is no need to check if this group exists; otherwise we would have catched it above */
|
||||
- there is no need to check if this group exists; otherwise we would have caught it above */
|
||||
grpid = create_adhoc_grp_id(context, member_ids);
|
||||
if !grpid.is_null() {
|
||||
if !mime_parser.subject.is_null()
|
||||
@@ -1477,7 +1501,7 @@ fn create_group_record(
|
||||
unsafe fn create_adhoc_grp_id(context: &Context, member_ids: *mut dc_array_t) -> *mut libc::c_char {
|
||||
/* algorithm:
|
||||
- sort normalized, lowercased, e-mail addresses alphabetically
|
||||
- put all e-mail addresses into a single string, separate the addresss by a single comma
|
||||
- put all e-mail addresses into a single string, separate the address by a single comma
|
||||
- sha-256 this string (without possibly terminating null-characters)
|
||||
- encode the first 64 bits of the sha-256 output as lowercase hex (results in 16 characters from the set [0-9a-f])
|
||||
*/
|
||||
@@ -1518,9 +1542,7 @@ fn hex_hash(s: impl AsRef<str>) -> *const libc::c_char {
|
||||
let bytes = s.as_ref().as_bytes();
|
||||
let result = Sha256::digest(bytes);
|
||||
let result_hex = hex::encode(&result[..8]);
|
||||
let result_cstring = to_cstring(result_hex);
|
||||
|
||||
unsafe { strdup(result_cstring.as_ptr()) }
|
||||
unsafe { to_cstring(result_hex) as *const _ }
|
||||
}
|
||||
|
||||
unsafe fn search_chat_ids_by_contact_ids(
|
||||
@@ -1604,8 +1626,7 @@ unsafe fn check_verified_properties(
|
||||
let contact = dc_contact_new(context);
|
||||
|
||||
let verify_fail = |reason: String| {
|
||||
*failure_reason =
|
||||
strdup(to_cstring(format!("{}. See \"Info\" for details.", reason)).as_ptr());
|
||||
*failure_reason = to_cstring(format!("{}. See \"Info\" for details.", reason));
|
||||
warn!(context, 0, "{}", reason);
|
||||
};
|
||||
|
||||
@@ -1651,68 +1672,61 @@ unsafe fn check_verified_properties(
|
||||
let to_ids_str = to_string(to_ids_str_c);
|
||||
free(to_ids_str_c as *mut libc::c_void);
|
||||
|
||||
let ok = context
|
||||
.sql
|
||||
.query_map(
|
||||
format!(
|
||||
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
|
||||
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
|
||||
&to_ids_str,
|
||||
),
|
||||
params![],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|
||||
|rows| {
|
||||
for row in rows {
|
||||
let (to_addr, mut is_verified) = row?;
|
||||
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
|
||||
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr)
|
||||
&& peerstate.is_some()
|
||||
{
|
||||
let peerstate = peerstate.as_mut().unwrap();
|
||||
let rows = context.sql.query_map(
|
||||
format!(
|
||||
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
|
||||
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
|
||||
&to_ids_str,
|
||||
),
|
||||
params![],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|
||||
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
);
|
||||
|
||||
// if we're here, we know the gossip key is verified:
|
||||
// - use the gossip-key as verified-key if there is no verified-key
|
||||
// - OR if the verified-key does not match public-key or gossip-key
|
||||
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
|
||||
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
|
||||
if 0 == is_verified
|
||||
|| peerstate.verified_key_fingerprint
|
||||
!= peerstate.public_key_fingerprint
|
||||
&& peerstate.verified_key_fingerprint
|
||||
!= peerstate.gossip_key_fingerprint
|
||||
{
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"{} has verfied {}.",
|
||||
as_str((*contact).addr),
|
||||
to_addr,
|
||||
);
|
||||
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||
if let Some(fp) = fp {
|
||||
peerstate.set_verified(0, &fp, 2);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
is_verified = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 == is_verified {
|
||||
verify_fail(format!(
|
||||
"{} is not a member of this verified group",
|
||||
to_addr
|
||||
));
|
||||
cleanup();
|
||||
return Err(failure::format_err!("not a valid memember").into());
|
||||
}
|
||||
if rows.is_err() {
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
|
||||
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
|
||||
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
|
||||
let peerstate = peerstate.as_mut().unwrap();
|
||||
|
||||
// if we're here, we know the gossip key is verified:
|
||||
// - use the gossip-key as verified-key if there is no verified-key
|
||||
// - OR if the verified-key does not match public-key or gossip-key
|
||||
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
|
||||
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
|
||||
if 0 == is_verified
|
||||
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
|
||||
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
|
||||
{
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"{} has verfied {}.",
|
||||
as_str((*contact).addr),
|
||||
to_addr,
|
||||
);
|
||||
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||
if let Some(fp) = fp {
|
||||
peerstate.set_verified(0, &fp, 2);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
is_verified = 1;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.is_ok(); // TODO: Better default
|
||||
}
|
||||
}
|
||||
if 0 == is_verified {
|
||||
verify_fail(format!(
|
||||
"{} is not a member of this verified group",
|
||||
to_addr
|
||||
));
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
ok as libc::c_int
|
||||
1
|
||||
}
|
||||
|
||||
unsafe fn set_better_msg(mime_parser: &dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
|
||||
|
||||
@@ -62,7 +62,7 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
free(group_name_urlencoded as *mut libc::c_void);
|
||||
|
||||
if let Some(qr) = qr {
|
||||
strdup(to_cstring(qr).as_ptr())
|
||||
to_cstring(qr)
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
@@ -267,23 +267,23 @@ unsafe fn send_handshake_msg(
|
||||
step,
|
||||
);
|
||||
(*msg).hidden = 1i32;
|
||||
dc_param_set_int((*msg).param, 'S' as i32, 7i32);
|
||||
dc_param_set((*msg).param, 'E' as i32, step);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_CMD as i32, 7);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG as i32, step);
|
||||
if !param2.is_null() {
|
||||
dc_param_set((*msg).param, 'F' as i32, param2);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG2 as i32, param2);
|
||||
}
|
||||
if !fingerprint.is_null() {
|
||||
dc_param_set((*msg).param, 'G' as i32, fingerprint);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG3 as i32, fingerprint);
|
||||
}
|
||||
if !grpid.is_null() {
|
||||
dc_param_set((*msg).param, 'H' as i32, grpid);
|
||||
dc_param_set((*msg).param, DC_PARAM_CMD_ARG4 as i32, grpid);
|
||||
}
|
||||
if strcmp(step, b"vg-request\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
|| strcmp(step, b"vc-request\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
{
|
||||
dc_param_set_int((*msg).param, 'u' as i32, 1i32);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_FORCE_PLAINTEXT as i32, 1);
|
||||
} else {
|
||||
dc_param_set_int((*msg).param, 'c' as i32, 1i32);
|
||||
dc_param_set_int((*msg).param, DC_PARAM_GUARANTEE_E2EE as i32, 1);
|
||||
}
|
||||
dc_send_msg(context, contact_chat_id, msg);
|
||||
dc_msg_unref(msg);
|
||||
@@ -939,15 +939,15 @@ pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate)
|
||||
&mut contact_chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
|
||||
let c_addr_ptr = if peerstate.addr.is_some() {
|
||||
c_addr.as_ptr()
|
||||
let c_addr_ptr = if let Some(ref addr) = peerstate.addr {
|
||||
to_cstring(addr)
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
};
|
||||
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
|
||||
dc_add_device_msg(context, contact_chat_id, msg);
|
||||
free(msg as *mut libc::c_void);
|
||||
free(c_addr_ptr as *mut _);
|
||||
context.call_cb(
|
||||
Event::CHAT_MODIFIED,
|
||||
contact_chat_id as uintptr_t,
|
||||
|
||||
@@ -225,7 +225,8 @@ unsafe fn dc_simplify_simplify_plain_text(
|
||||
pending_linebreaks -= 1
|
||||
}
|
||||
}
|
||||
ret += &to_string(line);
|
||||
// the incoming message might contain invalid UTF8
|
||||
ret += &to_string_lossy(line);
|
||||
content_lines_added += 1;
|
||||
pending_linebreaks = 1i32
|
||||
}
|
||||
@@ -238,7 +239,7 @@ unsafe fn dc_simplify_simplify_plain_text(
|
||||
}
|
||||
dc_free_splitted_lines(lines);
|
||||
|
||||
strdup(to_cstring(ret).as_ptr())
|
||||
to_cstring(ret)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +262,7 @@ unsafe fn is_quoted_headline(buf: *const libc::c_char) -> bool {
|
||||
/* This function may be called for the line _directly_ before a quote.
|
||||
The function checks if the line contains sth. like "On 01.02.2016, xy@z wrote:" in various languages.
|
||||
- Currently, we simply check if the last character is a ':'.
|
||||
- Checking for the existance of an email address may fail (headlines may show the user's name instead of the address) */
|
||||
- Checking for the existence of an email address may fail (headlines may show the user's name instead of the address) */
|
||||
let buf_len: libc::c_int = strlen(buf) as libc::c_int;
|
||||
if buf_len > 80i32 {
|
||||
return false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
|
||||
use charset::Charset;
|
||||
use mmime::mailmime_decode::*;
|
||||
@@ -689,10 +689,9 @@ pub unsafe fn dc_decode_ext_header(to_decode: *const libc::c_char) -> *mut libc:
|
||||
std::slice::from_raw_parts(decoded as *const u8, strlen(decoded));
|
||||
|
||||
let (res, _, _) = encoding.decode(data);
|
||||
free(decoded as *mut libc::c_void);
|
||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
||||
|
||||
decoded = strdup(res_c.as_ptr());
|
||||
free(decoded as *mut _);
|
||||
let r = std::ffi::CString::new(res.as_bytes()).unwrap();
|
||||
decoded = dc_strdup(r.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -712,7 +711,8 @@ unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
|
||||
|
||||
let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur));
|
||||
let raw = to_cstring(format!("={}", &hex::encode_upper(bytes)[..2]));
|
||||
libc::memcpy(target as *mut _, raw.as_ptr() as *const _, 4);
|
||||
libc::memcpy(target as *mut _, raw as *const _, 4);
|
||||
free(raw as *mut libc::c_void);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::sql;
|
||||
use crate::x::strdup;
|
||||
|
||||
// Token namespaces
|
||||
pub type dc_tokennamespc_t = usize;
|
||||
@@ -34,16 +33,16 @@ pub fn dc_token_lookup(
|
||||
namespc: dc_tokennamespc_t,
|
||||
foreign_id: u32,
|
||||
) -> *mut libc::c_char {
|
||||
if let Some(token) = context.sql.query_row_col::<_, String>(
|
||||
context,
|
||||
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
|
||||
params![namespc as i32, foreign_id as i32],
|
||||
0,
|
||||
) {
|
||||
unsafe { strdup(to_cstring(token).as_ptr()) }
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.query_row_col::<_, String>(
|
||||
context,
|
||||
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
|
||||
params![namespc as i32, foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.map(|s| unsafe { to_cstring(s) })
|
||||
.unwrap_or_else(|| std::ptr::null_mut())
|
||||
}
|
||||
|
||||
pub fn dc_token_exists(
|
||||
|
||||
150
src/dc_tools.rs
150
src/dc_tools.rs
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs;
|
||||
use std::time::SystemTime;
|
||||
|
||||
@@ -176,14 +177,14 @@ pub unsafe fn dc_trim(buf: *mut libc::c_char) {
|
||||
|
||||
/* the result must be free()'d */
|
||||
pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char {
|
||||
let raw = to_cstring(to_string(in_0).to_lowercase());
|
||||
strdup(raw.as_ptr())
|
||||
to_cstring(to_string(in_0).to_lowercase())
|
||||
}
|
||||
|
||||
pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) {
|
||||
let raw = to_cstring(to_string(in_0).to_lowercase());
|
||||
assert_eq!(strlen(in_0), strlen(raw.as_ptr()));
|
||||
memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0));
|
||||
assert_eq!(strlen(in_0), strlen(raw));
|
||||
memcpy(in_0 as *mut _, raw as *const _, strlen(in_0));
|
||||
free(raw as *mut _);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_str_contains(
|
||||
@@ -231,7 +232,7 @@ pub unsafe fn dc_binary_to_uc_hex(buf: *const uint8_t, bytes: size_t) -> *mut li
|
||||
|
||||
let buf = std::slice::from_raw_parts(buf, bytes);
|
||||
let raw = hex::encode_upper(buf);
|
||||
strdup(to_cstring(raw).as_ptr())
|
||||
to_cstring(raw)
|
||||
}
|
||||
|
||||
/* remove all \r characters from string */
|
||||
@@ -527,7 +528,7 @@ pub unsafe fn dc_str_from_clist(
|
||||
}
|
||||
}
|
||||
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_str_to_clist(
|
||||
@@ -563,7 +564,7 @@ pub unsafe fn dc_str_to_color(str: *const libc::c_char) -> libc::c_int {
|
||||
/* the colors must fulfill some criterions as:
|
||||
- contrast to black and to white
|
||||
- work as a text-color
|
||||
- being noticable on a typical map
|
||||
- being noticeable on a typical map
|
||||
- harmonize together while being different enough
|
||||
(therefore, we cannot just use random rgb colors :) */
|
||||
static mut colors: [uint32_t; 16] = [
|
||||
@@ -669,7 +670,7 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
||||
/* the return value must be free()'d */
|
||||
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
|
||||
let res = dc_timestamp_to_str_safe(wanted);
|
||||
strdup(to_cstring(res).as_ptr())
|
||||
to_cstring(res)
|
||||
}
|
||||
|
||||
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
|
||||
@@ -1077,40 +1078,28 @@ pub unsafe fn dc_get_abs_path(
|
||||
context: &Context,
|
||||
pathNfilename: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
let current_block: u64;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut pathNfilename_abs: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !pathNfilename.is_null() {
|
||||
pathNfilename_abs = dc_strdup(pathNfilename);
|
||||
if strncmp(
|
||||
pathNfilename_abs,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
8,
|
||||
) == 0i32
|
||||
{
|
||||
if !context.has_blobdir() {
|
||||
current_block = 3805228753452640762;
|
||||
} else {
|
||||
dc_str_replace(
|
||||
&mut pathNfilename_abs,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
context.get_blobdir(),
|
||||
);
|
||||
current_block = 6937071982253665452;
|
||||
}
|
||||
} else {
|
||||
current_block = 6937071982253665452;
|
||||
}
|
||||
match current_block {
|
||||
3805228753452640762 => {}
|
||||
_ => success = 1i32,
|
||||
}
|
||||
}
|
||||
if 0 == success {
|
||||
free(pathNfilename_abs as *mut libc::c_void);
|
||||
pathNfilename_abs = 0 as *mut libc::c_char
|
||||
if pathNfilename.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
let starts = strncmp(
|
||||
pathNfilename,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
8,
|
||||
) == 0i32;
|
||||
|
||||
if starts && !context.has_blobdir() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
let mut pathNfilename_abs: *mut libc::c_char = dc_strdup(pathNfilename);
|
||||
if starts && context.has_blobdir() {
|
||||
dc_str_replace(
|
||||
&mut pathNfilename_abs,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
context.get_blobdir(),
|
||||
);
|
||||
}
|
||||
pathNfilename_abs
|
||||
}
|
||||
|
||||
@@ -1254,8 +1243,12 @@ pub unsafe fn dc_write_file(
|
||||
}
|
||||
|
||||
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
let pathNfilename_abs = unsafe {
|
||||
let n = to_cstring(pathNfilename.as_ref());
|
||||
let res = dc_get_abs_path(context, n);
|
||||
free(n as *mut _);
|
||||
res
|
||||
};
|
||||
if pathNfilename_abs.is_null() {
|
||||
return false;
|
||||
}
|
||||
@@ -1299,8 +1292,13 @@ pub unsafe fn dc_read_file(
|
||||
}
|
||||
|
||||
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
|
||||
let pathNfilename_abs =
|
||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
||||
let pathNfilename_abs = unsafe {
|
||||
let n = to_cstring(pathNfilename.as_ref());
|
||||
let p = dc_get_abs_path(context, n);
|
||||
free(n as *mut _);
|
||||
p
|
||||
};
|
||||
|
||||
if pathNfilename_abs.is_null() {
|
||||
return None;
|
||||
}
|
||||
@@ -1506,20 +1504,20 @@ pub trait OsStrExt {
|
||||
///
|
||||
/// On windows when the string contains invalid Unicode
|
||||
/// `[Err]([CStringError::NotUnicode])` is returned.
|
||||
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError>;
|
||||
fn to_c_string(&self) -> Result<CString, CStringError>;
|
||||
}
|
||||
|
||||
impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError> {
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
std::ffi::CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
|
||||
CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn to_c_string(&self) -> Result<std::ffi::CString, CStringError> {
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
os_str_to_c_string_unicode(&self)
|
||||
}
|
||||
}
|
||||
@@ -1528,29 +1526,57 @@ impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
||||
#[allow(dead_code)]
|
||||
fn os_str_to_c_string_unicode(
|
||||
os_str: &dyn AsRef<std::ffi::OsStr>,
|
||||
) -> Result<std::ffi::CString, CStringError> {
|
||||
) -> Result<CString, CStringError> {
|
||||
match os_str.as_ref().to_str() {
|
||||
Some(val) => std::ffi::CString::new(val.as_bytes()).map_err(|err| match err {
|
||||
Some(val) => CString::new(val.as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
}),
|
||||
None => Err(CStringError::NotUnicode),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_cstring<S: AsRef<str>>(s: S) -> std::ffi::CString {
|
||||
std::ffi::CString::new(s.as_ref()).unwrap()
|
||||
/// Needs to free the result after use!
|
||||
pub unsafe fn to_cstring<S: AsRef<str>>(s: S) -> *mut libc::c_char {
|
||||
let cstr = CString::new(s.as_ref()).expect("invalid string converted");
|
||||
dc_strdup(cstr.as_ref().as_ptr())
|
||||
}
|
||||
|
||||
pub fn to_string(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap().to_string() }
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_str().map(|s| s.to_string()).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Non utf8 string: '{:?}' ({:?})",
|
||||
cstr.to_string_lossy(),
|
||||
err
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_string_lossy(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|_| cstr.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
pub fn as_str<'a>(s: *const libc::c_char) -> &'a str {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
unsafe { std::ffi::CStr::from_ptr(s).to_str().unwrap() }
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_str().unwrap_or_else(|err| {
|
||||
panic!("Non utf8 string: '{:?}' ({:?})", cstr.to_bytes(), err);
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert a C `*char` pointer to a [std::path::Path] slice.
|
||||
@@ -1582,7 +1608,7 @@ pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
as_path_unicode(s)
|
||||
}
|
||||
|
||||
// Implmentation for as_path() on Windows.
|
||||
// Implementation for as_path() on Windows.
|
||||
//
|
||||
// Having this as a separate function means it can be tested on unix
|
||||
// too.
|
||||
@@ -1981,7 +2007,7 @@ mod tests {
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
std::ffi::CString::new("/some/valid/utf8").unwrap()
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2006,7 +2032,7 @@ mod tests {
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
std::ffi::CString::new("/some/valid/utf8").unwrap()
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2015,7 +2041,7 @@ mod tests {
|
||||
let some_str = std::ffi::OsString::from("foo");
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_str).unwrap(),
|
||||
std::ffi::CString::new("foo").unwrap()
|
||||
CString::new("foo").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2025,7 +2051,7 @@ mod tests {
|
||||
let some_path = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_path).unwrap(),
|
||||
std::ffi::CString::new("/some/path").unwrap()
|
||||
CString::new("/some/path").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2040,15 +2066,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_as_path() {
|
||||
let some_path = std::ffi::CString::new("/some/path").unwrap();
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_path_unicode_fn() {
|
||||
let some_path = std::ffi::CString::new("/some/path").unwrap();
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"))
|
||||
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"));
|
||||
}
|
||||
}
|
||||
|
||||
254
src/imap.rs
254
src/imap.rs
@@ -1,4 +1,3 @@
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||
use std::time::{Duration, SystemTime};
|
||||
@@ -6,9 +5,10 @@ use std::time::{Duration, SystemTime};
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_loginparam::*;
|
||||
use crate::dc_tools::as_str;
|
||||
use crate::dc_tools::{as_str, to_cstring};
|
||||
use crate::oauth2::dc_get_oauth2_access_token;
|
||||
use crate::types::*;
|
||||
use crate::x::free;
|
||||
|
||||
pub const DC_IMAP_SEEN: usize = 0x0001;
|
||||
pub const DC_REGENERATE: usize = 0x01;
|
||||
@@ -32,7 +32,8 @@ pub struct Imap {
|
||||
precheck_imf: dc_precheck_imf_t,
|
||||
receive_imf: dc_receive_imf_t,
|
||||
|
||||
session: Arc<Mutex<(Option<Session>, Option<net::TcpStream>)>>,
|
||||
session: Arc<Mutex<Option<Session>>>,
|
||||
stream: Arc<RwLock<Option<net::TcpStream>>>,
|
||||
connected: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
@@ -350,7 +351,8 @@ impl Imap {
|
||||
receive_imf: dc_receive_imf_t,
|
||||
) -> Self {
|
||||
Imap {
|
||||
session: Arc::new(Mutex::new((None, None))),
|
||||
session: Arc::new(Mutex::new(None)),
|
||||
stream: Arc::new(RwLock::new(None)),
|
||||
config: Arc::new(RwLock::new(ImapConfig::default())),
|
||||
watch: Arc::new((Mutex::new(false), Condvar::new())),
|
||||
get_config,
|
||||
@@ -369,18 +371,18 @@ impl Imap {
|
||||
self.config.read().unwrap().should_reconnect
|
||||
}
|
||||
|
||||
fn setup_handle_if_needed(&self, context: &Context) -> libc::c_int {
|
||||
fn setup_handle_if_needed(&self, context: &Context) -> bool {
|
||||
if self.config.read().unwrap().imap_server.is_empty() {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.should_reconnect() {
|
||||
self.unsetup_handle(context);
|
||||
}
|
||||
|
||||
if self.is_connected() && self.session.lock().unwrap().1.is_some() {
|
||||
if self.is_connected() && self.stream.read().unwrap().is_some() {
|
||||
self.config.write().unwrap().should_reconnect = false;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
let server_flags = self.config.read().unwrap().server_flags;
|
||||
@@ -424,7 +426,7 @@ impl Imap {
|
||||
};
|
||||
client.authenticate("XOAUTH2", &auth)
|
||||
} else {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
client.login(imap_user, imap_pw)
|
||||
@@ -445,7 +447,7 @@ impl Imap {
|
||||
err
|
||||
);
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -453,29 +455,27 @@ impl Imap {
|
||||
|
||||
match login_res {
|
||||
Ok((session, stream)) => {
|
||||
*self.session.lock().unwrap() = (Some(session), Some(stream));
|
||||
1
|
||||
*self.session.lock().unwrap() = Some(session);
|
||||
*self.stream.write().unwrap() = Some(stream);
|
||||
true
|
||||
}
|
||||
Err((err, _)) => {
|
||||
log_event!(context, Event::ERROR_NETWORK, 0, "Cannot login ({})", err);
|
||||
self.unsetup_handle(context);
|
||||
|
||||
0
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unsetup_handle(&self, context: &Context) {
|
||||
let session = self.session.lock().unwrap().0.take();
|
||||
if session.is_some() {
|
||||
match session.unwrap().close() {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
eprintln!("failed to close connection: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
let stream = self.session.lock().unwrap().1.take();
|
||||
info!(context, 0, "IMAP unsetup_handle starts");
|
||||
|
||||
info!(
|
||||
context,
|
||||
0, "IMAP unsetup_handle step 1 (closing down stream)."
|
||||
);
|
||||
let stream = self.stream.write().unwrap().take();
|
||||
if stream.is_some() {
|
||||
match stream.unwrap().shutdown(net::Shutdown::Both) {
|
||||
Ok(_) => {}
|
||||
@@ -484,11 +484,24 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
}
|
||||
info!(
|
||||
context,
|
||||
0, "IMAP unsetup_handle step 2 (acquiring session.lock)"
|
||||
);
|
||||
let session = self.session.lock().unwrap().take();
|
||||
if session.is_some() {
|
||||
match session.unwrap().close() {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
eprintln!("failed to close connection: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cfg = self.config.write().unwrap();
|
||||
cfg.selected_folder = None;
|
||||
cfg.selected_mailbox = None;
|
||||
info!(context, 0, "IMAP disconnected.",);
|
||||
info!(context, 0, "IMAP unsetup_handle step 3 (clearing config).");
|
||||
self.config.write().unwrap().selected_folder = None;
|
||||
self.config.write().unwrap().selected_mailbox = None;
|
||||
info!(context, 0, "IMAP unsetup_handle step 4 (disconnected).",);
|
||||
}
|
||||
|
||||
fn free_connect_params(&self) {
|
||||
@@ -506,13 +519,13 @@ impl Imap {
|
||||
cfg.watch_folder = None;
|
||||
}
|
||||
|
||||
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> libc::c_int {
|
||||
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> bool {
|
||||
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.is_connected() {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -532,50 +545,55 @@ impl Imap {
|
||||
config.server_flags = server_flags;
|
||||
}
|
||||
|
||||
if self.setup_handle_if_needed(context) == 0 {
|
||||
if !self.setup_handle_if_needed(context) {
|
||||
self.free_connect_params();
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.session.lock().unwrap().0 {
|
||||
let teardown: bool;
|
||||
|
||||
match &mut *self.session.lock().unwrap() {
|
||||
Some(ref mut session) => {
|
||||
if let Ok(caps) = session.capabilities() {
|
||||
let can_idle = caps.has("IDLE");
|
||||
let has_xlist = caps.has("XLIST");
|
||||
|
||||
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
|
||||
s += " ";
|
||||
s += c;
|
||||
s
|
||||
});
|
||||
|
||||
log_event!(
|
||||
context,
|
||||
Event::IMAP_CONNECTED,
|
||||
0,
|
||||
"IMAP-LOGIN as {} ok",
|
||||
lp.mail_user,
|
||||
);
|
||||
info!(context, 0, "IMAP-capabilities:{}", caps_list);
|
||||
|
||||
let mut config = self.config.write().unwrap();
|
||||
config.can_idle = can_idle;
|
||||
config.has_xlist = has_xlist;
|
||||
*self.connected.lock().unwrap() = true;
|
||||
|
||||
1
|
||||
if !context.sql.is_open() {
|
||||
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
|
||||
teardown = true;
|
||||
} else {
|
||||
let can_idle = caps.has("IDLE");
|
||||
let has_xlist = caps.has("XLIST");
|
||||
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
|
||||
s += " ";
|
||||
s += c;
|
||||
s
|
||||
});
|
||||
log_event!(
|
||||
context,
|
||||
Event::IMAP_CONNECTED,
|
||||
0,
|
||||
"IMAP-LOGIN as {}, capabilities: {}",
|
||||
lp.mail_user,
|
||||
caps_list,
|
||||
);
|
||||
self.config.write().unwrap().can_idle = can_idle;
|
||||
self.config.write().unwrap().has_xlist = has_xlist;
|
||||
*self.connected.lock().unwrap() = true;
|
||||
teardown = false;
|
||||
}
|
||||
} else {
|
||||
self.unsetup_handle(context);
|
||||
self.free_connect_params();
|
||||
0
|
||||
teardown = true;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.unsetup_handle(context);
|
||||
self.free_connect_params();
|
||||
0
|
||||
teardown = true;
|
||||
}
|
||||
}
|
||||
if teardown {
|
||||
self.unsetup_handle(context);
|
||||
self.free_connect_params();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disconnect(&self, context: &Context) {
|
||||
@@ -591,7 +609,7 @@ impl Imap {
|
||||
}
|
||||
|
||||
pub fn fetch(&self, context: &Context) -> libc::c_int {
|
||||
if !self.is_connected() {
|
||||
if !self.is_connected() || !context.sql.is_open() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -615,7 +633,7 @@ impl Imap {
|
||||
}
|
||||
|
||||
fn select_folder<S: AsRef<str>>(&self, context: &Context, folder: Option<S>) -> usize {
|
||||
if self.session.lock().unwrap().0.is_none() {
|
||||
if self.session.lock().unwrap().is_none() {
|
||||
let mut cfg = self.config.write().unwrap();
|
||||
cfg.selected_folder = None;
|
||||
cfg.selected_folder_needs_expunge = false;
|
||||
@@ -639,7 +657,7 @@ impl Imap {
|
||||
|
||||
// A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see
|
||||
// https://tools.ietf.org/html/rfc3501#section-6.4.2
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.close() {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
@@ -655,7 +673,7 @@ impl Imap {
|
||||
|
||||
// select new folder
|
||||
if let Some(ref folder) = folder {
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.select(folder) {
|
||||
Ok(mailbox) => {
|
||||
let mut config = self.config.write().unwrap();
|
||||
@@ -688,17 +706,19 @@ impl Imap {
|
||||
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
|
||||
let key = format!("imap.mailbox.{}", folder.as_ref());
|
||||
let val1 = unsafe {
|
||||
(self.get_config)(
|
||||
context,
|
||||
CString::new(key).unwrap().as_ptr(),
|
||||
0 as *const libc::c_char,
|
||||
)
|
||||
let key_c = to_cstring(key);
|
||||
let val = (self.get_config)(context, key_c, 0 as *const libc::c_char);
|
||||
free(key_c as *mut _);
|
||||
val
|
||||
};
|
||||
if val1.is_null() {
|
||||
return (0, 0);
|
||||
}
|
||||
let entry = as_str(val1);
|
||||
|
||||
if entry.is_empty() {
|
||||
return (0, 0);
|
||||
}
|
||||
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
|
||||
let mut parts = entry.split(':');
|
||||
(
|
||||
@@ -761,7 +781,7 @@ impl Imap {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let list = if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
let list = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
// `FETCH <message sequence number> (UID)`
|
||||
let set = format!("{}", mailbox.exists);
|
||||
match session.fetch(set, PREFETCH_FLAGS) {
|
||||
@@ -805,7 +825,7 @@ impl Imap {
|
||||
let mut read_errors = 0;
|
||||
let mut new_last_seen_uid = 0;
|
||||
|
||||
let list = if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
let list = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
// fetch messages with larger UID than the last one seen
|
||||
// (`UID FETCH lastseenuid+1:*)`, see RFC 4549
|
||||
let set = format!("{}:*", last_seen_uid + 1);
|
||||
@@ -832,9 +852,11 @@ impl Imap {
|
||||
.message_id
|
||||
.expect("missing message id");
|
||||
|
||||
let message_id_c = CString::new(message_id).unwrap();
|
||||
if 0 == unsafe {
|
||||
(self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
|
||||
let message_id_c = to_cstring(message_id);
|
||||
let res = (self.precheck_imf)(context, message_id_c, folder.as_ref(), cur_uid);
|
||||
free(message_id_c as *mut _);
|
||||
res
|
||||
} {
|
||||
// check passed, go fetch the rest
|
||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||
@@ -903,11 +925,11 @@ impl Imap {
|
||||
let val = format!("{}:{}", uidvalidity, lastseenuid);
|
||||
|
||||
unsafe {
|
||||
(self.set_config)(
|
||||
context,
|
||||
CString::new(key).unwrap().as_ptr(),
|
||||
CString::new(val).unwrap().as_ptr(),
|
||||
)
|
||||
let key_c = to_cstring(key);
|
||||
let val_c = to_cstring(val);
|
||||
(self.set_config)(context, key_c, val_c);
|
||||
free(key_c as *mut _);
|
||||
free(val_c as *mut _);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -928,7 +950,7 @@ impl Imap {
|
||||
|
||||
let set = format!("{}", server_uid);
|
||||
|
||||
let msgs = if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
let msgs = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_fetch(set, BODY_FLAGS) {
|
||||
Ok(msgs) => msgs,
|
||||
Err(err) => {
|
||||
@@ -986,11 +1008,12 @@ impl Imap {
|
||||
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
|
||||
|
||||
if !is_deleted && msg.body().is_some() {
|
||||
let body = msg.body().unwrap();
|
||||
unsafe {
|
||||
(self.receive_imf)(
|
||||
context,
|
||||
msg.body().unwrap().as_ptr() as *const libc::c_char,
|
||||
msg.body().unwrap().len(),
|
||||
body.as_ptr() as *const libc::c_char,
|
||||
body.len(),
|
||||
folder.as_ref(),
|
||||
server_uid,
|
||||
flags as u32,
|
||||
@@ -1025,13 +1048,15 @@ impl Imap {
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let v = self.watch.clone();
|
||||
|
||||
info!(context, 0, "IMAP-IDLE SPAWNING");
|
||||
std::thread::spawn(move || {
|
||||
let &(ref lock, ref cvar) = &*v;
|
||||
if let Some(ref mut session) = session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *session.lock().unwrap() {
|
||||
let mut idle = match session.idle() {
|
||||
Ok(idle) => idle,
|
||||
Err(err) => {
|
||||
panic!("failed to setup idle: {:?}", err);
|
||||
eprintln!("failed to setup idle: {:?}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1139,7 +1164,7 @@ impl Imap {
|
||||
// check for new messages. fetch_from_single_folder() has the side-effect that messages
|
||||
// are also downloaded, however, typically this would take place in the FETCH command
|
||||
// following IDLE otherwise, so this seems okay here.
|
||||
if self.setup_handle_if_needed(context) != 0 {
|
||||
if self.setup_handle_if_needed(context) {
|
||||
if let Some(ref watch_folder) = self.config.read().unwrap().watch_folder {
|
||||
if 0 != self.fetch_from_single_folder(context, watch_folder) {
|
||||
do_fake_idle = false;
|
||||
@@ -1205,7 +1230,7 @@ impl Imap {
|
||||
folder.as_ref()
|
||||
);
|
||||
} else {
|
||||
let moved = if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_mv(&set, &dest_folder) {
|
||||
Ok(_) => {
|
||||
res = DC_SUCCESS;
|
||||
@@ -1230,7 +1255,7 @@ impl Imap {
|
||||
};
|
||||
|
||||
if !moved {
|
||||
let copied = if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
let copied = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_copy(&set, &dest_folder) {
|
||||
Ok(_) => true,
|
||||
Err(err) => {
|
||||
@@ -1275,7 +1300,7 @@ impl Imap {
|
||||
if server_uid == 0 {
|
||||
return 0;
|
||||
}
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
let set = format!("{}", server_uid);
|
||||
let query = format!("+FLAGS ({})", flag.as_ref());
|
||||
match session.uid_store(&set, &query) {
|
||||
@@ -1387,18 +1412,18 @@ impl Imap {
|
||||
.expect("just selected folder");
|
||||
|
||||
if can_create_flag {
|
||||
let fetched_msgs = if let Some(ref mut session) = self.session.lock().unwrap().0
|
||||
{
|
||||
match session.uid_fetch(set, FETCH_FLAGS) {
|
||||
Ok(res) => Some(res),
|
||||
Err(err) => {
|
||||
eprintln!("fetch error: {:?}", err);
|
||||
None
|
||||
let fetched_msgs =
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_fetch(set, FETCH_FLAGS) {
|
||||
Ok(res) => Some(res),
|
||||
Err(err) => {
|
||||
eprintln!("fetch error: {:?}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if let Some(msgs) = fetched_msgs {
|
||||
let flag_set = msgs
|
||||
@@ -1479,7 +1504,7 @@ impl Imap {
|
||||
);
|
||||
} else {
|
||||
let set = format!("{}", server_uid);
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_fetch(set, PREFETCH_FLAGS) {
|
||||
Ok(msgs) => {
|
||||
if msgs.is_empty()
|
||||
@@ -1561,7 +1586,7 @@ impl Imap {
|
||||
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
|
||||
info!(context, 0, "Creating MVBOX-folder \"DeltaChat\"...",);
|
||||
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.create("DeltaChat") {
|
||||
Ok(_) => {
|
||||
mvbox_folder = Some("DeltaChat".into());
|
||||
@@ -1597,18 +1622,25 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
context.sql.set_config_int(context, "folders_configured", 3);
|
||||
context
|
||||
.sql
|
||||
.set_config_int(context, "folders_configured", 3)
|
||||
.ok();
|
||||
if let Some(ref mvbox_folder) = mvbox_folder {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "configured_mvbox_folder", Some(mvbox_folder));
|
||||
.set_config(context, "configured_mvbox_folder", Some(mvbox_folder))
|
||||
.ok();
|
||||
}
|
||||
if let Some(ref sentbox_folder) = sentbox_folder {
|
||||
context.sql.set_config(
|
||||
context,
|
||||
"configured_sentbox_folder",
|
||||
Some(sentbox_folder.name()),
|
||||
);
|
||||
context
|
||||
.sql
|
||||
.set_config(
|
||||
context,
|
||||
"configured_sentbox_folder",
|
||||
Some(sentbox_folder.name()),
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1616,7 +1648,7 @@ impl Imap {
|
||||
&self,
|
||||
context: &Context,
|
||||
) -> Option<imap::types::ZeroCopy<Vec<imap::types::Name>>> {
|
||||
if let Some(ref mut session) = self.session.lock().unwrap().0 {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
// TODO: use xlist when available
|
||||
match session.list(Some(""), Some("*")) {
|
||||
Ok(list) => {
|
||||
|
||||
@@ -89,6 +89,9 @@ impl Key {
|
||||
}
|
||||
|
||||
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
|
||||
if 0 == bytes.len() {
|
||||
return None;
|
||||
}
|
||||
let res: Result<Key, _> = match key_type {
|
||||
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)).map(Into::into),
|
||||
KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes)).map(Into::into),
|
||||
|
||||
46
src/log.rs
46
src/log.rs
@@ -3,11 +3,14 @@ macro_rules! info {
|
||||
($ctx:expr, $data1:expr, $msg:expr) => {
|
||||
info!($ctx, $data1, $msg,)
|
||||
};
|
||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
|
||||
formatted_c.as_ptr() as libc::uintptr_t)
|
||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
|
||||
formatted_c as libc::uintptr_t);
|
||||
libc::free(formatted_c as *mut libc::c_void);
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -17,11 +20,14 @@ macro_rules! warn {
|
||||
warn!($ctx, $data1, $msg,)
|
||||
};
|
||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
|
||||
formatted_c.as_ptr() as libc::uintptr_t)
|
||||
};
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
|
||||
formatted_c as libc::uintptr_t);
|
||||
libc::free(formatted_c as *mut libc::c_void) ;
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
@@ -30,11 +36,14 @@ macro_rules! error {
|
||||
error!($ctx, $data1, $msg,)
|
||||
};
|
||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
|
||||
formatted_c.as_ptr() as libc::uintptr_t)
|
||||
};
|
||||
formatted_c as libc::uintptr_t);
|
||||
libc::free(formatted_c as *mut libc::c_void);
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
@@ -43,9 +52,12 @@ macro_rules! log_event {
|
||||
log_event!($ctx, $data1, $msg,)
|
||||
};
|
||||
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($event, $data1 as libc::uintptr_t,
|
||||
formatted_c.as_ptr() as libc::uintptr_t)
|
||||
};
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
let formatted = format!($msg, $($args),*);
|
||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||
$ctx.call_cb($event, $data1 as libc::uintptr_t,
|
||||
formatted_c as libc::uintptr_t);
|
||||
libc::free(formatted_c as *mut libc::c_void);
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -48,11 +48,17 @@ pub fn dc_get_oauth2_url(
|
||||
redirect_uri: impl AsRef<str>,
|
||||
) -> Option<String> {
|
||||
if let Some(oauth2) = Oauth2::from_address(addr) {
|
||||
context.sql.set_config(
|
||||
context,
|
||||
"oauth2_pending_redirect_uri",
|
||||
Some(redirect_uri.as_ref()),
|
||||
);
|
||||
if context
|
||||
.sql
|
||||
.set_config(
|
||||
context,
|
||||
"oauth2_pending_redirect_uri",
|
||||
Some(redirect_uri.as_ref()),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let oauth2_url = replace_in_uri(&oauth2.get_code, "$CLIENT_ID", &oauth2.client_id);
|
||||
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri.as_ref());
|
||||
|
||||
@@ -157,10 +163,12 @@ pub fn dc_get_oauth2_access_token(
|
||||
if let Some(ref token) = response.refresh_token {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_refresh_token", Some(token));
|
||||
.set_config(context, "oauth2_refresh_token", Some(token))
|
||||
.ok();
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_refresh_token_for", Some(code.as_ref()));
|
||||
.set_config(context, "oauth2_refresh_token_for", Some(code.as_ref()))
|
||||
.ok();
|
||||
}
|
||||
|
||||
// after that, save the access token.
|
||||
@@ -168,7 +176,8 @@ pub fn dc_get_oauth2_access_token(
|
||||
if let Some(ref token) = response.access_token {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_access_token", Some(token));
|
||||
.set_config(context, "oauth2_access_token", Some(token))
|
||||
.ok();
|
||||
let expires_in = response
|
||||
.expires_in
|
||||
// refresh a bet before
|
||||
@@ -176,12 +185,14 @@ pub fn dc_get_oauth2_access_token(
|
||||
.unwrap_or_else(|| 0);
|
||||
context
|
||||
.sql
|
||||
.set_config_int64(context, "oauth2_timestamp_expires", expires_in);
|
||||
.set_config_int64(context, "oauth2_timestamp_expires", expires_in)
|
||||
.ok();
|
||||
|
||||
if update_redirect_uri_on_success {
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()));
|
||||
.set_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()))
|
||||
.ok();
|
||||
}
|
||||
} else {
|
||||
warn!(context, 0, "Failed to find OAuth2 access token");
|
||||
|
||||
@@ -462,10 +462,12 @@ mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use crate::context::*;
|
||||
use crate::dc_tools::to_cstring;
|
||||
use crate::x::free;
|
||||
|
||||
#[test]
|
||||
fn test_peerstate_save_to_db() {
|
||||
@@ -520,16 +522,16 @@ mod tests {
|
||||
unsafe fn create_test_context() -> TestContext {
|
||||
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap();
|
||||
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
|
||||
assert_eq!(
|
||||
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
|
||||
dc_open(&mut ctx, dbfile, std::ptr::null()),
|
||||
1,
|
||||
"Failed to open {}",
|
||||
CStr::from_ptr(dbfile.as_ptr() as *const libc::c_char)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
CStr::from_ptr(dbfile as *const _).to_str().unwrap()
|
||||
);
|
||||
|
||||
free(dbfile as *mut _);
|
||||
|
||||
TestContext { ctx: ctx, dir: dir }
|
||||
}
|
||||
}
|
||||
|
||||
12
src/smtp.rs
12
src/smtp.rs
@@ -43,10 +43,10 @@ impl Smtp {
|
||||
}
|
||||
|
||||
/// Connect using the provided login params
|
||||
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> usize {
|
||||
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> bool {
|
||||
if self.is_connected() {
|
||||
warn!(context, 0, "SMTP already connected.");
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if lp.send_server.is_empty() || lp.send_port == 0 {
|
||||
@@ -61,7 +61,7 @@ impl Smtp {
|
||||
|
||||
if self.from.is_none() {
|
||||
// TODO: print error
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
let domain = &lp.send_server;
|
||||
@@ -82,7 +82,7 @@ impl Smtp {
|
||||
let send_pw = &lp.send_pw;
|
||||
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
|
||||
if access_token.is_none() {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
let user = &lp.send_user;
|
||||
|
||||
@@ -116,11 +116,11 @@ impl Smtp {
|
||||
"SMTP-LOGIN as {} ok",
|
||||
lp.send_user,
|
||||
);
|
||||
1
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, 0, "SMTP: failed to establish connection {:?}", err);
|
||||
0
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
182
src/sql.rs
182
src/sql.rs
@@ -1,7 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
|
||||
use thread_local_object::ThreadLocal;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
@@ -16,12 +17,14 @@ const DC_OPEN_READONLY: usize = 0x01;
|
||||
/// A wrapper around the underlying Sqlite3 object.
|
||||
pub struct Sql {
|
||||
pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>,
|
||||
in_use: Arc<ThreadLocal<String>>,
|
||||
}
|
||||
|
||||
impl Sql {
|
||||
pub fn new() -> Sql {
|
||||
Sql {
|
||||
pool: RwLock::new(None),
|
||||
in_use: Arc::new(ThreadLocal::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +34,7 @@ impl Sql {
|
||||
|
||||
pub fn close(&self, context: &Context) {
|
||||
let _ = self.pool.write().unwrap().take();
|
||||
self.in_use.remove();
|
||||
// drop closes the connection
|
||||
|
||||
info!(context, 0, "Database closed.");
|
||||
@@ -53,6 +57,7 @@ impl Sql {
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
{
|
||||
self.start_stmt(sql.to_string());
|
||||
self.with_conn(|conn| conn.execute(sql, params).map_err(Into::into))
|
||||
}
|
||||
|
||||
@@ -60,22 +65,25 @@ impl Sql {
|
||||
where
|
||||
G: FnOnce(&Connection) -> Result<T>,
|
||||
{
|
||||
match &*self.pool.read().unwrap() {
|
||||
let res = match &*self.pool.read().unwrap() {
|
||||
Some(pool) => {
|
||||
let conn = pool.get()?;
|
||||
g(&conn)
|
||||
}
|
||||
None => Err(Error::SqlNoConnection),
|
||||
}
|
||||
};
|
||||
self.in_use.remove();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn prepare<G, H>(&self, sql: &str, g: G) -> Result<H>
|
||||
where
|
||||
G: FnOnce(Statement<'_>) -> Result<H>,
|
||||
G: FnOnce(Statement<'_>, &Connection) -> Result<H>,
|
||||
{
|
||||
self.start_stmt(sql.to_string());
|
||||
self.with_conn(|conn| {
|
||||
let stmt = conn.prepare(sql)?;
|
||||
let res = g(stmt)?;
|
||||
let res = g(stmt, conn)?;
|
||||
Ok(res)
|
||||
})
|
||||
}
|
||||
@@ -84,6 +92,7 @@ impl Sql {
|
||||
where
|
||||
G: FnOnce(Statement<'_>, Statement<'_>, &Connection) -> Result<H>,
|
||||
{
|
||||
self.start_stmt(format!("{} - {}", sql1, sql2));
|
||||
self.with_conn(|conn| {
|
||||
let stmt1 = conn.prepare(sql1)?;
|
||||
let stmt2 = conn.prepare(sql2)?;
|
||||
@@ -109,8 +118,8 @@ impl Sql {
|
||||
F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>,
|
||||
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
|
||||
{
|
||||
self.start_stmt(sql.as_ref().to_string());
|
||||
self.with_conn(|conn| {
|
||||
eprintln!("query_map {}", sql.as_ref());
|
||||
let mut stmt = conn.prepare(sql.as_ref())?;
|
||||
let res = stmt.query_map(params, f)?;
|
||||
g(res)
|
||||
@@ -124,6 +133,7 @@ impl Sql {
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
{
|
||||
self.start_stmt(sql.to_string());
|
||||
self.with_conn(|conn| {
|
||||
let mut stmt = conn.prepare(sql)?;
|
||||
let res = stmt.exists(params)?;
|
||||
@@ -131,17 +141,19 @@ impl Sql {
|
||||
})
|
||||
}
|
||||
|
||||
/// Execute a query which is expected to return one row.
|
||||
pub fn query_row<T, P, F>(&self, sql: impl AsRef<str>, params: P, f: F) -> Result<T>
|
||||
where
|
||||
P: IntoIterator,
|
||||
P::Item: rusqlite::ToSql,
|
||||
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
|
||||
{
|
||||
self.start_stmt(sql.as_ref().to_string());
|
||||
self.with_conn(|conn| conn.query_row(sql.as_ref(), params, f).map_err(Into::into))
|
||||
}
|
||||
|
||||
pub fn table_exists(&self, name: impl AsRef<str>) -> bool {
|
||||
self.with_conn(|conn| Ok(table_exists(conn, name)))
|
||||
self.with_conn(|conn| table_exists(conn, name))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -173,7 +185,9 @@ impl Sql {
|
||||
}
|
||||
|
||||
/// Set private configuration options.
|
||||
/// Setting `None` deletes the value.
|
||||
///
|
||||
/// Setting `None` deletes the value. On failure an error message
|
||||
/// will already have been logged.
|
||||
pub fn set_config(
|
||||
&self,
|
||||
context: &Context,
|
||||
@@ -259,18 +273,27 @@ impl Sql {
|
||||
pub fn get_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
|
||||
self.get_config(context, key).and_then(|r| r.parse().ok())
|
||||
}
|
||||
|
||||
fn start_stmt(&self, stmt: impl AsRef<str>) {
|
||||
if let Some(query) = self.in_use.get_cloned() {
|
||||
let bt = backtrace::Backtrace::new();
|
||||
eprintln!("old query: {}", query);
|
||||
eprintln!("Connection is already used from this thread: {:?}", bt);
|
||||
panic!("Connection is already used from this thread");
|
||||
}
|
||||
|
||||
self.in_use.set(stmt.as_ref().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn table_exists(conn: &Connection, name: impl AsRef<str>) -> bool {
|
||||
fn table_exists(conn: &Connection, name: impl AsRef<str>) -> Result<bool> {
|
||||
let mut exists = false;
|
||||
conn.pragma(None, "table_info", &format!("{}", name.as_ref()), |_row| {
|
||||
// will only be executed if the info was found
|
||||
exists = true;
|
||||
Ok(())
|
||||
})
|
||||
.expect("bad sqlite state");
|
||||
|
||||
exists
|
||||
})?;
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
fn open(
|
||||
@@ -439,7 +462,7 @@ fn open(
|
||||
// cannot create the tables - maybe we cannot write?
|
||||
return Err(Error::SqlFailedToOpen);
|
||||
} else {
|
||||
sql.set_config_int(context, "dbversion", 0);
|
||||
sql.set_config_int(context, "dbversion", 0)?;
|
||||
}
|
||||
} else {
|
||||
exists_before_update = 1;
|
||||
@@ -464,7 +487,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 1;
|
||||
sql.set_config_int(context, "dbversion", 1);
|
||||
sql.set_config_int(context, "dbversion", 1)?;
|
||||
}
|
||||
if dbversion < 2 {
|
||||
sql.execute(
|
||||
@@ -472,7 +495,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 2;
|
||||
sql.set_config_int(context, "dbversion", 2);
|
||||
sql.set_config_int(context, "dbversion", 2)?;
|
||||
}
|
||||
if dbversion < 7 {
|
||||
sql.execute(
|
||||
@@ -486,7 +509,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 7;
|
||||
sql.set_config_int(context, "dbversion", 7);
|
||||
sql.set_config_int(context, "dbversion", 7)?;
|
||||
}
|
||||
if dbversion < 10 {
|
||||
sql.execute(
|
||||
@@ -504,7 +527,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 10;
|
||||
sql.set_config_int(context, "dbversion", 10);
|
||||
sql.set_config_int(context, "dbversion", 10)?;
|
||||
}
|
||||
if dbversion < 12 {
|
||||
sql.execute(
|
||||
@@ -516,7 +539,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 12;
|
||||
sql.set_config_int(context, "dbversion", 12);
|
||||
sql.set_config_int(context, "dbversion", 12)?;
|
||||
}
|
||||
if dbversion < 17 {
|
||||
sql.execute(
|
||||
@@ -530,7 +553,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("CREATE INDEX msgs_index5 ON msgs (starred);", params![])?;
|
||||
dbversion = 17;
|
||||
sql.set_config_int(context, "dbversion", 17);
|
||||
sql.set_config_int(context, "dbversion", 17)?;
|
||||
}
|
||||
if dbversion < 18 {
|
||||
sql.execute(
|
||||
@@ -539,7 +562,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("ALTER TABLE acpeerstates ADD COLUMN gossip_key;", params![])?;
|
||||
dbversion = 18;
|
||||
sql.set_config_int(context, "dbversion", 18);
|
||||
sql.set_config_int(context, "dbversion", 18)?;
|
||||
}
|
||||
if dbversion < 27 {
|
||||
sql.execute("DELETE FROM msgs WHERE chat_id=1 OR chat_id=2;", params![])?;
|
||||
@@ -556,7 +579,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 27;
|
||||
sql.set_config_int(context, "dbversion", 27);
|
||||
sql.set_config_int(context, "dbversion", 27)?;
|
||||
}
|
||||
if dbversion < 34 {
|
||||
sql.execute(
|
||||
@@ -585,7 +608,7 @@ fn open(
|
||||
)?;
|
||||
recalc_fingerprints = 1;
|
||||
dbversion = 34;
|
||||
sql.set_config_int(context, "dbversion", 34);
|
||||
sql.set_config_int(context, "dbversion", 34)?;
|
||||
}
|
||||
if dbversion < 39 {
|
||||
sql.execute(
|
||||
@@ -615,7 +638,7 @@ fn open(
|
||||
)?;
|
||||
}
|
||||
dbversion = 39;
|
||||
sql.set_config_int(context, "dbversion", 39);
|
||||
sql.set_config_int(context, "dbversion", 39)?;
|
||||
}
|
||||
if dbversion < 40 {
|
||||
sql.execute(
|
||||
@@ -623,22 +646,22 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 40;
|
||||
sql.set_config_int(context, "dbversion", 40);
|
||||
sql.set_config_int(context, "dbversion", 40)?;
|
||||
}
|
||||
if dbversion < 41 {
|
||||
update_file_paths = 1;
|
||||
dbversion = 41;
|
||||
sql.set_config_int(context, "dbversion", 41);
|
||||
sql.set_config_int(context, "dbversion", 41)?;
|
||||
}
|
||||
if dbversion < 42 {
|
||||
sql.execute("UPDATE msgs SET txt='' WHERE type!=10", params![])?;
|
||||
dbversion = 42;
|
||||
sql.set_config_int(context, "dbversion", 42);
|
||||
sql.set_config_int(context, "dbversion", 42)?;
|
||||
}
|
||||
if dbversion < 44 {
|
||||
sql.execute("ALTER TABLE msgs ADD COLUMN mime_headers TEXT;", params![])?;
|
||||
dbversion = 44;
|
||||
sql.set_config_int(context, "dbversion", 44);
|
||||
sql.set_config_int(context, "dbversion", 44)?;
|
||||
}
|
||||
if dbversion < 46 {
|
||||
sql.execute(
|
||||
@@ -650,7 +673,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 46;
|
||||
sql.set_config_int(context, "dbversion", 46);
|
||||
sql.set_config_int(context, "dbversion", 46)?;
|
||||
}
|
||||
if dbversion < 47 {
|
||||
info!(context, 0, "[migration] v47");
|
||||
@@ -659,7 +682,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 47;
|
||||
sql.set_config_int(context, "dbversion", 47);
|
||||
sql.set_config_int(context, "dbversion", 47)?;
|
||||
}
|
||||
if dbversion < 48 {
|
||||
info!(context, 0, "[migration] v48");
|
||||
@@ -673,7 +696,7 @@ fn open(
|
||||
assert_eq!(DC_MOVE_STATE_MOVING as libc::c_int, 3);
|
||||
|
||||
dbversion = 48;
|
||||
sql.set_config_int(context, "dbversion", 48);
|
||||
sql.set_config_int(context, "dbversion", 48)?;
|
||||
}
|
||||
if dbversion < 49 {
|
||||
info!(context, 0, "[migration] v49");
|
||||
@@ -682,15 +705,15 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 49;
|
||||
sql.set_config_int(context, "dbversion", 49);
|
||||
sql.set_config_int(context, "dbversion", 49)?;
|
||||
}
|
||||
if dbversion < 50 {
|
||||
info!(context, 0, "[migration] v50");
|
||||
if 0 != exists_before_update {
|
||||
sql.set_config_int(context, "show_emails", 2);
|
||||
sql.set_config_int(context, "show_emails", 2)?;
|
||||
}
|
||||
dbversion = 50;
|
||||
sql.set_config_int(context, "dbversion", 50);
|
||||
sql.set_config_int(context, "dbversion", 50)?;
|
||||
}
|
||||
if dbversion < 53 {
|
||||
info!(context, 0, "[migration] v53");
|
||||
@@ -723,7 +746,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
dbversion = 53;
|
||||
sql.set_config_int(context, "dbversion", 53);
|
||||
sql.set_config_int(context, "dbversion", 53)?;
|
||||
}
|
||||
if dbversion < 54 {
|
||||
info!(context, 0, "[migration] v54");
|
||||
@@ -733,7 +756,7 @@ fn open(
|
||||
)?;
|
||||
sql.execute("CREATE INDEX msgs_index6 ON msgs (location_id);", params![])?;
|
||||
dbversion = 54;
|
||||
sql.set_config_int(context, "dbversion", 54);
|
||||
sql.set_config_int(context, "dbversion", 54)?;
|
||||
}
|
||||
if dbversion < 55 {
|
||||
sql.execute(
|
||||
@@ -741,7 +764,7 @@ fn open(
|
||||
params![],
|
||||
)?;
|
||||
|
||||
sql.set_config_int(context, "dbversion", 55);
|
||||
sql.set_config_int(context, "dbversion", 55)?;
|
||||
}
|
||||
|
||||
if 0 != recalc_fingerprints {
|
||||
@@ -789,7 +812,7 @@ fn open(
|
||||
NO_PARAMS,
|
||||
)?;
|
||||
|
||||
sql.set_config(context, "backup_for", None);
|
||||
sql.set_config(context, "backup_for", None)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -841,10 +864,22 @@ pub fn get_rowid(
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
value: impl AsRef<str>,
|
||||
) -> u32 {
|
||||
sql.start_stmt("get rowid".to_string());
|
||||
sql.with_conn(|conn| Ok(get_rowid_with_conn(context, conn, table, field, value)))
|
||||
.unwrap_or_else(|_| 0)
|
||||
}
|
||||
|
||||
pub fn get_rowid_with_conn(
|
||||
context: &Context,
|
||||
conn: &Connection,
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
value: impl AsRef<str>,
|
||||
) -> u32 {
|
||||
// alternative to sqlite3_last_insert_rowid() which MUST NOT be used due to race conditions, see comment above.
|
||||
// the ORDER BY ensures, this function always returns the most recent id,
|
||||
// eg. if a Message-ID is splitted into different messages.
|
||||
// eg. if a Message-ID is split into different messages.
|
||||
let query = format!(
|
||||
"SELECT id FROM {} WHERE {}='{}' ORDER BY id DESC",
|
||||
table.as_ref(),
|
||||
@@ -852,7 +887,7 @@ pub fn get_rowid(
|
||||
value.as_ref()
|
||||
);
|
||||
|
||||
match sql.query_row(&query, NO_PARAMS, |row| row.get::<_, u32>(0)) {
|
||||
match conn.query_row(&query, NO_PARAMS, |row| row.get::<_, u32>(0)) {
|
||||
Ok(id) => id,
|
||||
Err(err) => {
|
||||
error!(
|
||||
@@ -863,7 +898,6 @@ pub fn get_rowid(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rowid2(
|
||||
context: &Context,
|
||||
sql: &Sql,
|
||||
@@ -873,6 +907,7 @@ pub fn get_rowid2(
|
||||
field2: impl AsRef<str>,
|
||||
value2: i32,
|
||||
) -> u32 {
|
||||
sql.start_stmt("get rowid2".to_string());
|
||||
sql.with_conn(|conn| {
|
||||
Ok(get_rowid2_with_conn(
|
||||
context, conn, table, field, value, field2, value2,
|
||||
@@ -972,31 +1007,36 @@ pub fn housekeeping(context: &Context) {
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name_c = to_cstring(name_f.to_string_lossy());
|
||||
let name_c = unsafe { to_cstring(name_f.to_string_lossy()) };
|
||||
|
||||
if unsafe {
|
||||
is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c.as_ptr())
|
||||
} || unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b".increation\x00" as *const u8 as *const libc::c_char,
|
||||
name_c.as_ptr(),
|
||||
)
|
||||
} || unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b".waveform\x00" as *const u8 as *const libc::c_char,
|
||||
name_c.as_ptr(),
|
||||
)
|
||||
} || unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
|
||||
name_c.as_ptr(),
|
||||
)
|
||||
} {
|
||||
if unsafe { is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c) }
|
||||
|| unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b".increation\x00" as *const u8 as *const libc::c_char,
|
||||
name_c,
|
||||
)
|
||||
}
|
||||
|| unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b".waveform\x00" as *const u8 as *const libc::c_char,
|
||||
name_c,
|
||||
)
|
||||
}
|
||||
|| unsafe {
|
||||
is_file_in_use(
|
||||
&mut files_in_use,
|
||||
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
|
||||
name_c,
|
||||
)
|
||||
}
|
||||
{
|
||||
unsafe { free(name_c as *mut _) };
|
||||
continue;
|
||||
}
|
||||
unsafe { free(name_c as *mut _) };
|
||||
|
||||
unreferenced_count += 1;
|
||||
|
||||
match std::fs::metadata(entry.path()) {
|
||||
@@ -1028,8 +1068,11 @@ pub fn housekeeping(context: &Context) {
|
||||
unreferenced_count,
|
||||
entry.file_name()
|
||||
);
|
||||
let path = to_cstring(entry.path().to_str().unwrap());
|
||||
unsafe { dc_delete_file(context, path.as_ptr()) };
|
||||
unsafe {
|
||||
let path = to_cstring(entry.path().to_str().unwrap());
|
||||
dc_delete_file(context, path);
|
||||
free(path as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -1087,14 +1130,16 @@ fn maybe_add_from_param(
|
||||
context
|
||||
.sql
|
||||
.query_row(query, NO_PARAMS, |row| {
|
||||
let v = to_cstring(row.get::<_, String>(0)?);
|
||||
unsafe {
|
||||
dc_param_set_packed(param, v.as_ptr() as *const libc::c_char);
|
||||
let file = dc_param_get(param, param_id, 0 as *const libc::c_char);
|
||||
let v = to_cstring(row.get::<_, String>(0)?);
|
||||
dc_param_set_packed(param, v as *const _);
|
||||
let file = dc_param_get(param, param_id, 0 as *const _);
|
||||
if !file.is_null() {
|
||||
maybe_add_file(files_in_use, as_str(file));
|
||||
free(file as *mut libc::c_void);
|
||||
}
|
||||
|
||||
free(v as *mut _);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
@@ -1128,7 +1173,6 @@ mod test {
|
||||
maybe_add_file(&mut files, "$BLOBDIR/world.txt");
|
||||
maybe_add_file(&mut files, "world2.txt");
|
||||
|
||||
println!("{:?}", files);
|
||||
assert!(unsafe {
|
||||
is_file_in_use(
|
||||
&mut files,
|
||||
|
||||
29
src/top_evil_rs.py
Executable file
29
src/top_evil_rs.py
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
filestats = []
|
||||
for fn in os.listdir():
|
||||
if fn.endswith(".rs"):
|
||||
s = open(fn).read()
|
||||
unsafe = s.count("unsafe")
|
||||
free = s.count("free(")
|
||||
gotoblocks = s.count("current_block =")
|
||||
filestats.append((fn, unsafe, free, gotoblocks))
|
||||
|
||||
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0
|
||||
|
||||
for fn, unsafe, free, gotoblocks in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
print("{0: <30} unsafe: {1: >3} free: {2: >3} goto-blocks: {3: >3}".format(fn, unsafe, free, gotoblocks))
|
||||
sum_unsafe += unsafe
|
||||
sum_free += free
|
||||
sum_gotoblocks += gotoblocks
|
||||
|
||||
|
||||
print()
|
||||
print("total unsafe:", sum_unsafe)
|
||||
print("total free:", sum_free)
|
||||
print("total gotoblocks:", sum_gotoblocks)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
|
||||
use mmime::mailimf_types::*;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
@@ -175,7 +174,7 @@ unsafe fn stress_functions(context: &Context) {
|
||||
"content"
|
||||
);
|
||||
|
||||
free(buf);
|
||||
free(buf as *mut _);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
@@ -691,7 +690,7 @@ fn test_encryption_decryption() {
|
||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
let ctext_signed_bytes = ctext.len();
|
||||
let ctext_signed = CString::new(ctext).unwrap();
|
||||
let ctext_signed = to_cstring(ctext);
|
||||
|
||||
let ctext = dc_pgp_pk_encrypt(
|
||||
original_text as *const libc::c_void,
|
||||
@@ -704,7 +703,7 @@ fn test_encryption_decryption() {
|
||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
let ctext_unsigned_bytes = ctext.len();
|
||||
let ctext_unsigned = CString::new(ctext).unwrap();
|
||||
let ctext_unsigned = to_cstring(ctext);
|
||||
|
||||
let mut keyring = Keyring::default();
|
||||
keyring.add_owned(private_key);
|
||||
@@ -718,7 +717,7 @@ fn test_encryption_decryption() {
|
||||
let mut valid_signatures: HashSet<String> = Default::default();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
@@ -733,7 +732,7 @@ fn test_encryption_decryption() {
|
||||
|
||||
let empty_keyring = Keyring::default();
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&empty_keyring,
|
||||
@@ -746,7 +745,7 @@ fn test_encryption_decryption() {
|
||||
valid_signatures.clear();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
@@ -761,7 +760,7 @@ fn test_encryption_decryption() {
|
||||
public_keyring2.add_ref(&public_key);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
@@ -774,13 +773,15 @@ fn test_encryption_decryption() {
|
||||
valid_signatures.clear();
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_unsigned.as_ptr() as *const _,
|
||||
ctext_unsigned as *const _,
|
||||
ctext_unsigned_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
Some(&mut valid_signatures),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
free(ctext_unsigned as *mut _);
|
||||
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
||||
|
||||
valid_signatures.clear();
|
||||
@@ -791,13 +792,15 @@ fn test_encryption_decryption() {
|
||||
public_keyring.add_ref(&public_key);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
free(ctext_signed as *mut _);
|
||||
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
||||
}
|
||||
}
|
||||
@@ -820,14 +823,14 @@ struct TestContext {
|
||||
unsafe fn create_test_context() -> TestContext {
|
||||
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = CString::new(dir.path().join("db.sqlite").to_str().unwrap()).unwrap();
|
||||
let dbfile = to_cstring(dir.path().join("db.sqlite").to_str().unwrap());
|
||||
assert_eq!(
|
||||
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
|
||||
dc_open(&mut ctx, dbfile, std::ptr::null()),
|
||||
1,
|
||||
"Failed to open {}",
|
||||
as_str(dbfile.as_ptr() as *const libc::c_char)
|
||||
as_str(dbfile as *const libc::c_char)
|
||||
);
|
||||
|
||||
free(dbfile as *mut _);
|
||||
TestContext { ctx: ctx, dir: dir }
|
||||
}
|
||||
|
||||
@@ -952,24 +955,29 @@ fn test_stress_tests() {
|
||||
fn test_get_contacts() {
|
||||
unsafe {
|
||||
let context = create_test_context();
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("some2").as_ptr());
|
||||
let name = to_cstring("some2");
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, name);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
free(name as *mut _);
|
||||
|
||||
let id = dc_create_contact(
|
||||
&context.ctx,
|
||||
to_cstring("bob").as_ptr(),
|
||||
to_cstring("bob@mail.de").as_ptr(),
|
||||
);
|
||||
let name = to_cstring("bob");
|
||||
let email = to_cstring("bob@mail.de");
|
||||
let id = dc_create_contact(&context.ctx, name, email);
|
||||
assert_ne!(id, 0);
|
||||
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("bob").as_ptr());
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, name);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 1);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("alice").as_ptr());
|
||||
let name2 = to_cstring("alice");
|
||||
let contacts = dc_get_contacts(&context.ctx, 0, name2);
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
free(name as *mut _);
|
||||
free(name2 as *mut _);
|
||||
free(email as *mut _);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,11 +985,12 @@ fn test_get_contacts() {
|
||||
fn test_chat() {
|
||||
unsafe {
|
||||
let context = create_test_context();
|
||||
let contact1 = dc_create_contact(
|
||||
&context.ctx,
|
||||
to_cstring("bob").as_ptr(),
|
||||
to_cstring("bob@mail.de").as_ptr(),
|
||||
);
|
||||
let name = to_cstring("bob");
|
||||
let email = to_cstring("bob@mail.de");
|
||||
|
||||
let contact1 = dc_create_contact(&context.ctx, name, email);
|
||||
free(name as *mut _);
|
||||
free(email as *mut _);
|
||||
assert_ne!(contact1, 0);
|
||||
|
||||
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
|
||||
@@ -998,6 +1007,21 @@ fn test_chat() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrong_db() {
|
||||
unsafe {
|
||||
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = dir.path().join("db.sqlite");
|
||||
std::fs::write(&dbfile, b"123").unwrap();
|
||||
|
||||
let dbfile_c = to_cstring(dbfile.to_str().unwrap());
|
||||
let res = dc_open(&mut ctx, dbfile_c, std::ptr::null());
|
||||
free(dbfile_c as *mut _);
|
||||
assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arr_to_string() {
|
||||
let arr2: [uint32_t; 4] = [
|
||||
|
||||
Reference in New Issue
Block a user