Compare commits

...

48 Commits

Author SHA1 Message Date
holger krekel
6bc5d1b90e fix fmt 2019-07-21 22:56:37 +02:00
holger krekel
197d94ad9d Merge remote-tracking branch 'origin/master' into eventlogging 2019-07-21 22:51:16 +02:00
holger krekel
7ce337c6d0 left-over error logging 2019-07-21 22:44:27 +02:00
holger krekel
10148d2e43 ignore non-utf8 parts of header fields (add comment why it shouldn't happen)
don't throw error if no sql rows are returned
2019-07-21 22:25:33 +02:00
dignifiedquire
69dc237ee3 fix(receive_imf): remove recursive sql call 2019-07-21 12:56:04 +02:00
dignifiedquire
df5464ea80 fix: blocked is an optional value 2019-07-20 17:05:24 +02:00
dignifiedquire
e4bf9956a5 fix(msg): handle optional in_reply_to 2019-07-20 16:50:56 +02:00
dignifiedquire
d353d9d9d8 fix(chat): remove recursive sql usage 2019-07-20 16:45:26 +02:00
holger krekel
1ad45ed4d6 fix rust fmt 2019-07-20 15:14:11 +02:00
dignifiedquire
496e980a17 use forked rusqlite 2019-07-20 14:34:27 +02:00
holger krekel
fa09e46ed9 another pace where we might (and in my case did) get invalid utf8 2019-07-20 12:37:51 +02:00
holger krekel
d6de420b9a fix some string issues, introduce to_string_lossy such that to_string() continues to panic on non-utf8 2019-07-20 12:30:48 +02:00
holger krekel
38eb708db8 for now make to_string() less strict as we often don't want to crash the whole app just because some non-proper utf8 came in (through a message we can't neccesarily congtrol) 2019-07-20 01:17:53 +02:00
holger krekel
7a59da5f8f fix linting 2019-07-19 22:48:39 +02:00
holger krekel
f13a1d4a2f fix some test flakyness 2019-07-19 22:46:58 +02:00
holger krekel
7b3a450918 - fix saved_mime test which broke to improper conversion of
imf_raw_not_terminated
- some cargo.toml updates no clue where they come from
- log Message-ID for received messages
2019-07-19 22:35:07 +02:00
holger krekel
169923b102 formatting 2019-07-19 12:31:22 +02:00
holger krekel
42688a0622 remove some print statements 2019-07-19 12:24:56 +02:00
holger krekel
35f3c0edd1 Merge branch 'master' into eventlogging 2019-07-19 10:25:21 +02:00
dignifiedquire
e7a236264a print invalid strings 2019-07-19 09:51:49 +02:00
dignifiedquire
aaa5b820d9 cleanup 2019-07-19 09:51:49 +02:00
dignifiedquire
e7f0745010 reduce direc usage of CString 2019-07-19 09:51:49 +02:00
dignifiedquire
c68e7ae14e audit use of to_cstring and fix ub 2019-07-19 09:51:49 +02:00
dignifiedquire
618087e5a7 fix(imap): body ptr lifetime 2019-07-19 09:51:49 +02:00
dignifiedquire
245abb8384 remove debug 2019-07-19 09:51:49 +02:00
dignifiedquire
a3e1042001 fix some things, add more debugging statements 2019-07-19 09:51:49 +02:00
holger krekel
7b7ce9348f fix python lint issues 2019-07-18 15:11:57 +02:00
holger krekel
7a4808ba0d cargofmt 2019-07-18 14:35:54 +02:00
holger krekel
8f240f7153 (dig,hpk) pull out job collection from sql query/lock logic 2019-07-18 14:03:57 +02:00
holger krekel
7d0b5d8abb remove print statements and fix a crash 2019-07-18 12:52:02 +02:00
holger krekel
ee317cb1b5 fix some merge issues 2019-07-18 11:38:10 +02:00
holger krekel
7b736fe635 (dig,hpk) add test and fix for wrong dbs 2019-07-18 11:16:38 +02:00
holger krekel
c7db15352a Merge branch 'master' into eventlogging 2019-07-18 09:59:56 +02:00
holger krekel
0b37167be8 address @dignifiedquire comments 2019-07-18 00:06:05 +02:00
holger krekel
5cac4b5076 remove spurious print 2019-07-17 12:47:22 +02:00
holger krekel
475a41beb3 address @dignifiedquire rustyness comment and fix changelog 2019-07-17 12:31:12 +02:00
holger krekel
ad4be80b4e make smtp/imap connect() return bool instead of c-int 2019-07-17 10:25:25 +02:00
holger krekel
8737c1d142 cleanup some parts, add comments 2019-07-17 09:26:33 +02:00
holger krekel
964fe466cc wip-commit which passes all tests with proper finalization 2019-07-16 20:05:41 +02:00
holger krekel
43936e7db7 snapshot of my current debugging state 2019-07-16 16:17:42 +02:00
holger krekel
0e80ce9c39 more aggressively skip perform API when threads are closing 2019-07-16 12:57:19 +02:00
holger krekel
c652bae68a intermediate wip commit 2019-07-16 12:06:05 +02:00
holger krekel
bc904a495d add some logging, and a more precise teardown for online python tests 2019-07-16 11:18:56 +02:00
holger krekel
8d99444c6a fix std 2019-07-16 00:22:12 +02:00
holger krekel
9dab53e0af rustfmt 2019-07-16 00:20:54 +02:00
holger krekel
360089ac74 remove some debugging 2019-07-16 00:08:10 +02:00
holger krekel
e892c5cf4d fix test for events 2019-07-15 23:31:30 +02:00
holger krekel
9ad4c9a6fe wip try test that we see INFO events from the core 2019-07-15 22:51:57 +02:00
45 changed files with 1165 additions and 836 deletions

140
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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"]

View File

@@ -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())
}

View File

@@ -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(())
} }

View File

@@ -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)
} }

View File

@@ -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
--------- ---------

View File

@@ -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 .

View 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", "."
])

View File

@@ -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={}):

View File

@@ -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']

View File

@@ -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:

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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():

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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)]

View File

@@ -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)

View File

@@ -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(&param); let r_0 = dc_loginparam_get_readable(&param);
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(&param); let r_1 = dc_loginparam_get_readable(&param);
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(&param); let r_2 = dc_loginparam_get_readable(&param);
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(&param_in.addr).as_ptr()); moz_ac.in_emaillocalpart = to_cstring(&param_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, &param) { if imap.connect(context, &param) {
ret_connected = 2; ret_connected = 2;
} }
} }

View File

@@ -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

View File

@@ -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(

View File

@@ -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,

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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),

View File

@@ -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

View File

@@ -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(

View File

@@ -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)? };

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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)
} }
/** /**

View File

@@ -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)]

View File

@@ -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(

View File

@@ -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"));
} }
} }

View File

@@ -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) => {

View File

@@ -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),

View File

@@ -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);
}};
} }

View File

@@ -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 }
} }
} }

View File

@@ -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
} }
} }
} }

View File

@@ -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,

View File

@@ -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] = [