mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Compare commits
48 Commits
v1.131.0
...
eventloggi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bc5d1b90e | ||
|
|
197d94ad9d | ||
|
|
7ce337c6d0 | ||
|
|
10148d2e43 | ||
|
|
69dc237ee3 | ||
|
|
df5464ea80 | ||
|
|
e4bf9956a5 | ||
|
|
d353d9d9d8 | ||
|
|
1ad45ed4d6 | ||
|
|
496e980a17 | ||
|
|
fa09e46ed9 | ||
|
|
d6de420b9a | ||
|
|
38eb708db8 | ||
|
|
7a59da5f8f | ||
|
|
f13a1d4a2f | ||
|
|
7b3a450918 | ||
|
|
169923b102 | ||
|
|
42688a0622 | ||
|
|
35f3c0edd1 | ||
|
|
e7a236264a | ||
|
|
aaa5b820d9 | ||
|
|
e7f0745010 | ||
|
|
c68e7ae14e | ||
|
|
618087e5a7 | ||
|
|
245abb8384 | ||
|
|
a3e1042001 | ||
|
|
7b7ce9348f | ||
|
|
7a4808ba0d | ||
|
|
8f240f7153 | ||
|
|
7d0b5d8abb | ||
|
|
ee317cb1b5 | ||
|
|
7b736fe635 | ||
|
|
c7db15352a | ||
|
|
0b37167be8 | ||
|
|
5cac4b5076 | ||
|
|
475a41beb3 | ||
|
|
ad4be80b4e | ||
|
|
8737c1d142 | ||
|
|
964fe466cc | ||
|
|
43936e7db7 | ||
|
|
0e80ce9c39 | ||
|
|
c652bae68a | ||
|
|
bc904a495d | ||
|
|
8d99444c6a | ||
|
|
9dab53e0af | ||
|
|
360089ac74 | ||
|
|
e892c5cf4d | ||
|
|
9ad4c9a6fe |
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"]
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -139,7 +139,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 +177,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 +380,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 +495,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 +536,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 +551,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 +588,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 +622,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 +780,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 +789,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 +828,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 +842,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 +933,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 +958,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 +972,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 +985,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 +1077,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 +1093,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 +1146,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 +1174,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 +1192,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +25,7 @@ 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']
|
||||
|
||||
@@ -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,12 +16,23 @@ def pytest_addoption(parser):
|
||||
)
|
||||
|
||||
|
||||
@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(
|
||||
@@ -52,7 +63,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):
|
||||
@@ -78,6 +88,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 +114,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 +125,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():
|
||||
|
||||
@@ -52,6 +52,7 @@ commands =
|
||||
python_files = tests/test_*.py
|
||||
norecursedirs = .tox
|
||||
xfail_strict=true
|
||||
timeout = 60
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -376,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
|
||||
@@ -398,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)]
|
||||
|
||||
196
src/dc_chat.rs
196
src/dc_chat.rs
@@ -130,20 +130,30 @@ 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 {
|
||||
Ok(_) => {
|
||||
let c = unsafe { &mut *chat };
|
||||
match c.id {
|
||||
1 => unsafe {
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
@@ -172,19 +182,18 @@ 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
|
||||
}
|
||||
Err(err) => match err {
|
||||
QueryReturnedNoRows => false,
|
||||
_ => {
|
||||
error!(
|
||||
context,
|
||||
0, "chat: failed to load from db {}: {:?}", chat_id, err
|
||||
);
|
||||
false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
@@ -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(
|
||||
@@ -761,9 +771,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 +789,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(())
|
||||
},
|
||||
)
|
||||
@@ -823,7 +830,8 @@ 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) {
|
||||
last_is_encrypted = 1;
|
||||
@@ -1962,73 +1970,69 @@ 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
|
||||
.sql
|
||||
.query_map(
|
||||
format!(
|
||||
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
||||
as_str(idsstr)
|
||||
),
|
||||
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(())
|
||||
},
|
||||
)
|
||||
.unwrap(); // TODO: better error handling
|
||||
let ids = context.sql.query_map(
|
||||
format!(
|
||||
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
||||
as_str(idsstr)
|
||||
),
|
||||
params![],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
);
|
||||
|
||||
for id in ids.unwrap() {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !created_db_entries.is_null() {
|
||||
@@ -2094,7 +2098,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)
|
||||
|
||||
@@ -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 {
|
||||
@@ -634,7 +634,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 +671,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 +703,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 +759,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 +774,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 +814,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 +860,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 +887,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,
|
||||
@@ -991,7 +991,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 +1039,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 +1098,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 +1162,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 +1302,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 +1318,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 +1522,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
@@ -735,7 +732,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 +902,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::*;
|
||||
@@ -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,
|
||||
|
||||
151
src/dc_imex.rs
151
src/dc_imex.rs
@@ -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) {
|
||||
@@ -806,77 +806,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(|_| {
|
||||
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
|
||||
sql::try_execute(context, &context.sql, "VACUUM;")?;
|
||||
Ok(())
|
||||
})
|
||||
.is_ok() as libc::c_int
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -897,7 +895,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.",);
|
||||
|
||||
@@ -973,7 +972,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 +1095,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 +1123,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 +1135,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 +1173,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 +1198,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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -1185,7 +1173,7 @@ 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());
|
||||
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 == DC_MSG_IMAGE as libc::c_int
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ffi::CStr;
|
||||
|
||||
use charset::Charset;
|
||||
use mmime::mailimf::*;
|
||||
@@ -833,6 +833,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 +843,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 +1204,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 +1340,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(
|
||||
|
||||
111
src/dc_msg.rs
111
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
|
||||
@@ -209,7 +209,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> {
|
||||
@@ -445,9 +445,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 +462,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);
|
||||
}
|
||||
@@ -478,10 +481,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
|
||||
}
|
||||
Err(err) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +494,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 +541,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 +606,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,7 +694,7 @@ 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 {
|
||||
@@ -1355,9 +1360,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)? };
|
||||
|
||||
10
src/dc_qr.rs
10
src/dc_qr.rs
@@ -239,13 +239,8 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
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()
|
||||
let addr_ptr = if let Some(ref addr) = peerstate.addr {
|
||||
to_cstring(addr)
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
@@ -256,6 +251,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
free(addr_ptr as *mut _);
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
(*qr_parsed).id,
|
||||
|
||||
@@ -443,7 +443,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 +503,21 @@ 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 = unsafe {
|
||||
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,11 +744,9 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed {
|
||||
let param = dc_param_new();
|
||||
dc_param_set(
|
||||
param,
|
||||
'Z' as i32,
|
||||
to_cstring(server_folder.as_ref()).as_ptr(),
|
||||
);
|
||||
let server_folder_c = to_cstring(server_folder.as_ref());
|
||||
dc_param_set(param, 'Z' as i32, server_folder_c);
|
||||
free(server_folder_c as *mut _);
|
||||
dc_param_set_int(param, 'z' as i32, server_uid as i32);
|
||||
if 0 != mime_parser.is_send_by_messenger
|
||||
&& 0 != context
|
||||
@@ -827,6 +830,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);
|
||||
@@ -1375,7 +1386,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()))
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1518,9 +1529,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 +1613,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 +1659,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 member").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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
@@ -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 {
|
||||
@@ -1254,8 +1255,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 +1304,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 +1516,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 +1538,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.
|
||||
@@ -1981,7 +2019,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 +2044,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 +2053,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 +2063,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 +2078,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"));
|
||||
}
|
||||
}
|
||||
|
||||
233
src/imap.rs
233
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());
|
||||
@@ -1616,7 +1641,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);
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
125
src/sql.rs
125
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)?;
|
||||
@@ -137,11 +147,12 @@ impl Sql {
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -259,18 +270,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(
|
||||
@@ -841,6 +861,18 @@ 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,
|
||||
@@ -852,7 +884,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 +895,6 @@ pub fn get_rowid(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rowid2(
|
||||
context: &Context,
|
||||
sql: &Sql,
|
||||
@@ -873,6 +904,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 +1004,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 +1065,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 +1127,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 +1170,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,
|
||||
|
||||
@@ -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