Compare commits

..

28 Commits

Author SHA1 Message Date
holger krekel
21f447f23c revert printing file/lineno in Error-messages as these are typically user-visible
For info and warn it's fine
2019-12-16 00:37:32 +01:00
Floris Bruynooghe
19e716b522 Add filename and line no to log entries
This is done for all logging calls, also those which call error! which
is normally directly shown to the user.
2019-12-16 00:33:57 +01:00
Alexander Krotov
1ee15942cc Simplify simplify.rs
* Remove Simplify structure.

* Match for lines starting with 5 markers, not consisting of exactly 5 markers.

This is a regression from C to Rust conversion, see
2bb1c280d5/src/dc_simplify.c (L154)

* Add tests.
2019-12-16 02:31:38 +03:00
björn petersen
898e641256 Merge pull request #1048 from deltachat/beta17
add changelog for beta17 and bump versions
2019-12-15 23:32:11 +01:00
holger krekel
cda4ccff2a add changelog for beta17 and bump versions 2019-12-15 23:26:05 +01:00
B. Petersen
ba274482f7 make d.png much smaller in size to avoid avatar-recoding and to allow checking file contents 2019-12-15 23:12:37 +01:00
B. Petersen
435f734d60 adapt tests for new avatar recoding 2019-12-15 23:12:37 +01:00
B. Petersen
a5f949c4e2 recode group- and user-avatar to 192x192 pixel 2019-12-15 23:12:37 +01:00
B. Petersen
9fc556864e add image crate 2019-12-15 23:12:37 +01:00
Alexander Krotov
a0645dc713 Resultify dc_create_folder and don't ignore its errors 2019-12-16 00:49:51 +03:00
holger krekel
5893cd309d fixate async-imap to the working commit so that no one accidentally does "cargo update" and breaks things. 2019-12-16 00:49:37 +03:00
holger krekel
09c7ab1ee6 avoid addrparse to panic() and refactor according code a little with test. 2019-12-15 21:54:20 +01:00
holger krekel
4bacae3711 fix #1037 and simplify mdn-report related code and state 2019-12-15 22:18:34 +03:00
Alexander Krotov
8d3e536582 Do not panic on SystemTimeDifference 2019-12-15 19:56:13 +01:00
Alexander Krotov
697cc0a79b Make needs_encryption a bool 2019-12-15 19:55:49 +01:00
Alexander Krotov
a34ed5c02a Make recalc_fingerprints a bool 2019-12-15 19:55:49 +01:00
Alexander Krotov
256bb01606 Make prepend_subject a bool 2019-12-15 19:55:49 +01:00
Alexander Krotov
1de535363d Move parse_message_id from wrapmime.rs to imap/mod.rs 2019-12-15 19:13:49 +03:00
Alexander Krotov
24d9011939 Move get_autocrypt_mime from wrapmime.rs to e2ee.rs 2019-12-15 19:13:49 +03:00
holger krekel
6284bdc98f pull in latest async-smtp master to fix #1030 2019-12-15 15:27:25 +01:00
Alexander Krotov
e7351b1bb8 Restore constant and remove parenthesis 2019-12-15 16:43:12 +03:00
Alexander Krotov
b3ee89c6e5 Documentation improvements 2019-12-15 16:15:09 +03:00
Alexander Krotov
3f49492ccf cargo fmt 2019-12-14 22:28:15 +01:00
Alexander Krotov
ad700b45d0 Make Imap.connect() async 2019-12-14 22:25:33 +01:00
Alexander Krotov
74923b4575 Enable clippy::type_complexity error 2019-12-14 22:00:38 +01:00
Alexander Krotov
81199e7ee0 Update Cargo.lock 2019-12-14 18:16:54 +00:00
Alexander Krotov
ccca1b0bea Do not format! SQL queries 2019-12-14 18:16:54 +00:00
Alexander Krotov
ba1ced5e08 Switch to master branch of async-imap 2019-12-14 17:51:36 +01:00
30 changed files with 785 additions and 476 deletions

View File

@@ -1,5 +1,23 @@
# Changelog
## 1.0.0-beta.17
- #1044 implement avatar recoding to 192x192 in core to keep file sizes small.
- #1024 fix #1021 SQL/injection malformed Chat-Group-Name breakage
- #1036 fix smtp crash by pulling in a fixed async-smtp
- #1039 fix read-receipts appearing as normal messages when you change
MDN settings
- #1040 do not panic on SystemTimeDifference
- #1043 avoid potential crashes in malformed From/Chat-Disposition... headers
- #1045 #1041 #1038 #1035 #1034 #1029 #1025 various cleanups and doc
improvments
## 1.0.0-beta.16
- alleviate login problems with providers which only

181
Cargo.lock generated
View File

