mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 15:02:11 +03:00
Compare commits
48 Commits
v2.34.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)",
|
"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)",
|
"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)",
|
"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)",
|
"rental 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -194,12 +194,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "buf_redux"
|
name = "buf_redux"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -409,7 +409,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 0.6.13 (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]]
|
[[package]]
|
||||||
@@ -443,7 +443,7 @@ dependencies = [
|
|||||||
"proc-macro2 0.4.30 (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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -453,7 +453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -461,6 +461,7 @@ name = "deltachat"
|
|||||||
version = "1.0.0-alpha.3"
|
version = "1.0.0-alpha.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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 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)",
|
"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)",
|
"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)",
|
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"reqwest 0.9.18 (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 (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)",
|
"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 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)",
|
"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 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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -515,7 +517,7 @@ dependencies = [
|
|||||||
"derive_builder_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -526,7 +528,7 @@ dependencies = [
|
|||||||
"darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -608,7 +610,7 @@ dependencies = [
|
|||||||
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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)",
|
"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)",
|
"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)",
|
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nom 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]]
|
[[package]]
|
||||||
@@ -974,8 +976,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.15.0"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+http://github.com/dignifiedquire/rusqlite?branch=fix/text#d81b8cdb175f7c27a3ace9ad46818e2a01434cdc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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-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)",
|
"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 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)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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]]
|
[[package]]
|
||||||
@@ -1278,7 +1280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.23"
|
version = "0.10.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -1304,7 +1306,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.47"
|
version = "0.9.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1320,7 +1322,7 @@ name = "os_type"
|
|||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -1433,7 +1435,7 @@ dependencies = [
|
|||||||
"block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"r2d2 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
@@ -1792,22 +1794,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.1.9"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.8"
|
version = "0.6.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -1834,12 +1836,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.9.18"
|
version = "0.9.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -1899,12 +1902,12 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rusqlite"
|
name = "rusqlite"
|
||||||
version = "0.19.0"
|
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 = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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-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)",
|
"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)",
|
"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)",
|
"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)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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]]
|
[[package]]
|
||||||
@@ -2103,7 +2106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slice-deque"
|
name = "slice-deque"
|
||||||
version = "0.1.16"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
@@ -2180,7 +2183,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.15.39"
|
version = "0.15.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -2386,6 +2397,11 @@ dependencies = [
|
|||||||
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -2416,7 +2432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-util"
|
name = "ucd-util"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2466,6 +2482,14 @@ name = "unicode-xid"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "1.7.2"
|
version = "1.7.2"
|
||||||
@@ -2582,6 +2606,14 @@ dependencies = [
|
|||||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "winutil"
|
name = "winutil"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -2624,7 +2656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 0.4.30 (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)",
|
"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]
|
[metadata]
|
||||||
@@ -2651,7 +2683,7 @@ dependencies = [
|
|||||||
"checksum block-modes 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529"
|
"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 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 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 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 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"
|
"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 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 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 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 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.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||||
"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff"
|
"checksum lock_api 0.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-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 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 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-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-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 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 output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
"checksum 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 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_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 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 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
|
||||||
"checksum regex-syntax 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9b01330cce219c1c6b2e209e5ed64ccd587ae5c67bed91c0b49eecf02ae40e21"
|
"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 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 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 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 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 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-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 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"
|
"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 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 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 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 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 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"
|
"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 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 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.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 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 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 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 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 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 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 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"
|
"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-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 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 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-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 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 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 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 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 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"
|
"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-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-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 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 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 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"
|
"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 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 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 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 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 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"
|
"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"
|
r2d2 = "0.8.5"
|
||||||
strum = "0.15.0"
|
strum = "0.15.0"
|
||||||
strum_macros = "0.15.0"
|
strum_macros = "0.15.0"
|
||||||
|
thread-local-object = "0.1.0"
|
||||||
|
backtrace = "0.3.33"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.0"
|
tempfile = "3.0"
|
||||||
@@ -52,6 +54,10 @@ members = [
|
|||||||
"deltachat-ffi"
|
"deltachat-ffi"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
rusqlite = { git = "http://github.com/dignifiedquire/rusqlite", branch = "fix/text", features = ["bundled"] }
|
||||||
|
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "simple"
|
name = "simple"
|
||||||
path = "examples/simple.rs"
|
path = "examples/simple.rs"
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ default = ["vendored", "nightly", "ringbuf"]
|
|||||||
vendored = ["deltachat/vendored"]
|
vendored = ["deltachat/vendored"]
|
||||||
nightly = ["deltachat/nightly"]
|
nightly = ["deltachat/nightly"]
|
||||||
ringbuf = ["deltachat/ringbuf"]
|
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)) {
|
match config::Config::from_str(dc_tools::as_str(key)) {
|
||||||
Ok(key) => {
|
Ok(key) => {
|
||||||
let value = context.get_config(key).unwrap_or_default();
|
let value = context.get_config(key).unwrap_or_default();
|
||||||
into_cstring(value)
|
dc_tools::to_cstring(value)
|
||||||
}
|
}
|
||||||
Err(_) => std::ptr::null_mut(),
|
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 addr = dc_tools::to_string(addr);
|
||||||
let redirect = dc_tools::to_string(redirect);
|
let redirect = dc_tools::to_string(redirect);
|
||||||
match oauth2::dc_get_oauth2_url(context, addr, 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(),
|
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))
|
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 {
|
} else {
|
||||||
current_block = 7149356873433890176;
|
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 {
|
match current_block {
|
||||||
8522321847195001863 => {}
|
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);
|
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||||
info!(context, 0, "Import: {}", path_plus_name);
|
info!(context, 0, "Import: {}", path_plus_name);
|
||||||
let path_plus_name_c = to_cstring(path_plus_name);
|
let path_plus_name_c = to_cstring(path_plus_name);
|
||||||
|
if 0 != dc_poke_eml_file(context, path_plus_name_c) {
|
||||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
|
||||||
read_cnt += 1
|
read_cnt += 1
|
||||||
}
|
}
|
||||||
|
free(path_plus_name_c as *mut _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_block = 1622411330066726685;
|
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 mut args = line.splitn(3, ' ');
|
||||||
let arg0 = args.next().unwrap_or_default();
|
let arg0 = args.next().unwrap_or_default();
|
||||||
let arg1 = args.next().unwrap_or_default();
|
let arg1 = args.next().unwrap_or_default();
|
||||||
let arg1_c = to_cstring(arg1);
|
let arg1_c = if arg1.is_empty() {
|
||||||
let arg1_c_ptr = if arg1.is_empty() {
|
|
||||||
std::ptr::null()
|
std::ptr::null()
|
||||||
} else {
|
} else {
|
||||||
arg1_c.as_ptr()
|
to_cstring(arg1) as *const _
|
||||||
};
|
};
|
||||||
let arg2 = args.next().unwrap_or_default();
|
let arg2 = args.next().unwrap_or_default();
|
||||||
let arg2_c = to_cstring(arg2);
|
let arg2_c = if arg2.is_empty() {
|
||||||
let arg2_c_ptr = if arg2.is_empty() {
|
|
||||||
std::ptr::null()
|
std::ptr::null()
|
||||||
} else {
|
} else {
|
||||||
arg2_c.as_ptr()
|
to_cstring(arg2) as *const _
|
||||||
};
|
};
|
||||||
|
|
||||||
match arg0 {
|
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");
|
ensure!(!arg1.is_empty(), "Argument <file> missing");
|
||||||
dc_close(context);
|
dc_close(context);
|
||||||
ensure!(
|
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"
|
"Open failed"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -538,7 +536,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
!arg1.is_empty() && !arg2.is_empty(),
|
!arg1.is_empty() && !arg2.is_empty(),
|
||||||
"Arguments <msg-id> <setup-code> expected"
|
"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");
|
bail!("Continue key transfer failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,7 +551,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
}
|
}
|
||||||
"import-backup" => {
|
"import-backup" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
|
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" => {
|
"export-keys" => {
|
||||||
dc_imex(context, 1, context.get_blobdir(), 0 as *const libc::c_char);
|
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);
|
free(setup_code as *mut libc::c_void);
|
||||||
}
|
}
|
||||||
"poke" => {
|
"poke" => {
|
||||||
ensure!(0 != poke_spec(context, arg1_c_ptr), "Poke failed");
|
ensure!(0 != poke_spec(context, arg1_c), "Poke failed");
|
||||||
}
|
}
|
||||||
"reset" => {
|
"reset" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
|
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" => {
|
"listchats" | "listarchived" | "chats" => {
|
||||||
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
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");
|
ensure!(!chatlist.is_null(), "Failed to retrieve chatlist");
|
||||||
|
|
||||||
let mut i: libc::c_int;
|
let mut i: libc::c_int;
|
||||||
@@ -782,8 +780,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
}
|
}
|
||||||
"creategroup" => {
|
"creategroup" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||||
let chat_id_1: libc::c_int =
|
let chat_id_1: libc::c_int = dc_create_group_chat(context, 0, arg1_c) as libc::c_int;
|
||||||
dc_create_group_chat(context, 0, arg1_c_ptr) as libc::c_int;
|
|
||||||
if chat_id_1 != 0 {
|
if chat_id_1 != 0 {
|
||||||
println!("Group#{} created successfully.", chat_id_1,);
|
println!("Group#{} created successfully.", chat_id_1,);
|
||||||
} else {
|
} else {
|
||||||
@@ -792,8 +789,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
}
|
}
|
||||||
"createverified" => {
|
"createverified" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||||
let chat_id_2: libc::c_int =
|
let chat_id_2: libc::c_int = dc_create_group_chat(context, 1, arg1_c) as libc::c_int;
|
||||||
dc_create_group_chat(context, 1, arg1_c_ptr) as libc::c_int;
|
|
||||||
if chat_id_2 != 0 {
|
if chat_id_2 != 0 {
|
||||||
println!("VerifiedGroup#{} created successfully.", chat_id_2,);
|
println!("VerifiedGroup#{} created successfully.", chat_id_2,);
|
||||||
} else {
|
} else {
|
||||||
@@ -832,7 +828,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
"groupname" => {
|
"groupname" => {
|
||||||
ensure!(!sel_chat.is_null(), "No chat selected.");
|
ensure!(!sel_chat.is_null(), "No chat selected.");
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
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");
|
println!("Chat name set");
|
||||||
} else {
|
} else {
|
||||||
bail!("Failed to set chat name");
|
bail!("Failed to set chat name");
|
||||||
@@ -846,7 +842,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
context,
|
context,
|
||||||
dc_chat_get_id(sel_chat),
|
dc_chat_get_id(sel_chat),
|
||||||
if !arg1.is_empty() {
|
if !arg1.is_empty() {
|
||||||
arg1_c_ptr
|
arg1_c
|
||||||
} else {
|
} else {
|
||||||
std::ptr::null_mut()
|
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));
|
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.");
|
println!("Message sent.");
|
||||||
|
free(msg as *mut _);
|
||||||
} else {
|
} else {
|
||||||
|
free(msg as *mut _);
|
||||||
bail!("Sending failed.");
|
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.");
|
ensure!(!arg1.is_empty() && !arg2.is_empty(), "No file given.");
|
||||||
|
|
||||||
let msg_0 = dc_msg_new(context, if arg0 == "sendimage" { 20 } else { 60 });
|
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_file(msg_0, arg1_c, 0 as *const libc::c_char);
|
||||||
dc_msg_set_text(msg_0, arg2_c_ptr);
|
dc_msg_set_text(msg_0, arg2_c);
|
||||||
dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0);
|
dc_send_msg(context, dc_chat_get_id(sel_chat), msg_0);
|
||||||
dc_msg_unref(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
|
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() {
|
if !msglist_0.is_null() {
|
||||||
log_msglist(context, msglist_0);
|
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() {
|
if !arg1.is_empty() {
|
||||||
let draft_0 = dc_msg_new(context, 10);
|
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_set_draft(context, dc_chat_get_id(sel_chat), draft_0);
|
||||||
dc_msg_unref(draft_0);
|
dc_msg_unref(draft_0);
|
||||||
println!("Draft saved.");
|
println!("Draft saved.");
|
||||||
@@ -1079,7 +1077,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
} else {
|
} else {
|
||||||
0x2
|
0x2
|
||||||
},
|
},
|
||||||
arg1_c_ptr,
|
arg1_c,
|
||||||
);
|
);
|
||||||
if !contacts.is_null() {
|
if !contacts.is_null() {
|
||||||
log_contactlist(context, contacts);
|
log_contactlist(context, contacts);
|
||||||
@@ -1095,13 +1093,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
if !arg2.is_empty() {
|
if !arg2.is_empty() {
|
||||||
let book = dc_mprintf(
|
let book = dc_mprintf(
|
||||||
b"%s\n%s\x00" as *const u8 as *const libc::c_char,
|
b"%s\n%s\x00" as *const u8 as *const libc::c_char,
|
||||||
arg1_c_ptr,
|
arg1_c,
|
||||||
arg2_c_ptr,
|
arg2_c,
|
||||||
);
|
);
|
||||||
dc_add_address_book(context, book);
|
dc_add_address_book(context, book);
|
||||||
free(book as *mut libc::c_void);
|
free(book as *mut libc::c_void);
|
||||||
} else {
|
} 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");
|
bail!("Failed to create contact");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1148,7 +1146,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
}
|
}
|
||||||
"checkqr" => {
|
"checkqr" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
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!(
|
println!(
|
||||||
"state={}, id={}, text1={}, text2={}",
|
"state={}, id={}, text1={}, text2={}",
|
||||||
(*res).state as libc::c_int,
|
(*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(
|
if 0 != dc_read_file(
|
||||||
context,
|
context,
|
||||||
arg1_c_ptr,
|
arg1_c,
|
||||||
&mut buf as *mut *mut libc::c_uchar as *mut *mut libc::c_void,
|
&mut buf as *mut *mut libc::c_uchar as *mut *mut libc::c_void,
|
||||||
&mut buf_bytes,
|
&mut buf_bytes,
|
||||||
) {
|
) {
|
||||||
@@ -1194,5 +1192,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
|||||||
dc_chat_unref(sel_chat);
|
dc_chat_unref(sel_chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(arg1_c as *mut _);
|
||||||
|
free(arg2_c as *mut _);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,11 +398,10 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
|||||||
|
|
||||||
if args.len() == 2 {
|
if args.len() == 2 {
|
||||||
if 0 == unsafe {
|
if 0 == unsafe {
|
||||||
dc_open(
|
let a = to_cstring(&args[1]);
|
||||||
&mut context,
|
let res = dc_open(&mut context, a, 0 as *const _);
|
||||||
to_cstring(&args[1]).as_ptr(),
|
free(a as *mut _);
|
||||||
0 as *const libc::c_char,
|
res
|
||||||
)
|
|
||||||
} {
|
} {
|
||||||
println!("Error: Cannot open {}.", args[0],);
|
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 mut args = line.splitn(2, ' ');
|
||||||
let arg0 = args.next().unwrap_or_default();
|
let arg0 = args.next().unwrap_or_default();
|
||||||
let arg1 = args.next().unwrap_or_default();
|
let arg1 = args.next().unwrap_or_default();
|
||||||
let arg1_c = to_cstring(arg1);
|
let arg1_c = if arg1.is_empty() {
|
||||||
let arg1_c_ptr = if arg1.is_empty() {
|
|
||||||
std::ptr::null()
|
std::ptr::null()
|
||||||
} else {
|
} else {
|
||||||
arg1_c.as_ptr()
|
to_cstring(arg1)
|
||||||
};
|
};
|
||||||
|
|
||||||
match arg0 {
|
match arg0 {
|
||||||
@@ -559,13 +557,15 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
|||||||
"joinqr" => {
|
"joinqr" => {
|
||||||
start_threads(ctx.clone());
|
start_threads(ctx.clone());
|
||||||
if !arg0.is_empty() {
|
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),
|
"exit" => return Ok(ExitResult::Exit),
|
||||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(arg1_c as *mut _);
|
||||||
|
|
||||||
Ok(ExitResult::Continue)
|
Ok(ExitResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
- introduce automatic versioning via setuptools_scm,
|
- introduce automatic versioning via setuptools_scm,
|
||||||
based on py-X.Y.Z tags
|
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
|
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:
|
try:
|
||||||
ret = callback(ctx, evt_name, data1, data2)
|
ret = callback(ctx, evt_name, data1, data2)
|
||||||
|
if ret is None:
|
||||||
|
ret = 0
|
||||||
|
assert isinstance(ret, int), repr(ret)
|
||||||
if event_sig_types & 4:
|
if event_sig_types & 4:
|
||||||
return ffi.cast('uintptr_t', ret)
|
return ffi.cast('uintptr_t', ret)
|
||||||
elif event_sig_types & 8:
|
elif event_sig_types & 8:
|
||||||
@@ -58,7 +61,10 @@ def set_context_callback(dc_context, func):
|
|||||||
|
|
||||||
|
|
||||||
def clear_context_callback(dc_context):
|
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={}):
|
def get_dc_event_name(integer, _DC_EVENTNAME_MAP={}):
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ def ffibuilder():
|
|||||||
else:
|
else:
|
||||||
raise NotImplementedError("Compilation not supported yet on Windows, can you help?")
|
raise NotImplementedError("Compilation not supported yet on Windows, can you help?")
|
||||||
objs = [os.path.join(projdir, 'target', target, 'libdeltachat.a')]
|
objs = [os.path.join(projdir, 'target', target, 'libdeltachat.a')]
|
||||||
|
assert os.path.exists(objs[0]), objs
|
||||||
incs = [os.path.join(projdir, 'deltachat-ffi')]
|
incs = [os.path.join(projdir, 'deltachat-ffi')]
|
||||||
else:
|
else:
|
||||||
libs = ['deltachat']
|
libs = ['deltachat']
|
||||||
|
|||||||
@@ -23,28 +23,36 @@ class Account(object):
|
|||||||
by the underlying deltachat c-library. All public Account methods are
|
by the underlying deltachat c-library. All public Account methods are
|
||||||
meant to be memory-safe and return memory-safe objects.
|
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.
|
""" initialize account object.
|
||||||
|
|
||||||
:param db_path: a path to the account database. The database
|
:param db_path: a path to the account database. The database
|
||||||
will be created if it doesn't exist.
|
will be created if it doesn't exist.
|
||||||
:param logid: an optional logging prefix that should be used with
|
:param logid: an optional logging prefix that should be used with
|
||||||
the default internal logging.
|
the default internal logging.
|
||||||
|
:param eventlogging: if False no eventlogging and no context callback will be configured
|
||||||
"""
|
"""
|
||||||
self._dc_context = ffi.gc(
|
self._dc_context = ffi.gc(
|
||||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||||
_destroy_dc_context,
|
_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"):
|
if hasattr(db_path, "encode"):
|
||||||
db_path = db_path.encode("utf8")
|
db_path = db_path.encode("utf8")
|
||||||
if not lib.dc_open(self._dc_context, db_path, ffi.NULL):
|
if not lib.dc_open(self._dc_context, db_path, ffi.NULL):
|
||||||
raise ValueError("Could not dc_open: {}".format(db_path))
|
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._configkeys = self.get_config("sys.config_keys").split()
|
||||||
self._imex_completed = threading.Event()
|
self._imex_completed = threading.Event()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.shutdown()
|
||||||
|
|
||||||
def _check_config_key(self, name):
|
def _check_config_key(self, name):
|
||||||
if name not in self._configkeys:
|
if name not in self._configkeys:
|
||||||
raise KeyError("{!r} not a valid config key, existing keys: {!r}".format(
|
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)
|
lib.dc_stop_ongoing_process(self._dc_context)
|
||||||
self._threads.stop(wait=wait)
|
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):
|
def _process_event(self, ctx, evt_name, data1, data2):
|
||||||
assert ctx == self._dc_context
|
assert ctx == self._dc_context
|
||||||
self._evlogger(evt_name, data1, data2)
|
if hasattr(self, "_evlogger"):
|
||||||
method = getattr(self, "on_" + evt_name.lower(), None)
|
self._evlogger(evt_name, data1, data2)
|
||||||
if method is not None:
|
method = getattr(self, "on_" + evt_name.lower(), None)
|
||||||
method(data1, data2)
|
if method is not None:
|
||||||
|
method(data1, data2)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def on_dc_event_imex_progress(self, data1, data2):
|
def on_dc_event_imex_progress(self, data1, data2):
|
||||||
@@ -347,10 +365,11 @@ class Account(object):
|
|||||||
|
|
||||||
|
|
||||||
class IOThreads:
|
class IOThreads:
|
||||||
def __init__(self, dc_context):
|
def __init__(self, dc_context, log_event=lambda *args: None):
|
||||||
self._dc_context = dc_context
|
self._dc_context = dc_context
|
||||||
self._thread_quitflag = False
|
self._thread_quitflag = False
|
||||||
self._name2thread = {}
|
self._name2thread = {}
|
||||||
|
self._log_event = log_event
|
||||||
|
|
||||||
def is_started(self):
|
def is_started(self):
|
||||||
return len(self._name2thread) > 0
|
return len(self._name2thread) > 0
|
||||||
@@ -376,15 +395,19 @@ class IOThreads:
|
|||||||
thread.join()
|
thread.join()
|
||||||
|
|
||||||
def imap_thread_run(self):
|
def imap_thread_run(self):
|
||||||
|
self._log_event("py-bindings-info", 0, "IMAP THREAD START")
|
||||||
while not self._thread_quitflag:
|
while not self._thread_quitflag:
|
||||||
lib.dc_perform_imap_jobs(self._dc_context)
|
lib.dc_perform_imap_jobs(self._dc_context)
|
||||||
lib.dc_perform_imap_fetch(self._dc_context)
|
lib.dc_perform_imap_fetch(self._dc_context)
|
||||||
lib.dc_perform_imap_idle(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):
|
def smtp_thread_run(self):
|
||||||
|
self._log_event("py-bindings-info", 0, "SMTP THREAD START")
|
||||||
while not self._thread_quitflag:
|
while not self._thread_quitflag:
|
||||||
lib.dc_perform_smtp_jobs(self._dc_context)
|
lib.dc_perform_smtp_jobs(self._dc_context)
|
||||||
lib.dc_perform_smtp_idle(self._dc_context)
|
lib.dc_perform_smtp_idle(self._dc_context)
|
||||||
|
self._log_event("py-bindings-info", 0, "SMTP THREAD FINISHED")
|
||||||
|
|
||||||
|
|
||||||
class EventLogger:
|
class EventLogger:
|
||||||
@@ -414,7 +437,7 @@ class EventLogger:
|
|||||||
raise ValueError("{}({!r},{!r})".format(*ev))
|
raise ValueError("{}({!r},{!r})".format(*ev))
|
||||||
return 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))
|
self._log("-- waiting for event with regex: {} --".format(event_name_regex))
|
||||||
rex = re.compile("(?:{}).*".format(event_name_regex))
|
rex = re.compile("(?:{}).*".format(event_name_regex))
|
||||||
while 1:
|
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):
|
def pytest_report_header(config, startdir):
|
||||||
t = tempfile.mktemp()
|
t = tempfile.mktemp()
|
||||||
try:
|
try:
|
||||||
ac = Account(t)
|
ac = Account(t, eventlogging=False)
|
||||||
info = ac.get_info()
|
info = ac.get_info()
|
||||||
del ac
|
ac.shutdown()
|
||||||
finally:
|
finally:
|
||||||
os.remove(t)
|
os.remove(t)
|
||||||
return "Deltachat core={} sqlite={}".format(
|
return "Deltachat core={} sqlite={}".format(
|
||||||
@@ -52,7 +63,6 @@ def acfactory(pytestconfig, tmpdir, request):
|
|||||||
self.live_count = 0
|
self.live_count = 0
|
||||||
self.offline_count = 0
|
self.offline_count = 0
|
||||||
self._finalizers = []
|
self._finalizers = []
|
||||||
request.addfinalizer(self.finalize)
|
|
||||||
self.init_time = time.time()
|
self.init_time = time.time()
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
@@ -78,6 +88,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
|||||||
ac = Account(tmpdb.strpath, logid="ac{}".format(self.offline_count))
|
ac = Account(tmpdb.strpath, logid="ac{}".format(self.offline_count))
|
||||||
ac._evlogger.init_time = self.init_time
|
ac._evlogger.init_time = self.init_time
|
||||||
ac._evlogger.set_timeout(2)
|
ac._evlogger.set_timeout(2)
|
||||||
|
self._finalizers.append(ac.shutdown)
|
||||||
return ac
|
return ac
|
||||||
|
|
||||||
def get_configured_offline_account(self):
|
def get_configured_offline_account(self):
|
||||||
@@ -103,7 +114,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
|||||||
ac._evlogger.set_timeout(30)
|
ac._evlogger.set_timeout(30)
|
||||||
ac.configure(**configdict)
|
ac.configure(**configdict)
|
||||||
ac.start_threads()
|
ac.start_threads()
|
||||||
self._finalizers.append(lambda: ac.stop_threads(wait=False))
|
self._finalizers.append(ac.shutdown)
|
||||||
return ac
|
return ac
|
||||||
|
|
||||||
def clone_online_account(self, account):
|
def clone_online_account(self, account):
|
||||||
@@ -114,7 +125,7 @@ def acfactory(pytestconfig, tmpdir, request):
|
|||||||
ac._evlogger.set_timeout(30)
|
ac._evlogger.set_timeout(30)
|
||||||
ac.configure(addr=account.get_config("addr"), mail_pw=account.get_config("mail_pw"))
|
ac.configure(addr=account.get_config("addr"), mail_pw=account.get_config("mail_pw"))
|
||||||
ac.start_threads()
|
ac.start_threads()
|
||||||
self._finalizers.append(lambda: ac.stop_threads(wait=False))
|
self._finalizers.append(ac.shutdown)
|
||||||
return ac
|
return ac
|
||||||
|
|
||||||
return AccountMaker()
|
return AccountMaker()
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import pytest
|
import pytest
|
||||||
import os
|
import os
|
||||||
from deltachat import const
|
from deltachat import const, Account
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
|
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
|
||||||
|
|
||||||
|
|
||||||
class TestOfflineAccount:
|
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):
|
def test_getinfo(self, acfactory):
|
||||||
ac1 = acfactory.get_unconfigured_account()
|
ac1 = acfactory.get_unconfigured_account()
|
||||||
d = ac1.get_info()
|
d = ac1.get_info()
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ class TestInCreation:
|
|||||||
chat2.add_contact(c2)
|
chat2.add_contact(c2)
|
||||||
wait_msgs_changed(ac1, 0, 0) # why not chat id?
|
wait_msgs_changed(ac1, 0, 0) # why not chat id?
|
||||||
ac1.forward_messages([prepared_original], chat2)
|
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)
|
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)
|
forwarded_msg = ac1.get_message_by_id(forwarded_id)
|
||||||
assert forwarded_msg.get_state().is_out_preparing()
|
assert forwarded_msg.get_state().is_out_preparing()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import pytest
|
from deltachat import capi, const, set_context_callback, clear_context_callback
|
||||||
from deltachat import capi, Account, const
|
from deltachat.capi import ffi
|
||||||
|
from deltachat.capi import lib
|
||||||
|
from deltachat.account import EventLogger
|
||||||
|
|
||||||
|
|
||||||
def test_empty_context():
|
def test_empty_context():
|
||||||
@@ -8,10 +10,45 @@ def test_empty_context():
|
|||||||
capi.lib.dc_close(ctx)
|
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):
|
def test_wrong_db(tmpdir):
|
||||||
tmpdir.join("hello.db").write("123")
|
dc_context = ffi.gc(
|
||||||
with pytest.raises(ValueError):
|
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||||
Account(db_path=tmpdir.strpath)
|
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():
|
def test_event_defines():
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ commands =
|
|||||||
python_files = tests/test_*.py
|
python_files = tests/test_*.py
|
||||||
norecursedirs = .tox
|
norecursedirs = .tox
|
||||||
xfail_strict=true
|
xfail_strict=true
|
||||||
|
timeout = 60
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
|
|||||||
@@ -71,7 +71,12 @@ impl Context {
|
|||||||
Config::Selfavatar => {
|
Config::Selfavatar => {
|
||||||
let rel_path = self.sql.get_config(self, key);
|
let rel_path = self.sql.get_config(self, key);
|
||||||
rel_path.map(|p| {
|
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);
|
let r = to_string(v);
|
||||||
unsafe { free(v as *mut _) };
|
unsafe { free(v as *mut _) };
|
||||||
r
|
r
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ unsafe fn cb_get_config(
|
|||||||
.sql
|
.sql
|
||||||
.get_config(context, as_str(key))
|
.get_config(context, as_str(key))
|
||||||
.unwrap_or_else(|| to_string(def));
|
.unwrap_or_else(|| to_string(def));
|
||||||
strdup(to_cstring(res).as_ptr())
|
to_cstring(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_context_unref(context: &mut Context) {
|
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) {
|
pub unsafe fn dc_close(context: &Context) {
|
||||||
|
info!(context, 0, "disconnecting INBOX-watch",);
|
||||||
context.inbox.read().unwrap().disconnect(context);
|
context.inbox.read().unwrap().disconnect(context);
|
||||||
|
info!(context, 0, "disconnecting sentbox-thread",);
|
||||||
context
|
context
|
||||||
.sentbox_thread
|
.sentbox_thread
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.imap
|
.imap
|
||||||
.disconnect(context);
|
.disconnect(context);
|
||||||
|
info!(context, 0, "disconnecting mvbox-thread",);
|
||||||
context
|
context
|
||||||
.mvbox_thread
|
.mvbox_thread
|
||||||
.read()
|
.read()
|
||||||
@@ -305,6 +308,7 @@ pub unsafe fn dc_close(context: &Context) {
|
|||||||
.imap
|
.imap
|
||||||
.disconnect(context);
|
.disconnect(context);
|
||||||
|
|
||||||
|
info!(context, 0, "disconnecting SMTP");
|
||||||
context.smtp.clone().lock().unwrap().disconnect();
|
context.smtp.clone().lock().unwrap().disconnect();
|
||||||
|
|
||||||
context.sql.close(context);
|
context.sql.close(context);
|
||||||
@@ -511,7 +515,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
|
|||||||
fingerprint_str,
|
fingerprint_str,
|
||||||
);
|
);
|
||||||
|
|
||||||
strdup(to_cstring(res).as_ptr())
|
to_cstring(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
|
pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ pub unsafe fn dc_array_get_string(
|
|||||||
}
|
}
|
||||||
res
|
res
|
||||||
});
|
});
|
||||||
strdup(to_cstring(res).as_ptr())
|
to_cstring(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return comma-separated value-string from integer array
|
/// 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
|
res
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
strdup(to_cstring(res).as_ptr())
|
to_cstring(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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.type_0 = row.get(1)?;
|
||||||
c.name = {
|
c.name = {
|
||||||
let raw: String = row.get(2)?;
|
let raw: String = row.get(2)?;
|
||||||
unsafe { strdup(to_cstring(raw).as_ptr()) }
|
unsafe { to_cstring(raw) }
|
||||||
};
|
};
|
||||||
c.grpid = {
|
c.grpid = {
|
||||||
let raw: String = row.get(3)?;
|
let raw: String = row.get(3)?;
|
||||||
unsafe { strdup(to_cstring(raw).as_ptr()) }
|
unsafe { to_cstring(raw) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let packed: String = row.get(4)?;
|
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.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.gossiped_timestamp = row.get(7)?;
|
||||||
c.is_sending_locations = row.get(8)?;
|
c.is_sending_locations = row.get(8)?;
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(_) => {
|
||||||
|
let c = unsafe { &mut *chat };
|
||||||
match c.id {
|
match c.id {
|
||||||
1 => unsafe {
|
1 => unsafe {
|
||||||
free((*chat).name as *mut libc::c_void);
|
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(())
|
true
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Ok(_) => true,
|
|
||||||
Err(err) => {
|
|
||||||
error!(
|
|
||||||
context,
|
|
||||||
0, "chat: failed to load from db {}: {:?}", chat_id, err
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
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(
|
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=?;",
|
"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],
|
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_id = id };
|
||||||
unsafe { *ret_chat_blocked = blocked };
|
unsafe { *ret_chat_blocked = blocked };
|
||||||
@@ -496,8 +505,9 @@ unsafe fn prepare_msg_raw(
|
|||||||
} else {
|
} else {
|
||||||
0 as *mut libc::c_char
|
0 as *mut libc::c_char
|
||||||
},
|
},
|
||||||
from_c.as_ptr(),
|
from_c,
|
||||||
);
|
);
|
||||||
|
free(from_c as *mut _);
|
||||||
|
|
||||||
if (*chat).type_0 == 100 {
|
if (*chat).type_0 == 100 {
|
||||||
if let Some(id) = context.sql.query_row_col(
|
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!=?);",
|
FROM msgs WHERE chat_id=? AND from_id!=?);",
|
||||||
params![(*chat).id as i32, 1],
|
params![(*chat).id as i32, 1],
|
||||||
|row| {
|
|row| {
|
||||||
*parent_rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
|
||||||
*parent_in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
|
||||||
*parent_references = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
*parent_references = to_cstring(row.get::<_, String>(2)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -779,12 +789,9 @@ unsafe fn get_parent_mime_headers(
|
|||||||
FROM msgs WHERE chat_id=? AND from_id==?);",
|
FROM msgs WHERE chat_id=? AND from_id==?);",
|
||||||
params![(*chat).id as i32, 1],
|
params![(*chat).id as i32, 1],
|
||||||
|row| {
|
|row| {
|
||||||
*parent_rfc724_mid =
|
*parent_rfc724_mid = to_cstring(row.get::<_, String>(0)?);
|
||||||
dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
*parent_in_reply_to = to_cstring(row.get::<_, String>(1)?);
|
||||||
*parent_in_reply_to =
|
*parent_references = to_cstring(row.get::<_, String>(2)?);
|
||||||
dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
|
||||||
*parent_references =
|
|
||||||
dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -823,7 +830,8 @@ unsafe fn last_msg_in_chat_encrypted(
|
|||||||
if let Some(packed) = packed {
|
if let Some(packed) = packed {
|
||||||
let msg_param = dc_param_new();
|
let msg_param = dc_param_new();
|
||||||
let packed_c = to_cstring(packed);
|
let packed_c = to_cstring(packed);
|
||||||
dc_param_set_packed(msg_param, packed_c.as_ptr());
|
dc_param_set_packed(msg_param, packed_c);
|
||||||
|
free(packed_c as *mut _);
|
||||||
|
|
||||||
if 0 != dc_param_exists(msg_param, 'c' as i32) {
|
if 0 != dc_param_exists(msg_param, 'c' as i32) {
|
||||||
last_is_encrypted = 1;
|
last_is_encrypted = 1;
|
||||||
@@ -1962,73 +1970,69 @@ pub unsafe fn dc_forward_msgs(
|
|||||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
|
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
|
||||||
idsstr = dc_arr_to_string(msg_ids, msg_cnt);
|
idsstr = dc_arr_to_string(msg_ids, msg_cnt);
|
||||||
|
|
||||||
context
|
let ids = context.sql.query_map(
|
||||||
.sql
|
format!(
|
||||||
.query_map(
|
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
||||||
format!(
|
as_str(idsstr)
|
||||||
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
|
),
|
||||||
as_str(idsstr)
|
params![],
|
||||||
),
|
|row| row.get::<_, i32>(0),
|
||||||
params![],
|
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||||
|row| row.get::<_, i32>(0),
|
);
|
||||||
|ids| {
|
|
||||||
for id in ids {
|
for id in ids.unwrap() {
|
||||||
let src_msg_id = id?;
|
let src_msg_id = id;
|
||||||
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
|
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dc_param_set_packed(original_param, (*(*msg).param).packed);
|
dc_param_set_packed(original_param, (*(*msg).param).packed);
|
||||||
if (*msg).from_id != 1i32 as libc::c_uint {
|
if (*msg).from_id != 1i32 as libc::c_uint {
|
||||||
dc_param_set_int((*msg).param, 'a' as i32, 1i32);
|
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, '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, 'u' as i32, 0 as *const libc::c_char);
|
||||||
dc_param_set((*msg).param, 'S' 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;
|
let new_msg_id: uint32_t;
|
||||||
if (*msg).state == 18i32 {
|
if (*msg).state == 18i32 {
|
||||||
let fresh9 = curr_timestamp;
|
let fresh9 = curr_timestamp;
|
||||||
curr_timestamp = curr_timestamp + 1;
|
curr_timestamp = curr_timestamp + 1;
|
||||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
|
new_msg_id = prepare_msg_raw(context, chat, msg, fresh9);
|
||||||
let save_param: *mut dc_param_t = (*msg).param;
|
let save_param: *mut dc_param_t = (*msg).param;
|
||||||
(*msg).param = original_param;
|
(*msg).param = original_param;
|
||||||
(*msg).id = src_msg_id as uint32_t;
|
(*msg).id = src_msg_id as uint32_t;
|
||||||
let old_fwd: *mut libc::c_char = dc_param_get(
|
let old_fwd: *mut libc::c_char = dc_param_get(
|
||||||
(*msg).param,
|
(*msg).param,
|
||||||
'P' as i32,
|
'P' as i32,
|
||||||
b"\x00" as *const u8 as *const libc::c_char,
|
b"\x00" as *const u8 as *const libc::c_char,
|
||||||
);
|
);
|
||||||
let new_fwd: *mut libc::c_char = dc_mprintf(
|
let new_fwd: *mut libc::c_char = dc_mprintf(
|
||||||
b"%s %d\x00" as *const u8 as *const libc::c_char,
|
b"%s %d\x00" as *const u8 as *const libc::c_char,
|
||||||
old_fwd,
|
old_fwd,
|
||||||
new_msg_id,
|
new_msg_id,
|
||||||
);
|
);
|
||||||
dc_param_set((*msg).param, 'P' as i32, new_fwd);
|
dc_param_set((*msg).param, 'P' as i32, new_fwd);
|
||||||
dc_msg_save_param_to_disk(msg);
|
dc_msg_save_param_to_disk(msg);
|
||||||
free(new_fwd as *mut libc::c_void);
|
free(new_fwd as *mut libc::c_void);
|
||||||
free(old_fwd as *mut libc::c_void);
|
free(old_fwd as *mut libc::c_void);
|
||||||
(*msg).param = save_param
|
(*msg).param = save_param
|
||||||
} else {
|
} else {
|
||||||
(*msg).state = 20i32;
|
(*msg).state = 20i32;
|
||||||
let fresh10 = curr_timestamp;
|
let fresh10 = curr_timestamp;
|
||||||
curr_timestamp = curr_timestamp + 1;
|
curr_timestamp = curr_timestamp + 1;
|
||||||
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
|
new_msg_id = prepare_msg_raw(context, chat, msg, fresh10);
|
||||||
dc_job_send_msg(context, new_msg_id);
|
dc_job_send_msg(context, new_msg_id);
|
||||||
}
|
}
|
||||||
carray_add(
|
carray_add(
|
||||||
created_db_entries,
|
created_db_entries,
|
||||||
chat_id as uintptr_t as *mut libc::c_void,
|
chat_id as uintptr_t as *mut libc::c_void,
|
||||||
0 as *mut libc::c_uint,
|
0 as *mut libc::c_uint,
|
||||||
);
|
);
|
||||||
carray_add(
|
carray_add(
|
||||||
created_db_entries,
|
created_db_entries,
|
||||||
new_msg_id as uintptr_t as *mut libc::c_void,
|
new_msg_id as uintptr_t as *mut libc::c_void,
|
||||||
0 as *mut libc::c_uint,
|
0 as *mut libc::c_uint,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap(); // TODO: better error handling
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !created_db_entries.is_null() {
|
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,
|
0,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| "Err".into());
|
.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 {
|
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
|
||||||
if (*chat).id == 1 {
|
if (*chat).id == 1 {
|
||||||
ret = dc_stock_str((*chat).context, 8)
|
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) {
|
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_job_t) {
|
||||||
let flags: libc::c_int;
|
let flags: libc::c_int;
|
||||||
let mut current_block: u64;
|
let mut current_block: u64;
|
||||||
let mut success: libc::c_int = 0i32;
|
let mut success = false;
|
||||||
let mut imap_connected_here: libc::c_int = 0i32;
|
let mut imap_connected_here = false;
|
||||||
let mut smtp_connected_here: libc::c_int = 0i32;
|
let mut smtp_connected_here = false;
|
||||||
let mut ongoing_allocated_here: libc::c_int = 0i32;
|
let mut ongoing_allocated_here = false;
|
||||||
|
|
||||||
let mut param_autoconfig = None;
|
let mut param_autoconfig = None;
|
||||||
if !(0 == dc_alloc_ongoing(context)) {
|
if !(0 == dc_alloc_ongoing(context)) {
|
||||||
ongoing_allocated_here = 1i32;
|
ongoing_allocated_here = true;
|
||||||
if !context.sql.is_open() {
|
if !context.sql.is_open() {
|
||||||
error!(context, 0, "Cannot configure, database not opened.",);
|
error!(context, 0, "Cannot configure, database not opened.",);
|
||||||
} else {
|
} 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);
|
let r_0 = dc_loginparam_get_readable(¶m);
|
||||||
info!(context, 0, "Trying: {}", r_0,);
|
info!(context, 0, "Trying: {}", r_0,);
|
||||||
|
|
||||||
if 0 != context
|
if context
|
||||||
.inbox
|
.inbox
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.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);
|
let r_1 = dc_loginparam_get_readable(¶m);
|
||||||
info!(context, 0, "Trying: {}", r_1,);
|
info!(context, 0, "Trying: {}", r_1,);
|
||||||
|
|
||||||
if 0 != context
|
if context
|
||||||
.inbox
|
.inbox
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.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);
|
let r_2 = dc_loginparam_get_readable(¶m);
|
||||||
info!(context, 0, "Trying: {}", r_2,);
|
info!(context, 0, "Trying: {}", r_2,);
|
||||||
|
|
||||||
if 0 != context
|
if context
|
||||||
.inbox
|
.inbox
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -759,7 +759,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
|||||||
match current_block {
|
match current_block {
|
||||||
2927484062889439186 => {}
|
2927484062889439186 => {}
|
||||||
_ => {
|
_ => {
|
||||||
imap_connected_here = 1;
|
imap_connected_here = true;
|
||||||
if !s.shall_stop_ongoing {
|
if !s.shall_stop_ongoing {
|
||||||
context.call_cb(
|
context.call_cb(
|
||||||
Event::CONFIGURE_PROGRESS,
|
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,
|
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 */
|
/* 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
|
.smtp
|
||||||
.clone()
|
.clone()
|
||||||
.lock()
|
.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,
|
0, "Trying: {}", r_3,
|
||||||
);
|
);
|
||||||
|
|
||||||
if 0 == context
|
if !context
|
||||||
.smtp
|
.smtp
|
||||||
.clone()
|
.clone()
|
||||||
.lock()
|
.lock()
|
||||||
@@ -860,7 +860,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
|||||||
r_4
|
r_4
|
||||||
);
|
);
|
||||||
|
|
||||||
if 0 == context
|
if !context
|
||||||
.smtp
|
.smtp
|
||||||
.clone()
|
.clone()
|
||||||
.lock()
|
.lock()
|
||||||
@@ -887,7 +887,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
|||||||
match current_block {
|
match current_block {
|
||||||
2927484062889439186 => {}
|
2927484062889439186 => {}
|
||||||
_ => {
|
_ => {
|
||||||
smtp_connected_here = 1;
|
smtp_connected_here = true;
|
||||||
if !s.shall_stop_ongoing {
|
if !s.shall_stop_ongoing {
|
||||||
context.call_cb(
|
context.call_cb(
|
||||||
Event::CONFIGURE_PROGRESS,
|
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
|
uintptr_t
|
||||||
);
|
);
|
||||||
dc_ensure_secret_key_exists(context);
|
dc_ensure_secret_key_exists(context);
|
||||||
success = 1;
|
success = true;
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
@@ -1039,21 +1039,37 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_j
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if imap_connected_here {
|
||||||
if 0 != imap_connected_here {
|
|
||||||
context.inbox.read().unwrap().disconnect(context);
|
context.inbox.read().unwrap().disconnect(context);
|
||||||
}
|
}
|
||||||
if 0 != smtp_connected_here {
|
if smtp_connected_here {
|
||||||
context.smtp.clone().lock().unwrap().disconnect();
|
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);
|
dc_free_ongoing(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.call_cb(
|
context.call_cb(
|
||||||
Event::CONFIGURE_PROGRESS,
|
Event::CONFIGURE_PROGRESS,
|
||||||
(if 0 != success { 1000 } else { 0 }) as uintptr_t,
|
(if success { 1000 } else { 0 }) as uintptr_t,
|
||||||
0 as uintptr_t,
|
0 as uintptr_t,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1082,12 +1098,14 @@ unsafe fn moz_autoconfigure(
|
|||||||
tag_config: 0,
|
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() {
|
if xml_raw.is_null() {
|
||||||
return None;
|
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);
|
let p = strchr(moz_ac.in_emaillocalpart, '@' as i32);
|
||||||
|
|
||||||
if p.is_null() {
|
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 moz_ac: *mut moz_autoconfigure_t = userdata as *mut moz_autoconfigure_t;
|
||||||
let mut val: *mut libc::c_char = dc_strdup(text);
|
let mut val: *mut libc::c_char = dc_strdup(text);
|
||||||
dc_trim(val);
|
dc_trim(val);
|
||||||
|
let addr = to_cstring(&(*moz_ac).in_0.addr);
|
||||||
dc_str_replace(
|
dc_str_replace(
|
||||||
&mut val,
|
&mut val,
|
||||||
b"%EMAILADDRESS%\x00" as *const u8 as *const libc::c_char,
|
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(
|
dc_str_replace(
|
||||||
&mut val,
|
&mut val,
|
||||||
b"%EMAILLOCALPART%\x00" as *const u8 as *const libc::c_char,
|
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()
|
.send()
|
||||||
.and_then(|mut res| res.text())
|
.and_then(|mut res| res.text())
|
||||||
{
|
{
|
||||||
Ok(res) => unsafe { libc::strdup(to_cstring(res).as_ptr()) },
|
Ok(res) => unsafe { to_cstring(res) },
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
info!(context, 0, "Can\'t read file.",);
|
info!(context, 0, "Can\'t read file.",);
|
||||||
|
|
||||||
@@ -1298,7 +1318,7 @@ unsafe fn outlk_autodiscover(
|
|||||||
) -> Option<dc_loginparam_t> {
|
) -> Option<dc_loginparam_t> {
|
||||||
let current_block: u64;
|
let current_block: u64;
|
||||||
let mut xml_raw: *mut libc::c_char = 0 as *mut libc::c_char;
|
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 {
|
let mut outlk_ad = outlk_autodiscover_t {
|
||||||
in_0: param_in,
|
in_0: param_in,
|
||||||
out: dc_loginparam_new(),
|
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_");
|
let param = dc_loginparam_read(context, &context.sql, "configured_");
|
||||||
// the trailing underscore is correct
|
// the trailing underscore is correct
|
||||||
|
|
||||||
if 0 != imap.connect(context, ¶m) {
|
if imap.connect(context, ¶m) {
|
||||||
ret_connected = 2;
|
ret_connected = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,15 +277,12 @@ pub unsafe fn dc_contact_load_from_db(
|
|||||||
if contact_id == 1 as libc::c_uint {
|
if contact_id == 1 as libc::c_uint {
|
||||||
(*contact).id = contact_id;
|
(*contact).id = contact_id;
|
||||||
(*contact).name = dc_stock_str((*contact).context, 2);
|
(*contact).name = dc_stock_str((*contact).context, 2);
|
||||||
(*contact).addr = dc_strdup(
|
(*contact).addr = to_cstring(
|
||||||
to_cstring(
|
(*contact)
|
||||||
(*contact)
|
.context
|
||||||
.context
|
.sql
|
||||||
.sql
|
.get_config((*contact).context, "configured_addr")
|
||||||
.get_config((*contact).context, "configured_addr")
|
.unwrap_or_default(),
|
||||||
.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -294,11 +291,11 @@ pub unsafe fn dc_contact_load_from_db(
|
|||||||
params![contact_id as i32],
|
params![contact_id as i32],
|
||||||
|row| {
|
|row| {
|
||||||
(*contact).id = contact_id;
|
(*contact).id = contact_id;
|
||||||
(*contact).name = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
|
(*contact).name = to_cstring(row.get::<_, String>(0)?);
|
||||||
(*contact).addr = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
(*contact).addr = to_cstring(row.get::<_, String>(1)?);
|
||||||
(*contact).origin = row.get(2)?;
|
(*contact).origin = row.get(2)?;
|
||||||
(*contact).blocked = row.get(3)?;
|
(*contact).blocked = row.get::<_, Option<i32>>(3)?.unwrap_or_default();
|
||||||
(*contact).authname = dc_strdup(to_cstring(row.get::<_, String>(4)?).as_ptr());
|
(*contact).authname = to_cstring(row.get::<_, String>(4)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
).is_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_verified as *mut libc::c_void);
|
||||||
free(fingerprint_other_unverified 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(
|
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 {
|
if unsafe { (*contact).id } == 1 {
|
||||||
let context = unsafe { (*contact) }.context;
|
let context = unsafe { (*contact) }.context;
|
||||||
if let Some(avatar) = context.get_config(config::Config::Selfavatar) {
|
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
|
// 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);
|
dc_saxparser_parse(&mut saxparser, buf_terminated);
|
||||||
free(dehtml.last_href as *mut libc::c_void);
|
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(
|
unsafe fn dehtml_text_cb(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::CStr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use mmime::clist::*;
|
use mmime::clist::*;
|
||||||
@@ -184,7 +184,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
b"Autocrypt-Gossip\x00" as *const u8
|
b"Autocrypt-Gossip\x00" as *const u8
|
||||||
as *const libc::c_char,
|
as *const libc::c_char,
|
||||||
),
|
),
|
||||||
strdup(header.as_ptr()),
|
header,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -294,10 +294,8 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
sign_key.as_ref(),
|
sign_key.as_ref(),
|
||||||
) {
|
) {
|
||||||
let ctext_bytes = ctext_v.len();
|
let ctext_bytes = ctext_v.len();
|
||||||
let ctext_c = CString::new(ctext_v).unwrap();
|
let ctext = to_cstring(ctext_v);
|
||||||
let ctext = strdup(ctext_c.as_ptr());
|
(*helper).cdata_to_free = ctext as *mut _;
|
||||||
|
|
||||||
(*helper).cdata_to_free = ctext as *mut libc::c_void;
|
|
||||||
|
|
||||||
/* create MIME-structure that will contain the encrypted text */
|
/* create MIME-structure that will contain the encrypted text */
|
||||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||||
@@ -354,13 +352,13 @@ pub unsafe fn dc_e2ee_encrypt(
|
|||||||
14181132614457621749 => {}
|
14181132614457621749 => {}
|
||||||
_ => {
|
_ => {
|
||||||
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
|
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(
|
mailimf_fields_add(
|
||||||
imffields_unprotected,
|
imffields_unprotected,
|
||||||
mailimf_field_new_custom(
|
mailimf_field_new_custom(
|
||||||
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
|
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,
|
add_signatures,
|
||||||
) {
|
) {
|
||||||
let plain_bytes = plain.len();
|
let plain_bytes = plain.len();
|
||||||
let plain_c = CString::new(plain).unwrap();
|
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||||
let plain_buf = strdup(plain_c.as_ptr());
|
|
||||||
|
|
||||||
let mut index: size_t = 0i32 as size_t;
|
let mut index: size_t = 0i32 as size_t;
|
||||||
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
||||||
if mailmime_parse(
|
if mailmime_parse(
|
||||||
plain_buf as *const libc::c_char,
|
plain_buf as *const _,
|
||||||
plain_bytes,
|
plain_bytes,
|
||||||
&mut index,
|
&mut index,
|
||||||
&mut decrypted_mime,
|
&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
|
// TODO should return bool /rtn
|
||||||
@@ -539,7 +539,7 @@ pub unsafe fn dc_normalize_setup_code(
|
|||||||
p1 = p1.offset(1);
|
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) {
|
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,
|
0, "***IMPORT-in-progress: total_files_cnt={:?}", total_files_cnt,
|
||||||
);
|
);
|
||||||
|
|
||||||
context
|
let res = context.sql.query_map(
|
||||||
.sql
|
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
|
||||||
.query_map(
|
params![],
|
||||||
"SELECT file_name, file_content FROM backup_blobs ORDER BY id;",
|
|row| {
|
||||||
params![],
|
let name: String = row.get(0)?;
|
||||||
|row| {
|
let blob: Vec<u8> = row.get(1)?;
|
||||||
let name: String = row.get(0)?;
|
|
||||||
let blob: Vec<u8> = row.get(1)?;
|
|
||||||
|
|
||||||
Ok((name, blob))
|
Ok((name, blob))
|
||||||
},
|
},
|
||||||
|files| {
|
|files| {
|
||||||
let mut loop_success = true;
|
let mut loop_success = true;
|
||||||
let mut processed_files_cnt = 0;
|
let mut processed_files_cnt = 0;
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
if file.is_err() {
|
let (file_name, file_blob) = file?;
|
||||||
loop_success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let (file_name, file_blob) = file.unwrap();
|
|
||||||
|
|
||||||
if context
|
if context
|
||||||
.running_state
|
.running_state
|
||||||
.clone()
|
.clone()
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.shall_stop_ongoing
|
.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 ...
|
|
||||||
loop_success = false;
|
loop_success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
processed_files_cnt += 1;
|
||||||
if !loop_success {
|
let mut permille = processed_files_cnt * 1000 / total_files_cnt;
|
||||||
return Err(format_err!("fail").into());
|
if permille < 10 {
|
||||||
|
permille = 10
|
||||||
}
|
}
|
||||||
sql::execute(context, &context.sql, "DROP TABLE backup_blobs;", params![])?;
|
if permille > 990 {
|
||||||
sql::try_execute(context, &context.sql, "VACUUM;");
|
permille = 990
|
||||||
Ok(())
|
}
|
||||||
},
|
context.call_cb(Event::IMEX_PROGRESS, permille as uintptr_t, 0);
|
||||||
)
|
if file_blob.is_empty() {
|
||||||
.is_ok() as libc::c_int
|
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")
|
.format("delta-chat-%Y-%m-%d.bak")
|
||||||
.to_string();
|
.to_string();
|
||||||
let buffer = to_cstring(res);
|
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() {
|
if dest_pathNfilename.is_null() {
|
||||||
error!(context, 0, "Cannot get backup file name.",);
|
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(
|
sql.prepare(
|
||||||
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
|
||||||
move |mut stmt| {
|
move |mut stmt, _| {
|
||||||
let mut processed_files_cnt = 0;
|
let mut processed_files_cnt = 0;
|
||||||
for entry in dir_handle {
|
for entry in dir_handle {
|
||||||
if entry.is_err() {
|
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 imported_cnt: libc::c_int = 0;
|
||||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
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 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 set_default: libc::c_int;
|
||||||
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
|
let mut buf: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||||
let mut buf_bytes: size_t = 0 as size_t;
|
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();
|
let entry = entry.unwrap();
|
||||||
free(suffix as *mut libc::c_void);
|
free(suffix as *mut libc::c_void);
|
||||||
let name_f = entry.file_name();
|
let name_f = entry.file_name();
|
||||||
let name_c = to_cstring(name_f.to_string_lossy());
|
free(name_c as *mut libc::c_void);
|
||||||
suffix = dc_get_filesuffix_lc(name_c.as_ptr());
|
name_c = to_cstring(name_f.to_string_lossy());
|
||||||
|
suffix = dc_get_filesuffix_lc(name_c);
|
||||||
if suffix.is_null()
|
if suffix.is_null()
|
||||||
|| strcmp(suffix, b"asc\x00" as *const u8 as *const libc::c_char) != 0
|
|| 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(
|
path_plus_name = dc_mprintf(
|
||||||
b"%s/%s\x00" as *const u8 as *const libc::c_char,
|
b"%s/%s\x00" as *const u8 as *const libc::c_char,
|
||||||
dir_name,
|
dir_name,
|
||||||
name_c.as_ptr(),
|
name_c,
|
||||||
);
|
);
|
||||||
info!(context, 0, "Checking: {}", as_str(path_plus_name));
|
info!(context, 0, "Checking: {}", as_str(path_plus_name));
|
||||||
free(buf as *mut libc::c_void);
|
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;
|
set_default = 1;
|
||||||
if !strstr(
|
if !strstr(name_c, b"legacy\x00" as *const u8 as *const libc::c_char).is_null() {
|
||||||
name_c.as_ptr(),
|
|
||||||
b"legacy\x00" as *const u8 as *const libc::c_char,
|
|
||||||
)
|
|
||||||
.is_null()
|
|
||||||
{
|
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
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(suffix as *mut libc::c_void);
|
||||||
free(path_plus_name as *mut libc::c_void);
|
free(path_plus_name as *mut libc::c_void);
|
||||||
free(buf 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) {
|
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();
|
let probe_imap_network = *context.probe_imap_network.clone().read().unwrap();
|
||||||
*context.probe_imap_network.write().unwrap() = 0;
|
*context.probe_imap_network.write().unwrap() = 0;
|
||||||
*context.perform_inbox_jobs_needed.write().unwrap() = 0;
|
*context.perform_inbox_jobs_needed.write().unwrap() = 0;
|
||||||
|
|
||||||
dc_job_perform(context, 100, probe_imap_network);
|
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) {
|
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
|
params_probe
|
||||||
};
|
};
|
||||||
|
|
||||||
let jobs: Vec<dc_job_t> = context
|
let jobs: Result<Vec<dc_job_t>, _> = context.sql.query_map(
|
||||||
.sql
|
query,
|
||||||
.query_map(
|
params,
|
||||||
query,
|
|row| {
|
||||||
params,
|
let job = dc_job_t {
|
||||||
|row| {
|
job_id: row.get(0)?,
|
||||||
let job = dc_job_t {
|
action: row.get(1)?,
|
||||||
job_id: row.get(0)?,
|
foreign_id: row.get(2)?,
|
||||||
action: row.get(1)?,
|
desired_timestamp: row.get(5)?,
|
||||||
foreign_id: row.get(2)?,
|
added_timestamp: row.get(4)?,
|
||||||
desired_timestamp: row.get(5)?,
|
tries: row.get(6)?,
|
||||||
added_timestamp: row.get(4)?,
|
param: dc_param_new(),
|
||||||
tries: row.get(6)?,
|
try_again: 0,
|
||||||
param: dc_param_new(),
|
pending_error: 0 as *mut libc::c_char,
|
||||||
try_again: 0,
|
};
|
||||||
pending_error: 0 as *mut libc::c_char,
|
|
||||||
};
|
|
||||||
|
|
||||||
let packed: String = row.get(3)?;
|
let packed: String = row.get(3)?;
|
||||||
dc_param_set_packed(job.param, to_cstring(packed).as_ptr());
|
let packed_c = to_cstring(packed);
|
||||||
Ok(job)
|
dc_param_set_packed(job.param, packed_c);
|
||||||
},
|
free(packed_c as *mut _);
|
||||||
|jobs| {
|
Ok(job)
|
||||||
jobs.collect::<Result<Vec<dc_job_t>, _>>()
|
},
|
||||||
.map_err(Into::into)
|
|jobs| {
|
||||||
},
|
let res = jobs
|
||||||
)
|
.collect::<Result<Vec<dc_job_t>, _>>()
|
||||||
.unwrap_or_default();
|
.map_err(Into::into);
|
||||||
|
res
|
||||||
for mut job in jobs {
|
},
|
||||||
|
);
|
||||||
|
match jobs {
|
||||||
|
Ok(ref res) => {}
|
||||||
|
Err(ref err) => {
|
||||||
|
info!(context, 0, "query failed: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for mut job in jobs.unwrap_or_default() {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
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 loginparam = dc_loginparam_read(context, &context.sql, "configured_");
|
||||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
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);
|
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||||
current_block = 14216916617354591294;
|
current_block = 14216916617354591294;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -215,8 +215,10 @@ pub fn dc_get_locations(
|
|||||||
if 0 != (*loc).msg_id {
|
if 0 != (*loc).msg_id {
|
||||||
let txt: String = row.get(9)?;
|
let txt: String = row.get(9)?;
|
||||||
let txt_c = to_cstring(txt);
|
let txt_c = to_cstring(txt);
|
||||||
if 0 != is_marker(txt_c.as_ptr()) {
|
if 0 != is_marker(txt_c) {
|
||||||
(*loc).marker = strdup(txt_c.as_ptr());
|
(*loc).marker = txt_c;
|
||||||
|
} else {
|
||||||
|
free(txt_c as *mut _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(loc)
|
Ok(loc)
|
||||||
@@ -330,9 +332,9 @@ pub fn dc_get_location_kml(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if 0 != success {
|
if 0 != success {
|
||||||
unsafe { strdup(to_cstring(ret).as_ptr()) }
|
unsafe { to_cstring(ret) }
|
||||||
} else {
|
} 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)
|
let res = chrono::NaiveDateTime::from_timestamp(utc, 0)
|
||||||
.format("%Y-%m-%dT%H:%M:%SZ")
|
.format("%Y-%m-%dT%H:%M:%SZ")
|
||||||
.to_string();
|
.to_string();
|
||||||
strdup(to_cstring(res).as_ptr())
|
to_cstring(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_get_message_kml(
|
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 timestamp>? \
|
||||||
AND independent=0 \
|
AND independent=0 \
|
||||||
ORDER BY timestamp;",
|
ORDER BY timestamp;",
|
||||||
|mut stmt_locations| {
|
|mut stmt_locations, _| {
|
||||||
for (chat_id, locations_send_begin, locations_last_sent) in
|
for (chat_id, locations_send_begin, locations_last_sent) in
|
||||||
rows.filter_map(|r| match r {
|
rows.filter_map(|r| match r {
|
||||||
Ok(Some(v)) => Some(v),
|
Ok(Some(v)) => Some(v),
|
||||||
|
|||||||
@@ -161,24 +161,20 @@ pub unsafe fn dc_mimefactory_load_msg(
|
|||||||
for row in rows {
|
for row in rows {
|
||||||
let (authname, addr) = row?;
|
let (authname, addr) = row?;
|
||||||
let addr_c = to_cstring(addr);
|
let addr_c = to_cstring(addr);
|
||||||
if clist_search_string_nocase(
|
if clist_search_string_nocase((*factory).recipients_addr, addr_c) == 0 {
|
||||||
(*factory).recipients_addr,
|
|
||||||
addr_c.as_ptr(),
|
|
||||||
) == 0
|
|
||||||
{
|
|
||||||
clist_insert_after(
|
clist_insert_after(
|
||||||
(*factory).recipients_names,
|
(*factory).recipients_names,
|
||||||
(*(*factory).recipients_names).last,
|
(*(*factory).recipients_names).last,
|
||||||
if !authname.is_empty() {
|
if !authname.is_empty() {
|
||||||
dc_strdup(to_cstring(authname).as_ptr())
|
to_cstring(authname)
|
||||||
} else {
|
} else {
|
||||||
0 as *mut libc::c_char
|
std::ptr::null_mut()
|
||||||
} as *mut libc::c_void,
|
} as *mut libc::c_void,
|
||||||
);
|
);
|
||||||
clist_insert_after(
|
clist_insert_after(
|
||||||
(*factory).recipients_addr,
|
(*factory).recipients_addr,
|
||||||
(*(*factory).recipients_addr).last,
|
(*(*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 {
|
match row {
|
||||||
Ok((in_reply_to, references)) => {
|
Ok((in_reply_to, references)) => {
|
||||||
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
|
(*factory).in_reply_to = to_cstring(in_reply_to);
|
||||||
(*factory).references = dc_strdup(to_cstring(references).as_ptr());
|
(*factory).references = to_cstring(references);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -266,32 +262,24 @@ pub unsafe fn dc_mimefactory_load_msg(
|
|||||||
|
|
||||||
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
|
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
|
||||||
let context = (*factory).context;
|
let context = (*factory).context;
|
||||||
(*factory).from_addr = strdup(
|
(*factory).from_addr = to_cstring(
|
||||||
to_cstring(
|
context
|
||||||
context
|
.sql
|
||||||
.sql
|
.get_config(context, "configured_addr")
|
||||||
.get_config(context, "configured_addr")
|
.unwrap_or_default(),
|
||||||
.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
);
|
||||||
(*factory).from_displayname = strdup(
|
|
||||||
to_cstring(
|
(*factory).from_displayname = to_cstring(
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.get_config(context, "displayname")
|
.get_config(context, "displayname")
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
)
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
);
|
||||||
(*factory).selfstatus = strdup(
|
(*factory).selfstatus = to_cstring(
|
||||||
to_cstring(
|
context
|
||||||
context
|
.sql
|
||||||
.sql
|
.get_config(context, "selfstatus")
|
||||||
.get_config(context, "selfstatus")
|
.unwrap_or_default(),
|
||||||
.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
);
|
||||||
if (*factory).selfstatus.is_null() {
|
if (*factory).selfstatus.is_null() {
|
||||||
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
|
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
|
||||||
@@ -1185,7 +1173,7 @@ unsafe fn build_body_file(
|
|||||||
let res = ts
|
let res = ts
|
||||||
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
|
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
|
||||||
.to_string();
|
.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 {
|
} else if (*msg).type_0 == DC_MSG_AUDIO as libc::c_int {
|
||||||
filename_to_send = dc_get_filename(pathNfilename)
|
filename_to_send = dc_get_filename(pathNfilename)
|
||||||
} else if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|
} else if (*msg).type_0 == DC_MSG_IMAGE as libc::c_int
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use charset::Charset;
|
use charset::Charset;
|
||||||
use mmime::mailimf::*;
|
use mmime::mailimf::*;
|
||||||
@@ -833,6 +833,7 @@ unsafe fn hash_header(
|
|||||||
18 => key = b"References\x00" as *const u8 as *const libc::c_char,
|
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,
|
19 => key = b"Subject\x00" as *const u8 as *const libc::c_char,
|
||||||
22 => {
|
22 => {
|
||||||
|
// MAILIMF_FIELD_OPTIONAL_FIELD
|
||||||
let optional_field: *const mailimf_optional_field =
|
let optional_field: *const mailimf_optional_field =
|
||||||
(*field).fld_data.fld_optional_field;
|
(*field).fld_data.fld_optional_field;
|
||||||
if !optional_field.is_null() {
|
if !optional_field.is_null() {
|
||||||
@@ -842,17 +843,16 @@ unsafe fn hash_header(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if !key.is_null() {
|
if !key.is_null() {
|
||||||
let key_len: libc::c_int = strlen(key) as libc::c_int;
|
// XXX the optional field sometimes contains invalid UTF8
|
||||||
if out.contains_key(as_str(key)) {
|
// which should not happen (according to the mime standard).
|
||||||
if (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|
// This might point to a bug in our mime parsing/processing
|
||||||
|| key_len > 5i32
|
// logic. As mmime/dc_mimeparser is scheduled fore replacement
|
||||||
&& strncasecmp(key, b"Chat-\x00" as *const u8 as *const libc::c_char, 5)
|
// anyway we just use a lossy conversion.
|
||||||
== 0i32
|
let key_r = &to_string_lossy(key);
|
||||||
{
|
if !out.contains_key(key_r) || // key already exists, only overwrite known types (protected headers)
|
||||||
out.insert(to_string(key), field);
|
(*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as i32 || key_r.starts_with("Chat-")
|
||||||
}
|
{
|
||||||
} else {
|
out.insert(key_r.to_string(), field);
|
||||||
out.insert(to_string(key), field);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur1 = if !cur1.is_null() {
|
cur1 = if !cur1.is_null() {
|
||||||
@@ -1204,8 +1204,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
|||||||
current_block = 8795901732489102124;
|
current_block = 8795901732489102124;
|
||||||
} else {
|
} else {
|
||||||
decoded_data_bytes = res.len();
|
decoded_data_bytes = res.len();
|
||||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
decoded_data = res.as_ptr() as *const libc::c_char;
|
||||||
decoded_data = strdup(res_c.as_ptr());
|
|
||||||
current_block = 17788412896529399552;
|
current_block = 17788412896529399552;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1341,8 +1340,9 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
|||||||
}
|
}
|
||||||
if !filename_parts.is_empty() {
|
if !filename_parts.is_empty() {
|
||||||
free(desired_filename as *mut libc::c_void);
|
free(desired_filename as *mut libc::c_void);
|
||||||
desired_filename =
|
let parts_c = to_cstring(filename_parts);
|
||||||
dc_decode_ext_header(to_cstring(filename_parts).as_ptr());
|
desired_filename = dc_decode_ext_header(parts_c);
|
||||||
|
free(parts_c as *mut _);
|
||||||
}
|
}
|
||||||
if desired_filename.is_null() {
|
if desired_filename.is_null() {
|
||||||
let param = mailmime_find_ct_parameter(
|
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);
|
ret += &format!("Cannot load message #{}.", msg_id as usize);
|
||||||
dc_msg_unref(msg);
|
dc_msg_unref(msg);
|
||||||
dc_contact_unref(contact_from);
|
dc_contact_unref(contact_from);
|
||||||
return strdup(to_cstring(ret).as_ptr());
|
return to_cstring(ret);
|
||||||
}
|
}
|
||||||
let rawtxt = rawtxt.unwrap();
|
let rawtxt = rawtxt.unwrap();
|
||||||
let rawtxt = dc_truncate_str(rawtxt.trim(), 100000);
|
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
|
// device-internal message, no further details needed
|
||||||
dc_msg_unref(msg);
|
dc_msg_unref(msg);
|
||||||
dc_contact_unref(contact_from);
|
dc_contact_unref(contact_from);
|
||||||
return strdup(to_cstring(ret).as_ptr());
|
return to_cstring(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
context
|
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_msg_unref(msg);
|
||||||
dc_contact_unref(contact_from);
|
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> {
|
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);
|
dc_msg_empty(msg);
|
||||||
|
|
||||||
(*msg).id = row.get::<_, i32>(0)? as u32;
|
(*msg).id = row.get::<_, i32>(0)? as u32;
|
||||||
(*msg).rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
|
(*msg).rfc724_mid = to_cstring(row.get::<_, String>(1)?);
|
||||||
(*msg).in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
|
(*msg).in_reply_to = match row.get::<_, Option<String>>(2)? {
|
||||||
(*msg).server_folder = dc_strdup(to_cstring(row.get::<_, String>(3)?).as_ptr());
|
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).server_uid = row.get(4)?;
|
||||||
(*msg).move_state = row.get(5)?;
|
(*msg).move_state = row.get(5)?;
|
||||||
(*msg).chat_id = row.get(6)?;
|
(*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).type_0 = row.get(12)?;
|
||||||
(*msg).state = row.get(13)?;
|
(*msg).state = row.get(13)?;
|
||||||
(*msg).is_dc_message = row.get(14)?;
|
(*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(
|
dc_param_set_packed(
|
||||||
(*msg).param,
|
(*msg).param,
|
||||||
to_cstring(row.get::<_, String>(16)?).as_ptr()
|
to_cstring(row.get::<_, String>(16)?)
|
||||||
);
|
);
|
||||||
(*msg).starred = row.get(17)?;
|
(*msg).starred = row.get(17)?;
|
||||||
(*msg).hidden = row.get(18)?;
|
(*msg).hidden = row.get(18)?;
|
||||||
(*msg).location_id = row.get(19)?;
|
(*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 {
|
if (*msg).chat_blocked == 2 {
|
||||||
dc_truncate_n_unwrap_str((*msg).text, 256, 0);
|
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 {
|
match res {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(err) => {
|
Err(err) => false,
|
||||||
error!(context, 0, "msg: load from db failed: {:?}", 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 {
|
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 {
|
} else {
|
||||||
std::ptr::null_mut()
|
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 {
|
if msg_ids.is_null() || msg_cnt <= 0 {
|
||||||
return false;
|
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",
|
"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| {
|
|mut stmt, _| {
|
||||||
let mut send_event = false;
|
let mut res = Vec::with_capacity(msg_cnt);
|
||||||
|
|
||||||
for i in 0..msg_cnt {
|
for i in 0..msg_cnt {
|
||||||
// TODO: do I need to reset?
|
|
||||||
let id = unsafe { *msg_ids.offset(i as isize) };
|
let id = unsafe { *msg_ids.offset(i as isize) };
|
||||||
if let Ok((curr_state, curr_blocked)) = stmt
|
let (state, blocked) = stmt.query_row(params![id as i32], |row| {
|
||||||
.query_row(params![id as i32], |row| {
|
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<i32>>(1)?.unwrap_or_default()))
|
||||||
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
|
})?;
|
||||||
})
|
res.push((id, state, blocked));
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Ok(res)
|
||||||
if send_event {
|
|
||||||
context.call_cb(Event::MSGS_CHANGED, 0, 0);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
).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 {
|
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
|
context
|
||||||
.sql
|
.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 {
|
for i in 0..msg_cnt {
|
||||||
stmt.execute(params![star, unsafe { *msg_ids.offset(i as isize) as i32 }])?;
|
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);
|
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 {
|
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)],
|
&[as_str(rfc724_mid)],
|
||||||
|row| {
|
|row| {
|
||||||
if !ret_server_folder.is_null() {
|
if !ret_server_folder.is_null() {
|
||||||
unsafe {
|
unsafe { *ret_server_folder = to_cstring(row.get::<_, String>(0)?) };
|
||||||
*ret_server_folder = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if !ret_server_uid.is_null() {
|
if !ret_server_uid.is_null() {
|
||||||
unsafe { *ret_server_uid = row.get(1)? };
|
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 addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||||
if let Some(peerstate) = peerstate {
|
if let Some(peerstate) = peerstate {
|
||||||
(*qr_parsed).state = 210i32;
|
(*qr_parsed).state = 210i32;
|
||||||
let c_addr = peerstate
|
let addr_ptr = if let Some(ref addr) = peerstate.addr {
|
||||||
.addr
|
to_cstring(addr)
|
||||||
.as_ref()
|
|
||||||
.map(to_cstring)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let addr_ptr = if peerstate.addr.is_some() {
|
|
||||||
c_addr.as_ptr()
|
|
||||||
} else {
|
} else {
|
||||||
std::ptr::null()
|
std::ptr::null()
|
||||||
};
|
};
|
||||||
@@ -256,6 +251,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
|
|||||||
0x80i32,
|
0x80i32,
|
||||||
0 as *mut libc::c_int,
|
0 as *mut libc::c_int,
|
||||||
);
|
);
|
||||||
|
free(addr_ptr as *mut _);
|
||||||
dc_create_or_lookup_nchat_by_contact_id(
|
dc_create_or_lookup_nchat_by_contact_id(
|
||||||
context,
|
context,
|
||||||
(*qr_parsed).id,
|
(*qr_parsed).id,
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ pub unsafe fn dc_receive_imf(
|
|||||||
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
|
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
|
||||||
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
|
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
|
||||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
||||||
|mut stmt| {
|
|mut stmt, conn| {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
if !(i < icnt) {
|
if !(i < icnt) {
|
||||||
@@ -503,16 +503,21 @@ pub unsafe fn dc_receive_imf(
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
|
// txt_raw might contain invalid utf8
|
||||||
if !txt_raw.is_null() {
|
if !txt_raw.is_null() {
|
||||||
as_str(txt_raw)
|
to_string_lossy(txt_raw)
|
||||||
} else {
|
} else {
|
||||||
""
|
String::new()
|
||||||
},
|
},
|
||||||
as_str((*(*part).param).packed),
|
as_str((*(*part).param).packed),
|
||||||
(*part).bytes,
|
(*part).bytes,
|
||||||
hidden,
|
hidden,
|
||||||
if 0 != save_mime_headers {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@@ -528,9 +533,9 @@ pub unsafe fn dc_receive_imf(
|
|||||||
} else {
|
} else {
|
||||||
free(txt_raw as *mut libc::c_void);
|
free(txt_raw as *mut libc::c_void);
|
||||||
txt_raw = 0 as *mut libc::c_char;
|
txt_raw = 0 as *mut libc::c_char;
|
||||||
insert_msg_id = sql::get_rowid(
|
insert_msg_id = sql::get_rowid_with_conn(
|
||||||
context,
|
context,
|
||||||
&context.sql,
|
conn,
|
||||||
"msgs",
|
"msgs",
|
||||||
"rfc724_mid",
|
"rfc724_mid",
|
||||||
as_str(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 {
|
if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed {
|
||||||
let param = dc_param_new();
|
let param = dc_param_new();
|
||||||
dc_param_set(
|
let server_folder_c = to_cstring(server_folder.as_ref());
|
||||||
param,
|
dc_param_set(param, 'Z' as i32, server_folder_c);
|
||||||
'Z' as i32,
|
free(server_folder_c as *mut _);
|
||||||
to_cstring(server_folder.as_ref()).as_ptr(),
|
|
||||||
);
|
|
||||||
dc_param_set_int(param, 'z' as i32, server_uid as i32);
|
dc_param_set_int(param, 'z' as i32, server_uid as i32);
|
||||||
if 0 != mime_parser.is_send_by_messenger
|
if 0 != mime_parser.is_send_by_messenger
|
||||||
&& 0 != context
|
&& 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(rfc724_mid as *mut libc::c_void);
|
||||||
free(mime_in_reply_to as *mut libc::c_void);
|
free(mime_in_reply_to as *mut libc::c_void);
|
||||||
free(mime_references 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![],
|
params![],
|
||||||
|row| {
|
|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 bytes = s.as_ref().as_bytes();
|
||||||
let result = Sha256::digest(bytes);
|
let result = Sha256::digest(bytes);
|
||||||
let result_hex = hex::encode(&result[..8]);
|
let result_hex = hex::encode(&result[..8]);
|
||||||
let result_cstring = to_cstring(result_hex);
|
unsafe { to_cstring(result_hex) as *const _ }
|
||||||
|
|
||||||
unsafe { strdup(result_cstring.as_ptr()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn search_chat_ids_by_contact_ids(
|
unsafe fn search_chat_ids_by_contact_ids(
|
||||||
@@ -1604,8 +1613,7 @@ unsafe fn check_verified_properties(
|
|||||||
let contact = dc_contact_new(context);
|
let contact = dc_contact_new(context);
|
||||||
|
|
||||||
let verify_fail = |reason: String| {
|
let verify_fail = |reason: String| {
|
||||||
*failure_reason =
|
*failure_reason = to_cstring(format!("{}. See \"Info\" for details.", reason));
|
||||||
strdup(to_cstring(format!("{}. See \"Info\" for details.", reason)).as_ptr());
|
|
||||||
warn!(context, 0, "{}", reason);
|
warn!(context, 0, "{}", reason);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1651,68 +1659,61 @@ unsafe fn check_verified_properties(
|
|||||||
let to_ids_str = to_string(to_ids_str_c);
|
let to_ids_str = to_string(to_ids_str_c);
|
||||||
free(to_ids_str_c as *mut libc::c_void);
|
free(to_ids_str_c as *mut libc::c_void);
|
||||||
|
|
||||||
let ok = context
|
let rows = context.sql.query_map(
|
||||||
.sql
|
format!(
|
||||||
.query_map(
|
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
|
||||||
format!(
|
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
|
||||||
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
|
&to_ids_str,
|
||||||
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)?)),
|
||||||
params![],
|
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||||
|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();
|
|
||||||
|
|
||||||
// if we're here, we know the gossip key is verified:
|
if rows.is_err() {
|
||||||
// - use the gossip-key as verified-key if there is no verified-key
|
cleanup();
|
||||||
// - OR if the verified-key does not match public-key or gossip-key
|
return 0;
|
||||||
// (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)
|
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
|
||||||
if 0 == is_verified
|
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
|
||||||
|| peerstate.verified_key_fingerprint
|
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
|
||||||
!= peerstate.public_key_fingerprint
|
let peerstate = peerstate.as_mut().unwrap();
|
||||||
&& peerstate.verified_key_fingerprint
|
|
||||||
!= peerstate.gossip_key_fingerprint
|
// if we're here, we know the gossip key is verified:
|
||||||
{
|
// - use the gossip-key as verified-key if there is no verified-key
|
||||||
info!(
|
// - OR if the verified-key does not match public-key or gossip-key
|
||||||
context,
|
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
|
||||||
0,
|
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
|
||||||
"{} has verfied {}.",
|
if 0 == is_verified
|
||||||
as_str((*contact).addr),
|
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
|
||||||
to_addr,
|
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
|
||||||
);
|
{
|
||||||
let fp = peerstate.gossip_key_fingerprint.clone();
|
info!(
|
||||||
if let Some(fp) = fp {
|
context,
|
||||||
peerstate.set_verified(0, &fp, 2);
|
0,
|
||||||
peerstate.save_to_db(&context.sql, false);
|
"{} has verfied {}.",
|
||||||
is_verified = 1;
|
as_str((*contact).addr),
|
||||||
}
|
to_addr,
|
||||||
}
|
);
|
||||||
}
|
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||||
if 0 == is_verified {
|
if let Some(fp) = fp {
|
||||||
verify_fail(format!(
|
peerstate.set_verified(0, &fp, 2);
|
||||||
"{} is not a member of this verified group",
|
peerstate.save_to_db(&context.sql, false);
|
||||||
to_addr
|
is_verified = 1;
|
||||||
));
|
|
||||||
cleanup();
|
|
||||||
return Err(failure::format_err!("not a valid member").into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
},
|
}
|
||||||
)
|
if 0 == is_verified {
|
||||||
.is_ok(); // TODO: Better default
|
verify_fail(format!(
|
||||||
|
"{} is not a member of this verified group",
|
||||||
|
to_addr
|
||||||
|
));
|
||||||
|
cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup();
|
1
|
||||||
|
|
||||||
ok as libc::c_int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_better_msg(mime_parser: &dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
|
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);
|
free(group_name_urlencoded as *mut libc::c_void);
|
||||||
|
|
||||||
if let Some(qr) = qr {
|
if let Some(qr) = qr {
|
||||||
strdup(to_cstring(qr).as_ptr())
|
to_cstring(qr)
|
||||||
} else {
|
} else {
|
||||||
std::ptr::null_mut()
|
std::ptr::null_mut()
|
||||||
}
|
}
|
||||||
@@ -939,15 +939,15 @@ pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate)
|
|||||||
&mut contact_chat_id,
|
&mut contact_chat_id,
|
||||||
0 as *mut libc::c_int,
|
0 as *mut libc::c_int,
|
||||||
);
|
);
|
||||||
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
|
let c_addr_ptr = if let Some(ref addr) = peerstate.addr {
|
||||||
let c_addr_ptr = if peerstate.addr.is_some() {
|
to_cstring(addr)
|
||||||
c_addr.as_ptr()
|
|
||||||
} else {
|
} else {
|
||||||
std::ptr::null_mut()
|
std::ptr::null_mut()
|
||||||
};
|
};
|
||||||
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
|
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
|
||||||
dc_add_device_msg(context, contact_chat_id, msg);
|
dc_add_device_msg(context, contact_chat_id, msg);
|
||||||
free(msg as *mut libc::c_void);
|
free(msg as *mut libc::c_void);
|
||||||
|
free(c_addr_ptr as *mut _);
|
||||||
context.call_cb(
|
context.call_cb(
|
||||||
Event::CHAT_MODIFIED,
|
Event::CHAT_MODIFIED,
|
||||||
contact_chat_id as uintptr_t,
|
contact_chat_id as uintptr_t,
|
||||||
|
|||||||
@@ -225,7 +225,8 @@ unsafe fn dc_simplify_simplify_plain_text(
|
|||||||
pending_linebreaks -= 1
|
pending_linebreaks -= 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret += &to_string(line);
|
// the incoming message might contain invalid UTF8
|
||||||
|
ret += &to_string_lossy(line);
|
||||||
content_lines_added += 1;
|
content_lines_added += 1;
|
||||||
pending_linebreaks = 1i32
|
pending_linebreaks = 1i32
|
||||||
}
|
}
|
||||||
@@ -238,7 +239,7 @@ unsafe fn dc_simplify_simplify_plain_text(
|
|||||||
}
|
}
|
||||||
dc_free_splitted_lines(lines);
|
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 charset::Charset;
|
||||||
use mmime::mailmime_decode::*;
|
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));
|
std::slice::from_raw_parts(decoded as *const u8, strlen(decoded));
|
||||||
|
|
||||||
let (res, _, _) = encoding.decode(data);
|
let (res, _, _) = encoding.decode(data);
|
||||||
free(decoded as *mut libc::c_void);
|
free(decoded as *mut _);
|
||||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
let r = std::ffi::CString::new(res.as_bytes()).unwrap();
|
||||||
|
decoded = dc_strdup(r.as_ptr());
|
||||||
decoded = strdup(res_c.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 bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur));
|
||||||
let raw = to_cstring(format!("={}", &hex::encode_upper(bytes)[..2]));
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::x::strdup;
|
|
||||||
|
|
||||||
// Token namespaces
|
// Token namespaces
|
||||||
pub type dc_tokennamespc_t = usize;
|
pub type dc_tokennamespc_t = usize;
|
||||||
@@ -34,16 +33,16 @@ pub fn dc_token_lookup(
|
|||||||
namespc: dc_tokennamespc_t,
|
namespc: dc_tokennamespc_t,
|
||||||
foreign_id: u32,
|
foreign_id: u32,
|
||||||
) -> *mut libc::c_char {
|
) -> *mut libc::c_char {
|
||||||
if let Some(token) = context.sql.query_row_col::<_, String>(
|
context
|
||||||
context,
|
.sql
|
||||||
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
|
.query_row_col::<_, String>(
|
||||||
params![namespc as i32, foreign_id as i32],
|
context,
|
||||||
0,
|
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
|
||||||
) {
|
params![namespc as i32, foreign_id as i32],
|
||||||
unsafe { strdup(to_cstring(token).as_ptr()) }
|
0,
|
||||||
} else {
|
)
|
||||||
std::ptr::null_mut()
|
.map(|s| unsafe { to_cstring(s) })
|
||||||
}
|
.unwrap_or_else(|| std::ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_token_exists(
|
pub fn dc_token_exists(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
@@ -176,14 +177,14 @@ pub unsafe fn dc_trim(buf: *mut libc::c_char) {
|
|||||||
|
|
||||||
/* the result must be free()'d */
|
/* the result must be free()'d */
|
||||||
pub unsafe fn dc_strlower(in_0: *const libc::c_char) -> *mut libc::c_char {
|
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());
|
to_cstring(to_string(in_0).to_lowercase())
|
||||||
strdup(raw.as_ptr())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) {
|
pub unsafe fn dc_strlower_in_place(in_0: *mut libc::c_char) {
|
||||||
let raw = to_cstring(to_string(in_0).to_lowercase());
|
let raw = to_cstring(to_string(in_0).to_lowercase());
|
||||||
assert_eq!(strlen(in_0), strlen(raw.as_ptr()));
|
assert_eq!(strlen(in_0), strlen(raw));
|
||||||
memcpy(in_0 as *mut _, raw.as_ptr() as *const _, strlen(in_0));
|
memcpy(in_0 as *mut _, raw as *const _, strlen(in_0));
|
||||||
|
free(raw as *mut _);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dc_str_contains(
|
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 buf = std::slice::from_raw_parts(buf, bytes);
|
||||||
let raw = hex::encode_upper(buf);
|
let raw = hex::encode_upper(buf);
|
||||||
strdup(to_cstring(raw).as_ptr())
|
to_cstring(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove all \r characters from string */
|
/* 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(
|
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 */
|
/* the return value must be free()'d */
|
||||||
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
|
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
|
||||||
let res = dc_timestamp_to_str_safe(wanted);
|
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 {
|
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 {
|
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
|
||||||
let pathNfilename_abs =
|
let pathNfilename_abs = unsafe {
|
||||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
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() {
|
if pathNfilename_abs.is_null() {
|
||||||
return false;
|
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>> {
|
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
|
||||||
let pathNfilename_abs =
|
let pathNfilename_abs = unsafe {
|
||||||
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
|
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() {
|
if pathNfilename_abs.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -1506,20 +1516,20 @@ pub trait OsStrExt {
|
|||||||
///
|
///
|
||||||
/// On windows when the string contains invalid Unicode
|
/// On windows when the string contains invalid Unicode
|
||||||
/// `[Err]([CStringError::NotUnicode])` is returned.
|
/// `[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 {
|
impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[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;
|
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,
|
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[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)
|
os_str_to_c_string_unicode(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1528,29 +1538,57 @@ impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn os_str_to_c_string_unicode(
|
fn os_str_to_c_string_unicode(
|
||||||
os_str: &dyn AsRef<std::ffi::OsStr>,
|
os_str: &dyn AsRef<std::ffi::OsStr>,
|
||||||
) -> Result<std::ffi::CString, CStringError> {
|
) -> Result<CString, CStringError> {
|
||||||
match os_str.as_ref().to_str() {
|
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,
|
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||||
}),
|
}),
|
||||||
None => Err(CStringError::NotUnicode),
|
None => Err(CStringError::NotUnicode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_cstring<S: AsRef<str>>(s: S) -> std::ffi::CString {
|
/// Needs to free the result after use!
|
||||||
std::ffi::CString::new(s.as_ref()).unwrap()
|
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 {
|
pub fn to_string(s: *const libc::c_char) -> String {
|
||||||
if s.is_null() {
|
if s.is_null() {
|
||||||
return "".into();
|
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 {
|
pub fn as_str<'a>(s: *const libc::c_char) -> &'a str {
|
||||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
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.
|
/// 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);
|
let some_dir = std::path::Path::new(&some_str);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
some_dir.as_os_str().to_c_string().unwrap(),
|
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);
|
let some_dir = std::path::Path::new(&some_str);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
some_dir.as_os_str().to_c_string().unwrap(),
|
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");
|
let some_str = std::ffi::OsString::from("foo");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
os_str_to_c_string_unicode(&some_str).unwrap(),
|
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);
|
let some_path = std::path::Path::new(&some_str);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
os_str_to_c_string_unicode(&some_path).unwrap(),
|
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]
|
#[test]
|
||||||
fn test_as_path() {
|
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();
|
let ptr = some_path.as_ptr();
|
||||||
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
|
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_as_path_unicode_fn() {
|
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();
|
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::net;
|
||||||
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
use std::sync::{Arc, Condvar, Mutex, RwLock};
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
@@ -6,9 +5,10 @@ use std::time::{Duration, SystemTime};
|
|||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_loginparam::*;
|
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::oauth2::dc_get_oauth2_access_token;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
use crate::x::free;
|
||||||
|
|
||||||
pub const DC_IMAP_SEEN: usize = 0x0001;
|
pub const DC_IMAP_SEEN: usize = 0x0001;
|
||||||
pub const DC_REGENERATE: usize = 0x01;
|
pub const DC_REGENERATE: usize = 0x01;
|
||||||
@@ -32,7 +32,8 @@ pub struct Imap {
|
|||||||
precheck_imf: dc_precheck_imf_t,
|
precheck_imf: dc_precheck_imf_t,
|
||||||
receive_imf: dc_receive_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>>,
|
connected: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +351,8 @@ impl Imap {
|
|||||||
receive_imf: dc_receive_imf_t,
|
receive_imf: dc_receive_imf_t,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Imap {
|
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())),
|
config: Arc::new(RwLock::new(ImapConfig::default())),
|
||||||
watch: Arc::new((Mutex::new(false), Condvar::new())),
|
watch: Arc::new((Mutex::new(false), Condvar::new())),
|
||||||
get_config,
|
get_config,
|
||||||
@@ -369,18 +371,18 @@ impl Imap {
|
|||||||
self.config.read().unwrap().should_reconnect
|
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() {
|
if self.config.read().unwrap().imap_server.is_empty() {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.should_reconnect() {
|
if self.should_reconnect() {
|
||||||
self.unsetup_handle(context);
|
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;
|
self.config.write().unwrap().should_reconnect = false;
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_flags = self.config.read().unwrap().server_flags;
|
let server_flags = self.config.read().unwrap().server_flags;
|
||||||
@@ -424,7 +426,7 @@ impl Imap {
|
|||||||
};
|
};
|
||||||
client.authenticate("XOAUTH2", &auth)
|
client.authenticate("XOAUTH2", &auth)
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.login(imap_user, imap_pw)
|
client.login(imap_user, imap_pw)
|
||||||
@@ -445,7 +447,7 @@ impl Imap {
|
|||||||
err
|
err
|
||||||
);
|
);
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -453,29 +455,27 @@ impl Imap {
|
|||||||
|
|
||||||
match login_res {
|
match login_res {
|
||||||
Ok((session, stream)) => {
|
Ok((session, stream)) => {
|
||||||
*self.session.lock().unwrap() = (Some(session), Some(stream));
|
*self.session.lock().unwrap() = Some(session);
|
||||||
1
|
*self.stream.write().unwrap() = Some(stream);
|
||||||
|
true
|
||||||
}
|
}
|
||||||
Err((err, _)) => {
|
Err((err, _)) => {
|
||||||
log_event!(context, Event::ERROR_NETWORK, 0, "Cannot login ({})", err);
|
log_event!(context, Event::ERROR_NETWORK, 0, "Cannot login ({})", err);
|
||||||
self.unsetup_handle(context);
|
self.unsetup_handle(context);
|
||||||
|
|
||||||
0
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unsetup_handle(&self, context: &Context) {
|
fn unsetup_handle(&self, context: &Context) {
|
||||||
let session = self.session.lock().unwrap().0.take();
|
info!(context, 0, "IMAP unsetup_handle starts");
|
||||||
if session.is_some() {
|
|
||||||
match session.unwrap().close() {
|
info!(
|
||||||
Ok(_) => {}
|
context,
|
||||||
Err(err) => {
|
0, "IMAP unsetup_handle step 1 (closing down stream)."
|
||||||
eprintln!("failed to close connection: {:?}", err);
|
);
|
||||||
}
|
let stream = self.stream.write().unwrap().take();
|
||||||
}
|
|
||||||
}
|
|
||||||
let stream = self.session.lock().unwrap().1.take();
|
|
||||||
if stream.is_some() {
|
if stream.is_some() {
|
||||||
match stream.unwrap().shutdown(net::Shutdown::Both) {
|
match stream.unwrap().shutdown(net::Shutdown::Both) {
|
||||||
Ok(_) => {}
|
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();
|
info!(context, 0, "IMAP unsetup_handle step 3 (clearing config).");
|
||||||
cfg.selected_folder = None;
|
self.config.write().unwrap().selected_folder = None;
|
||||||
cfg.selected_mailbox = None;
|
self.config.write().unwrap().selected_mailbox = None;
|
||||||
info!(context, 0, "IMAP disconnected.",);
|
info!(context, 0, "IMAP unsetup_handle step 4 (disconnected).",);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_connect_params(&self) {
|
fn free_connect_params(&self) {
|
||||||
@@ -506,13 +519,13 @@ impl Imap {
|
|||||||
cfg.watch_folder = None;
|
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() {
|
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_connected() {
|
if self.is_connected() {
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -532,50 +545,55 @@ impl Imap {
|
|||||||
config.server_flags = server_flags;
|
config.server_flags = server_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.setup_handle_if_needed(context) == 0 {
|
if !self.setup_handle_if_needed(context) {
|
||||||
self.free_connect_params();
|
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) => {
|
Some(ref mut session) => {
|
||||||
if let Ok(caps) = session.capabilities() {
|
if let Ok(caps) = session.capabilities() {
|
||||||
let can_idle = caps.has("IDLE");
|
if !context.sql.is_open() {
|
||||||
let has_xlist = caps.has("XLIST");
|
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
|
||||||
|
teardown = true;
|
||||||
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
|
} else {
|
||||||
s += " ";
|
let can_idle = caps.has("IDLE");
|
||||||
s += c;
|
let has_xlist = caps.has("XLIST");
|
||||||
s
|
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
|
||||||
});
|
s += " ";
|
||||||
|
s += c;
|
||||||
log_event!(
|
s
|
||||||
context,
|
});
|
||||||
Event::IMAP_CONNECTED,
|
log_event!(
|
||||||
0,
|
context,
|
||||||
"IMAP-LOGIN as {} ok",
|
Event::IMAP_CONNECTED,
|
||||||
lp.mail_user,
|
0,
|
||||||
);
|
"IMAP-LOGIN as {}, capabilities: {}",
|
||||||
info!(context, 0, "IMAP-capabilities:{}", caps_list);
|
lp.mail_user,
|
||||||
|
caps_list,
|
||||||
let mut config = self.config.write().unwrap();
|
);
|
||||||
config.can_idle = can_idle;
|
self.config.write().unwrap().can_idle = can_idle;
|
||||||
config.has_xlist = has_xlist;
|
self.config.write().unwrap().has_xlist = has_xlist;
|
||||||
*self.connected.lock().unwrap() = true;
|
*self.connected.lock().unwrap() = true;
|
||||||
|
teardown = false;
|
||||||
1
|
}
|
||||||
} else {
|
} else {
|
||||||
self.unsetup_handle(context);
|
teardown = true;
|
||||||
self.free_connect_params();
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.unsetup_handle(context);
|
teardown = true;
|
||||||
self.free_connect_params();
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if teardown {
|
||||||
|
self.unsetup_handle(context);
|
||||||
|
self.free_connect_params();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disconnect(&self, context: &Context) {
|
pub fn disconnect(&self, context: &Context) {
|
||||||
@@ -591,7 +609,7 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch(&self, context: &Context) -> libc::c_int {
|
pub fn fetch(&self, context: &Context) -> libc::c_int {
|
||||||
if !self.is_connected() {
|
if !self.is_connected() || !context.sql.is_open() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,7 +633,7 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn select_folder<S: AsRef<str>>(&self, context: &Context, folder: Option<S>) -> usize {
|
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();
|
let mut cfg = self.config.write().unwrap();
|
||||||
cfg.selected_folder = None;
|
cfg.selected_folder = None;
|
||||||
cfg.selected_folder_needs_expunge = false;
|
cfg.selected_folder_needs_expunge = false;
|
||||||
@@ -639,7 +657,7 @@ impl Imap {
|
|||||||
|
|
||||||
// A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see
|
// A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see
|
||||||
// https://tools.ietf.org/html/rfc3501#section-6.4.2
|
// 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() {
|
match session.close() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -655,7 +673,7 @@ impl Imap {
|
|||||||
|
|
||||||
// select new folder
|
// select new folder
|
||||||
if let Some(ref folder) = 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) {
|
match session.select(folder) {
|
||||||
Ok(mailbox) => {
|
Ok(mailbox) => {
|
||||||
let mut config = self.config.write().unwrap();
|
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) {
|
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 key = format!("imap.mailbox.{}", folder.as_ref());
|
||||||
let val1 = unsafe {
|
let val1 = unsafe {
|
||||||
(self.get_config)(
|
let key_c = to_cstring(key);
|
||||||
context,
|
let val = (self.get_config)(context, key_c, 0 as *const libc::c_char);
|
||||||
CString::new(key).unwrap().as_ptr(),
|
free(key_c as *mut _);
|
||||||
0 as *const libc::c_char,
|
val
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if val1.is_null() {
|
if val1.is_null() {
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
}
|
}
|
||||||
let entry = as_str(val1);
|
let entry = as_str(val1);
|
||||||
|
|
||||||
|
if entry.is_empty() {
|
||||||
|
return (0, 0);
|
||||||
|
}
|
||||||
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
|
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
|
||||||
let mut parts = entry.split(':');
|
let mut parts = entry.split(':');
|
||||||
(
|
(
|
||||||
@@ -761,7 +781,7 @@ impl Imap {
|
|||||||
return 0;
|
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)`
|
// `FETCH <message sequence number> (UID)`
|
||||||
let set = format!("{}", mailbox.exists);
|
let set = format!("{}", mailbox.exists);
|
||||||
match session.fetch(set, PREFETCH_FLAGS) {
|
match session.fetch(set, PREFETCH_FLAGS) {
|
||||||
@@ -805,7 +825,7 @@ impl Imap {
|
|||||||
let mut read_errors = 0;
|
let mut read_errors = 0;
|
||||||
let mut new_last_seen_uid = 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
|
// fetch messages with larger UID than the last one seen
|
||||||
// (`UID FETCH lastseenuid+1:*)`, see RFC 4549
|
// (`UID FETCH lastseenuid+1:*)`, see RFC 4549
|
||||||
let set = format!("{}:*", last_seen_uid + 1);
|
let set = format!("{}:*", last_seen_uid + 1);
|
||||||
@@ -832,9 +852,11 @@ impl Imap {
|
|||||||
.message_id
|
.message_id
|
||||||
.expect("missing message id");
|
.expect("missing message id");
|
||||||
|
|
||||||
let message_id_c = CString::new(message_id).unwrap();
|
|
||||||
if 0 == unsafe {
|
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
|
// check passed, go fetch the rest
|
||||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||||
@@ -903,11 +925,11 @@ impl Imap {
|
|||||||
let val = format!("{}:{}", uidvalidity, lastseenuid);
|
let val = format!("{}:{}", uidvalidity, lastseenuid);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.set_config)(
|
let key_c = to_cstring(key);
|
||||||
context,
|
let val_c = to_cstring(val);
|
||||||
CString::new(key).unwrap().as_ptr(),
|
(self.set_config)(context, key_c, val_c);
|
||||||
CString::new(val).unwrap().as_ptr(),
|
free(key_c as *mut _);
|
||||||
)
|
free(val_c as *mut _);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,7 +950,7 @@ impl Imap {
|
|||||||
|
|
||||||
let set = format!("{}", server_uid);
|
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) {
|
match session.uid_fetch(set, BODY_FLAGS) {
|
||||||
Ok(msgs) => msgs,
|
Ok(msgs) => msgs,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -986,11 +1008,12 @@ impl Imap {
|
|||||||
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
|
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
|
||||||
|
|
||||||
if !is_deleted && msg.body().is_some() {
|
if !is_deleted && msg.body().is_some() {
|
||||||
|
let body = msg.body().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.receive_imf)(
|
(self.receive_imf)(
|
||||||
context,
|
context,
|
||||||
msg.body().unwrap().as_ptr() as *const libc::c_char,
|
body.as_ptr() as *const libc::c_char,
|
||||||
msg.body().unwrap().len(),
|
body.len(),
|
||||||
folder.as_ref(),
|
folder.as_ref(),
|
||||||
server_uid,
|
server_uid,
|
||||||
flags as u32,
|
flags as u32,
|
||||||
@@ -1025,13 +1048,15 @@ impl Imap {
|
|||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
let (sender, receiver) = std::sync::mpsc::channel();
|
||||||
let v = self.watch.clone();
|
let v = self.watch.clone();
|
||||||
|
|
||||||
|
info!(context, 0, "IMAP-IDLE SPAWNING");
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let &(ref lock, ref cvar) = &*v;
|
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() {
|
let mut idle = match session.idle() {
|
||||||
Ok(idle) => idle,
|
Ok(idle) => idle,
|
||||||
Err(err) => {
|
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
|
// 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
|
// are also downloaded, however, typically this would take place in the FETCH command
|
||||||
// following IDLE otherwise, so this seems okay here.
|
// 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 let Some(ref watch_folder) = self.config.read().unwrap().watch_folder {
|
||||||
if 0 != self.fetch_from_single_folder(context, watch_folder) {
|
if 0 != self.fetch_from_single_folder(context, watch_folder) {
|
||||||
do_fake_idle = false;
|
do_fake_idle = false;
|
||||||
@@ -1205,7 +1230,7 @@ impl Imap {
|
|||||||
folder.as_ref()
|
folder.as_ref()
|
||||||
);
|
);
|
||||||
} else {
|
} 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) {
|
match session.uid_mv(&set, &dest_folder) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
res = DC_SUCCESS;
|
res = DC_SUCCESS;
|
||||||
@@ -1230,7 +1255,7 @@ impl Imap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !moved {
|
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) {
|
match session.uid_copy(&set, &dest_folder) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -1275,7 +1300,7 @@ impl Imap {
|
|||||||
if server_uid == 0 {
|
if server_uid == 0 {
|
||||||
return 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 set = format!("{}", server_uid);
|
||||||
let query = format!("+FLAGS ({})", flag.as_ref());
|
let query = format!("+FLAGS ({})", flag.as_ref());
|
||||||
match session.uid_store(&set, &query) {
|
match session.uid_store(&set, &query) {
|
||||||
@@ -1387,18 +1412,18 @@ impl Imap {
|
|||||||
.expect("just selected folder");
|
.expect("just selected folder");
|
||||||
|
|
||||||
if can_create_flag {
|
if can_create_flag {
|
||||||
let fetched_msgs = if let Some(ref mut session) = self.session.lock().unwrap().0
|
let fetched_msgs =
|
||||||
{
|
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||||
match session.uid_fetch(set, FETCH_FLAGS) {
|
match session.uid_fetch(set, FETCH_FLAGS) {
|
||||||
Ok(res) => Some(res),
|
Ok(res) => Some(res),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("fetch error: {:?}", err);
|
eprintln!("fetch error: {:?}", err);
|
||||||
None
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
unreachable!();
|
||||||
unreachable!();
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(msgs) = fetched_msgs {
|
if let Some(msgs) = fetched_msgs {
|
||||||
let flag_set = msgs
|
let flag_set = msgs
|
||||||
@@ -1479,7 +1504,7 @@ impl Imap {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let set = format!("{}", server_uid);
|
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) {
|
match session.uid_fetch(set, PREFETCH_FLAGS) {
|
||||||
Ok(msgs) => {
|
Ok(msgs) => {
|
||||||
if msgs.is_empty()
|
if msgs.is_empty()
|
||||||
@@ -1561,7 +1586,7 @@ impl Imap {
|
|||||||
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
|
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
|
||||||
info!(context, 0, "Creating MVBOX-folder \"DeltaChat\"...",);
|
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") {
|
match session.create("DeltaChat") {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
mvbox_folder = Some("DeltaChat".into());
|
mvbox_folder = Some("DeltaChat".into());
|
||||||
@@ -1616,7 +1641,7 @@ impl Imap {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
) -> Option<imap::types::ZeroCopy<Vec<imap::types::Name>>> {
|
) -> 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
|
// TODO: use xlist when available
|
||||||
match session.list(Some(""), Some("*")) {
|
match session.list(Some(""), Some("*")) {
|
||||||
Ok(list) => {
|
Ok(list) => {
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ impl Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
|
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
|
||||||
|
if 0 == bytes.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let res: Result<Key, _> = match key_type {
|
let res: Result<Key, _> = match key_type {
|
||||||
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)).map(Into::into),
|
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)).map(Into::into),
|
||||||
KeyType::Private => SignedSecretKey::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) => {
|
($ctx:expr, $data1:expr, $msg:expr) => {
|
||||||
info!($ctx, $data1, $msg,)
|
info!($ctx, $data1, $msg,)
|
||||||
};
|
};
|
||||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||||
let formatted = format!($msg, $($args),*);
|
#[allow(unused_unsafe)]
|
||||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
unsafe {
|
||||||
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
|
let formatted = format!($msg, $($args),*);
|
||||||
formatted_c.as_ptr() as libc::uintptr_t)
|
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,)
|
warn!($ctx, $data1, $msg,)
|
||||||
};
|
};
|
||||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||||
let formatted = format!($msg, $($args),*);
|
#[allow(unused_unsafe)]
|
||||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
unsafe {
|
||||||
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
|
let formatted = format!($msg, $($args),*);
|
||||||
formatted_c.as_ptr() as libc::uintptr_t)
|
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]
|
#[macro_export]
|
||||||
@@ -30,11 +36,14 @@ macro_rules! error {
|
|||||||
error!($ctx, $data1, $msg,)
|
error!($ctx, $data1, $msg,)
|
||||||
};
|
};
|
||||||
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
unsafe {
|
||||||
let formatted = format!($msg, $($args),*);
|
let formatted = format!($msg, $($args),*);
|
||||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
||||||
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
|
$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]
|
#[macro_export]
|
||||||
@@ -43,9 +52,12 @@ macro_rules! log_event {
|
|||||||
log_event!($ctx, $data1, $msg,)
|
log_event!($ctx, $data1, $msg,)
|
||||||
};
|
};
|
||||||
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
|
||||||
let formatted = format!($msg, $($args),*);
|
#[allow(unused_unsafe)]
|
||||||
let formatted_c = $crate::dc_tools::to_cstring(formatted);
|
unsafe {
|
||||||
$ctx.call_cb($event, $data1 as libc::uintptr_t,
|
let formatted = format!($msg, $($args),*);
|
||||||
formatted_c.as_ptr() as libc::uintptr_t)
|
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 super::*;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::CStr;
|
||||||
use tempfile::{tempdir, TempDir};
|
use tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
use crate::context::*;
|
use crate::context::*;
|
||||||
|
use crate::dc_tools::to_cstring;
|
||||||
|
use crate::x::free;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_peerstate_save_to_db() {
|
fn test_peerstate_save_to_db() {
|
||||||
@@ -520,16 +522,16 @@ mod tests {
|
|||||||
unsafe fn create_test_context() -> TestContext {
|
unsafe fn create_test_context() -> TestContext {
|
||||||
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
||||||
let dir = tempdir().unwrap();
|
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!(
|
assert_eq!(
|
||||||
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
|
dc_open(&mut ctx, dbfile, std::ptr::null()),
|
||||||
1,
|
1,
|
||||||
"Failed to open {}",
|
"Failed to open {}",
|
||||||
CStr::from_ptr(dbfile.as_ptr() as *const libc::c_char)
|
CStr::from_ptr(dbfile as *const _).to_str().unwrap()
|
||||||
.to_str()
|
|
||||||
.unwrap()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
free(dbfile as *mut _);
|
||||||
|
|
||||||
TestContext { ctx: ctx, dir: dir }
|
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
|
/// 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() {
|
if self.is_connected() {
|
||||||
warn!(context, 0, "SMTP already connected.");
|
warn!(context, 0, "SMTP already connected.");
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if lp.send_server.is_empty() || lp.send_port == 0 {
|
if lp.send_server.is_empty() || lp.send_port == 0 {
|
||||||
@@ -61,7 +61,7 @@ impl Smtp {
|
|||||||
|
|
||||||
if self.from.is_none() {
|
if self.from.is_none() {
|
||||||
// TODO: print error
|
// TODO: print error
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let domain = &lp.send_server;
|
let domain = &lp.send_server;
|
||||||
@@ -82,7 +82,7 @@ impl Smtp {
|
|||||||
let send_pw = &lp.send_pw;
|
let send_pw = &lp.send_pw;
|
||||||
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
|
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
|
||||||
if access_token.is_none() {
|
if access_token.is_none() {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
let user = &lp.send_user;
|
let user = &lp.send_user;
|
||||||
|
|
||||||
@@ -116,11 +116,11 @@ impl Smtp {
|
|||||||
"SMTP-LOGIN as {} ok",
|
"SMTP-LOGIN as {} ok",
|
||||||
lp.send_user,
|
lp.send_user,
|
||||||
);
|
);
|
||||||
1
|
true
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(context, 0, "SMTP: failed to establish connection {:?}", 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::collections::HashSet;
|
||||||
use std::sync::RwLock;
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
|
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
|
||||||
|
use thread_local_object::ThreadLocal;
|
||||||
|
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
@@ -16,12 +17,14 @@ const DC_OPEN_READONLY: usize = 0x01;
|
|||||||
/// A wrapper around the underlying Sqlite3 object.
|
/// A wrapper around the underlying Sqlite3 object.
|
||||||
pub struct Sql {
|
pub struct Sql {
|
||||||
pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>,
|
pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>,
|
||||||
|
in_use: Arc<ThreadLocal<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sql {
|
impl Sql {
|
||||||
pub fn new() -> Sql {
|
pub fn new() -> Sql {
|
||||||
Sql {
|
Sql {
|
||||||
pool: RwLock::new(None),
|
pool: RwLock::new(None),
|
||||||
|
in_use: Arc::new(ThreadLocal::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +34,7 @@ impl Sql {
|
|||||||
|
|
||||||
pub fn close(&self, context: &Context) {
|
pub fn close(&self, context: &Context) {
|
||||||
let _ = self.pool.write().unwrap().take();
|
let _ = self.pool.write().unwrap().take();
|
||||||
|
self.in_use.remove();
|
||||||
// drop closes the connection
|
// drop closes the connection
|
||||||
|
|
||||||
info!(context, 0, "Database closed.");
|
info!(context, 0, "Database closed.");
|
||||||
@@ -53,6 +57,7 @@ impl Sql {
|
|||||||
P: IntoIterator,
|
P: IntoIterator,
|
||||||
P::Item: rusqlite::ToSql,
|
P::Item: rusqlite::ToSql,
|
||||||
{
|
{
|
||||||
|
self.start_stmt(sql.to_string());
|
||||||
self.with_conn(|conn| conn.execute(sql, params).map_err(Into::into))
|
self.with_conn(|conn| conn.execute(sql, params).map_err(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,22 +65,25 @@ impl Sql {
|
|||||||
where
|
where
|
||||||
G: FnOnce(&Connection) -> Result<T>,
|
G: FnOnce(&Connection) -> Result<T>,
|
||||||
{
|
{
|
||||||
match &*self.pool.read().unwrap() {
|
let res = match &*self.pool.read().unwrap() {
|
||||||
Some(pool) => {
|
Some(pool) => {
|
||||||
let conn = pool.get()?;
|
let conn = pool.get()?;
|
||||||
g(&conn)
|
g(&conn)
|
||||||
}
|
}
|
||||||
None => Err(Error::SqlNoConnection),
|
None => Err(Error::SqlNoConnection),
|
||||||
}
|
};
|
||||||
|
self.in_use.remove();
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare<G, H>(&self, sql: &str, g: G) -> Result<H>
|
pub fn prepare<G, H>(&self, sql: &str, g: G) -> Result<H>
|
||||||
where
|
where
|
||||||
G: FnOnce(Statement<'_>) -> Result<H>,
|
G: FnOnce(Statement<'_>, &Connection) -> Result<H>,
|
||||||
{
|
{
|
||||||
|
self.start_stmt(sql.to_string());
|
||||||
self.with_conn(|conn| {
|
self.with_conn(|conn| {
|
||||||
let stmt = conn.prepare(sql)?;
|
let stmt = conn.prepare(sql)?;
|
||||||
let res = g(stmt)?;
|
let res = g(stmt, conn)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -84,6 +92,7 @@ impl Sql {
|
|||||||
where
|
where
|
||||||
G: FnOnce(Statement<'_>, Statement<'_>, &Connection) -> Result<H>,
|
G: FnOnce(Statement<'_>, Statement<'_>, &Connection) -> Result<H>,
|
||||||
{
|
{
|
||||||
|
self.start_stmt(format!("{} - {}", sql1, sql2));
|
||||||
self.with_conn(|conn| {
|
self.with_conn(|conn| {
|
||||||
let stmt1 = conn.prepare(sql1)?;
|
let stmt1 = conn.prepare(sql1)?;
|
||||||
let stmt2 = conn.prepare(sql2)?;
|
let stmt2 = conn.prepare(sql2)?;
|
||||||
@@ -109,8 +118,8 @@ impl Sql {
|
|||||||
F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>,
|
F: FnMut(&rusqlite::Row) -> rusqlite::Result<T>,
|
||||||
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
|
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
|
||||||
{
|
{
|
||||||
|
self.start_stmt(sql.as_ref().to_string());
|
||||||
self.with_conn(|conn| {
|
self.with_conn(|conn| {
|
||||||
eprintln!("query_map {}", sql.as_ref());
|
|
||||||
let mut stmt = conn.prepare(sql.as_ref())?;
|
let mut stmt = conn.prepare(sql.as_ref())?;
|
||||||
let res = stmt.query_map(params, f)?;
|
let res = stmt.query_map(params, f)?;
|
||||||
g(res)
|
g(res)
|
||||||
@@ -124,6 +133,7 @@ impl Sql {
|
|||||||
P: IntoIterator,
|
P: IntoIterator,
|
||||||
P::Item: rusqlite::ToSql,
|
P::Item: rusqlite::ToSql,
|
||||||
{
|
{
|
||||||
|
self.start_stmt(sql.to_string());
|
||||||
self.with_conn(|conn| {
|
self.with_conn(|conn| {
|
||||||
let mut stmt = conn.prepare(sql)?;
|
let mut stmt = conn.prepare(sql)?;
|
||||||
let res = stmt.exists(params)?;
|
let res = stmt.exists(params)?;
|
||||||
@@ -137,11 +147,12 @@ impl Sql {
|
|||||||
P::Item: rusqlite::ToSql,
|
P::Item: rusqlite::ToSql,
|
||||||
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
|
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))
|
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 {
|
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()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,18 +270,27 @@ impl Sql {
|
|||||||
pub fn get_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
|
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())
|
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;
|
let mut exists = false;
|
||||||
conn.pragma(None, "table_info", &format!("{}", name.as_ref()), |_row| {
|
conn.pragma(None, "table_info", &format!("{}", name.as_ref()), |_row| {
|
||||||
// will only be executed if the info was found
|
// will only be executed if the info was found
|
||||||
exists = true;
|
exists = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})?;
|
||||||
.expect("bad sqlite state");
|
Ok(exists)
|
||||||
|
|
||||||
exists
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(
|
fn open(
|
||||||
@@ -841,6 +861,18 @@ pub fn get_rowid(
|
|||||||
table: impl AsRef<str>,
|
table: impl AsRef<str>,
|
||||||
field: impl AsRef<str>,
|
field: impl AsRef<str>,
|
||||||
value: 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 {
|
) -> u32 {
|
||||||
// alternative to sqlite3_last_insert_rowid() which MUST NOT be used due to race conditions, see comment above.
|
// 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,
|
// the ORDER BY ensures, this function always returns the most recent id,
|
||||||
@@ -852,7 +884,7 @@ pub fn get_rowid(
|
|||||||
value.as_ref()
|
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,
|
Ok(id) => id,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(
|
error!(
|
||||||
@@ -863,7 +895,6 @@ pub fn get_rowid(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rowid2(
|
pub fn get_rowid2(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
sql: &Sql,
|
sql: &Sql,
|
||||||
@@ -873,6 +904,7 @@ pub fn get_rowid2(
|
|||||||
field2: impl AsRef<str>,
|
field2: impl AsRef<str>,
|
||||||
value2: i32,
|
value2: i32,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
|
sql.start_stmt("get rowid2".to_string());
|
||||||
sql.with_conn(|conn| {
|
sql.with_conn(|conn| {
|
||||||
Ok(get_rowid2_with_conn(
|
Ok(get_rowid2_with_conn(
|
||||||
context, conn, table, field, value, field2, value2,
|
context, conn, table, field, value, field2, value2,
|
||||||
@@ -972,31 +1004,36 @@ pub fn housekeeping(context: &Context) {
|
|||||||
}
|
}
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
let name_f = entry.file_name();
|
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 {
|
if unsafe { is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c) }
|
||||||
is_file_in_use(&mut files_in_use, 0 as *const libc::c_char, name_c.as_ptr())
|
|| unsafe {
|
||||||
} || unsafe {
|
is_file_in_use(
|
||||||
is_file_in_use(
|
&mut files_in_use,
|
||||||
&mut files_in_use,
|
b".increation\x00" as *const u8 as *const libc::c_char,
|
||||||
b".increation\x00" as *const u8 as *const libc::c_char,
|
name_c,
|
||||||
name_c.as_ptr(),
|
)
|
||||||
)
|
}
|
||||||
} || unsafe {
|
|| unsafe {
|
||||||
is_file_in_use(
|
is_file_in_use(
|
||||||
&mut files_in_use,
|
&mut files_in_use,
|
||||||
b".waveform\x00" as *const u8 as *const libc::c_char,
|
b".waveform\x00" as *const u8 as *const libc::c_char,
|
||||||
name_c.as_ptr(),
|
name_c,
|
||||||
)
|
)
|
||||||
} || unsafe {
|
}
|
||||||
is_file_in_use(
|
|| unsafe {
|
||||||
&mut files_in_use,
|
is_file_in_use(
|
||||||
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
|
&mut files_in_use,
|
||||||
name_c.as_ptr(),
|
b"-preview.jpg\x00" as *const u8 as *const libc::c_char,
|
||||||
)
|
name_c,
|
||||||
} {
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
unsafe { free(name_c as *mut _) };
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
unsafe { free(name_c as *mut _) };
|
||||||
|
|
||||||
unreferenced_count += 1;
|
unreferenced_count += 1;
|
||||||
|
|
||||||
match std::fs::metadata(entry.path()) {
|
match std::fs::metadata(entry.path()) {
|
||||||
@@ -1028,8 +1065,11 @@ pub fn housekeeping(context: &Context) {
|
|||||||
unreferenced_count,
|
unreferenced_count,
|
||||||
entry.file_name()
|
entry.file_name()
|
||||||
);
|
);
|
||||||
let path = to_cstring(entry.path().to_str().unwrap());
|
unsafe {
|
||||||
unsafe { dc_delete_file(context, path.as_ptr()) };
|
let path = to_cstring(entry.path().to_str().unwrap());
|
||||||
|
dc_delete_file(context, path);
|
||||||
|
free(path as *mut _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -1087,14 +1127,16 @@ fn maybe_add_from_param(
|
|||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.query_row(query, NO_PARAMS, |row| {
|
.query_row(query, NO_PARAMS, |row| {
|
||||||
let v = to_cstring(row.get::<_, String>(0)?);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
dc_param_set_packed(param, v.as_ptr() as *const libc::c_char);
|
let v = to_cstring(row.get::<_, String>(0)?);
|
||||||
let file = dc_param_get(param, param_id, 0 as *const libc::c_char);
|
dc_param_set_packed(param, v as *const _);
|
||||||
|
let file = dc_param_get(param, param_id, 0 as *const _);
|
||||||
if !file.is_null() {
|
if !file.is_null() {
|
||||||
maybe_add_file(files_in_use, as_str(file));
|
maybe_add_file(files_in_use, as_str(file));
|
||||||
free(file as *mut libc::c_void);
|
free(file as *mut libc::c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(v as *mut _);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@@ -1128,7 +1170,6 @@ mod test {
|
|||||||
maybe_add_file(&mut files, "$BLOBDIR/world.txt");
|
maybe_add_file(&mut files, "$BLOBDIR/world.txt");
|
||||||
maybe_add_file(&mut files, "world2.txt");
|
maybe_add_file(&mut files, "world2.txt");
|
||||||
|
|
||||||
println!("{:?}", files);
|
|
||||||
assert!(unsafe {
|
assert!(unsafe {
|
||||||
is_file_in_use(
|
is_file_in_use(
|
||||||
&mut files,
|
&mut files,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
//! Stress some functions for testing; if used as a lib, this file is obsolete.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
use mmime::mailimf_types::*;
|
use mmime::mailimf_types::*;
|
||||||
use tempfile::{tempdir, TempDir};
|
use tempfile::{tempdir, TempDir};
|
||||||
@@ -175,7 +174,7 @@ unsafe fn stress_functions(context: &Context) {
|
|||||||
"content"
|
"content"
|
||||||
);
|
);
|
||||||
|
|
||||||
free(buf);
|
free(buf as *mut _);
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
0,
|
0,
|
||||||
dc_delete_file(
|
dc_delete_file(
|
||||||
@@ -691,7 +690,7 @@ fn test_encryption_decryption() {
|
|||||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||||
|
|
||||||
let ctext_signed_bytes = ctext.len();
|
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(
|
let ctext = dc_pgp_pk_encrypt(
|
||||||
original_text as *const libc::c_void,
|
original_text as *const libc::c_void,
|
||||||
@@ -704,7 +703,7 @@ fn test_encryption_decryption() {
|
|||||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||||
|
|
||||||
let ctext_unsigned_bytes = ctext.len();
|
let ctext_unsigned_bytes = ctext.len();
|
||||||
let ctext_unsigned = CString::new(ctext).unwrap();
|
let ctext_unsigned = to_cstring(ctext);
|
||||||
|
|
||||||
let mut keyring = Keyring::default();
|
let mut keyring = Keyring::default();
|
||||||
keyring.add_owned(private_key);
|
keyring.add_owned(private_key);
|
||||||
@@ -718,7 +717,7 @@ fn test_encryption_decryption() {
|
|||||||
let mut valid_signatures: HashSet<String> = Default::default();
|
let mut valid_signatures: HashSet<String> = Default::default();
|
||||||
|
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_signed.as_ptr() as *const _,
|
ctext_signed as *const _,
|
||||||
ctext_signed_bytes,
|
ctext_signed_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&public_keyring,
|
&public_keyring,
|
||||||
@@ -733,7 +732,7 @@ fn test_encryption_decryption() {
|
|||||||
|
|
||||||
let empty_keyring = Keyring::default();
|
let empty_keyring = Keyring::default();
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_signed.as_ptr() as *const _,
|
ctext_signed as *const _,
|
||||||
ctext_signed_bytes,
|
ctext_signed_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&empty_keyring,
|
&empty_keyring,
|
||||||
@@ -746,7 +745,7 @@ fn test_encryption_decryption() {
|
|||||||
valid_signatures.clear();
|
valid_signatures.clear();
|
||||||
|
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_signed.as_ptr() as *const _,
|
ctext_signed as *const _,
|
||||||
ctext_signed_bytes,
|
ctext_signed_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&public_keyring2,
|
&public_keyring2,
|
||||||
@@ -761,7 +760,7 @@ fn test_encryption_decryption() {
|
|||||||
public_keyring2.add_ref(&public_key);
|
public_keyring2.add_ref(&public_key);
|
||||||
|
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_signed.as_ptr() as *const _,
|
ctext_signed as *const _,
|
||||||
ctext_signed_bytes,
|
ctext_signed_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&public_keyring2,
|
&public_keyring2,
|
||||||
@@ -774,13 +773,15 @@ fn test_encryption_decryption() {
|
|||||||
valid_signatures.clear();
|
valid_signatures.clear();
|
||||||
|
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_unsigned.as_ptr() as *const _,
|
ctext_unsigned as *const _,
|
||||||
ctext_unsigned_bytes,
|
ctext_unsigned_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&public_keyring,
|
&public_keyring,
|
||||||
Some(&mut valid_signatures),
|
Some(&mut valid_signatures),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
free(ctext_unsigned as *mut _);
|
||||||
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
||||||
|
|
||||||
valid_signatures.clear();
|
valid_signatures.clear();
|
||||||
@@ -791,13 +792,15 @@ fn test_encryption_decryption() {
|
|||||||
public_keyring.add_ref(&public_key);
|
public_keyring.add_ref(&public_key);
|
||||||
|
|
||||||
let plain = dc_pgp_pk_decrypt(
|
let plain = dc_pgp_pk_decrypt(
|
||||||
ctext_signed.as_ptr() as *const _,
|
ctext_signed as *const _,
|
||||||
ctext_signed_bytes,
|
ctext_signed_bytes,
|
||||||
&keyring,
|
&keyring,
|
||||||
&public_keyring,
|
&public_keyring,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
free(ctext_signed as *mut _);
|
||||||
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -820,14 +823,14 @@ struct TestContext {
|
|||||||
unsafe fn create_test_context() -> TestContext {
|
unsafe fn create_test_context() -> TestContext {
|
||||||
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
let mut ctx = dc_context_new(Some(cb), std::ptr::null_mut(), std::ptr::null_mut());
|
||||||
let dir = tempdir().unwrap();
|
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!(
|
assert_eq!(
|
||||||
dc_open(&mut ctx, dbfile.as_ptr(), std::ptr::null()),
|
dc_open(&mut ctx, dbfile, std::ptr::null()),
|
||||||
1,
|
1,
|
||||||
"Failed to open {}",
|
"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 }
|
TestContext { ctx: ctx, dir: dir }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,24 +955,29 @@ fn test_stress_tests() {
|
|||||||
fn test_get_contacts() {
|
fn test_get_contacts() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context = create_test_context();
|
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);
|
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||||
dc_array_unref(contacts);
|
dc_array_unref(contacts);
|
||||||
|
free(name as *mut _);
|
||||||
|
|
||||||
let id = dc_create_contact(
|
let name = to_cstring("bob");
|
||||||
&context.ctx,
|
let email = to_cstring("bob@mail.de");
|
||||||
to_cstring("bob").as_ptr(),
|
let id = dc_create_contact(&context.ctx, name, email);
|
||||||
to_cstring("bob@mail.de").as_ptr(),
|
|
||||||
);
|
|
||||||
assert_ne!(id, 0);
|
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);
|
assert_eq!(dc_array_get_cnt(contacts), 1);
|
||||||
dc_array_unref(contacts);
|
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);
|
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||||
dc_array_unref(contacts);
|
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() {
|
fn test_chat() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context = create_test_context();
|
let context = create_test_context();
|
||||||
let contact1 = dc_create_contact(
|
let name = to_cstring("bob");
|
||||||
&context.ctx,
|
let email = to_cstring("bob@mail.de");
|
||||||
to_cstring("bob").as_ptr(),
|
|
||||||
to_cstring("bob@mail.de").as_ptr(),
|
let contact1 = dc_create_contact(&context.ctx, name, email);
|
||||||
);
|
free(name as *mut _);
|
||||||
|
free(email as *mut _);
|
||||||
assert_ne!(contact1, 0);
|
assert_ne!(contact1, 0);
|
||||||
|
|
||||||
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
|
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]
|
#[test]
|
||||||
fn test_arr_to_string() {
|
fn test_arr_to_string() {
|
||||||
let arr2: [uint32_t; 4] = [
|
let arr2: [uint32_t; 4] = [
|
||||||
|
|||||||
Reference in New Issue
Block a user