Compare commits

..

1 Commits

Author SHA1 Message Date
holger krekel
477c818631 adding git gc to cargo-induced git checkouts. This avoids problems with dangling commits. 2019-11-24 00:35:50 +01:00
41 changed files with 395 additions and 895 deletions

View File

@@ -1,37 +1,5 @@
# Changelog
## 1.0.0-beta.8
- now uses async-email/async-imap as the new base
which makes imap-idle interruptible and thus fixes
several issues around the imap thread being in zombie state .
thanks @dignifiedquire, @hpk42 and @link2xt.
- fixes imap-protocol parsing bugs that lead to infinitely
repeated crashing while trying to receive messages with
a subjec that contained non-utf8. thanks @link2xt
- fixed logic to find encryption subkey -- previously
delta chat would use the primary key for encryption
(which works with RSA but not ECC). thanks @link2xt
- introduce a new device chat where core and UIs can
add "device" messages. Android uses it for an initial
welcome message. thanks @r10s
- fix time smearing (when two message are virtually send
in the same second, there would be misbehaviour because
we didn't persist smeared time). thanks @r10s
- fix double-dotted extensions like .html.zip or .tar.gz
to not mangle them when creating blobfiles. thanks @flub
- fix backup/exports where the wrong sql file would be modified,
leading to problems when exporting twice. thanks @hpk42
- several other little fixes and improvements
## 1.0.0-beta.7
- fix location-streaming #782

83
Cargo.lock generated
View File

@@ -52,7 +52,7 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.23"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -90,7 +90,7 @@ dependencies = [
[[package]]
name = "async-imap"
version = "0.1.1"
source = "git+https://github.com/async-email/async-imap#377d40837028b454c6365ff13e3f35cc341a908e"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-std 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -100,7 +100,7 @@ dependencies = [
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures_codec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"imap-proto 0.9.1 (git+https://github.com/djc/tokio-imap)",
"imap-proto 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rental 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -410,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -608,9 +608,9 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.0.0-beta.8"
version = "1.0.0-beta.7"
dependencies = [
"async-imap 0.1.1 (git+https://github.com/async-email/async-imap)",
"async-imap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-std 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"async-tls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -626,14 +626,14 @@ dependencies = [
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jetscii 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lettre 0.9.2 (git+https://github.com/deltachat/lettre?branch=feat/rustls)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"mmime 0.1.2",
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pgp 0.3.2 (git+https://github.com/rpgp/rpgp)",
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -683,13 +683,13 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.0.0-beta.8"
version = "1.0.0-beta.7"
dependencies = [
"deltachat 1.0.0-beta.8",
"deltachat 1.0.0-beta.7",
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -795,6 +795,14 @@ name = "entities"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "enum_primitive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.6.2"
@@ -1225,7 +1233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1235,7 +1243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1251,7 +1259,7 @@ dependencies = [
[[package]]
name = "imap-proto"
version = "0.9.1"
source = "git+https://github.com/djc/tokio-imap#a26056915f1d715f97935da1f0c97c6d0174f292"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1274,7 +1282,7 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1589,7 +1597,7 @@ dependencies = [
"libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1612,7 +1620,7 @@ version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1622,12 +1630,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.10"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1713,7 +1729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pgp"
version = "0.3.2"
source = "git+https://github.com/rpgp/rpgp#4cc60a1e45a781ea6e7f394ae2583844ac75d214"
source = "git+https://github.com/rpgp/rpgp#33ff206379d826a922c9fad822f178a0987e657c"
dependencies = [
"aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1733,6 +1749,7 @@ dependencies = [
"des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1743,7 +1760,7 @@ dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint-dig 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rsa 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1838,7 +1855,7 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2208,7 +2225,7 @@ dependencies = [
"num-bigint-dig 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2868,7 +2885,7 @@ dependencies = [
[[package]]
name = "unicode-normalization"
version = "0.1.11"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3061,7 +3078,7 @@ name = "wasm-bindgen-webidl"
version = "0.2.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
"anyhow 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3076,7 +3093,7 @@ name = "web-sys"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
"anyhow 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
"sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3239,13 +3256,13 @@ dependencies = [
"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1072d8f55592084072d2d3cb23a4b680a8543c00f10d446118e85ad3718142"
"checksum anyhow 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "e19f23ab207147bbdbcdfa7f7e4ca5e84963d79bae3937074682177ab9150968"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
"checksum async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "efd3d156917d94862e779f356c5acae312b08fd3121e792c857d7928c8088423"
"checksum async-imap 0.1.1 (git+https://github.com/async-email/async-imap)" = "<none>"
"checksum async-imap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ead31adf9bcfa6d52605882b93458c63432f06c428edf4558f956807ad7103be"
"checksum async-macros 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "644a5a8de80f2085a1e7e57cd1544a2a7438f6e003c0790999bd43b92a77cdb2"
"checksum async-std 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56933da6903b273923d13f4746d829f66ff9b444173f6743d831e80f4da15446"
"checksum async-task 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de6bd58f7b9cc49032559422595c81cbfcf04db2f2133592f70af19e258a1ced"
@@ -3316,6 +3333,7 @@ dependencies = [
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9"
"checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
"checksum escaper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39da344028c2227132b2dfa7c186e2104ecc153467583d00ed9c398f9ff693b0"
@@ -3367,10 +3385,10 @@ dependencies = [
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b00861cbbb254a627d8acc0cec786b484297d896ab8f20fdc8e28536a3e918ef"
"checksum imap-proto 0.9.1 (git+https://github.com/djc/tokio-imap)" = "<none>"
"checksum imap-proto 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e0690d689f8afe8111dfe1daedd9ef0d232868c7819da3c1f9252fd260aff7f7"
"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jetscii 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5f25cca2463cb19dbb1061eb3bd38a8b5e4ce1cc5a5a9fc0e02de486d92b9b05"
"checksum js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "1c840fdb2167497b0bd0db43d6dfe61e91637fa72f9d061f8bd17ddc44ba6414"
@@ -3409,7 +3427,8 @@ dependencies = [
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
@@ -3540,7 +3559,7 @@ dependencies = [
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf"
"checksum unicode-normalization 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f0d98d53dfd9509a7c7f36fa8857b8f1fb699edbddd7dc2fb688db2ae5d0b2c1"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-beta.8"
version = "1.0.0-beta.7"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL"
@@ -19,7 +19,7 @@ reqwest = { version = "0.9.15", default-features = false, features = ["rustls-tl
num-derive = "0.2.5"
num-traits = "0.2.6"
lettre = { git = "https://github.com/deltachat/lettre", branch = "feat/rustls" }
async-imap = { git = "https://github.com/async-email/async-imap", branch="master" }
async-imap = "0.1.1"
async-tls = "0.6"
async-std = { version = "1.0", features = ["unstable"] }
base64 = "0.10"

View File

@@ -14,7 +14,7 @@ curl https://sh.rustup.rs -sSf | sh
## Using the CLI client
Compile and run Delta Chat Core command line utility, using `cargo`:
Compile and run Delta Chat Core using `cargo`:
```
cargo run --example repl -- /path/to/db

View File

@@ -1,5 +1,4 @@
environment:
RUST_BACKTRACE: full
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017

View File

@@ -22,7 +22,7 @@ export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
# delta@py.delta.chat:build/${BRANCH}
# C docs to c.delta.chat
ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@c.delta.chat mkdir -p build-c/${BRANCH}
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@c.delta.chat mkdir -p build-c/${BRANCH}
rsync -avz \
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
"$DOXYDOCDIR/html/" \

View File

@@ -12,7 +12,7 @@ echo "--- Copying files to $SSHTARGET:$BUILDDIR"
set -xe
ssh -oBatchMode=yes -oStrictHostKeyChecking=no $SSHTARGET mkdir -p "$BUILDDIR"
ssh -oStrictHostKeyChecking=no $SSHTARGET mkdir -p "$BUILDDIR"
git ls-files >.rsynclist
# we seem to need .git for setuptools_scm versioning
find .git >>.rsynclist
@@ -25,6 +25,8 @@ echo "--- Running $CIRCLE_JOB remotely"
ssh $SSHTARGET <<_HERE
set +x -e
cd $BUILDDIR
# make sure git checkouts are clean (no dangling revspcs)
cargo cache --gc
# let's share the target dir with our last run on this branch/job-type
# cargo will make sure to block/unblock us properly
export CARGO_TARGET_DIR=\`pwd\`/../target

View File

@@ -12,7 +12,7 @@ set -e
echo "--- Copying files to $SSHTARGET:$BUILDDIR"
ssh -oBatchMode=yes -oStrictHostKeyChecking=no $SSHTARGET mkdir -p "$BUILDDIR"
ssh -oStrictHostKeyChecking=no $SSHTARGET mkdir -p "$BUILDDIR"
git ls-files >.rsynclist
rsync --delete --files-from=.rsynclist -az ./ "$SSHTARGET:$BUILDDIR"
@@ -21,6 +21,8 @@ echo "--- Running $CIRCLE_JOB remotely"
ssh $SSHTARGET <<_HERE
set +x -e
cd $BUILDDIR
# make sure git checkouts are clean (no dangling revspecs)
cargo cache --gc
# let's share the target dir with our last run on this branch/job-type
# cargo will make sure to block/unblock us properly
export CARGO_TARGET_DIR=\`pwd\`/../target

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.0.0-beta.8"
version = "1.0.0-beta.7"
description = "Deltachat FFI"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"

View File

@@ -4387,16 +4387,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
#define DC_EVENT_SECUREJOIN_JOINER_PROGRESS 2061
/**
* This event is sent out to the inviter when a joiner successfully joined a group.
*
* @param data1 (int) chat_id
* @param data2 (int) contact_id
* @return 0
*/
#define DC_EVENT_SECUREJOIN_MEMBER_ADDED 2062
/**
* @}
*/

View File

@@ -24,7 +24,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
use deltachat::contact::Contact;
use deltachat::context::{Context, ContextBuilder};
use deltachat::context::Context;
use deltachat::dc_tools::{
as_path, dc_strdup, to_opt_string_lossy, to_string_lossy, OsStrExt, StrExt,
};
@@ -175,15 +175,6 @@ impl ContextWrapper {
contact_id as uintptr_t,
progress as uintptr_t,
),
Event::SecurejoinMemberAdded {
chat_id,
contact_id,
} => ffi_cb(
self,
event_id,
chat_id as uintptr_t,
contact_id as uintptr_t,
),
}
}
None => 0,
@@ -248,15 +239,22 @@ pub unsafe extern "C" fn dc_open(
}
let ffi_context = &*context;
let rust_cb = move |_ctx: &Context, evt: Event| ffi_context.translate_cb(evt);
let mut builder = ContextBuilder::new(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
);
if !blobdir.is_null() && *blobdir != 0 {
builder = builder.blobdir(as_path(blobdir).to_path_buf());
}
match builder.create() {
let ctx = if blobdir.is_null() || *blobdir == 0 {
Context::new(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
)
} else {
Context::with_blobdir(
Box::new(rust_cb),
ffi_context.os_name.clone(),
as_path(dbfile).to_path_buf(),
as_path(blobdir).to_path_buf(),
)
};
match ctx {
Ok(ctx) => {
let mut inner_guard = ffi_context.inner.write().unwrap();
*inner_guard = Some(ctx);

View File

@@ -132,8 +132,10 @@ fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
real_spec = rs.unwrap();
}
if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
if suffix == "eml" && dc_poke_eml_file(context, &real_spec).is_ok() {
read_cnt += 1
if suffix == "eml" {
if dc_poke_eml_file(context, &real_spec).is_ok() {
read_cnt += 1
}
}
} else {
/* import a directory */
@@ -586,7 +588,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let members = chat::get_chat_contacts(context, sel_chat.id);
let subtitle = if sel_chat.is_device_talk() {
"device-talk".to_string()
} else if sel_chat.get_type() == Chattype::Single && !members.is_empty() {
} else if sel_chat.get_type() == Chattype::Single && members.len() >= 1 {
let contact = Contact::get_by_id(context, members[0])?;
contact.get_addr().to_string()
} else {
@@ -860,7 +862,11 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"archive" | "unarchive" => {
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
let chat_id = arg1.parse()?;
chat::archive(context, chat_id, arg0 == "archive")?;
chat::archive(
context,
chat_id,
if arg0 == "archive" { true } else { false },
)?;
}
"delchat" => {
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");

View File

@@ -235,7 +235,7 @@ impl Completer for DcHelper {
}
}
const IMEX_COMMANDS: [&str; 12] = [
const IMEX_COMMANDS: [&'static str; 12] = [
"initiate-key-transfer",
"get-setupcodebegin",
"continue-key-transfer",
@@ -250,7 +250,7 @@ const IMEX_COMMANDS: [&str; 12] = [
"stop",
];
const DB_COMMANDS: [&str; 11] = [
const DB_COMMANDS: [&'static str; 11] = [
"info",
"open",
"close",
@@ -264,7 +264,7 @@ const DB_COMMANDS: [&str; 11] = [
"housekeeping",
];
const CHAT_COMMANDS: [&str; 24] = [
const CHAT_COMMANDS: [&'static str; 24] = [
"listchats",
"listarchived",
"chat",
@@ -290,7 +290,7 @@ const CHAT_COMMANDS: [&str; 24] = [
"unarchive",
"delchat",
];
const MESSAGE_COMMANDS: [&str; 8] = [
const MESSAGE_COMMANDS: [&'static str; 8] = [
"listmsgs",
"msginfo",
"listfresh",
@@ -300,7 +300,7 @@ const MESSAGE_COMMANDS: [&str; 8] = [
"unstar",
"delmsg",
];
const CONTACT_COMMANDS: [&str; 6] = [
const CONTACT_COMMANDS: [&'static str; 6] = [
"listcontacts",
"listverified",
"addcontact",
@@ -308,7 +308,7 @@ const CONTACT_COMMANDS: [&str; 6] = [
"delcontact",
"cleanupcontacts",
];
const MISC_COMMANDS: [&str; 9] = [
const MISC_COMMANDS: [&'static str; 9] = [
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "quit", "help",
];
@@ -334,8 +334,8 @@ impl Hinter for DcHelper {
}
}
static COLORED_PROMPT: &str = "\x1b[1;32m> \x1b[0m";
static PROMPT: &str = "> ";
static COLORED_PROMPT: &'static str = "\x1b[1;32m> \x1b[0m";
static PROMPT: &'static str = "> ";
impl Highlighter for DcHelper {
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
@@ -366,12 +366,11 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
println!("Error: Bad arguments, expected [db-name].");
return Err(format_err!("No db-name specified"));
}
let context = ContextBuilder::new(
let context = Context::new(
Box::new(receive_event),
"CLI".into(),
Path::new(&args[1]).to_path_buf(),
)
.create()?;
)?;
println!("Delta Chat Core is awaiting your commands.");

View File

@@ -39,9 +39,8 @@ fn main() {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
println!("creating database {:?}", dbfile);
let ctx = ContextBuilder::new(Box::new(cb), "FakeOs".into(), dbfile)
.create()
.expect("Failed to create context");
let ctx =
Context::new(Box::new(cb), "FakeOs".into(), dbfile).expect("Failed to create context");
let running = Arc::new(RwLock::new(true));
let info = ctx.get_info();
let duration = time::Duration::from_millis(4000);
@@ -114,7 +113,7 @@ fn main() {
println!("stopping threads");
*running.write().unwrap() = false;
*running.clone().write().unwrap() = false;
deltachat::job::interrupt_inbox_idle(&ctx, true);
deltachat::job::interrupt_smtp_idle(&ctx);

View File

@@ -98,7 +98,6 @@ DC_EVENT_IMEX_PROGRESS = 2051
DC_EVENT_IMEX_FILE_WRITTEN = 2052
DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
DC_EVENT_SECUREJOIN_MEMBER_ADDED = 2062
DC_EVENT_FILE_COPIED = 2055
DC_EVENT_IS_OFFLINE = 2081
DC_EVENT_GET_STRING = 2091
@@ -151,8 +150,7 @@ DC_STR_MSGLOCATIONENABLED = 64
DC_STR_MSGLOCATIONDISABLED = 65
DC_STR_LOCATION = 66
DC_STR_STICKER = 67
DC_STR_DEVICE_MESSAGES = 68
DC_STR_COUNT = 68
DC_STR_COUNT = 67
# end const generated

View File

@@ -461,20 +461,6 @@ class TestOnlineAccount:
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
ev = ac2._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
def test_move_works_on_self_sent(self, acfactory):
ac1 = acfactory.get_online_configuring_account(mvbox=True)
ac1.set_config("bcc_self", "1")
ac2 = acfactory.get_online_configuring_account()
wait_configuration_progress(ac2, 1000)
wait_configuration_progress(ac1, 1000)
chat = self.get_chat(ac1, ac2)
chat.send_text("message1")
chat.send_text("message2")
chat.send_text("message3")
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
def test_forward_messages(self, acfactory):
ac1, ac2 = acfactory.get_two_online_accounts()
chat = self.get_chat(ac1, ac2)
@@ -782,7 +768,6 @@ class TestOnlineAccount:
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_DELETED")
ac2._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_DELETED")
wait_securejoin_inviter_progress(ac1, 1000)
ac1._evlogger.get_matching("DC_EVENT_SECUREJOIN_MEMBER_ADDED")
def test_qr_verified_group_and_chatting(self, acfactory, lp):
ac1, ac2 = acfactory.get_two_online_accounts()

View File

@@ -53,7 +53,7 @@ deps =
sphinx==2.2.0
breathe
commands =
sphinx-build -Q -w toxdoc-warnings.log -b html . _build/html
sphinx-build -w toxdoc-warnings.log -b html . _build/html
[testenv:lintdoc]

View File

@@ -3,7 +3,6 @@
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
use crate::blob::BlobObject;
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
use crate::dc_tools::*;
@@ -116,8 +115,9 @@ impl Context {
pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> {
match key {
Config::Selfavatar if value.is_some() => {
let blob = BlobObject::create_from_path(&self, value.unwrap())?;
self.sql.set_raw_config(self, key, Some(blob.as_name()))
let rel_path = std::fs::canonicalize(value.unwrap())?;
self.sql
.set_raw_config(self, key, Some(&rel_path.to_string_lossy()))
}
Config::InboxWatch => {
let ret = self.sql.set_raw_config(self, key, value);
@@ -167,8 +167,6 @@ mod tests {
use std::str::FromStr;
use std::string::ToString;
use crate::test_utils::*;
#[test]
fn test_to_string() {
assert_eq!(Config::MailServer.to_string(), "mail_server");
@@ -185,32 +183,4 @@ mod tests {
fn test_default_prop() {
assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX"));
}
#[test]
fn test_selfavatar() -> failure::Fallible<()> {
let t = dummy_context();
let avatar_src = t.dir.path().join("avatar.jpg");
std::fs::write(&avatar_src, b"avatar")?;
let avatar_blob = t.ctx.get_blobdir().join("avatar.jpg");
assert!(!avatar_blob.exists());
t.ctx
.set_config(Config::Selfavatar, Some(&avatar_src.to_str().unwrap()))?;
assert!(avatar_blob.exists());
assert_eq!(std::fs::read(&avatar_blob)?, b"avatar");
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);
assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string()));
Ok(())
}
#[test]
fn test_selfavatar_in_blobdir() -> failure::Fallible<()> {
let t = dummy_context();
let avatar_src = t.ctx.get_blobdir().join("avatar.jpg");
std::fs::write(&avatar_src, b"avatar")?;
t.ctx
.set_config(Config::Selfavatar, Some(&avatar_src.to_str().unwrap()))?;
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);
assert_eq!(avatar_cfg, avatar_src.to_str().map(|s| s.to_string()));
Ok(())
}
}

View File

@@ -45,8 +45,9 @@ pub fn dc_is_configured(context: &Context) -> bool {
/*******************************************************************************
* Configure JOB
******************************************************************************/
// the other dc_job_do_DC_JOB_*() functions are declared static in the c-file
#[allow(non_snake_case, unused_must_use)]
pub fn JobConfigureImap(context: &Context) {
pub fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
if !context.sql.is_open() {
error!(context, "Cannot configure, database not opened.",);
progress!(context, 0);
@@ -353,14 +354,19 @@ pub fn JobConfigureImap(context: &Context) {
}
16 => {
progress!(context, 900);
let create_mvbox = context.get_config_bool(Config::MvboxWatch)
|| context.get_config_bool(Config::MvboxMove);
let flags: libc::c_int = if context.get_config_bool(Config::MvboxWatch)
|| context.get_config_bool(Config::MvboxMove)
{
DC_CREATE_MVBOX as i32
} else {
0
};
context
.inbox_thread
.read()
.unwrap()
.imap
.configure_folders(context, create_mvbox);
.configure_folders(context, flags);
true
}
17 => {
@@ -600,7 +606,7 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> Option<String> {
mod tests {
use crate::config::*;
use crate::configure::JobConfigureImap;
use crate::configure::dc_job_do_DC_JOB_CONFIGURE_IMAP;
use crate::test_utils::*;
#[test]
@@ -610,6 +616,6 @@ mod tests {
.set_config(Config::Addr, Some("probably@unexistant.addr"))
.unwrap();
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
JobConfigureImap(&t.ctx);
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
}
}

View File

@@ -8,6 +8,21 @@ lazy_static! {
pub static ref DC_VERSION_STR: String = env!("CARGO_PKG_VERSION").to_string();
}
#[repr(u8)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)]
pub enum MoveState {
Undefined = 0,
Pending = 1,
Stay = 2,
Moving = 3,
}
impl Default for MoveState {
fn default() -> Self {
MoveState::Undefined
}
}
// some defaults
const DC_E2EE_DEFAULT_ENABLED: i32 = 1;
const DC_INBOX_WATCH_DEFAULT: i32 = 1;
@@ -119,6 +134,8 @@ pub const DC_CONTACT_ID_INFO: u32 = 2;
pub const DC_CONTACT_ID_DEVICE: u32 = 5;
pub const DC_CONTACT_ID_LAST_SPECIAL: u32 = 9;
pub const DC_CREATE_MVBOX: usize = 1;
// Flags for empty server job
pub const DC_EMPTY_MVBOX: u32 = 0x01;

View File

@@ -585,12 +585,7 @@ impl Contact {
let mut self_key = Key::from_self_public(context, &loginparam.addr, &context.sql);
if peerstate.is_some()
&& peerstate
.as_ref()
.and_then(|p| p.peek_key(PeerstateVerifiedStatus::Unverified))
.is_some()
{
if peerstate.is_some() && peerstate.as_ref().and_then(|p| p.peek_key(0)).is_some() {
let peerstate = peerstate.as_ref().unwrap();
let p =
context.stock_str(if peerstate.prefer_encrypt == EncryptPreference::Mutual {
@@ -610,11 +605,11 @@ impl Contact {
.map(|k| k.formatted_fingerprint())
.unwrap_or_default();
let fingerprint_other_verified = peerstate
.peek_key(PeerstateVerifiedStatus::BidirectVerified)
.peek_key(2)
.map(|k| k.formatted_fingerprint())
.unwrap_or_default();
let fingerprint_other_unverified = peerstate
.peek_key(PeerstateVerifiedStatus::Unverified)
.peek_key(0)
.map(|k| k.formatted_fingerprint())
.unwrap_or_default();
if peerstate.addr.is_some() && &loginparam.addr < peerstate.addr.as_ref().unwrap() {

View File

@@ -15,7 +15,6 @@ use crate::imap::*;
use crate::job::*;
use crate::job_thread::JobThread;
use crate::key::*;
use crate::log;
use crate::login_param::LoginParam;
use crate::lot::Lot;
use crate::message::{self, Message, MsgId};
@@ -63,7 +62,6 @@ pub struct Context {
/// Mutex to avoid generating the key for the user more than once.
pub generating_key_mutex: Mutex<()>,
pub translated_stockstrings: RwLock<HashMap<usize, String>>,
pub logger: RwLock<log::Logger>,
}
#[derive(Debug, PartialEq, Eq)]
@@ -96,92 +94,30 @@ pub fn get_info() -> HashMap<&'static str, String> {
res
}
/// Builder for [Context].
///
/// # Example
///
/// ```
/// use deltachat::context::ContextBuilder;
/// let dir = tempfile::tempdir().unwrap();
/// let dbfile = dir.path().join("my-context.db");
/// let ctx = ContextBuilder::new(Box::new(|_, _| 0), "AppName".into(), dbfile)
/// .blobdir(dir.path().join("my-context-blobs"))
/// .logdir(dir.path().join("my-context-logs"))
/// .create()
/// .unwrap();
/// assert_eq!(ctx.get_blobdir(), dir.path().join("my-context-blobs"));
/// ```
#[derive(DebugStub)]
pub struct ContextBuilder {
#[debug_stub = "Callback"]
cb: Box<ContextCallback>,
os_name: String,
dbfile: PathBuf,
blobdir: PathBuf,
logdir: PathBuf,
}
impl ContextBuilder {
pub fn new(cb: Box<ContextCallback>, os_name: String, dbfile: PathBuf) -> Self {
let db_fname = OsString::from(dbfile.file_name().unwrap_or(&OsString::from("dc-context")));
let mut blob_fname = db_fname.clone();
blob_fname.push("-blobs");
let mut log_fname = db_fname.clone();
log_fname.push("-logs");
ContextBuilder {
cb,
os_name,
blobdir: dbfile.with_file_name(blob_fname),
logdir: dbfile.with_file_name(log_fname),
dbfile,
}
}
pub fn blobdir(mut self, path: PathBuf) -> Self {
self.blobdir = path;
self
}
pub fn logdir(mut self, path: PathBuf) -> Self {
self.logdir = path;
self
}
pub fn create(self) -> Result<Context> {
if !self.blobdir.exists() {
std::fs::create_dir_all(&self.blobdir)?;
}
if !self.logdir.exists() {
std::fs::create_dir_all(&self.logdir)?;
}
Context::new(
self.cb,
self.os_name,
self.dbfile,
self.blobdir,
self.logdir,
)
}
}
impl Context {
fn new(
/// Creates new context.
pub fn new(cb: Box<ContextCallback>, os_name: String, dbfile: PathBuf) -> Result<Context> {
let mut blob_fname = OsString::new();
blob_fname.push(dbfile.file_name().unwrap_or_default());
blob_fname.push("-blobs");
let blobdir = dbfile.with_file_name(blob_fname);
if !blobdir.exists() {
std::fs::create_dir_all(&blobdir)?;
}
Context::with_blobdir(cb, os_name, dbfile, blobdir)
}
pub fn with_blobdir(
cb: Box<ContextCallback>,
os_name: String,
dbfile: PathBuf,
blobdir: PathBuf,
logdir: PathBuf,
) -> Result<Context> {
ensure!(
blobdir.is_dir(),
"Blobdir does not exist: {}",
blobdir.display()
);
ensure!(
logdir.is_dir(),
"Logdir does not exist: {}",
logdir.display()
);
let ctx = Context {
blobdir,
dbfile,
@@ -214,7 +150,6 @@ impl Context {
perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
generating_key_mutex: Mutex::new(()),
translated_stockstrings: RwLock::new(HashMap::new()),
logger: RwLock::new(log::Logger::new(logdir)?),
};
ensure!(
@@ -500,9 +435,10 @@ impl Context {
return;
}
if self.is_mvbox(folder) {
if !self.is_inbox(folder) && !self.is_sentbox(folder) {
return;
}
if let Ok(msg) = Message::load_from_db(self, msg_id) {
if msg.is_setupmessage() {
// do not move setup messages;
@@ -510,6 +446,10 @@ impl Context {
return;
}
if self.is_mvbox(folder) {
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay);
}
// 1 = dc message, 2 = reply to dc message
if 0 != msg.is_dc_message {
job_add(
@@ -519,6 +459,7 @@ impl Context {
Params::new(),
0,
);
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving);
}
}
}
@@ -554,25 +495,12 @@ pub struct BobStatus {
pub qr_scan: Option<Lot>,
}
#[derive(Debug, PartialEq)]
pub enum PerformJobsNeeded {
Not,
AtOnce,
AvoidDos,
}
impl Default for PerformJobsNeeded {
fn default() -> Self {
Self::Not
}
}
#[derive(Default, Debug)]
pub struct SmtpState {
pub idle: bool,
pub suspended: bool,
pub doing_jobs: bool,
pub perform_jobs_needed: PerformJobsNeeded,
pub perform_jobs_needed: i32,
pub probe_network: bool,
}
@@ -591,7 +519,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
std::fs::write(&dbfile, b"123").unwrap();
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOs".into(), dbfile).create();
let res = Context::new(Box::new(|_, _| 0), "FakeOs".into(), dbfile);
assert!(res.is_err());
}
@@ -606,9 +534,7 @@ mod tests {
fn test_blobdir_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.create()
.unwrap();
Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).unwrap();
let blobdir = tmp.path().join("db.sqlite-blobs");
assert!(blobdir.is_dir());
}
@@ -619,7 +545,7 @@ mod tests {
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("db.sqlite-blobs");
std::fs::write(&blobdir, b"123").unwrap();
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).create();
let res = Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile);
assert!(res.is_err());
}
@@ -629,9 +555,7 @@ mod tests {
let subdir = tmp.path().join("subdir");
let dbfile = subdir.join("db.sqlite");
let dbfile2 = dbfile.clone();
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.create()
.unwrap();
Context::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile).unwrap();
assert!(subdir.is_dir());
assert!(dbfile2.is_file());
}
@@ -641,9 +565,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = PathBuf::new();
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.blobdir(blobdir)
.create();
let res = Context::with_blobdir(Box::new(|_, _| 0), "FakeOS".into(), dbfile, blobdir);
assert!(res.is_err());
}
@@ -652,36 +574,10 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let blobdir = tmp.path().join("blobs");
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.blobdir(blobdir.clone())
.create()
.unwrap();
assert!(blobdir.is_dir());
}
#[test]
fn test_with_empty_logdir() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let logdir = PathBuf::new();
let res = ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.logdir(logdir)
.create();
let res = Context::with_blobdir(Box::new(|_, _| 0), "FakeOS".into(), dbfile, blobdir);
assert!(res.is_err());
}
#[test]
fn test_with_logdir_not_exists() {
let tmp = tempfile::tempdir().unwrap();
let dbfile = tmp.path().join("db.sqlite");
let logdir = tmp.path().join("logs");
ContextBuilder::new(Box::new(|_, _| 0), "FakeOS".into(), dbfile)
.logdir(logdir.clone())
.create()
.unwrap();
assert!(logdir.is_dir());
}
#[test]
fn no_crashes_on_context_deref() {
let t = dummy_context();

View File

@@ -799,12 +799,9 @@ unsafe fn handle_reports(
&& !of_org_msgid.is_null()
&& !(*of_org_msgid).fld_value.is_null()
{
if let Ok(rfc724_mid) =
wrapmime::parse_message_id(std::slice::from_raw_parts(
(*of_org_msgid).fld_value as *const u8,
libc::strlen((*of_org_msgid).fld_value),
))
{
if let Ok(rfc724_mid) = wrapmime::parse_message_id(
&to_string_lossy((*of_org_msgid).fld_value),
) {
if let Some((chat_id, msg_id)) = message::mdn_from_ext(
context,
from_id,
@@ -1640,11 +1637,7 @@ fn check_verified_properties(
info!(context, "{} has verified {}.", contact.get_addr(), to_addr,);
let fp = peerstate.gossip_key_fingerprint.clone();
if let Some(fp) = fp {
peerstate.set_verified(
DC_PS_GOSSIP_KEY,
&fp,
PeerstateVerifiedStatus::BidirectVerified,
);
peerstate.set_verified(0, &fp, 2);
peerstate.save_to_db(&context.sql, false)?;
is_verified = true;
}

View File

@@ -75,7 +75,7 @@ impl EncryptHelper {
&mut self,
factory: &mut MimeFactory,
e2ee_guaranteed: bool,
min_verified: PeerstateVerifiedStatus,
min_verified: libc::c_int,
do_gossip: bool,
mut in_out_message: *mut Mailmime,
imffields_unprotected: *mut mailimf_fields,
@@ -118,10 +118,10 @@ impl EncryptHelper {
return Ok(false);
}
if let Some(key) = peerstate.peek_key(min_verified) {
if let Some(key) = peerstate.peek_key(min_verified as usize) {
keyring.add_owned(key.clone());
if do_gossip {
if let Some(header) = peerstate.render_gossip_header(min_verified) {
if let Some(header) = peerstate.render_gossip_header(min_verified as usize) {
gossip_headers.push(header.to_string());
}
}

View File

@@ -243,11 +243,4 @@ pub enum Event {
/// @return 0
#[strum(props(id = "2061"))]
SecurejoinJoinerProgress { contact_id: u32, progress: usize },
/// This event is sent out to the inviter when a joiner successfully joined a group.
/// @param data1 (int) chat_id
/// @param data2 (int) contact_id
/// @return 0
#[strum(props(id = "2062"))]
SecurejoinMemberAdded { chat_id: u32, contact_id: u32 },
}

View File

@@ -12,7 +12,7 @@ use async_imap::{
types::{Fetch, Flag, Mailbox, Name, NameAttribute},
};
use async_std::prelude::*;
use async_std::sync::{Mutex, RwLock};
use async_std::sync::{Arc, Mutex, RwLock};
use async_std::task;
use crate::constants::*;
@@ -23,7 +23,7 @@ use crate::events::Event;
use crate::imap_client::*;
use crate::job::{job_add, Action};
use crate::login_param::{CertificateChecks, LoginParam};
use crate::message::{self, update_server_uid};
use crate::message::{self, update_msg_move_state, update_server_uid};
use crate::oauth2::dc_get_oauth2_access_token;
use crate::param::Params;
use crate::stock::StockMessage;
@@ -45,10 +45,11 @@ const SELECT_ALL: &str = "1:*";
#[derive(Debug)]
pub struct Imap {
config: RwLock<ImapConfig>,
session: Mutex<Option<Session>>,
connected: Mutex<bool>,
interrupt: Mutex<Option<stop_token::StopSource>>,
config: Arc<RwLock<ImapConfig>>,
session: Arc<Mutex<Option<Session>>>,
connected: Arc<Mutex<bool>>,
interrupt: Arc<Mutex<Option<stop_token::StopSource>>>,
skip_next_idle_wait: AtomicBool,
should_reconnect: AtomicBool,
}
@@ -117,10 +118,10 @@ impl Default for ImapConfig {
impl Imap {
pub fn new() -> Self {
Imap {
session: Mutex::new(None),
config: RwLock::new(ImapConfig::default()),
interrupt: Mutex::new(None),
connected: Mutex::new(false),
session: Arc::new(Mutex::new(None)),
config: Arc::new(RwLock::new(ImapConfig::default())),
interrupt: Arc::new(Mutex::new(None)),
connected: Arc::new(Mutex::new(false)),
skip_next_idle_wait: AtomicBool::new(false),
should_reconnect: AtomicBool::new(false),
}
@@ -305,7 +306,7 @@ impl Imap {
.unwrap_or_default()
< 3
{
self.configure_folders(context, true);
self.configure_folders(context, 0x1);
}
return Ok(());
}
@@ -886,44 +887,38 @@ impl Imap {
let interval = async_std::stream::interval(Duration::from_secs(60));
let mut interrupt_interval = interrupt.stop_token().stop_stream(interval);
*self.interrupt.lock().await = Some(interrupt);
if self.skip_next_idle_wait.load(Ordering::SeqCst) {
// interrupt_idle has happened before we
// provided self.interrupt
self.skip_next_idle_wait.store(false, Ordering::SeqCst);
info!(context, "fake-idle wait was skipped");
} else {
// loop until we are interrupted or if we fetched something
while let Some(_) = interrupt_interval.next().await {
// try to connect with proper login params
// (setup_handle_if_needed might not know about them if we
// never successfully connected)
if let Err(err) = self.connect_configured(context) {
warn!(context, "fake_idle: could not connect: {}", err);
continue;
}
if self.config.read().await.can_idle {
// we only fake-idled because network was gone during IDLE, probably
break;
}
info!(context, "fake_idle is connected");
// we are connected, let's see if fetching messages results
// in anything. If so, we behave as if IDLE had data but
// will have already fetched the messages so perform_*_fetch
// will not find any new.
if let Some(ref watch_folder) = watch_folder {
match self.fetch_from_single_folder(context, watch_folder).await {
Ok(res) => {
info!(context, "fetch_from_single_folder returned {:?}", res);
if res {
break;
}
}
Err(err) => {
error!(context, "could not fetch from folder: {}", err);
self.trigger_reconnect()
// loop until we are interrupted or if we fetched something
while let Some(_) = interrupt_interval.next().await {
// try to connect with proper login params
// (setup_handle_if_needed might not know about them if we
// never successfully connected)
if let Err(err) = self.connect_configured(context) {
warn!(context, "fake_idle: could not connect: {}", err);
continue;
}
if self.config.read().await.can_idle {
// we only fake-idled because network was gone during IDLE, probably
break;
}
info!(context, "fake_idle is connected");
// we are connected, let's see if fetching messages results
// in anything. If so, we behave as if IDLE had data but
// will have already fetched the messages so perform_*_fetch
// will not find any new.
if let Some(ref watch_folder) = watch_folder {
match self.fetch_from_single_folder(context, watch_folder).await {
Ok(res) => {
info!(context, "fetch_from_single_folder returned {:?}", res);
if res {
break;
}
}
Err(err) => {
error!(context, "could not fetch from folder: {}", err);
self.trigger_reconnect()
}
}
}
}
@@ -1206,7 +1201,7 @@ impl Imap {
})
}
pub fn configure_folders(&self, context: &Context, create_mvbox: bool) {
pub fn configure_folders(&self, context: &Context, flags: libc::c_int) {
task::block_on(async move {
if !self.is_connected().await {
return;
@@ -1237,7 +1232,7 @@ impl Imap {
.find(|folder| folder.name() == "DeltaChat" || folder.name() == fallback_folder)
.map(|n| n.name().to_string());
if mvbox_folder.is_none() && create_mvbox {
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
info!(context, "Creating MVBOX-folder \"DeltaChat\"...",);
match session.create("DeltaChat").await {
@@ -1413,7 +1408,6 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server
{
if old_server_folder.is_empty() && old_server_uid == 0 {
info!(context, "[move] detected bbc-self {}", rfc724_mid,);
context.do_heuristics_moves(server_folder.as_ref(), msg_id);
job_add(
context,
Action::MarkseenMsgOnImap,
@@ -1423,6 +1417,7 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server
);
} else if old_server_folder != server_folder {
info!(context, "[move] detected moved message {}", rfc724_mid,);
update_msg_move_state(context, &rfc724_mid, MoveState::Stay);
}
if old_server_folder != server_folder || old_server_uid != server_uid {

View File

@@ -72,12 +72,11 @@ impl Client {
pub async fn secure<S: AsRef<str>>(
self,
domain: S,
certificate_checks: CertificateChecks,
_certificate_checks: CertificateChecks,
) -> ImapResult<Client> {
match self {
Client::Insecure(client) => {
let tls_config = dc_build_tls_config(certificate_checks);
let tls: async_tls::TlsConnector = Arc::new(tls_config).into();
let tls = async_tls::TlsConnector::new();
let client_sec = client.secure(domain, &tls).await?;

View File

@@ -367,7 +367,7 @@ pub fn normalize_setup_code(s: &str) -> String {
}
#[allow(non_snake_case)]
pub fn JobImexImap(context: &Context, job: &Job) -> Result<()> {
pub fn job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
ensure!(context.alloc_ongoing(), "could not allocate ongoing");
let what: Option<ImexMode> = job.param.get_int(Param::Cmd).and_then(ImexMode::from_i32);
let param = job.param.get(Param::Arg).unwrap_or_default();

View File

@@ -8,7 +8,7 @@ use crate::chat;
use crate::config::Config;
use crate::configure::*;
use crate::constants::*;
use crate::context::{Context, PerformJobsNeeded};
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::Error;
use crate::events::Event;
@@ -22,9 +22,6 @@ use crate::mimefactory::{vec_contains_lowercase, Loaded, MimeFactory};
use crate::param::*;
use crate::sql;
// results in ~3 weeks for the last backoff timespan
const JOB_RETRIES: u32 = 17;
/// Thread IDs
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
#[repr(i32)]
@@ -34,13 +31,6 @@ enum Thread {
Smtp = 5000,
}
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
enum TryAgain {
Dont,
AtOnce,
StandardDelay,
}
impl Default for Thread {
fn default() -> Self {
Thread::Unknown
@@ -110,9 +100,9 @@ pub struct Job {
pub foreign_id: u32,
pub desired_timestamp: i64,
pub added_timestamp: i64,
pub tries: u32,
pub tries: i32,
pub param: Params,
try_again: TryAgain,
pub try_again: i32,
pub pending_error: Option<String>,
}
@@ -140,13 +130,13 @@ impl Job {
}
#[allow(non_snake_case)]
fn SendMsgToSmtp(&mut self, context: &Context) {
fn do_DC_JOB_SEND(&mut self, context: &Context) {
/* connect to SMTP server, if not yet done */
if !context.smtp.lock().unwrap().is_connected() {
let loginparam = LoginParam::from_database(context, "configured_");
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
if connected.is_err() {
self.try_again_later(TryAgain::StandardDelay, None);
self.try_again_later(3, None);
return;
}
}
@@ -187,7 +177,7 @@ impl Job {
Err(err) => {
smtp.disconnect();
warn!(context, "smtp failed: {}", err);
self.try_again_later(TryAgain::AtOnce, Some(err.to_string()));
self.try_again_later(-1, Some(err.to_string()));
}
Ok(()) => {
// smtp success, update db ASAP, then delete smtp file
@@ -206,13 +196,13 @@ impl Job {
}
// this value does not increase the number of tries
fn try_again_later(&mut self, try_again: TryAgain, pending_error: Option<String>) {
fn try_again_later(&mut self, try_again: i32, pending_error: Option<String>) {
self.try_again = try_again;
self.pending_error = pending_error;
}
#[allow(non_snake_case)]
fn MoveMsg(&mut self, context: &Context) {
fn do_DC_JOB_MOVE_MSG(&mut self, context: &Context) {
let imap_inbox = &context.inbox_thread.read().unwrap().imap;
if let Ok(msg) = Message::load_from_db(context, MsgId::new(self.foreign_id)) {
@@ -222,7 +212,7 @@ impl Job {
.unwrap_or_default()
< 3
{
imap_inbox.configure_folders(context, true);
imap_inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context
.sql
@@ -240,7 +230,7 @@ impl Job {
&mut dest_uid,
) {
ImapActionResult::RetryLater => {
self.try_again_later(TryAgain::StandardDelay, None);
self.try_again_later(3i32, None);
}
ImapActionResult::Success => {
message::update_server_uid(
@@ -257,7 +247,7 @@ impl Job {
}
#[allow(non_snake_case)]
fn DeleteMsgOnImap(&mut self, context: &Context) {
fn do_DC_JOB_DELETE_MSG_ON_IMAP(&mut self, context: &Context) {
let imap_inbox = &context.inbox_thread.read().unwrap().imap;
if let Ok(mut msg) = Message::load_from_db(context, MsgId::new(self.foreign_id)) {
@@ -276,7 +266,7 @@ impl Job {
let res =
imap_inbox.delete_msg(context, &mid, server_folder, &mut msg.server_uid);
if res == ImapActionResult::RetryLater {
self.try_again_later(TryAgain::AtOnce, None);
self.try_again_later(-1i32, None);
return;
}
}
@@ -286,7 +276,7 @@ impl Job {
}
#[allow(non_snake_case)]
fn EmptyServer(&mut self, context: &Context) {
fn do_DC_JOB_EMPTY_SERVER(&mut self, context: &Context) {
let imap_inbox = &context.inbox_thread.read().unwrap().imap;
if self.foreign_id & DC_EMPTY_MVBOX > 0 {
if let Some(mvbox_folder) = context
@@ -302,14 +292,14 @@ impl Job {
}
#[allow(non_snake_case)]
fn MarkseenMsgOnImap(&mut self, context: &Context) {
fn do_DC_JOB_MARKSEEN_MSG_ON_IMAP(&mut self, context: &Context) {
let imap_inbox = &context.inbox_thread.read().unwrap().imap;
if let Ok(msg) = Message::load_from_db(context, MsgId::new(self.foreign_id)) {
let folder = msg.server_folder.as_ref().unwrap();
match imap_inbox.set_seen(context, folder, msg.server_uid) {
ImapActionResult::RetryLater => {
self.try_again_later(TryAgain::StandardDelay, None);
self.try_again_later(3i32, None);
}
ImapActionResult::AlreadyDone => {}
ImapActionResult::Success | ImapActionResult::Failed => {
@@ -330,7 +320,7 @@ impl Job {
}
#[allow(non_snake_case)]
fn MarkseenMdnOnImap(&mut self, context: &Context) {
fn do_DC_JOB_MARKSEEN_MDN_ON_IMAP(&mut self, context: &Context) {
let folder = self
.param
.get(Param::ServerFolder)
@@ -339,7 +329,7 @@ impl Job {
let uid = self.param.get_int(Param::ServerUid).unwrap_or_default() as u32;
let imap_inbox = &context.inbox_thread.read().unwrap().imap;
if imap_inbox.set_seen(context, &folder, uid) == ImapActionResult::RetryLater {
self.try_again_later(TryAgain::StandardDelay, None);
self.try_again_later(3i32, None);
return;
}
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
@@ -349,7 +339,7 @@ impl Job {
.unwrap_or_default()
< 3
{
imap_inbox.configure_folders(context, true);
imap_inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context
.sql
@@ -359,7 +349,7 @@ impl Job {
if ImapActionResult::RetryLater
== imap_inbox.mv(context, &folder, uid, &dest_folder, &mut dest_uid)
{
self.try_again_later(TryAgain::StandardDelay, None);
self.try_again_later(3, None);
}
}
}
@@ -480,7 +470,7 @@ pub fn perform_smtp_jobs(context: &Context) {
let probe_smtp_network = state.probe_network;
state.probe_network = false;
state.perform_jobs_needed = PerformJobsNeeded::Not;
state.perform_jobs_needed = 0;
if state.suspended {
info!(context, "SMTP-jobs suspended.",);
@@ -508,27 +498,24 @@ pub fn perform_smtp_idle(context: &Context) {
let &(ref lock, ref cvar) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap();
match state.perform_jobs_needed {
PerformJobsNeeded::AtOnce => {
info!(
context,
"SMTP-idle will not be started because of waiting jobs.",
);
}
PerformJobsNeeded::Not | PerformJobsNeeded::AvoidDos => {
let dur = get_next_wakeup_time(context, Thread::Smtp);
if state.perform_jobs_needed == 1 {
info!(
context,
"SMTP-idle will not be started because of waiting jobs.",
);
} else {
let dur = get_next_wakeup_time(context, Thread::Smtp);
loop {
let res = cvar.wait_timeout(state, dur).unwrap();
state = res.0;
loop {
let res = cvar.wait_timeout(state, dur).unwrap();
state = res.0;
if state.idle || res.1.timed_out() {
// We received the notification and the value has been updated, we can leave.
break;
}
if state.idle || res.1.timed_out() {
// We received the notification and the value has been updated, we can leave.
break;
}
state.idle = false;
}
state.idle = false;
}
}
@@ -720,9 +707,54 @@ pub fn perform_sentbox_jobs(context: &Context) {
}
fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
let jobs: Vec<Job> = load_jobs(context, thread, probe_network);
let query = if !probe_network {
// processing for first-try and after backoff-timeouts:
// process jobs in the order they were added.
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;"
} else {
// processing after call to dc_maybe_network():
// process _all_ pending jobs that failed before
// in the order of their backoff-times.
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;"
};
for mut job in jobs {
let params_no_probe = params![thread as i64, time()];
let params_probe = params![thread as i64];
let params: &[&dyn rusqlite::ToSql] = if !probe_network {
params_no_probe
} else {
params_probe
};
let jobs: Result<Vec<Job>, _> = context
.sql
.query_map(
query,
params,
|row| {
let job = Job {
job_id: row.get(0)?,
action: row.get(1)?,
foreign_id: row.get(2)?,
desired_timestamp: row.get(5)?,
added_timestamp: row.get(4)?,
tries: row.get(6)?,
param: row.get::<_, String>(3)?.parse().unwrap_or_default(),
try_again: 0,
pending_error: None,
};
Ok(job)
},
|jobs| jobs.collect::<Result<Vec<Job>, _>>().map_err(Into::into),
)
.map_err(|err| {
warn!(context, "query failed: {:?}", err);
});
for mut job in jobs.unwrap_or_default() {
info!(
context,
"{}-job #{}, action {} started...",
@@ -756,39 +788,43 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
suspend_smtp_thread(context, true);
}
for _tries in 0..2 {
let mut tries = 0;
while tries <= 1 {
// this can be modified by a job using dc_job_try_again_later()
job.try_again = TryAgain::Dont;
job.try_again = 0;
match job.action {
Action::Unknown => {
info!(context, "Unknown job id found");
warn!(context, "Unknown job id found");
}
Action::SendMsgToSmtp => job.SendMsgToSmtp(context),
Action::EmptyServer => job.EmptyServer(context),
Action::DeleteMsgOnImap => job.DeleteMsgOnImap(context),
Action::MarkseenMsgOnImap => job.MarkseenMsgOnImap(context),
Action::MarkseenMdnOnImap => job.MarkseenMdnOnImap(context),
Action::MoveMsg => job.MoveMsg(context),
Action::SendMdn => job.SendMsgToSmtp(context),
Action::ConfigureImap => JobConfigureImap(context),
Action::ImexImap => match JobImexImap(context, &job) {
Action::SendMsgToSmtp => job.do_DC_JOB_SEND(context),
Action::EmptyServer => job.do_DC_JOB_EMPTY_SERVER(context),
Action::DeleteMsgOnImap => job.do_DC_JOB_DELETE_MSG_ON_IMAP(context),
Action::MarkseenMsgOnImap => job.do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context),
Action::MarkseenMdnOnImap => job.do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context),
Action::MoveMsg => job.do_DC_JOB_MOVE_MSG(context),
Action::SendMdn => job.do_DC_JOB_SEND(context),
Action::ConfigureImap => dc_job_do_DC_JOB_CONFIGURE_IMAP(context),
Action::ImexImap => match job_do_DC_JOB_IMEX_IMAP(context, &job) {
Ok(()) => {}
Err(err) => {
error!(context, "{}", err);
}
},
Action::MaybeSendLocations => location::JobMaybeSendLocations(context, &job),
Action::MaybeSendLocations => {
location::job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context, &job)
}
Action::MaybeSendLocationsEnded => {
location::JobMaybeSendLocationsEnded(context, &mut job)
location::job_do_DC_JOB_MAYBE_SEND_LOC_ENDED(context, &mut job)
}
Action::Housekeeping => sql::housekeeping(context),
Action::SendMdnOld => {}
Action::SendMsgToSmtpOld => {}
}
if job.try_again != TryAgain::AtOnce {
if job.try_again != -1 {
break;
}
tries += 1
}
if Action::ConfigureImap == job.action || Action::ImexImap == job.action {
context
@@ -805,16 +841,28 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
.unsuspend(context);
suspend_smtp_thread(context, false);
break;
} else if job.try_again == TryAgain::AtOnce || job.try_again == TryAgain::StandardDelay {
} else if job.try_again == 2 {
// just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready
info!(
context,
"{}-job #{} not yet ready and will be delayed.",
if thread == Thread::Imap {
"INBOX"
} else {
"SMTP"
},
job.job_id
);
} else if job.try_again == -1 || job.try_again == 3 {
let tries = job.tries + 1;
if tries < JOB_RETRIES {
if tries < 17 {
job.tries = tries;
let time_offset = get_backoff_time_offset(tries);
job.desired_timestamp = time() + time_offset;
job.desired_timestamp = job.added_timestamp + time_offset;
job.update(context);
info!(
context,
"{}-job #{} not succeeded on try #{}, retry in {} seconds.",
"{}-job #{} not succeeded on try #{}, retry in ADD_TIME+{} (in {} seconds).",
if thread == Thread::Imap {
"INBOX"
} else {
@@ -822,16 +870,17 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
},
job.job_id as u32,
tries,
time_offset
time_offset,
job.added_timestamp + time_offset - time()
);
if thread == Thread::Smtp && tries < JOB_RETRIES - 1 {
if thread == Thread::Smtp && tries < 17 - 1 {
context
.smtp_state
.clone()
.0
.lock()
.unwrap()
.perform_jobs_needed = PerformJobsNeeded::AvoidDos;
.perform_jobs_needed = 2;
}
} else {
if job.action == Action::SendMsgToSmtp {
@@ -857,11 +906,13 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
}
}
fn get_backoff_time_offset(tries: u32) -> i64 {
let n = 2_i32.pow(tries - 1) * 60;
#[allow(non_snake_case)]
fn get_backoff_time_offset(c_tries: libc::c_int) -> i64 {
// results in ~3 weeks for the last backoff timespan
let N = 2_i32.pow((c_tries - 1) as u32) * 60;
let mut rng = thread_rng();
let r: i32 = rng.gen();
let mut seconds = r % (n + 1);
let n: i32 = rng.gen();
let mut seconds = n % (N + 1);
if seconds < 1 {
seconds = 1;
}
@@ -962,110 +1013,7 @@ pub fn interrupt_smtp_idle(context: &Context) {
let &(ref lock, ref cvar) = &*context.smtp_state.clone();
let mut state = lock.lock().unwrap();
state.perform_jobs_needed = PerformJobsNeeded::AtOnce;
state.perform_jobs_needed = 1;
state.idle = true;
cvar.notify_one();
info!(context, "Interrupting SMTP-idle... ended",);
}
/// Load jobs from the database.
///
/// Load jobs for this "[Thread]", i.e. either load SMTP jobs or load
/// IMAP jobs. The `probe_network` parameter decides how to query
/// jobs, this is tricky and probably wrong currently. Look at the
/// SQL queries for details.
fn load_jobs(context: &Context, thread: Thread, probe_network: bool) -> Vec<Job> {
let query = if !probe_network {
// processing for first-try and after backoff-timeouts:
// process jobs in the order they were added.
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
FROM jobs WHERE thread=? AND desired_timestamp<=? ORDER BY action DESC, added_timestamp;"
} else {
// processing after call to dc_maybe_network():
// process _all_ pending jobs that failed before
// in the order of their backoff-times.
"SELECT id, action, foreign_id, param, added_timestamp, desired_timestamp, tries \
FROM jobs WHERE thread=? AND tries>0 ORDER BY desired_timestamp, action DESC;"
};
let params_no_probe = params![thread as i64, time()];
let params_probe = params![thread as i64];
let params: &[&dyn rusqlite::ToSql] = if !probe_network {
params_no_probe
} else {
params_probe
};
context
.sql
.query_map(
query,
params,
|row| {
let job = Job {
job_id: row.get(0)?,
action: row.get(1)?,
foreign_id: row.get(2)?,
desired_timestamp: row.get(5)?,
added_timestamp: row.get(4)?,
tries: row.get(6)?,
param: row.get::<_, String>(3)?.parse().unwrap_or_default(),
try_again: TryAgain::Dont,
pending_error: None,
};
Ok(job)
},
|jobs| {
let mut ret: Vec<Job> = Vec::new();
for job in jobs {
match job {
Ok(j) => ret.push(j),
Err(e) => warn!(context, "Bad job from the database: {}", e),
}
}
Ok(ret)
},
)
.unwrap_or_default()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::*;
fn insert_job(context: &Context, foreign_id: i64) {
let now = time();
context
.sql
.execute(
"INSERT INTO jobs
(added_timestamp, thread, action, foreign_id, param, desired_timestamp)
VALUES (?, ?, ?, ?, ?, ?);",
params![
now,
Thread::from(Action::MoveMsg),
Action::MoveMsg,
foreign_id,
Params::new().to_string(),
now
],
)
.unwrap();
}
#[test]
fn test_load_jobs() {
// We want to ensure that loading jobs skips over jobs which
// fails to load from the database instead of failing to load
// all jobs.
let t = dummy_context();
insert_job(&t.ctx, 0);
insert_job(&t.ctx, -1); // This can not be loaded into Job struct.
insert_job(&t.ctx, 1);
let jobs = load_jobs(&t.ctx, Thread::from(Action::MoveMsg), false);
assert_eq!(jobs.len(), 2);
}
}

View File

@@ -70,7 +70,6 @@ impl JobThread {
state.idle = true;
cvar.notify_one();
info!(context, "Interrupting {}-IDLE... finished", self.name);
}
pub fn fetch(&mut self, context: &Context, use_network: bool) {

View File

@@ -22,7 +22,7 @@ extern crate jetscii;
extern crate debug_stub_derive;
#[macro_use]
pub mod log;
mod log;
#[macro_use]
pub mod error;

View File

@@ -538,7 +538,7 @@ pub fn save(
}
#[allow(non_snake_case)]
pub fn JobMaybeSendLocations(context: &Context, _job: &Job) {
pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
let now = time();
let mut continue_streaming = false;
info!(
@@ -628,7 +628,7 @@ pub fn JobMaybeSendLocations(context: &Context, _job: &Job) {
}
#[allow(non_snake_case)]
pub fn JobMaybeSendLocationsEnded(context: &Context, job: &mut Job) {
pub fn job_do_DC_JOB_MAYBE_SEND_LOC_ENDED(context: &Context, job: &mut Job) {
// this function is called when location-streaming _might_ have ended for a chat.
// the function checks, if location-streaming is really ended;
// if so, a device-message is added if not yet done.

View File

@@ -1,180 +1,14 @@
//! # Logging support
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
/// A logger for a [Context].
#[derive(Debug)]
pub struct Logger {
created: std::time::Instant,
logdir: PathBuf,
logfile: String,
file_handle: fs::File,
max_files: u32,
max_filesize: usize,
bytes_written: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LogLevel {
Info,
Warning,
Error,
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LogLevel::Info => write!(f, "I"),
LogLevel::Warning => write!(f, "W"),
LogLevel::Error => write!(f, "E"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Callsite<'a> {
pub file: &'a str,
pub line: u32,
}
impl fmt::Display for Callsite<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.file, self.line)
}
}
impl Logger {
pub fn new(logdir: PathBuf) -> Result<Logger, io::Error> {
let (fname, file) = Self::open(&logdir)?;
let max_files = 5;
Self::prune(&logdir, max_files)?;
Ok(Logger {
created: std::time::Instant::now(),
logdir,
logfile: fname,
file_handle: file,
max_files,
max_filesize: 4 * 1024 * 1024, // 4 Mb
bytes_written: 0,
})
}
/// Opens a new logfile, returning a tuple of (file_name, file_handle).
///
/// This tries to create a new logfile based on the current time,
/// creating .0.log, .1.log etc if this file already exists (up to 32).
fn open(logdir: &Path) -> Result<(String, fs::File), io::Error> {
let basename =
chrono::offset::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
let mut fname = sanitize_filename::sanitize_with_options(
format!("{}.log", &basename),
sanitize_filename::Options {
truncate: true,
windows: true,
replacement: ".",
},
);
let mut counter = 0;
loop {
match std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(logdir.join(&fname))
{
Ok(file) => {
return Ok((fname, file));
}
Err(e) => {
if counter >= 32 {
return Err(e);
} else {
counter += 1;
fname =
sanitize_filename::sanitize(format!("{}-{}.log", &basename, counter));
continue;
}
}
}
}
}
/// Cleans up old logfiles.
fn prune(logdir: &Path, max_files: u32) -> Result<(), io::Error> {
let mut names: Vec<std::ffi::OsString> = Vec::new();
for dirent in fs::read_dir(logdir)? {
names.push(dirent?.file_name());
}
// Sorting like this sorts: 23.log, 24.1.log, 24.2.log,
// 24.log, 25.log. That is 24.log is out of sequence. Oh well.
names.sort();
names.reverse();
while names.len() > max_files as usize {
if let Some(name) = names.pop() {
fs::remove_file(logdir.join(name))?;
}
}
Ok(())
}
pub fn log(
&mut self,
level: LogLevel,
callsite: Callsite,
msg: &str,
) -> Result<(), std::io::Error> {
if self.bytes_written > self.max_filesize {
self.flush()?;
let (fname, handle) = Self::open(&self.logdir)?;
self.logfile = fname;
self.file_handle = handle;
Self::prune(&self.logdir, self.max_files)?;
}
let thread = std::thread::current();
let msg = format!(
"{time:8.2} {level} {thid:?}/{thname} [{callsite}]: {msg}\n",
time = self.created.elapsed().as_secs_f64(),
level = level,
thid = thread.id(),
thname = thread.name().unwrap_or("unnamed"),
callsite = callsite,
msg = msg,
);
self.file_handle.write_all(msg.as_bytes())?;
self.bytes_written += msg.len();
Ok(())
}
pub fn flush(&mut self) -> Result<(), std::io::Error> {
self.file_handle.flush()
}
}
#[macro_export]
macro_rules! callsite {
() => {
$crate::log::Callsite {
file: file!(),
line: line!(),
}
};
}
//! # Logging macros
#[macro_export]
macro_rules! info {
($ctx:expr, $msg:expr) => {
info!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
if let Ok(mut logger) = $ctx.logger.write() {
logger.log($crate::log::LogLevel::Info, callsite!(), &formatted).ok();
}
emit_event!($ctx, $crate::Event::Info(formatted));
}};
};
}
#[macro_export]
@@ -182,13 +16,10 @@ macro_rules! warn {
($ctx:expr, $msg:expr) => {
warn!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
if let Ok(mut logger) = $ctx.logger.write() {
logger.log($crate::log::LogLevel::Warning, callsite!(), &formatted).ok();
}
emit_event!($ctx, $crate::Event::Warning(formatted));
}};
};
}
#[macro_export]
@@ -196,13 +27,10 @@ macro_rules! error {
($ctx:expr, $msg:expr) => {
error!($ctx, $msg,)
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
if let Ok(mut logger) = $ctx.logger.write() {
logger.log($crate::log::LogLevel::Error, callsite!(), &formatted).ok();
}
emit_event!($ctx, $crate::Event::Error(formatted));
}};
};
}
#[macro_export]
@@ -211,80 +39,3 @@ macro_rules! emit_event {
$ctx.call_cb($event);
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_logging() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let mut logger = Logger::new(dir.to_path_buf()).unwrap();
logger.log(LogLevel::Info, callsite!(), "foo").unwrap();
logger.log(LogLevel::Warning, callsite!(), "bar").unwrap();
logger.log(LogLevel::Error, callsite!(), "baz").unwrap();
logger.flush().unwrap();
let log = fs::read_to_string(logger.logdir.join(logger.logfile)).unwrap();
println!("{}", log);
let lines: Vec<&str> = log.lines().collect();
assert!(lines[0].contains(" I "));
assert!(lines[0].contains(format!("{:?}", std::thread::current().id()).as_str()));
assert!(lines[0]
.contains(format!("{}", std::thread::current().name().unwrap_or("unnamed")).as_str()));
assert!(lines[0].contains(&format!("src{}log.rs", std::path::MAIN_SEPARATOR)));
assert!(lines[0].contains("foo"));
assert!(lines[1].contains(" W "));
assert!(lines[1].contains(format!("{:?}", std::thread::current().id()).as_str()));
assert!(lines[1]
.contains(format!("{}", std::thread::current().name().unwrap_or("unnamed")).as_str()));
assert!(lines[1].contains(&format!("src{}log.rs", std::path::MAIN_SEPARATOR)));
assert!(lines[1].contains("bar"));
assert!(lines[2].contains(" E "));
assert!(lines[2].contains(format!("{:?}", std::thread::current().id()).as_str()));
assert!(lines[2]
.contains(format!("{}", std::thread::current().name().unwrap_or("unnamed")).as_str()));
assert!(lines[2].contains(&format!("src{}log.rs", std::path::MAIN_SEPARATOR)));
assert!(lines[2].contains("baz"));
}
#[test]
fn test_reopen_logfile() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let mut logger = Logger::new(dir.to_path_buf()).unwrap();
logger.max_filesize = 5;
let fname0 = logger.logfile.clone();
assert!(fname0.ends_with(".log"));
logger
.log(LogLevel::Info, callsite!(), "more than 5 bytes are written")
.unwrap();
logger.log(LogLevel::Info, callsite!(), "2nd msg").unwrap();
let fname1 = logger.logfile.clone();
assert!(fname1.ends_with("-1.log"));
assert_ne!(fname0, fname1);
let log0 = fs::read_to_string(logger.logdir.join(&fname0)).unwrap();
assert!(log0.contains("more than 5 bytes are written"));
let log1 = fs::read_to_string(logger.logdir.join(&fname1)).unwrap();
assert!(log1.contains("2nd msg"));
}
#[test]
fn test_prune() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
Logger::new(dir.to_path_buf()).unwrap();
Logger::new(dir.to_path_buf()).unwrap();
Logger::new(dir.to_path_buf()).unwrap();
Logger::new(dir.to_path_buf()).unwrap();
let dirents0: Vec<fs::DirEntry> = fs::read_dir(&dir).unwrap().map(|r| r.unwrap()).collect();
assert_eq!(dirents0.len(), 4);
Logger::prune(&dir, 3).unwrap();
let dirents1: Vec<fs::DirEntry> = fs::read_dir(&dir).unwrap().map(|r| r.unwrap()).collect();
assert_eq!(dirents1.len(), 3);
}
}

View File

@@ -159,6 +159,7 @@ pub struct Message {
pub(crate) from_id: u32,
pub(crate) to_id: u32,
pub(crate) chat_id: u32,
pub(crate) move_state: MoveState,
pub(crate) type_0: Viewtype,
pub(crate) state: MessageState,
pub(crate) hidden: bool,
@@ -199,6 +200,7 @@ impl Message {
" m.mime_in_reply_to AS mime_in_reply_to,",
" m.server_folder AS server_folder,",
" m.server_uid AS server_uid,",
" m.move_state as move_state,",
" m.chat_id AS chat_id,",
" m.from_id AS from_id,",
" m.to_id AS to_id,",
@@ -226,6 +228,7 @@ impl Message {
msg.in_reply_to = row.get::<_, Option<String>>("mime_in_reply_to")?;
msg.server_folder = row.get::<_, Option<String>>("server_folder")?;
msg.server_uid = row.get("server_uid")?;
msg.move_state = row.get("move_state")?;
msg.chat_id = row.get("chat_id")?;
msg.from_id = row.get("from_id")?;
msg.to_id = row.get("to_id")?;
@@ -1071,6 +1074,18 @@ pub fn exists(context: &Context, msg_id: MsgId) -> bool {
}
}
pub fn update_msg_move_state(context: &Context, rfc724_mid: &str, state: MoveState) -> bool {
// we update the move_state for all messages belonging to a given Message-ID
// so that the state stay intact when parts are deleted
sql::execute(
context,
&context.sql,
"UPDATE msgs SET move_state=? WHERE rfc724_mid=?;",
params![state as i32, rfc724_mid],
)
.is_ok()
}
pub fn set_msg_failed(context: &Context, msg_id: MsgId, error: Option<impl AsRef<str>>) {
if let Ok(mut msg) = Message::load_from_db(context, msg_id) {
if msg.state.can_fail() {

View File

@@ -230,7 +230,7 @@ impl<'a> MimeFactory<'a> {
// 1=add Autocrypt-header (needed eg. for handshaking), 2=no Autocrypte-header (used for MDN)
let mut e2ee_guaranteed = false;
let mut min_verified = crate::peerstate::PeerstateVerifiedStatus::Unverified;
let mut min_verified: libc::c_int = 0;
let mut do_gossip = false;
let mut grpimage = None;
let force_plaintext: libc::c_int;
@@ -246,7 +246,7 @@ impl<'a> MimeFactory<'a> {
wrapmime::new_custom_field(imf_fields, "Chat-Verified", "1");
force_plaintext = 0;
e2ee_guaranteed = true;
min_verified = crate::peerstate::PeerstateVerifiedStatus::BidirectVerified;
min_verified = 2
} else {
force_plaintext = self
.msg

View File

@@ -12,17 +12,6 @@ use crate::error::*;
use crate::key::*;
use crate::sql::{self, Sql};
pub const DC_PS_GOSSIP_KEY: u32 = 0;
pub const DC_PS_PUBLIC_KEY: u32 = 1;
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
#[repr(u8)]
pub enum PeerstateVerifiedStatus {
Unverified = 0,
//Verified = 1, // not used
BidirectVerified = 2,
}
/// Peerstate represents the state of an Autocrypt peer.
pub struct Peerstate<'a> {
pub context: &'a Context,
@@ -322,7 +311,7 @@ impl<'a> Peerstate<'a> {
};
}
pub fn render_gossip_header(&self, min_verified: PeerstateVerifiedStatus) -> Option<String> {
pub fn render_gossip_header(&self, min_verified: usize) -> Option<String> {
if let Some(ref addr) = self.addr {
if let Some(key) = self.peek_key(min_verified) {
// TODO: avoid cloning
@@ -338,12 +327,12 @@ impl<'a> Peerstate<'a> {
None
}
pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&Key> {
pub fn peek_key(&self, min_verified: usize) -> Option<&Key> {
if self.public_key.is_none() && self.gossip_key.is_none() && self.verified_key.is_none() {
return None;
}
if min_verified != PeerstateVerifiedStatus::Unverified {
if 0 != min_verified {
return self.verified_key.as_ref();
}
if self.public_key.is_some() {
@@ -353,17 +342,10 @@ impl<'a> Peerstate<'a> {
self.gossip_key.as_ref()
}
pub fn set_verified(
&mut self,
which_key: u32,
fingerprint: &str,
verified: PeerstateVerifiedStatus,
) -> bool {
pub fn set_verified(&mut self, which_key: usize, fingerprint: &str, verified: usize) -> bool {
let mut success = false;
if !(which_key != DC_PS_GOSSIP_KEY && which_key != DC_PS_PUBLIC_KEY
|| verified != PeerstateVerifiedStatus::BidirectVerified)
{
if which_key == DC_PS_PUBLIC_KEY
if !(which_key != 0 && which_key != 1 || verified != 2) {
if which_key == 1
&& self.public_key_fingerprint.is_some()
&& self.public_key_fingerprint.as_ref().unwrap() == fingerprint
{
@@ -372,7 +354,7 @@ impl<'a> Peerstate<'a> {
self.verified_key_fingerprint = self.public_key_fingerprint.clone();
success = true;
}
if which_key == DC_PS_GOSSIP_KEY
if which_key == 0
&& self.gossip_key_fingerprint.is_some()
&& self.gossip_key_fingerprint.as_ref().unwrap() == fingerprint
{

View File

@@ -611,14 +611,6 @@ pub fn handle_securejoin_handshake(
}
inviter_progress!(context, contact_id, 800);
inviter_progress!(context, contact_id, 1000);
let field_grpid = mimeparser
.lookup_optional_field("Secure-Join-Group")
.unwrap_or_default();
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, &field_grpid);
context.call_cb(Event::SecurejoinMemberAdded {
chat_id: group_chat_id,
contact_id: contact_id,
});
} else {
warn!(context, "vg-member-added-received invalid.",);
return ret;
@@ -672,11 +664,7 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
if let Some(ref mut peerstate) =
Peerstate::from_fingerprint(context, &context.sql, fingerprint.as_ref())
{
if peerstate.set_verified(
DC_PS_PUBLIC_KEY,
fingerprint.as_ref(),
PeerstateVerifiedStatus::BidirectVerified,
) {
if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.to_save = Some(ToSave::All);
peerstate

View File

@@ -729,7 +729,6 @@ fn open(
}
if dbversion < 48 {
info!(context, "[migration] v48");
// NOTE: move_state is not used anymore
sql.execute(
"ALTER TABLE msgs ADD COLUMN move_state INTEGER DEFAULT 1;",
params![],

View File

@@ -7,7 +7,7 @@ use tempfile::{tempdir, TempDir};
use crate::config::Config;
use crate::constants::KeyType;
use crate::context::{Context, ContextBuilder, ContextCallback};
use crate::context::{Context, ContextCallback};
use crate::events::Event;
use crate::key;
@@ -33,9 +33,7 @@ pub fn test_context(callback: Option<Box<ContextCallback>>) -> TestContext {
Some(cb) => cb,
None => Box::new(|_, _| 0),
};
let ctx = ContextBuilder::new(cb, "FakeOs".into(), dbfile)
.create()
.unwrap();
let ctx = Context::new(cb, "FakeOs".into(), dbfile).unwrap();
TestContext { ctx: ctx, dir: dir }
}

View File

@@ -49,27 +49,20 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
}
}
pub fn parse_message_id(message_id: &[u8]) -> Result<String, Error> {
pub fn parse_message_id(message_id: &str) -> Result<String, Error> {
let mut dummy = 0;
let c_message_id = CString::new(message_id).unwrap_or_default();
let c_ptr = c_message_id.as_ptr();
let mut rfc724_mid_c = std::ptr::null_mut();
if unsafe {
mailimf_msg_id_parse(
message_id.as_ptr() as *const libc::c_char,
message_id.len(),
&mut dummy,
&mut rfc724_mid_c,
)
} == MAIL_NO_ERROR as libc::c_int
if unsafe { mailimf_msg_id_parse(c_ptr, libc::strlen(c_ptr), &mut dummy, &mut rfc724_mid_c) }
== MAIL_NO_ERROR as libc::c_int
&& !rfc724_mid_c.is_null()
{
let res = to_string_lossy(rfc724_mid_c);
unsafe { libc::free(rfc724_mid_c.cast()) };
Ok(res)
} else {
bail!(
"could not parse message_id: {}",
String::from_utf8_lossy(message_id)
);
bail!("could not parse message_id: {}", message_id);
}
}
@@ -550,11 +543,11 @@ mod tests {
#[test]
fn test_parse_message_id() {
assert_eq!(
parse_message_id(b"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
parse_message_id("Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
assert_eq!(
parse_message_id(b"<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
parse_message_id("<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
}

View File

@@ -128,7 +128,7 @@ fn test_encryption_decryption() {
public_keyring.add_ref(&public_key);
let mut public_keyring2 = Keyring::default();
public_keyring2.add_owned(public_key2);
public_keyring2.add_owned(public_key2.clone());
let mut valid_signatures: HashSet<String> = Default::default();
@@ -219,10 +219,8 @@ struct TestContext {
fn create_test_context() -> TestContext {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
let ctx = ContextBuilder::new(Box::new(cb), "FakeOs".into(), dbfile)
.create()
.unwrap();
TestContext { ctx, dir }
let ctx = Context::new(Box::new(cb), "FakeOs".into(), dbfile).unwrap();
TestContext { ctx: ctx, dir: dir }
}
#[test]