@@ -85,7 +85,7 @@ dependencies = [
[[package]]
name = "async-imap"
version = "0.1.1"
source = "git+https://github.com/async-email/async-imap?branch=native_tls#3dc3681a9b158504a0cf11656854db5096476e2f"
source = "git+https://github.com/async-email/async-imap?rev=d7836416766b55d8d03587ea5326eecf501c2030#d7836416766b55d8d03587ea5326eecf501c2030"
dependencies = [
"async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -124,7 +124,7 @@ dependencies = [
[[package]]
name = "async-smtp"
version = "0.1.0"
source = "git+https://github.com/async-email/async-smtp#4f8416a0b8e0f8369459bb2fd342e79a17eb836b"
source = "git+https://github.com/async-email/async-smtp#c26ce542e847c502654c471ebc50d6c996f86cee"
dependencies = [
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-std 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -456,6 +456,11 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color_quant"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "constant_time_eq"
version = "0.1.4"
@@ -552,6 +557,14 @@ dependencies = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-queue"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
version = "0.6.6"
@@ -634,10 +647,19 @@ dependencies = [
]
[[package]]
name = "deltachat"
version = "1.0.0-beta.16"
name = "deflate"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"async-imap 0.1.1 (git+https://github.com/async-email/async-imap?branch=native_tls)",
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "deltachat"
version = "1.0.0-beta.17"
dependencies = [
"async-imap 0.1.1 (git+https://github.com/async-email/async-imap?rev=d7836416766b55d8d03587ea5326eecf501c2030)",
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-smtp 0.1.0 (git+https://github.com/async-email/async-smtp)",
"async-std 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -655,6 +677,7 @@ dependencies = [
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"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 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)",
"image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -711,9 +734,9 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.0.0-beta.16"
version = "1.0.0-beta.17"
dependencies = [
"deltachat 1.0.0-beta.16",
"deltachat 1.0.0-beta.17",
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1182,6 +1205,15 @@ dependencies = [
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gif"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glob"
version = "0.2.11"
@@ -1355,6 +1387,22 @@ dependencies = [
"unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "image"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "image-meta"
version = "0.1.0"
@@ -1381,6 +1429,14 @@ dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iovec"
version = "0.1.4"
@@ -1402,6 +1458,15 @@ name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jpeg-decoder"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "keccak"
version = "0.1.0"
@@ -1515,6 +1580,11 @@ dependencies = [
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzw"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mach"
version = "0.2.3"
@@ -1708,6 +1778,16 @@ dependencies = [
"zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-derive"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-derive"
version = "0.3.0"
@@ -1737,6 +1817,16 @@ dependencies = [
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.2.2"
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)",
]
[[package]]
name = "num-traits"
version = "0.2.10"
@@ -1963,6 +2053,17 @@ name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "png"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ppv-lite86"
version = "0.2.6"
@@ -2263,6 +2364,28 @@ dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
@@ -2498,6 +2621,11 @@ dependencies = [
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "1.0.0"
@@ -2757,6 +2885,16 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.11"
@@ -2858,6 +2996,17 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tiff"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.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)",
]
[[package]]
name = "time"
version = "0.1.42"
@@ -3320,7 +3469,7 @@ dependencies = [
"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?branch=native_tls)" = "<none>"
"checksum async-imap 0.1.1 (git+https://github.com/async-email/async-imap?rev=d7836416766b55d8d03587ea5326eecf501c2030)" = "<none>"
"checksum async-macros 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "644a5a8de80f2085a1e7e57cd1544a2a7438f6e003c0790999bd43b92a77cdb2"
"checksum async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a29e9e4ed87f4070dd6099d0bd5edfc7692c94442c80d656b50a802c6fde23b7"
"checksum async-smtp 0.1.0 (git+https://github.com/async-email/async-smtp)" = "<none>"
@@ -3361,6 +3510,7 @@ dependencies = [
"checksum circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea"
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
@@ -3372,6 +3522,7 @@ dependencies = [
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
@@ -3380,6 +3531,7 @@ dependencies = [
"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
"checksum debug_stub_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "496b7f8a2f853313c3ca370641d7ff3e42c32974fdccda8f0684599ed0a3ff6b"
"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
"checksum deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "814dba060d9fdc7a989fccdc4810ada9d1c7a1f09131c78e42412bc6c634b93b"
"checksum derive_builder 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
"checksum derive_builder_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
@@ -3437,6 +3589,7 @@ dependencies = [
"checksum futures_codec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "793d2283ff61ffff52d51cc631be0c8e75370d96056a38e09f124a67263913da"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
@@ -3454,12 +3607,15 @@ dependencies = [
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
"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 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4be8aaefbe7545dc42ae925afb55a0098f226a3fe5ef721872806f44f57826"
"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 indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
"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 itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0256f0aec7352539102a9efbcb75543227b7ab1117e0f95450023af730128451"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum kv-log-macro 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c54d9f465d530a752e6ebdc217e081a7a614b48cb200f6f0aee21ba6bc9aabb"
@@ -3474,6 +3630,7 @@ dependencies = [
"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
"checksum mailparse 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c00eb97cc18f08aaadd02808328dcc9be94948d8e5b54adbfd3414d2f87f7bf1"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
@@ -3494,9 +3651,11 @@ dependencies = [
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
"checksum num-bigint-dig 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d03c330f9f7a2c19e3c0b42698e48141d0809c78cd9b6219f85bd7d7e892aa"
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
"checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
"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-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"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"
@@ -3520,6 +3679,7 @@ dependencies = [
"checksum pin-project-lite 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f0af6cbca0e6e3ce8692ee19fb8d734b641899e07b68eb73e9bbbd32f1703991"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum png 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "247cb804bd7fc86d0c2b153d1374265e67945875720136ca8fe451f11c6aed52"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
"checksum pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074"
@@ -3553,6 +3713,8 @@ dependencies = [
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd"
"checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
@@ -3576,6 +3738,7 @@ dependencies = [
"checksum sanitize-filename 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23fd0fec94ec480abfd86bb8f4f6c57e0efb36dac5c852add176ea7b04c74801"
"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
"checksum scheduled-thread-pool 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f5de7bc31f28f8e6c28df5e1bf3d10610f5fdc14cc95f272853512c70a2bd779"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df"
"checksum security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e31493fc37615debb8c5090a7aeb4a9730bc61e77ab10b9af59f1a202284f895"
@@ -3607,6 +3770,7 @@ dependencies = [
"checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
@@ -3618,6 +3782,7 @@ dependencies = [
"checksum thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef"
"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 tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d"
"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-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-beta.16"
version = "1.0.0-beta.17"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL"
@@ -20,7 +20,10 @@ num-traits = "0.2.6"
async-smtp = { git = "https://github.com/async-email/async-smtp", branch = "master" }
email = { git = "https://github.com/deltachat/rust-email", branch = "master" }
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "native_tls" }
async-imap = { git = "https://github.com/async-email/async-imap", branch="native_tls", default-features = false, features = ["tls_native"] }
# XXX newer commits of async-imap lead to import-export tests hanging
async-imap = { git = "https://github.com/async-email/async-imap", rev="d7836416766b55d8d03587ea5326eecf501c2030"}
async-native-tls = "0.1.1"
async-std = { version = "1.0", features = ["unstable"] }
base64 = "0.11"
@@ -55,6 +58,7 @@ stop-token = { version = "0.1.1", features = ["unstable"] }
mailparse = "0.10.1"
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
native-tls = "0.2.3"
image = "0.22.3"
[dev-dependencies]
tempfile = "3.0"

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -687,6 +687,39 @@ class TestOnlineAccount:
except queue.Empty:
pass # mark_seen_messages() has generated events before it returns
def test_mdn_asymetric(self, acfactory, lp):
ac1, ac2 = acfactory.get_two_online_accounts()
lp.sec("ac1: create chat with ac2")
chat = self.get_chat(ac1, ac2, both_created=True)
# make sure mdns are enabled (usually enabled by default already)
ac1.set_config("mdns_enabled", "1")
ac2.set_config("mdns_enabled", "1")
lp.sec("sending text message from ac1 to ac2")
msg_out = chat.send_text("message1")
assert len(chat.get_messages()) == 1
lp.sec("disable ac1 MDNs")
ac1.set_config("mdns_enabled", "0")
lp.sec("wait for ac2 to receive message")
msg = ac2.wait_next_incoming_message()
assert len(msg.chat.get_messages()) == 1
lp.sec("ac2: mark incoming message as seen")
ac2.mark_seen_messages([msg])
lp.sec("ac1: waiting for incoming activity")
# wait for MOVED event because even ignored read-receipts should be moved
ac1._evlogger.get_matching("DC_EVENT_IMAP_MESSAGE_MOVED")
assert len(chat.get_messages()) == 1
assert not msg_out.is_out_mdn_received()
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
ac1, ac2 = acfactory.get_two_online_accounts()

View File

@@ -55,6 +55,7 @@ if __name__ == "__main__":
replace_toml_version("Cargo.toml", newversion)
replace_toml_version("deltachat-ffi/Cargo.toml", newversion)
subprocess.call(["cargo", "check"])
subprocess.call(["git", "add", "-u"])
# subprocess.call(["cargo", "update", "-p", "deltachat"])

View File

@@ -6,9 +6,13 @@ use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use self::image::GenericImageView;
use crate::constants::AVATAR_SIZE;
use crate::context::Context;
use crate::events::Event;
extern crate image;
/// Represents a file in the blob directory.
///
/// The object has a name, which will always be valid UTF-8. Having a
@@ -349,6 +353,31 @@ impl<'a> BlobObject<'a> {
}
true
}
pub fn recode_to_avatar_size(&self, context: &Context) -> Result<(), BlobError> {
let blob_abs = self.to_abs_path();
let img = image::open(&blob_abs).map_err(|err| BlobError::RecodeFailure {
blobdir: context.get_blobdir().to_path_buf(),
blobname: blob_abs.to_str().unwrap_or_default().to_string(),
cause: err,
backtrace: failure::Backtrace::new(),
})?;
if img.width() <= AVATAR_SIZE && img.height() <= AVATAR_SIZE {
return Ok(());
}
let img = img.thumbnail(AVATAR_SIZE, AVATAR_SIZE);
img.save(&blob_abs).map_err(|err| BlobError::WriteFailure {
blobdir: context.get_blobdir().to_path_buf(),
blobname: blob_abs.to_str().unwrap_or_default().to_string(),
cause: err,
backtrace: failure::Backtrace::new(),
})?;
Ok(())
}
}
impl<'a> fmt::Display for BlobObject<'a> {
@@ -382,6 +411,13 @@ pub enum BlobError {
cause: std::io::Error,
backtrace: failure::Backtrace,
},
RecodeFailure {
blobdir: PathBuf,
blobname: String,
#[cause]
cause: image::ImageError,
backtrace: failure::Backtrace,
},
WrongBlobdir {
blobdir: PathBuf,
src: PathBuf,
@@ -429,6 +465,9 @@ impl fmt::Display for BlobError {
blobname,
blobdir.display(),
),
BlobError::RecodeFailure {
blobdir, blobname, ..
} => write!(f, "Failed to recode {} in {}", blobname, blobdir.display(),),
BlobError::WrongBlobdir { blobdir, src, .. } => write!(
f,
"File path {} is not in blobdir {}",

View File

@@ -116,10 +116,12 @@ impl Chat {
self.param.exists(Param::Selftalk)
}
/// Returns true if chat is a device chat.
pub fn is_device_talk(&self) -> bool {
self.param.exists(Param::Devicetalk)
}
/// Returns true if user can send messages to this chat.
pub fn can_send(&self) -> bool {
self.id > DC_CHAT_ID_LAST_SPECIAL && !self.is_device_talk()
}
@@ -134,14 +136,17 @@ impl Chat {
Ok(())
}
/// Returns chat ID.
pub fn get_id(&self) -> u32 {
self.id
}
/// Returns chat type.
pub fn get_type(&self) -> Chattype {
self.typ
}
/// Returns chat name.
pub fn get_name(&self) -> &str {
&self.name
}
@@ -167,7 +172,7 @@ impl Chat {
}
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
if self.id == 1 {
if self.id == DC_CHAT_ID_DEADDROP {
return context.stock_str(StockMessage::DeadDrop).into();
}
let cnt = get_chat_contact_cnt(context, self.id);
@@ -248,10 +253,12 @@ impl Chat {
!self.is_unpromoted()
}
/// Returns true if chat is a verified group chat.
pub fn is_verified(&self) -> bool {
(self.typ == Chattype::VerifiedGroup)
self.typ == Chattype::VerifiedGroup
}
/// Returns true if location streaming is enabled in the chat.
pub fn is_sending_locations(&self) -> bool {
self.is_sending_locations
}
@@ -646,8 +653,8 @@ pub fn create_or_lookup_by_contact_id(
sql::execute(
context,
&context.sql,
format!(
"INSERT INTO chats (type, name, param, blocked, grpid, created_timestamp) VALUES({}, '{}', '{}', {}, '{}', {})",
"INSERT INTO chats (type, name, param, blocked, grpid, created_timestamp) VALUES(?, ?, ?, ?, ?, ?)",
params![
100,
chat_name,
match contact_id {
@@ -658,8 +665,7 @@ pub fn create_or_lookup_by_contact_id(
create_blocked as u8,
contact.get_addr(),
time(),
),
params![],
]
)?;
let chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", contact.get_addr());
@@ -667,11 +673,8 @@ pub fn create_or_lookup_by_contact_id(
sql::execute(
context,
&context.sql,
format!(
"INSERT INTO chats_contacts (chat_id, contact_id) VALUES({}, {})",
chat_id, contact_id
),
params![],
"INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)",
params![chat_id, contact_id],
)?;
if contact_id == DC_CONTACT_ID_SELF {
@@ -818,6 +821,7 @@ fn last_msg_in_chat_encrypted(context: &Context, sql: &Sql, chat_id: u32) -> boo
}
}
/// Returns whether a contact is in a chat or not.
pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
/* this function works for group and for normal chats, however, it is more useful for group chats.
DC_CONTACT_ID_SELF may be used to check, if the user itself is in a group chat (DC_CONTACT_ID_SELF is not added to normal chats) */
@@ -1108,6 +1112,7 @@ pub fn get_chat_msgs(
}
}
/// Returns number of messages in a chat.
pub fn get_msg_cnt(context: &Context, chat_id: u32) -> usize {
context
.sql
@@ -1278,6 +1283,7 @@ pub fn get_next_media(
ret
}
/// Archives or unarchives a chat.
pub fn archive(context: &Context, chat_id: u32, archive: bool) -> Result<(), Error> {
ensure!(
chat_id > DC_CHAT_ID_LAST_SPECIAL,
@@ -1313,6 +1319,7 @@ pub fn archive(context: &Context, chat_id: u32, archive: bool) -> Result<(), Err
Ok(())
}
/// Deletes a chat.
pub fn delete(context: &Context, chat_id: u32) -> Result<(), Error> {
ensure!(
chat_id > DC_CHAT_ID_LAST_SPECIAL,
@@ -1443,6 +1450,7 @@ pub fn add_to_chat_contacts_table(context: &Context, chat_id: u32, contact_id: u
.is_ok()
}
/// Adds a contact to the chat.
pub fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
match add_contact_to_chat_ex(context, chat_id, contact_id, false) {
Ok(res) => res,
@@ -1875,6 +1883,7 @@ pub fn set_chat_profile_image(
_ => Err(err),
},
)?;
image_blob.recode_to_avatar_size(context)?;
chat.param.set(Param::ProfileImage, image_blob.as_name());
msg.param.set(Param::Arg, image_blob.as_name());
msg.text = Some(context.stock_system_msg(
@@ -1915,8 +1924,11 @@ pub fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: u32) -> Resul
ensure!(chat.can_send(), "cannot send to chat #{}", chat_id);
curr_timestamp = dc_create_smeared_timestamps(context, msg_ids.len());
let ids = context.sql.query_map(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
params![msg_ids.iter().map(|_| "?").join(",")],
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
msg_ids.iter().map(|_| "?").join(",")
),
msg_ids,
|row| row.get::<_, MsgId>(0),
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
)?;
@@ -2070,6 +2082,9 @@ pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32,
.unwrap_or((0, false, Blocked::Not))
}
/// Adds a message to device chat.
///
/// Optional `label` can be provided to ensure that message is added only once.
pub fn add_device_msg(
context: &Context,
label: Option<&str>,
@@ -2144,6 +2159,9 @@ pub fn was_device_msg_ever_added(context: &Context, label: &str) -> Result<bool,
Ok(false)
}
/// Adds an informational message to chat.
///
/// For example, it can be a message showing that a member was added to a group.
pub fn add_info_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");

View File

@@ -314,7 +314,7 @@ impl Chatlist {
}
}
/// Get the number of archived chats
/// Returns the number of archived chats
pub fn dc_get_archived_cnt(context: &Context) -> u32 {
context
.sql

View File

@@ -136,6 +136,7 @@ impl Context {
match value {
Some(value) => {
let blob = BlobObject::new_from_path(&self, value)?;
blob.recode_to_avatar_size(self)?;
self.sql.set_raw_config(self, key, Some(blob.as_name()))
}
None => self.sql.set_raw_config(self, key, None),
@@ -190,6 +191,8 @@ mod tests {
use std::string::ToString;
use crate::test_utils::*;
use std::fs::File;
use std::io::Write;
#[test]
fn test_to_string() {
@@ -209,16 +212,17 @@ mod tests {
}
#[test]
fn test_selfavatar() -> failure::Fallible<()> {
fn test_selfavatar_outside_blobdir() -> failure::Fallible<()> {
let t = dummy_context();
let avatar_src = t.dir.path().join("avatar.jpg");
std::fs::write(&avatar_src, b"avatar")?;
let avatar_bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg");
File::create(&avatar_src)?.write_all(avatar_bytes)?;
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");
assert!(std::fs::metadata(&avatar_blob).unwrap().len() < avatar_bytes.len() as u64);
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);
assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string()));
Ok(())
@@ -228,7 +232,8 @@ mod tests {
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")?;
let avatar_bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg");
File::create(&avatar_src)?.write_all(avatar_bytes)?;
t.ctx
.set_config(Config::Selfavatar, Some(&avatar_src.to_str().unwrap()))?;
let avatar_cfg = t.ctx.get_config(Config::Selfavatar);

View File

@@ -6,6 +6,8 @@ mod read_url;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use async_std::task;
use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
@@ -540,13 +542,14 @@ fn try_imap_one_param(context: &Context, param: &LoginParam) -> Option<bool> {
param.imap_certificate_checks
);
info!(context, "Trying: {}", inf);
if context
.inbox_thread
.read()
.unwrap()
.imap
.connect(context, &param)
{
if task::block_on(
context
.inbox_thread
.read()
.unwrap()
.imap
.connect(context, &param),
) {
info!(context, "success: {}", inf);
return Some(true);
}

View File

@@ -184,6 +184,9 @@ pub const DC_VC_CONTACT_CONFIRM: i32 = 6;
pub const DC_BOB_ERROR: i32 = 0;
pub const DC_BOB_SUCCESS: i32 = 1;
// max. width/height of an avatar
pub const AVATAR_SIZE: u32 = 192;
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
#[repr(i32)]
pub enum Viewtype {

View File

@@ -1,3 +1,5 @@
//! Contacts module
use std::path::PathBuf;
use deltachat_derive::*;
@@ -969,7 +971,7 @@ fn set_block_contact(context: &Context, contact_id: u32, new_blocking: bool) {
pub fn set_profile_image(
context: &Context,
contact_id: u32,
profile_image: AvatarAction,
profile_image: &AvatarAction,
) -> Result<()> {
// the given profile image is expected to be already in the blob directory
// as profile images can be set only by receiving messages, this should be always the case, however.

View File

@@ -1,4 +1,4 @@
//! Contacts module
//! Context module
use std::collections::HashMap;
use std::ffi::OsString;

View File

@@ -73,15 +73,13 @@ pub fn dc_receive_imf(
let mut sent_timestamp = 0;
let mut created_db_entries = Vec::new();
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
let mut rr_event_to_send = Vec::new();
let mut to_ids = ContactIds::new();
// helper method to handle early exit and memory cleanup
let cleanup = |context: &Context,
create_event_to_send: &Option<CreateEvent>,
created_db_entries: &Vec<(usize, MsgId)>,
rr_event_to_send: &Vec<(u32, MsgId)>| {
created_db_entries: &Vec<(usize, MsgId)>| {
if let Some(create_event_to_send) = create_event_to_send {
for (chat_id, msg_id) in created_db_entries {
let event = match create_event_to_send {
@@ -97,12 +95,6 @@ pub fn dc_receive_imf(
context.call_cb(event);
}
}
for (chat_id, msg_id) in rr_event_to_send {
context.call_cb(Event::MsgRead {
chat_id: *chat_id,
msg_id: *msg_id,
});
}
};
if let Some(value) = mime_parser.get(HeaderDef::Date) {
@@ -179,7 +171,7 @@ pub fn dc_receive_imf(
}
}
};
if mime_parser.get_last_nonmeta().is_some() {
if mime_parser.parts.last().is_some() {
if let Err(err) = add_parts(
context,
&mut mime_parser,
@@ -202,30 +194,17 @@ pub fn dc_receive_imf(
&mut created_db_entries,
&mut create_event_to_send,
) {
cleanup(
context,
&create_event_to_send,
&created_db_entries,
&rr_event_to_send,
);
cleanup(context, &create_event_to_send, &created_db_entries);
bail!("add_parts error: {:?}", err);
}
} else {
// there are no non-meta data in message, do some basic calculations so that the varaiables
// there are parts in this message, do some basic calculations so that the variables
// are correct in the further processing
if sent_timestamp > time() {
sent_timestamp = time()
}
}
mime_parser.handle_reports(
from_id,
sent_timestamp,
&mut rr_event_to_send,
&server_folder,
server_uid,
);
if mime_parser.location_kml.is_some() || mime_parser.message_kml.is_some() {
save_locations(
context,
@@ -238,7 +217,7 @@ pub fn dc_receive_imf(
}
if mime_parser.user_avatar != AvatarAction::None {
match contact::set_profile_image(&context, from_id, mime_parser.user_avatar) {
match contact::set_profile_image(&context, from_id, &mime_parser.user_avatar) {
Ok(()) => {
context.call_cb(Event::ChatModified(chat_id));
}
@@ -266,12 +245,9 @@ pub fn dc_receive_imf(
"received message {} has Message-Id: {}", server_uid, rfc724_mid
);
cleanup(
context,
&create_event_to_send,
&created_db_entries,
&rr_event_to_send,
);
cleanup(context, &create_event_to_send, &created_db_entries);
mime_parser.handle_reports(from_id, sent_timestamp, &server_folder, server_uid);
Ok(())
}
@@ -612,10 +588,6 @@ fn add_parts(
let subject = mime_parser.get_subject().unwrap_or_default();
for part in mime_parser.parts.iter_mut() {
if part.is_meta {
continue;
}
if mime_parser.location_kml.is_some()
&& icnt == 1
&& (part.msg == "-location-" || part.msg.is_empty())
@@ -1148,9 +1120,12 @@ fn create_or_lookup_adhoc_group(
if !chat_ids.is_empty() {
let chat_ids_str = join(chat_ids.iter().map(|x| x.to_string()), ",");
let res = context.sql.query_row(
"SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
params!(chat_ids_str),
format!(
"SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
chat_ids_str
),
params![],
|row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<Blocked>>(1)?.unwrap_or_default()))
}
@@ -1249,8 +1224,11 @@ fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> String {
let members = context
.sql
.query_map(
"SELECT addr FROM contacts WHERE id IN({}) AND id!=1", // 1=DC_CONTACT_ID_SELF
params![member_ids_str],
format!(
"SELECT addr FROM contacts WHERE id IN({}) AND id!=1", // 1=DC_CONTACT_ID_SELF
member_ids_str
),
params![],
|row| row.get::<_, String>(0),
|rows| {
let mut addrs = rows.collect::<std::result::Result<Vec<_>, _>>()?;
@@ -1294,14 +1272,17 @@ fn search_chat_ids_by_contact_ids(
contact_ids.sort();
let contact_ids_str = join(contact_ids.iter().map(|x| x.to_string()), ",");
context.sql.query_map(
"SELECT DISTINCT cc.chat_id, cc.contact_id \
FROM chats_contacts cc \
LEFT JOIN chats c ON c.id=cc.chat_id \
WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN({})) \
AND c.type=120 \
AND cc.contact_id!=1 \
ORDER BY cc.chat_id, cc.contact_id;", // 1=DC_CONTACT_ID_SELF
params![contact_ids_str],
format!(
"SELECT DISTINCT cc.chat_id, cc.contact_id \
FROM chats_contacts cc \
LEFT JOIN chats c ON c.id=cc.chat_id \
WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN({})) \
AND c.type=120 \
AND cc.contact_id!=1 \
ORDER BY cc.chat_id, cc.contact_id;", // 1=DC_CONTACT_ID_SELF
contact_ids_str
),
params![],
|row| Ok((row.get::<_, u32>(0)?, row.get::<_, u32>(1)?)),
|rows| {
let mut last_chat_id = 0;
@@ -1328,8 +1309,8 @@ fn search_chat_ids_by_contact_ids(
if matches == contact_ids.len() && mismatches == 0 {
chat_ids.push(last_chat_id);
}
Ok(())
},
Ok(())
}
)?;
}
}
@@ -1382,9 +1363,12 @@ fn check_verified_properties(
let to_ids_str = join(to_ids.iter().map(|x| x.to_string()), ",");
let rows = context.sql.query_map(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
params![to_ids_str],
format!(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
to_ids_str
),
params![],
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1).unwrap_or(0))),
|rows| {
rows.collect::<std::result::Result<Vec<_>, _>>()

View File

@@ -1,175 +1,169 @@
use crate::dehtml::*;
#[derive(Copy, Clone)]
pub struct Simplify {
pub is_forwarded: bool,
}
/// Return index of footer line in vector of message lines, or vector length if
/// no footer is found.
///
/// Also return whether not-standard (rfc3676, §4.3) footer is found.
fn find_message_footer(lines: &[&str]) -> (usize, bool) {
/// Remove standard (RFC 3676, §4.3) footer if it is found.
fn remove_message_footer<'a>(lines: &'a [&str]) -> &'a [&'a str] {
for (ix, &line) in lines.iter().enumerate() {
// quoted-printable may encode `-- ` to `-- =20` which is converted
// back to `-- `
match line {
"-- " | "-- " => return (ix, false),
"--" | "---" | "----" => return (ix, true),
"-- " | "-- " => return &lines[..ix],
_ => (),
}
}
(lines.len(), false)
lines
}
impl Simplify {
pub fn new() -> Self {
Simplify {
is_forwarded: false,
/// Remove nonstandard footer and a boolean indicating whether such
/// footer was removed.
fn remove_nonstandard_footer<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
for (ix, &line) in lines.iter().enumerate() {
if line == "--"
|| line == "---"
|| line == "----"
|| line.starts_with("-----")
|| line.starts_with("_____")
|| line.starts_with("=====")
|| line.starts_with("*****")
|| line.starts_with("~~~~~")
{
return (&lines[..ix], true);
}
}
(lines, false)
}
/// Simplify and normalise text: Remove quotes, signatures, unnecessary
/// lineends etc.
/// The data returned from simplify() must be free()'d when no longer used.
pub fn simplify(&mut self, input: &str, is_html: bool, is_msgrmsg: bool) -> String {
let mut out = if is_html {
dehtml(input)
} else {
input.to_string()
};
fn split_lines(buf: &str) -> Vec<&str> {
buf.split('\n').collect()
}
out.retain(|c| c != '\r');
out = self.simplify_plain_text(&out, is_msgrmsg);
out.retain(|c| c != '\r');
/// Simplify message text for chat display.
/// Remove quotes, signatures, trailing empty lines etc.
pub fn simplify(input: &str, is_html: bool, is_chat_message: bool) -> (String, bool) {
let mut out = if is_html {
dehtml(input)
} else {
input.to_string()
};
out
out.retain(|c| c != '\r');
let lines = split_lines(&out);
let (lines, is_forwarded) = skip_forward_header(&lines);
let lines = remove_message_footer(lines);
let (lines, has_nonstandard_footer) = remove_nonstandard_footer(lines);
let (lines, has_bottom_quote) = if !is_chat_message {
remove_bottom_quote(lines)
} else {
(lines, false)
};
let (lines, has_top_quote) = if !is_chat_message {
remove_top_quote(lines)
} else {
(lines, false)
};
// re-create buffer from the remaining lines
let text = render_message(
lines,
has_top_quote,
has_nonstandard_footer || has_bottom_quote,
);
(text, is_forwarded)
}
/// Skips "forwarded message" header.
/// Returns message body lines and a boolean indicating whether
/// a message is forwarded or not.
fn skip_forward_header<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
if lines.len() >= 3
&& lines[0] == "---------- Forwarded message ----------"
&& lines[1].starts_with("From: ")
&& lines[2].is_empty()
{
(&lines[3..], true)
} else {
(lines, false)
}
}
/**
* Simplify Plain Text
*/
#[allow(non_snake_case, clippy::mut_range_bound, clippy::needless_range_loop)]
fn simplify_plain_text(&mut self, buf_terminated: &str, is_msgrmsg: bool) -> String {
/* This function ...
... removes all text after the line `-- ` (footer mark)
... removes full quotes at the beginning and at the end of the text -
these are all lines starting with the character `>`
... remove a non-empty line before the removed quote (contains sth. like "On 2.9.2016, Bjoern wrote:" in different formats and lanugages) */
/* split the given buffer into lines */
let lines: Vec<_> = buf_terminated.split('\n').collect();
let mut l_first: usize = 0;
let mut is_cut_at_begin = false;
let (mut l_last, mut is_cut_at_end) = find_message_footer(&lines);
if l_last > l_first + 2 {
let line0 = lines[l_first];
let line1 = lines[l_first + 1];
let line2 = lines[l_first + 2];
if line0 == "---------- Forwarded message ----------"
&& line1.starts_with("From: ")
&& line2.is_empty()
{
self.is_forwarded = true;
l_first += 3
fn remove_bottom_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
let mut last_quoted_line = None;
for (l, line) in lines.iter().enumerate().rev() {
if is_plain_quote(line) {
last_quoted_line = Some(l)
} else if !is_empty_line(line) {
break;
}
}
if let Some(mut l_last) = last_quoted_line {
if l_last > 1 && is_empty_line(lines[l_last - 1]) {
l_last -= 1
}
if l_last > 1 {
let line = lines[l_last - 1];
if is_quoted_headline(line) {
l_last -= 1
}
}
for l in l_first..l_last {
let line = lines[l];
if line == "-----"
|| line == "_____"
|| line == "====="
|| line == "*****"
|| line == "~~~~~"
{
l_last = l;
is_cut_at_end = true;
/* done */
(&lines[..l_last], true)
} else {
(lines, false)
}
}
fn remove_top_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
let mut last_quoted_line = None;
let mut has_quoted_headline = false;
for (l, line) in lines.iter().enumerate() {
if is_plain_quote(line) {
last_quoted_line = Some(l)
} else if !is_empty_line(line) {
if is_quoted_headline(line) && !has_quoted_headline && last_quoted_line.is_none() {
has_quoted_headline = true
} else {
/* non-quoting line found */
break;
}
}
if !is_msgrmsg {
let mut l_lastQuotedLine = None;
for l in (l_first..l_last).rev() {
let line = lines[l];
if is_plain_quote(line) {
l_lastQuotedLine = Some(l)
} else if !is_empty_line(line) {
break;
}
}
if let Some(last_quoted_line) = l_lastQuotedLine {
l_last = last_quoted_line;
is_cut_at_end = true;
if l_last > 1 && is_empty_line(lines[l_last - 1]) {
l_last -= 1
}
if l_last > 1 {
let line = lines[l_last - 1];
if is_quoted_headline(line) {
l_last -= 1
}
}
}
}
if !is_msgrmsg {
let mut l_lastQuotedLine_0 = None;
let mut hasQuotedHeadline = 0;
for l in l_first..l_last {
let line = lines[l];
if is_plain_quote(line) {
l_lastQuotedLine_0 = Some(l)
} else if !is_empty_line(line) {
if is_quoted_headline(line)
&& 0 == hasQuotedHeadline
&& l_lastQuotedLine_0.is_none()
{
hasQuotedHeadline = 1i32
} else {
/* non-quoting line found */
break;
}
}
}
if let Some(last_quoted_line) = l_lastQuotedLine_0 {
l_first = last_quoted_line + 1;
is_cut_at_begin = true
}
}
/* re-create buffer from the remaining lines */
let mut ret = String::new();
if is_cut_at_begin {
ret += "[...]";
}
/* we write empty lines only in case and non-empty line follows */
let mut pending_linebreaks = 0;
let mut content_lines_added = 0;
for l in l_first..l_last {
let line = lines[l];
if is_empty_line(line) {
pending_linebreaks += 1
} else {
if 0 != content_lines_added {
if pending_linebreaks > 2i32 {
pending_linebreaks = 2i32
}
while 0 != pending_linebreaks {
ret += "\n";
pending_linebreaks -= 1
}
}
// the incoming message might contain invalid UTF8
ret += line;
content_lines_added += 1;
pending_linebreaks = 1i32
}
}
if is_cut_at_end && (!is_cut_at_begin || 0 != content_lines_added) {
ret += " [...]";
}
ret
}
if let Some(last_quoted_line) = last_quoted_line {
(&lines[last_quoted_line + 1..], true)
} else {
(lines, false)
}
}
fn render_message(lines: &[&str], is_cut_at_begin: bool, is_cut_at_end: bool) -> String {
let mut ret = String::new();
if is_cut_at_begin {
ret += "[...]";
}
/* we write empty lines only in case and non-empty line follows */
let mut pending_linebreaks = 0;
let mut empty_body = true;
for line in lines {
if is_empty_line(line) {
pending_linebreaks += 1
} else {
if !empty_body {
if pending_linebreaks > 2 {
pending_linebreaks = 2
}
while 0 != pending_linebreaks {
ret += "\n";
pending_linebreaks -= 1
}
}
// the incoming message might contain invalid UTF8
ret += line;
empty_body = false;
pending_linebreaks = 1
}
}
if is_cut_at_end && (!is_cut_at_begin || !empty_body) {
ret += " [...]";
}
ret
}
/**
@@ -213,50 +207,59 @@ mod tests {
#[test]
// proptest does not support [[:graphical:][:space:]] regex.
fn test_simplify_plain_text_fuzzy(input in "[!-~\t \n]+") {
let output = Simplify::new().simplify_plain_text(&input, true);
let (output, _is_forwarded) = simplify(&input, false, true);
assert!(output.split('\n').all(|s| s != "-- "));
}
}
#[test]
fn test_simplify_trim() {
let mut simplify = Simplify::new();
let html = "\r\r\nline1<br>\r\n\r\n\r\rline2\n\r";
let plain = simplify.simplify(html, true, false);
let (plain, is_forwarded) = simplify(html, true, false);
assert_eq!(plain, "line1\nline2");
assert!(!is_forwarded);
}
#[test]
fn test_simplify_parse_href() {
let mut simplify = Simplify::new();
let html = "<a href=url>text</a";
let plain = simplify.simplify(html, true, false);
let (plain, is_forwarded) = simplify(html, true, false);
assert_eq!(plain, "[text](url)");
assert!(!is_forwarded);
}
#[test]
fn test_simplify_bold_text() {
let mut simplify = Simplify::new();
let html = "<!DOCTYPE name [<!DOCTYPE ...>]><!-- comment -->text <b><?php echo ... ?>bold</b><![CDATA[<>]]>";
let plain = simplify.simplify(html, true, false);
let (plain, is_forwarded) = simplify(html, true, false);
assert_eq!(plain, "text *bold*<>");
assert!(!is_forwarded);
}
#[test]
fn test_simplify_forwarded_message() {
let text = "---------- Forwarded message ----------\r\nFrom: test@example.com\r\n\r\nForwarded message\r\n-- \r\nSignature goes here";
let (plain, is_forwarded) = simplify(text, false, false);
assert_eq!(plain, "Forwarded message");
assert!(is_forwarded);
}
#[test]
fn test_simplify_html_encoded() {
let mut simplify = Simplify::new();
let html =
"&lt;&gt;&quot;&apos;&amp; &auml;&Auml;&ouml;&Ouml;&uuml;&Uuml;&szlig; foo&AElig;&ccedil;&Ccedil; &diams;&lrm;&rlm;&zwnj;&noent;&zwj;";
let plain = simplify.simplify(html, true, false);
let (plain, is_forwarded) = simplify(html, true, false);
assert_eq!(
plain,
"<>\"\'& äÄöÖüÜß fooÆçÇ \u{2666}\u{200e}\u{200f}\u{200c}&noent;\u{200d}"
);
assert!(!is_forwarded);
}
#[test]
@@ -270,4 +273,19 @@ mod tests {
assert!(!is_plain_quote("Life is pain"));
assert!(!is_plain_quote(""));
}
#[test]
fn test_remove_top_quote() {
let (lines, has_top_quote) = remove_top_quote(&["> first", "> second"]);
assert!(lines.is_empty());
assert!(has_top_quote);
let (lines, has_top_quote) = remove_top_quote(&["> first", "> second", "not a quote"]);
assert_eq!(lines, &["not a quote"]);
assert!(has_top_quote);
let (lines, has_top_quote) = remove_top_quote(&["not a quote", "> first", "> second"]);
assert_eq!(lines, &["not a quote", "> first", "> second"]);
assert!(!has_top_quote);
}
}

View File

@@ -381,11 +381,14 @@ pub(crate) fn dc_copy_file(
}
}
pub(crate) fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
pub(crate) fn dc_create_folder(
context: &Context,
path: impl AsRef<std::path::Path>,
) -> Result<(), std::io::Error> {
let path_abs = dc_get_abs_path(context, &path);
if !path_abs.exists() {
match fs::create_dir_all(path_abs) {
Ok(_) => true,
Ok(_) => Ok(()),
Err(err) => {
warn!(
context,
@@ -393,11 +396,11 @@ pub(crate) fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Pa
path.as_ref().display(),
err
);
false
Err(err)
}
}
} else {
true
Ok(())
}
}
@@ -825,7 +828,7 @@ mod tests {
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder").is_ok());
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder"));

View File

@@ -2,7 +2,7 @@
use std::collections::HashSet;
use mailparse::MailHeaderMap;
use mailparse::{MailHeaderMap, ParsedMail};
use num_traits::FromPrimitive;
use crate::aheader::*;
@@ -14,7 +14,6 @@ use crate::keyring::*;
use crate::peerstate::*;
use crate::pgp;
use crate::securejoin::handle_degrade_event;
use crate::wrapmime;
#[derive(Debug)]
pub struct EncryptHelper {
@@ -118,7 +117,7 @@ impl EncryptHelper {
pub fn try_decrypt(
context: &Context,
mail: &mailparse::ParsedMail<'_>,
mail: &ParsedMail<'_>,
message_time: i64,
) -> Result<(Option<Vec<u8>>, HashSet<String>)> {
let from = mail
@@ -232,9 +231,36 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
}
}
/// Returns a reference to the encrypted payload and validates the autocrypt structure.
fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail<'b>> {
ensure!(
mail.ctype.mimetype == "multipart/encrypted",
"Not a multipart/encrypted message: {}",
mail.ctype.mimetype
);
ensure!(
mail.subparts.len() == 2,
"Invalid Autocrypt Level 1 Mime Parts"
);
ensure!(
mail.subparts[0].ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 version part: {:?}",
mail.subparts[0].ctype,
);
ensure!(
mail.subparts[1].ctype.mimetype == "application/octet-stream",
"Invalid Autocrypt Level 1 encrypted part: {:?}",
mail.subparts[1].ctype
);
Ok(&mail.subparts[1])
}
fn decrypt_if_autocrypt_message<'a>(
context: &Context,
mail: &mailparse::ParsedMail<'a>,
mail: &ParsedMail<'a>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>,
@@ -246,7 +272,7 @@ fn decrypt_if_autocrypt_message<'a>(
//
// Errors are returned for failures related to decryption of AC-messages.
let encrypted_data_part = match wrapmime::get_autocrypt_mime(mail) {
let encrypted_data_part = match get_autocrypt_mime(mail) {
Err(_) => {
// not an autocrypt mime message, abort and ignore
return Ok(None);
@@ -267,7 +293,7 @@ fn decrypt_if_autocrypt_message<'a>(
/// Returns Ok(None) if nothing encrypted was found.
fn decrypt_part(
_context: &Context,
mail: &mailparse::ParsedMail<'_>,
mail: &ParsedMail<'_>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>,
@@ -313,7 +339,7 @@ fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
/// However, Delta Chat itself has no problem with encrypted multipart/report
/// parts and MUAs should be encouraged to encrpyt multipart/reports as well so
/// that we could use the normal Autocrypt processing.
fn contains_report(mail: &mailparse::ParsedMail<'_>) -> bool {
fn contains_report(mail: &ParsedMail<'_>) -> bool {
mail.ctype.mimetype == "multipart/report"
}

View File

@@ -241,7 +241,7 @@ impl Imap {
"IMAP-fake-IDLE done after {:.4}s",
SystemTime::now()
.duration_since(fake_idle_start_time)
.unwrap()
.unwrap_or_default()
.as_millis() as f64
/ 1000.,
);

View File

@@ -23,7 +23,6 @@ use crate::message::{self, update_server_uid};
use crate::oauth2::dc_get_oauth2_access_token;
use crate::param::Params;
use crate::stock::StockMessage;
use crate::wrapmime;
mod idle;
pub mod select_folder;
@@ -339,7 +338,7 @@ impl Imap {
let param = LoginParam::from_database(context, "configured_");
// the trailing underscore is correct
if self.connect(context, &param) {
if task::block_on(self.connect(context, &param)) {
self.ensure_configured_folders(context, true)
} else {
Err(Error::ConnectionFailed(format!("{}", param)))
@@ -348,82 +347,80 @@ impl Imap {
/// tries connecting to imap account using the specific login
/// parameters
pub fn connect(&self, context: &Context, lp: &LoginParam) -> bool {
task::block_on(async move {
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
return false;
}
pub async fn connect(&self, context: &Context, lp: &LoginParam) -> bool {
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
return false;
}
{
let addr = &lp.addr;
let imap_server = &lp.mail_server;
let imap_port = lp.mail_port as u16;
let imap_user = &lp.mail_user;
let imap_pw = &lp.mail_pw;
let server_flags = lp.server_flags as usize;
{
let addr = &lp.addr;
let imap_server = &lp.mail_server;
let imap_port = lp.mail_port as u16;
let imap_user = &lp.mail_user;
let imap_pw = &lp.mail_pw;
let server_flags = lp.server_flags as usize;
let mut config = self.config.write().await;
config.addr = addr.to_string();
config.imap_server = imap_server.to_string();
config.imap_port = imap_port;
config.imap_user = imap_user.to_string();
config.imap_pw = imap_pw.to_string();
config.certificate_checks = lp.imap_certificate_checks;
config.server_flags = server_flags;
}
let mut config = self.config.write().await;
config.addr = addr.to_string();
config.imap_server = imap_server.to_string();
config.imap_port = imap_port;
config.imap_user = imap_user.to_string();
config.imap_pw = imap_pw.to_string();
config.certificate_checks = lp.imap_certificate_checks;
config.server_flags = server_flags;
}
if let Err(err) = self.setup_handle_if_needed(context).await {
warn!(context, "failed to setup imap handle: {}", err);
self.free_connect_params().await;
return false;
}
if let Err(err) = self.setup_handle_if_needed(context).await {
warn!(context, "failed to setup imap handle: {}", err);
self.free_connect_params().await;
return false;
}
let teardown = match &mut *self.session.lock().await {
Some(ref mut session) => match session.capabilities().await {
Ok(caps) => {
if !context.sql.is_open() {
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
true
} else {
let can_idle = caps.has_str("IDLE");
let has_xlist = caps.has_str("XLIST");
let caps_list = caps.iter().fold(String::new(), |s, c| {
if let Capability::Atom(x) = c {
s + &format!(" {}", x)
} else {
s + &format!(" {:?}", c)
}
});
self.config.write().await.can_idle = can_idle;
self.config.write().await.has_xlist = has_xlist;
*self.connected.lock().await = true;
emit_event!(
context,
Event::ImapConnected(format!(
"IMAP-LOGIN as {}, capabilities: {}",
lp.mail_user, caps_list,
))
);
false
}
}
Err(err) => {
info!(context, "CAPABILITY command error: {}", err);
let teardown = match &mut *self.session.lock().await {
Some(ref mut session) => match session.capabilities().await {
Ok(caps) => {
if !context.sql.is_open() {
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
true
} else {
let can_idle = caps.has_str("IDLE");
let has_xlist = caps.has_str("XLIST");
let caps_list = caps.iter().fold(String::new(), |s, c| {
if let Capability::Atom(x) = c {
s + &format!(" {}", x)
} else {
s + &format!(" {:?}", c)
}
});
self.config.write().await.can_idle = can_idle;
self.config.write().await.has_xlist = has_xlist;
*self.connected.lock().await = true;
emit_event!(
context,
Event::ImapConnected(format!(
"IMAP-LOGIN as {}, capabilities: {}",
lp.mail_user, caps_list,
))
);
false
}
},
None => true,
};
}
Err(err) => {
info!(context, "CAPABILITY command error: {}", err);
true
}
},
None => true,
};
if teardown {
self.disconnect(context);
if teardown {
self.disconnect(context);
false
} else {
true
}
})
false
} else {
true
}
}
pub fn disconnect(&self, context: &Context) {
@@ -1225,6 +1222,18 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server
}
}
fn parse_message_id(message_id: &[u8]) -> crate::error::Result<String> {
let value = std::str::from_utf8(message_id)?;
let addrs = mailparse::addrparse(value)
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
if let Some(info) = addrs.extract_single_info() {
return Ok(info.addr);
}
bail!("could not parse message_id: {}", value);
}
fn prefetch_get_message_id(prefetch_msg: &Fetch) -> Result<String> {
if prefetch_msg.envelope().is_none() {
return Err(Error::Other(
@@ -1237,5 +1246,22 @@ fn prefetch_get_message_id(prefetch_msg: &Fetch) -> Result<String> {
return Err(Error::Other("prefetch: No message ID found".to_string()));
}
wrapmime::parse_message_id(&message_id.unwrap()).map_err(Into::into)
parse_message_id(&message_id.unwrap()).map_err(Into::into)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_message_id() {
assert_eq!(
parse_message_id(b"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
assert_eq!(
parse_message_id(b"<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
}
}

View File

@@ -380,7 +380,7 @@ pub fn JobImexImap(context: &Context, job: &Job) -> Result<()> {
context.free_ongoing();
bail!("Cannot create private key or private key not available.");
} else {
dc_create_folder(context, &param);
dc_create_folder(context, &param)?;
}
}
let path = Path::new(param);

View File

@@ -631,7 +631,7 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
msg.try_calc_and_set_dimensions(context).ok();
/* create message */
let needs_encryption = msg.param.get_int(Param::GuaranteeE2ee).unwrap_or_default();
let needs_encryption = msg.param.get_bool(Param::GuaranteeE2ee).unwrap_or_default();
let attach_selfavatar = match chat::shall_attach_selfavatar(context, msg.chat_id) {
Ok(attach_selfavatar) => attach_selfavatar,
@@ -647,7 +647,7 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
err
})?;
if 0 != needs_encryption && !rendered_msg.is_encrypted {
if needs_encryption && !rendered_msg.is_encrypted {
/* unrecoverable */
message::set_msg_failed(
context,
@@ -700,7 +700,7 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
}
}
if rendered_msg.is_encrypted && needs_encryption == 0 {
if rendered_msg.is_encrypted && !needs_encryption {
msg.param.set_int(Param::GuaranteeE2ee, 1);
msg.save_param_to_disk(context);
}

View File

@@ -1,10 +1,6 @@
#![deny(clippy::correctness, missing_debug_implementations, clippy::all)]
// for now we hide warnings to not clutter/hide errors during "cargo clippy"
#![allow(
clippy::type_complexity,
clippy::cognitive_complexity,
clippy::too_many_arguments
)]
#![allow(clippy::cognitive_complexity, clippy::too_many_arguments)]
#![allow(clippy::unreadable_literal, clippy::match_bool)]
#![feature(ptr_wrapping_offset_from)]
#![feature(drain_filter)]
@@ -24,7 +20,7 @@ extern crate strum_macros;
extern crate debug_stub_derive;
#[macro_use]
mod log;
pub mod log;
#[macro_use]
pub mod error;
@@ -67,7 +63,6 @@ pub mod sql;
pub mod stock;
mod token;
#[macro_use]
mod wrapmime;
mod dehtml;
pub mod dc_receive_imf;

View File

@@ -7,7 +7,8 @@ macro_rules! info {
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
emit_event!($ctx, $crate::Event::Info(formatted));
let full = format!("{}:{}: {}", file!(), line!(), &formatted);
emit_event!($ctx, $crate::Event::Info(full));
}};
}
@@ -18,7 +19,8 @@ macro_rules! warn {
};
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
emit_event!($ctx, $crate::Event::Warning(formatted));
let full = format!("{}:{}: {}", file!(), line!(), &formatted);
emit_event!($ctx, $crate::Event::Warning(full));
}};
}

View File

@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use deltachat_derive::{FromSql, ToSql};
use lettre_email::mime::{self, Mime};
use mailparse::{DispositionType, MailHeaderMap};
use mailparse::{DispositionType, MailAddr, MailHeaderMap};
use crate::aheader::Aheader;
use crate::blob::BlobObject;
@@ -14,11 +14,11 @@ use crate::dc_simplify::*;
use crate::dc_tools::*;
use crate::e2ee;
use crate::error::Result;
use crate::events::Event;
use crate::headerdef::HeaderDef;
use crate::job::{job_add, Action};
use crate::location;
use crate::message;
use crate::message::MsgId;
use crate::param::*;
use crate::peerstate::Peerstate;
use crate::securejoin::handle_degrade_event;
@@ -40,7 +40,6 @@ pub struct MimeParser<'a> {
pub user_avatar: AvatarAction,
pub group_avatar: AvatarAction,
reports: Vec<Report>,
mdns_enabled: bool,
parsed_protected_headers: bool,
}
@@ -86,7 +85,6 @@ const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup";
impl<'a> MimeParser<'a> {
pub fn from_bytes(context: &'a Context, body: &[u8]) -> Result<Self> {
let mail = mailparse::parse_mail(body)?;
let mdns_enabled = context.get_config_bool(Config::MdnsEnabled);
let mut parser = MimeParser {
parts: Vec::new(),
@@ -104,7 +102,6 @@ impl<'a> MimeParser<'a> {
message_kml: None,
user_avatar: AvatarAction::None,
group_avatar: AvatarAction::None,
mdns_enabled,
parsed_protected_headers: false,
};
@@ -211,7 +208,6 @@ impl<'a> MimeParser<'a> {
|| filepart.typ == Viewtype::Voice
|| filepart.typ == Viewtype::Video
|| filepart.typ == Viewtype::File)
&& !filepart.is_meta
};
if need_drop {
@@ -228,7 +224,7 @@ impl<'a> MimeParser<'a> {
}
}
if let Some(ref subject) = self.get_subject() {
let mut prepend_subject = 1i32;
let mut prepend_subject = true;
if !self.decrypting_failed {
let colon = subject.find(':');
if colon == Some(2)
@@ -236,10 +232,10 @@ impl<'a> MimeParser<'a> {
|| self.has_chat_version()
|| subject.contains("Chat:")
{
prepend_subject = 0i32
prepend_subject = false
}
}
if 0 != prepend_subject {
if prepend_subject {
let subj = if let Some(n) = subject.find('[') {
&subject[0..n]
} else {
@@ -291,30 +287,27 @@ impl<'a> MimeParser<'a> {
}
}
}
if !self.decrypting_failed {
if let Some(dn_field) = self.get(HeaderDef::ChatDispositionNotificationTo) {
if self.get_last_nonmeta().is_some() {
let addrs = mailparse::addrparse(&dn_field).unwrap();
if let Some(dn_to_addr) = addrs.first() {
if let Some(from_field) = self.get(HeaderDef::From_) {
let from_addrs = mailparse::addrparse(&from_field).unwrap();
if let Some(from_addr) = from_addrs.first() {
if compare_addrs(from_addr, dn_to_addr) {
if let Some(part_4) = self.get_last_nonmeta_mut() {
part_4.param.set_int(Param::WantsMdn, 1);
}
}
}
// See if an MDN is requested from the other side
if !self.decrypting_failed && !self.parts.is_empty() {
if let Some(ref dn_to_addr) =
self.parse_first_addr(HeaderDef::ChatDispositionNotificationTo)
{
if let Some(ref from_addr) = self.parse_first_addr(HeaderDef::From_) {
if compare_addrs(from_addr, dn_to_addr) {
if let Some(part) = self.parts.last_mut() {
part.param.set_int(Param::WantsMdn, 1);
}
}
}
}
}
// Cleanup - and try to create at least an empty part if there are no parts yet
if self.get_last_nonmeta().is_none() && self.reports.is_empty() {
// If there were no parts, especially a non-DC mail user may
// just have send a message in the subject with an empty body.
// Besides, we want to show something in case our incoming-processing
// failed to properly handle an incoming message.
if self.parts.is_empty() && self.reports.is_empty() {
let mut part = Part::default();
part.typ = Viewtype::Text;
@@ -353,14 +346,6 @@ impl<'a> MimeParser<'a> {
AvatarAction::None
}
pub fn get_last_nonmeta(&self) -> Option<&Part> {
self.parts.iter().rev().find(|part| !part.is_meta)
}
pub fn get_last_nonmeta_mut(&mut self) -> Option<&mut Part> {
self.parts.iter_mut().rev().find(|part| !part.is_meta)
}
pub fn was_encrypted(&self) -> bool {
!self.signatures.is_empty()
}
@@ -388,6 +373,20 @@ impl<'a> MimeParser<'a> {
self.header.get(&headerdef.get_headername())
}
fn parse_first_addr(&self, headerdef: HeaderDef) -> Option<MailAddr> {
if let Some(value) = self.get(headerdef.clone()) {
match mailparse::addrparse(&value) {
Ok(ref addrs) => {
return addrs.first().cloned();
}
Err(err) => {
warn!(self.context, "header {} parse error: {:?}", headerdef, err);
}
}
}
None
}
fn parse_mime_recursive(&mut self, mail: &mailparse::ParsedMail<'_>) -> Result<bool> {
if mail.ctype.params.get("protected-headers").is_some() {
if mail.ctype.mimetype == "text/rfc822-headers" {
@@ -577,12 +576,11 @@ impl<'a> MimeParser<'a> {
}
};
let mut simplifier = Simplify::new();
let simplified_txt = if decoded_data.is_empty() {
"".into()
let (simplified_txt, is_forwarded) = if decoded_data.is_empty() {
("".into(), false)
} else {
let is_html = mime_type == mime::TEXT_HTML;
simplifier.simplify(&decoded_data, is_html, self.has_chat_version())
simplify(&decoded_data, is_html, self.has_chat_version())
};
if !simplified_txt.is_empty() {
@@ -594,7 +592,7 @@ impl<'a> MimeParser<'a> {
self.do_add_single_part(part);
}
if simplifier.is_forwarded {
if is_forwarded {
self.is_forwarded = true;
}
}
@@ -726,11 +724,6 @@ impl<'a> MimeParser<'a> {
}
fn process_report(&self, report: &mailparse::ParsedMail<'_>) -> Result<Option<Report>> {
// to get a clear functionality, do not show incoming MDNs if the options is disabled
if !self.mdns_enabled {
return Ok(None);
}
// parse as mailheaders
let report_body = report.subparts[1].get_body_raw()?;
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
@@ -749,33 +742,46 @@ impl<'a> MimeParser<'a> {
}));
}
}
warn!(
self.context,
"ignoring unknown disposition-notification, Message-Id: {:?}",
report_fields.get_first_value("Message-ID").ok()
);
Ok(None)
}
// Handle reports (mainly MDNs)
// Handle reports (only MDNs for now)
pub fn handle_reports(
&self,
from_id: u32,
sent_timestamp: i64,
rr_event_to_send: &mut Vec<(u32, MsgId)>,
server_folder: impl AsRef<str>,
server_uid: u32,
) {
for report in &self.reports {
let mut mdn_consumed = false;
if self.reports.is_empty() {
return;
}
// If a user disabled MDNs we do not show pending incoming ones anymore
// but we do want them to potentially get moved from the INBOX still.
let mdns_enabled = self.context.get_config_bool(Config::MdnsEnabled);
if let Some((chat_id, msg_id)) = message::mdn_from_ext(
self.context,
from_id,
&report.original_message_id,
sent_timestamp,
) {
rr_event_to_send.push((chat_id, msg_id));
mdn_consumed = true;
for report in &self.reports {
let mut mdn_recognized = false;
if mdns_enabled {
if let Some((chat_id, msg_id)) = message::mdn_from_ext(
self.context,
from_id,
&report.original_message_id,
sent_timestamp,
) {
self.context.call_cb(Event::MsgRead { chat_id, msg_id });
mdn_recognized = true;
}
}
if self.has_chat_version() || mdn_consumed {
if self.has_chat_version() || mdn_recognized || !mdns_enabled {
let mut param = Params::new();
param.set(Param::ServerFolder, server_folder.as_ref());
param.set_int(Param::ServerUid, server_uid as i32);
@@ -868,7 +874,6 @@ fn is_known(key: &str) -> bool {
#[derive(Debug, Default, Clone)]
pub struct Part {
pub typ: Viewtype,
pub is_meta: bool,
pub mimetype: Option<Mime>,
pub msg: String,
pub msg_raw: Option<String>,
@@ -1110,6 +1115,26 @@ mod tests {
);
}
#[test]
fn test_parse_first_addr() {
let context = dummy_context();
let raw = b"From: hello@one.org, world@two.org\n\
Chat-Disposition-Notification-To: wrong
Content-Type: text/plain;
Chat-Version: 1.0\n\
\n\
test1\n\
\x00";
let mimeparser = MimeParser::from_bytes(&context.ctx, &raw[..]).unwrap();
let of = mimeparser.parse_first_addr(HeaderDef::From_).unwrap();
assert_eq!(of, mailparse::addrparse("hello@one.org").unwrap()[0]);
let of = mimeparser.parse_first_addr(HeaderDef::ChatDispositionNotificationTo);
assert!(of.is_none());
}
#[test]
fn test_mimeparser_with_context() {
let context = dummy_context();

View File

@@ -16,7 +16,7 @@ use pgp::types::{
};
use rand::{thread_rng, CryptoRng, Rng};
use crate::error::Error;
use crate::error::Result;
use crate::key::*;
use crate::keyring::*;
@@ -88,9 +88,7 @@ impl<'a> PublicKeyTrait for SignedPublicKeyOrSubkey<'a> {
/// Split data from PGP Armored Data as defined in https://tools.ietf.org/html/rfc4880#section-6.2.
///
/// Returns (type, headers, base64 encoded body).
pub fn split_armored_data(
buf: &[u8],
) -> Result<(BlockType, BTreeMap<String, String>, Vec<u8>), Error> {
pub fn split_armored_data(buf: &[u8]) -> Result<(BlockType, BTreeMap<String, String>, Vec<u8>)> {
use std::io::Read;
let cursor = Cursor::new(buf);
@@ -194,7 +192,7 @@ pub fn pk_encrypt(
plain: &[u8],
public_keys_for_encryption: &Keyring,
private_key_for_signing: Option<&Key>,
) -> Result<String, Error> {
) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
.keys()
@@ -236,7 +234,7 @@ pub fn pk_decrypt(
private_keys_for_decryption: &Keyring,
public_keys_for_validation: &Keyring,
ret_signature_fingerprints: Option<&mut HashSet<String>>,
) -> Result<Vec<u8>, Error> {
) -> Result<Vec<u8>> {
let (msg, _) = Message::from_armor_single(Cursor::new(ctext))?;
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
.keys()
@@ -248,7 +246,7 @@ pub fn pk_decrypt(
.collect();
let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?;
let msgs = decryptor.collect::<Result<Vec<_>, _>>()?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
let dec_msg = &msgs[0];
@@ -280,7 +278,7 @@ pub fn pk_decrypt(
}
/// Symmetric encryption.
pub fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Error> {
pub fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
let mut rng = thread_rng();
let lit_msg = Message::new_literal_bytes("", plain);
@@ -297,11 +295,11 @@ pub fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Error> {
pub fn symm_decrypt<T: std::io::Read + std::io::Seek>(
passphrase: &str,
ctext: T,
) -> Result<Vec<u8>, Error> {
) -> Result<Vec<u8>> {
let (enc_msg, _) = Message::from_armor_single(ctext)?;
let decryptor = enc_msg.decrypt_with_password(|| passphrase.into())?;
let msgs = decryptor.collect::<Result<Vec<_>, _>>()?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
match msgs[0].get_content()? {

View File

@@ -544,7 +544,7 @@ fn open(
// --------------------------------------------------------------------
let mut dbversion = dbversion_before_update;
let mut recalc_fingerprints = 0;
let mut recalc_fingerprints = false;
let mut update_icons = false;
if dbversion < 1 {
@@ -687,7 +687,7 @@ fn open(
"CREATE INDEX acpeerstates_index4 ON acpeerstates (gossip_key_fingerprint);",
params![],
)?;
recalc_fingerprints = 1;
recalc_fingerprints = true;
dbversion = 34;
sql.set_raw_config_int(context, "dbversion", 34)?;
}
@@ -872,7 +872,7 @@ fn open(
// (the structure is complete now and all objects are usable)
// --------------------------------------------------------------------
if 0 != recalc_fingerprints {
if recalc_fingerprints {
info!(context, "[migration] recalc fingerprints");
sql.query_map(
"SELECT addr FROM acpeerstates;",

View File

@@ -1,59 +0,0 @@
use mailparse::ParsedMail;
use crate::error::Error;
pub fn parse_message_id(message_id: &[u8]) -> Result<String, Error> {
let value = std::str::from_utf8(message_id)?;
let addrs = mailparse::addrparse(value)
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
if let Some(info) = addrs.extract_single_info() {
return Ok(info.addr);
}
bail!("could not parse message_id: {}", value);
}
/// Returns a reference to the encrypted payload and validates the autocrypt structure.
pub fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail<'b>, Error> {
ensure!(
mail.ctype.mimetype == "multipart/encrypted",
"Not a multipart/encrypted message: {}",
mail.ctype.mimetype
);
ensure!(
mail.subparts.len() == 2,
"Invalid Autocrypt Level 1 Mime Parts"
);
ensure!(
mail.subparts[0].ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 version part: {:?}",
mail.subparts[0].ctype,
);
ensure!(
mail.subparts[1].ctype.mimetype == "application/octet-stream",
"Invalid Autocrypt Level 1 encrypted part: {:?}",
mail.subparts[1].ctype
);
Ok(&mail.subparts[1])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_message_id() {
assert_eq!(
parse_message_id(b"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
assert_eq!(
parse_message_id(b"<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB