Compare commits

...

88 Commits

Author SHA1 Message Date
B. Petersen
31a5811241 bump version to 1.38 2020-06-20 19:16:07 +02:00
B. Petersen
cd1f5bf229 update changelog for 1.38 2020-06-20 19:09:33 +02:00
bjoern
632fc19f41 Merge pull request #1645 from deltachat/correct-seen
give correct "fresh" flag to calc_sort_timestamp()
2020-06-20 19:05:34 +02:00
B. Petersen
7ad95ea165 give correct "fresh" flag to calc_sort_timestamp()
for "fresh" messages, calc_sort_timestamp() makes sure,
the sorting timestamp is not less than the last-non-fresh message.

this commit fixes the "fresh" state we give to calc_sort_timestamp(),
it just uses the message-state we've already calculated.

the old assumption, that unseen messages are always fresh
is wrong as this "seen" flag just comes from an imap-flag
that is not set for self-sent messages.

therefore, in a multi-device-setup, things are totally messed up.
(the bug was probably in there since a long time,
however did not came to light until the async-move)
2020-06-20 18:36:09 +02:00
Floris Bruynooghe
9d7b756ddb Unify some testing interfaces
This tidies up our testing tools a little bit.  We had several
functions which through various changes ended up doing the same and
some more which did very similar stuff, so I merged them to have
things simpler.  Also moved towards methods on the TestContext struct
while cleaning this up anyway, seems like this structure is going to
stay around for a bit anyway.

The intersting change is in `test_utils.rs`, everything else is just
updating callers.  A few tests used example.org which I moved to
example.com to be able to re-use more configuration of the test
context.
2020-06-20 14:37:41 +02:00
bjoern
73412db267 Merge pull request #1644 from deltachat/stop-time-in-repl
print time needed to build chatlist in repl tool
2020-06-20 13:07:50 +02:00
B. Petersen
059a7bcd7f print time needed to build chatlist in repl tool
the chatlist is the most complicated list to get from sql
and is also the most used list,
so it makes sense to keep an eye on the timing of that.
2020-06-20 00:56:43 +02:00
bjoern
3e47564b2f Merge pull request #1643 from deltachat/prep-1.37
prepare 1.37
2020-06-19 21:54:04 +02:00
B. Petersen
d8be0cdf35 bump version to 1.37 2020-06-19 21:32:47 +02:00
B. Petersen
26a44b6d32 update changelog for 1.37 2020-06-19 21:31:34 +02:00
bjoern
12eacaae36 Merge pull request #1641 from deltachat/oauth2-provider-db
get Oauth2-information from provider-db
2020-06-19 21:13:36 +02:00
B. Petersen
2d8148a1a3 make use of new oauth2-authorizer information in the provider-db 2020-06-19 17:06:31 +02:00
B. Petersen
916007ed2d run update.py 2020-06-19 16:38:03 +02:00
B. Petersen
b91b88e11b let update.py add information of oauth2-authorizer 2020-06-19 16:37:43 +02:00
bjoern
b6c0f44608 Merge pull request #1635 from deltachat/fix-chatlist-hidden
fix getting last message for chatlist, avoid empty summaries
2020-06-19 13:36:08 +02:00
Alexander Krotov
2a623541d7 configure/mod.rs: forbid indexing and slicing 2020-06-19 14:24:53 +03:00
Alexander Krotov
0007e93e80 scheduler: forbid indexing and slicing 2020-06-19 14:24:53 +03:00
Alexander Krotov
c655fd8a64 contact: forbid indexing and slicing 2020-06-19 14:24:53 +03:00
Alexander Krotov
ad531876fd contact: simplify name normalization
This removes one indexing operation and reduces surprises when comma
means something other than first name and last name separator.
2020-06-19 14:24:53 +03:00
Alexander Krotov
53bee68acb smtp/mod.rs: forbid indexing and slicing 2020-06-19 00:56:01 +03:00
Alexander Krotov
b5400cf551 Refactor imap/mod.rs to avoid indexing
Also replace assert! with debug_assert!
2020-06-19 00:56:01 +03:00
B. Petersen
491af1b583 fix getting last message for chatlist
the last message shown in a chatlist
is the one with the largets timestamp that is not hidden.

in the past, we calcualted the last timestamp using a subquery
and uses that timestamp to finally get the message.
this may fail when there are two messages with the same max. timestamp.

with this fix, we return the id from the subquery and use that
(the subquery already filters by hidden etc.)

in practise, by time-smearing,
usually delta-chat avoids messages from the same device
having the same timestamp - however, this may not be true for multi-device
and/or read-receipts.

i have not seen this error all the years, however, it happens with
the async move several times - maybe because things are just sent faster
and things become more probabe.
2020-06-18 14:46:04 +02:00
bjoern
5b1d06cb28 Merge pull request #1634 from deltachat/typo-faild
fix typo
2020-06-18 03:02:23 +02:00
B. Petersen
7df5195d77 fix typo 2020-06-18 00:31:40 +02:00
dignifiedquire
baff13ecab fix warnings and bugs, noticed on nightly 2020-06-17 19:27:27 +02:00
bjoern
a7bf05bebb Merge pull request #1629 from deltachat/prep-1.36
prepare 1.36
2020-06-17 16:06:21 +02:00
B. Petersen
aa9b5da1c0 bump version to 1.36 2020-06-17 15:45:38 +02:00
B. Petersen
dfd705f9c6 update changelog for 1.36.0 2020-06-17 15:45:37 +02:00
bjoern
472c0bcea5 Merge pull request #1631 from deltachat/fix-securejoin
s/fingerprint/fingerprint.hex()/
2020-06-17 15:45:11 +02:00
Hocuri
8c2af132c8 Sync heuristically_parse_ndn() and maybe_ndn in prefetch_should_download() 2020-06-17 12:42:40 +02:00
Hocuri
79145576ab s/fingerprint/fingerpring.hex()/ 2020-06-17 11:08:38 +02:00
Hocuri
8ca55b0f60 clippy 2020-06-17 10:58:27 +02:00
Hocuri
74cb4ca1cd Check for mime_parser.has_chat_version() instead of is_dc_message != MessengerMessage::No and avoid passing is_dc_message around, this will save us output &mut argument and simplify the logic. 2020-06-17 10:58:27 +02:00
Hocuri
351e5dc6f3 Add Python test 2020-06-17 10:58:27 +02:00
Hocuri
4eee4a08e7 Mark read receipts as read 2020-06-17 10:58:27 +02:00
Maykel Moya
b5fa0f8924 Add support for G Suite domains
Do a lookup based on domain's MX servers. G Suite domains are expected
to have at least 'aspmx.l.google.com' listed in MXs.

See https://support.google.com/a/answer/140034

fixes #1425
2020-06-17 11:50:46 +03:00
Alexander Krotov
baba91c054 pgp: refactor and document pk_decrypt()
Avoid unnecessary indexing, decompress only once and check if the message
is Signed before trying to verify it.
2020-06-17 11:48:29 +03:00
Hocuri
40c9c2752b Parse ndns from Tiscali 2020-06-17 10:39:05 +02:00
bjoern
f4a1a526f5 Merge pull request #1628 from deltachat/lto
Re-enable lto=true for release builds
2020-06-16 22:58:54 +02:00
Alexander Krotov
7d80179ed1 Re-enable lto=true for release builds 2020-06-16 23:12:07 +03:00
bjoern
71080ed6d5 Merge pull request #1620 from deltachat/update-docs
update docs
2020-06-16 18:41:00 +02:00
bjoern
44037dd711 Update deltachat-ffi/deltachat.h
Co-authored-by: Hocuri <hocuri@gmx.de>
2020-06-15 23:36:22 +02:00
B. Petersen
bc275d8670 update docs 2020-06-15 23:36:22 +02:00
Hocuri
eb29f9c4c1 Parse testrun NDNs 2020-06-15 16:20:23 +02:00
bjoern
6340b278d9 Merge pull request #1619 from deltachat/rotate-images
respect image orientation from exif on recoding
2020-06-15 11:37:31 +02:00
B. Petersen
519e1c1cd0 warn about unused orientation values, add a comment about the orientation values 2020-06-15 02:18:48 +02:00
B. Petersen
d2320394ca convert exif orientation to desired pixel rotation 2020-06-15 01:13:37 +02:00
B. Petersen
9307f2d49f rotate image pixels, prototype a function to get exif data 2020-06-15 01:13:37 +02:00
B. Petersen
7362941245 add kamadak-exif crate 2020-06-15 00:32:13 +02:00
Alexander Krotov
f7c7f414ed refactor: remove .unwrap() from Peerstate.has_verified_key() 2020-06-15 00:47:25 +03:00
Hocuri
23d6012c1f Start parsing ndns (#1552)
Fix  #1478

I changed my original plans a little because I had so many extra ideas and then sorted that I should rather look at actual NDNs and look what is necessary to parse them:

- Recognize NDNs by ~the sender address, which is in a regex the providers database. The problem with heuristics would be that someone could send fake-NDNs and mark messages as failed.~ the standard ("report/delivery-status") and heuristics ("subject contains 'fail' and sender contains 'daemon'"). If there is a valid Message-ID, then rely on that this is an NDN (of course, generally someone might try to find out a Message-ID and send a fake NDN).
- ~Look for `In-Reply-To`~ (only Gmail did this and Gmail uses rfc822 anyway.)
- ~Look for a mimepart `message/delivery-status`, which might contain a `X-Original-Message-ID`~ (only Gmail did this and Gmail uses rfc822, too, anyway.).
- Search through the body and look for a line `Message-ID: *` (remember to remove `<`, `>`), in the hope that that's the original header
- Look for a mime-part containing the string `rfc822`, which will contain the original header. Parse them with Mailparse and look for `Message-ID`.
2020-06-13 17:44:29 +02:00
Hocuri
15b30ceed1 check for sender mailer-daemon as link2xt proposed 2020-06-13 17:29:38 +02:00
Hocuri
45b871f76d Look at From instead of Subject and ContentType in prefetch_should_download. 2020-06-13 14:18:16 +02:00
Hocuri
9f1112833f let prefetch_should_download() check if it might be an ndn 2020-06-13 12:06:30 +02:00
B. Petersen
fc88bff32f make clippy happy 2020-06-13 10:18:18 +02:00
Hocuri
bbf049e95b string 2020-06-13 10:18:18 +02:00
Hocuri
52dfa9b536 Renaming, comment 2020-06-13 10:18:18 +02:00
Hocuri
1fe85dfb3c more functional 2020-06-13 10:18:17 +02:00
Hocuri
27ff1c4a75 check in heuristically_parse_ndn() that rfc724_mid_exists() so that we do not ignore emails because we erreneously thought that it was an ndn 2020-06-13 10:18:17 +02:00
Hocuri
adf4035775 rename reports 2020-06-13 10:18:17 +02:00
Hocuri
990c80cedf lots of small fixes from the reviews 2020-06-13 10:18:17 +02:00
Hocuri
8ebce0c861 warn instead of error 2020-06-13 10:18:16 +02:00
Hocuri
ffb6a84b1f Warn instead of error 2020-06-13 10:18:16 +02:00
Hocuri
c60ec00aac Oops #2, adapt DC_STR_COUNT in deltachat.h 2020-06-13 10:18:16 +02:00
Hocuri
dd3f81a556 Oops, add FAILED_SENDING_TO to deltachat.h 2020-06-13 10:18:16 +02:00
Hocuri
8938cb2573 clippy 2020-06-13 10:18:16 +02:00
Hocuri
995660020b rm unused aol_ndn.eml (aol's ndns are very similar to these of Yahoo) 2020-06-13 10:18:15 +02:00
Hocuri
7997e7dde4 remove println 2020-06-13 10:18:15 +02:00
Hocuri
20ad98d168 typo 2020-06-13 10:18:15 +02:00
Hocuri
c827c9d209 Add yahoo test 2020-06-13 10:18:15 +02:00
Hocuri
bde97b20e9 Repair getting x-failed-recipients header, all tests passing now 2020-06-13 10:18:15 +02:00
Hocuri
777df24c75 Make the gmx test pass 2020-06-13 10:18:14 +02:00
Hocuri
e1711855cc Make the posteo test pass 2020-06-13 10:18:14 +02:00
Hocuri
3899d70b3c I hate SQL 2020-06-13 10:18:14 +02:00
Hocuri
e7aee5b4f4 add gmx and posteo tests 2020-06-13 10:18:14 +02:00
Hocuri
bd2a7a3d40 Correct failed recipient 2020-06-13 10:18:13 +02:00
Hocuri
2e59d5674e fix sql 2020-06-13 10:18:13 +02:00
Hocuri
98b5f768b6 Improve test, fixed compile errors from rebasing 2020-06-13 10:18:13 +02:00
Hocuri
b7d0f29002 Add test-data/message/gmx_ndn.eml 2020-06-13 10:18:13 +02:00
Hocuri
df9cb5e3b8 Fix error in message info 2020-06-13 10:18:12 +02:00
Hocuri
a30486112f Add test 2020-06-13 10:18:12 +02:00
Hocuri
016b96e30e Fix migration 2020-06-13 10:18:12 +02:00
Hocuri
6b763bf417 Return true for MessageState::OutMdnRcvd.can_fail() because it could be a group message and only some recipients failed 2020-06-13 10:18:12 +02:00
Hocuri
6ded0d3bc1 Do not show error messages in chat 2020-06-13 10:18:12 +02:00
Hocuri
f0837cfa73 Repair errors saved for messages 2020-06-13 10:18:11 +02:00
Hocuri
8350729cbb Improve errors 2020-06-13 10:18:11 +02:00
Hocuri
3757e5dca1 Try to add decent error msg (doesnt work yet) 2020-06-13 10:18:11 +02:00
Hocuri
f02c17cae4 Parse standard ndns (e.g. Gmail) 2020-06-13 10:18:11 +02:00
50 changed files with 2412 additions and 517 deletions

View File

@@ -1,5 +1,43 @@
# Changelog
## 1.38.0
- fix sorting, esp. for multi-device
## 1.37.0
- improve ndn heuristics #1630
- get oauth2 authorizer from provider-db #1641
- removed linebreaks and spaces from generated qr-code #1631
- more fixes #1633 #1635 #1636 #1637
## 1.36.0
- parse ndn (network delivery notification) reports
and report failed messages as such #1552 #1622 #1630
- read image orientation from exif before recoding #1619
- improve logging #1593 #1598
- improve python and bot bindings #1583 #1609
- improve imap logout #1595
- fix sorting #1600 #1604
- fix qr code generation #1631
- update rustcrypto releases #1603
- refactorings #1617
## 1.35.0
- enable strict-tls from a new provider-db setting #1587

227
Cargo.lock generated
View File

@@ -11,9 +11,9 @@ dependencies = [
[[package]]
name = "adler32"
version = "1.0.4"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d"
[[package]]
name = "aead"
@@ -187,7 +187,7 @@ checksum = "2a397614997df8e3a8b81ff8d882c0fdc100568d3162fadbd1b1410f95c40277"
dependencies = [
"async-native-tls",
"async-std",
"base64 0.12.1",
"base64 0.12.2",
"byte-pool",
"chrono",
"futures 0.3.5",
@@ -215,17 +215,17 @@ dependencies = [
[[package]]
name = "async-smtp"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81598a96675097ba5df18eec536a0c1d669244aeb4170f2dfa5ef12e1b2ee4b1"
checksum = "a9720181a7d56bf3b4d0cfdcb6353df975125996bdd2958b4e639c8317fcaa68"
dependencies = [
"async-native-tls",
"async-std",
"async-trait",
"base64 0.12.1",
"base64 0.12.2",
"bufstream",
"fast_chemail",
"hostname",
"hostname 0.1.5",
"log",
"nom 5.1.2",
"pin-project",
@@ -261,6 +261,18 @@ dependencies = [
"wasm-bindgen-futures",
]
[[package]]
name = "async-std-resolver"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d113439234775ae3e43d4e7589c5cc64fa3565996ae82dfe26b4ed78c02165be"
dependencies = [
"async-std",
"async-trait",
"futures 0.3.5",
"trust-dns-resolver",
]
[[package]]
name = "async-task"
version = "3.0.0"
@@ -303,13 +315,14 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
version = "0.3.48"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130"
checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
@@ -337,9 +350,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "base64"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42"
checksum = "e223af0dc48c96d4f8342ec01a4974f139df863896b316681efd36742f22cc67"
[[package]]
name = "bit-set"
@@ -633,7 +646,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca761767cf3fa9068cc893ec8c247a22d0fd0535848e65640c0548bd1f8bbb36"
dependencies = [
"aes-gcm",
"base64 0.12.1",
"base64 0.12.2",
"hkdf",
"hmac",
"percent-encoding",
@@ -801,7 +814,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.35.0"
version = "1.38.0"
dependencies = [
"ansi_term 0.12.1",
"anyhow",
@@ -809,9 +822,10 @@ dependencies = [
"async-native-tls",
"async-smtp",
"async-std",
"async-std-resolver",
"async-trait",
"backtrace",
"base64 0.12.1",
"base64 0.12.2",
"bitflags",
"byteorder",
"charset",
@@ -826,6 +840,7 @@ dependencies = [
"image-meta",
"indexmap",
"itertools",
"kamadak-exif",
"lazy_static",
"lettre_email",
"libc",
@@ -871,7 +886,7 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.35.0"
version = "1.38.0"
dependencies = [
"anyhow",
"async-std",
@@ -1092,6 +1107,18 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
[[package]]
name = "enum-as-inner"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc4bfcfacb61d231109d1d55202c1f33263319668b168843e02ad4652725ec9c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@@ -1388,9 +1415,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.13"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
dependencies = [
"libc",
]
@@ -1431,6 +1458,17 @@ dependencies = [
"winutil",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "http-client"
version = "3.0.0"
@@ -1568,15 +1606,6 @@ dependencies = [
"byteorder",
]
[[package]]
name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
dependencies = [
"adler32",
]
[[package]]
name = "iovec"
version = "0.1.4"
@@ -1586,6 +1615,18 @@ dependencies = [
"libc",
]
[[package]]
name = "ipconfig"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7"
dependencies = [
"socket2",
"widestring",
"winapi",
"winreg",
]
[[package]]
name = "itertools"
version = "0.8.2"
@@ -1619,6 +1660,15 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kamadak-exif"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5e66d5b5469321038611f7f0e845a48989e4fd54987b6e5bb4c8ae3adbace7"
dependencies = [
"mutate_once",
]
[[package]]
name = "keccak"
version = "0.1.0"
@@ -1753,6 +1803,12 @@ dependencies = [
"quoted_printable",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matches"
version = "0.1.8"
@@ -1816,6 +1872,12 @@ dependencies = [
"adler32",
]
[[package]]
name = "mutate_once"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b"
[[package]]
name = "native-tls"
version = "0.2.4"
@@ -1962,9 +2024,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.19.0"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2"
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
[[package]]
name = "once_cell"
@@ -2078,7 +2140,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59698ea79df9bf77104aefd39cc3ec990cb9693fb59c3b0a70ddf2646fdffb4b"
dependencies = [
"base64 0.12.1",
"base64 0.12.2",
"once_cell",
"regex",
]
@@ -2096,7 +2158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d3fd4e0b2b7a8195b22e196a947c9ceb0d0f722d060e38e0641f48f56e195b"
dependencies = [
"aes 0.4.0",
"base64 0.12.1",
"base64 0.12.2",
"bitfield",
"block-modes",
"block-padding 0.2.0",
@@ -2139,18 +2201,18 @@ dependencies = [
[[package]]
name = "pin-project"
version = "0.4.20"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e75373ff9037d112bb19bc61333a06a159eaeb217660dcfbea7d88e1db823919"
checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "0.4.20"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10b4b44893d3c370407a1d6a5cfde7c41ae0478e31c516c85f67eb3adc51be6d"
checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
dependencies = [
"proc-macro2",
"quote",
@@ -2189,14 +2251,14 @@ checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
name = "png"
version = "0.16.4"
version = "0.16.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12faa637ed9ae3d3c881332e54b5ae2dba81cda9fc4bbce0faa1ba53abcead50"
checksum = "34ccdd66f6fe4b2433b07e4728e9a013e43233120427046e93ceb709c3a439bf"
dependencies = [
"bitflags",
"crc32fast",
"deflate",
"inflate",
"miniz_oxide",
]
[[package]]
@@ -2245,9 +2307,9 @@ checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
[[package]]
name = "proc-macro-nested"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0afe1bd463b9e9ed51d0e0f0b50b6b146aec855c56fd182bb242388710a9b6de"
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
[[package]]
name = "proc-macro2"
@@ -2463,9 +2525,9 @@ checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "remove_dir_all"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
@@ -2491,6 +2553,16 @@ dependencies = [
"syn",
]
[[package]]
name = "resolv-conf"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11834e137f3b14e309437a8276714eed3a80d1ef894869e510f2c0c0b98b9f4a"
dependencies = [
"hostname 0.3.1",
"quick-error",
]
[[package]]
name = "ripemd160"
version = "0.9.0"
@@ -2705,18 +2777,18 @@ checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0"
[[package]]
name = "serde"
version = "1.0.111"
version = "1.0.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.111"
version = "1.0.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57"
dependencies = [
"proc-macro2",
"quote",
@@ -2842,9 +2914,9 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
[[package]]
name = "smol"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "845f5e7db6b614a8f4f59e565c3035f0fab2f71c9537ff0119eddb60d866cae3"
checksum = "afcf8beb4aa23cc616e3351e49585153b462637c8fec929163b54d88e522b3b0"
dependencies = [
"async-task",
"crossbeam-deque",
@@ -3082,18 +3154,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344"
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479"
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [
"proc-macro2",
"quote",
@@ -3177,6 +3249,44 @@ dependencies = [
"serde",
]
[[package]]
name = "trust-dns-proto"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdd7061ba6f4d4d9721afedffbfd403f20f39a4301fee1b70d6fcd09cca69f28"
dependencies = [
"async-trait",
"backtrace",
"enum-as-inner",
"futures 0.3.5",
"idna",
"lazy_static",
"log",
"rand 0.7.3",
"smallvec",
"thiserror",
"url",
]
[[package]]
name = "trust-dns-resolver"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f23cdfdc3d8300b3c50c9e84302d3bd6d860fb9529af84ace6cf9665f181b77"
dependencies = [
"backtrace",
"cfg-if",
"futures 0.3.5",
"ipconfig",
"lazy_static",
"log",
"lru-cache",
"resolv-conf",
"smallvec",
"thiserror",
"trust-dns-proto",
]
[[package]]
name = "try_from"
version = "0.3.2"
@@ -3429,6 +3539,12 @@ dependencies = [
"cc",
]
[[package]]
name = "widestring"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c"
[[package]]
name = "winapi"
version = "0.3.8"
@@ -3460,6 +3576,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winreg"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
dependencies = [
"winapi",
]
[[package]]
name = "winutil"
version = "0.1.1"

View File

@@ -1,12 +1,12 @@
[package]
name = "deltachat"
version = "1.35.0"
version = "1.38.0"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL-2.0"
[profile.release]
# lto = true
lto = true
[dependencies]
deltachat_derive = { path = "./deltachat_derive" }
@@ -33,6 +33,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = "0.4.6"
indexmap = "1.3.0"
kamadak-exif = "0.5"
lazy_static = "1.4.0"
regex = "1.1.6"
rusqlite = { version = "0.23", features = ["bundled"] }
@@ -58,6 +59,7 @@ thiserror = "1.0.14"
anyhow = "1.0.28"
async-trait = "0.1.31"
url = "2.1.1"
async-std-resolver = "0.19.5"
pretty_env_logger = { version = "0.4.0", optional = true }
log = {version = "0.4.8", optional = true }

View File

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

View File

@@ -307,9 +307,9 @@ char* dc_get_blobdir (const dc_context_t* context);
* DC_MEDIA_QUALITY_WORSE (1)
* allow worse images/videos/voice quality to gain smaller sizes,
* suitable for providers or areas known to have a bad connection.
* In contrast to other options, the implementation of this option is currently up to the UIs;
* this may change in future, however,
* having the option in the core allows provider-specific-defaults already today.
* The library uses the `media_quality` setting to use different defaults
* for recoding images sent with type DC_MSG_IMAGE.
* If needed, recoding other file types is up to the UI.
*
* If you want to retrieve a value, use dc_get_config().
*
@@ -528,9 +528,20 @@ int dc_is_io_running(const dc_context_t* context);
void dc_stop_io(dc_context_t* context);
/**
* This function can be called whenever there is a hint
* that the network is available again.
* The library will try to send pending messages out.
* This function should be called when there is a hint
* that the network is available again,
* eg. as a response to system event reporting network availability.
* The library will try to send pending messages out immediately.
*
* Moreover, to have a reliable state
* when the app comes to foreground with network available,
* it may be reasonable to call the function also at that moment.
*
* It is okay to call the function unconditionally when there is
* network available, however, calling the function
* _without_ having network may interfere with the backoff algorithm
* and will led to let the jobs fail faster, with fewer retries
* and may avoid messages being sent out.
*
* @memberof dc_context_t
* @param context The context as created by dc_context_new().
@@ -754,6 +765,15 @@ uint32_t dc_prepare_msg (dc_context_t* context, uint32_t ch
* dc_msg_unref(msg);
* ~~~
*
* If you send images with the DC_MSG_IMAGE type,
* they will be recoded to a reasonable size before sending, if possible
* (cmp the dc_set_config()-option `media_quality`).
* If that fails, is not possible, or the image is already small enough, the image is sent as original.
* If you want images to be always sent as the original file, use the DC_MSG_FILE type.
*
* Videos and other file types are currently not recoded by the library,
* with dc_prepare_msg(), however, you can do that from the UI.
*
* @memberof dc_context_t
* @param context The context object as returned from dc_context_new().
* @param chat_id Chat ID to send the message to.
@@ -2782,6 +2802,9 @@ int dc_msg_get_viewtype (const dc_msg_t* msg);
* If a sent message changes to this state, you'll receive the event #DC_EVENT_MSG_DELIVERED.
* - DC_STATE_OUT_MDN_RCVD (28) - Outgoing message read by the recipient (two checkmarks; this requires goodwill on the receiver's side)
* If a sent message changes to this state, you'll receive the event #DC_EVENT_MSG_READ.
* Also messages already read by some recipients
* may get into the state DC_STATE_OUT_FAILED at a later point,
* eg. when in a group, delivery fails for some recipients.
*
* If you just want to check if a message is sent or not, please use dc_msg_is_sent() which regards all states accordingly.
*
@@ -4117,8 +4140,9 @@ void dc_event_unref(dc_event_t* event);
/**
* A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to
* DC_STATE_OUT_FAILED, see dc_msg_get_state().
* A single message could not be sent.
* State changed from DC_STATE_OUT_PENDING, DC_STATE_OUT_DELIVERED or DC_STATE_OUT_MDN_RCVD
* to DC_STATE_OUT_FAILED, see dc_msg_get_state().
*
* @param data1 (int) chat_id
* @param data2 (int) msg_id
@@ -4428,7 +4452,9 @@ void dc_event_unref(dc_event_t* event);
#define DC_STR_WELCOME_MESSAGE 71
#define DC_STR_UNKNOWN_SENDER_FOR_CHAT 72
#define DC_STR_SUBJECT_FOR_NEW_CONTACT 73
#define DC_STR_COUNT 73
#define DC_STR_FAILED_SENDING_TO 74
#define DC_STR_COUNT 74
/*
* @}

View File

@@ -285,7 +285,7 @@ pub unsafe extern "C" fn dc_start_io(context: *mut dc_context_t) {
}
let ctx = &*context;
block_on({ ctx.start_io() })
block_on(ctx.start_io())
}
#[no_mangle]
@@ -295,7 +295,7 @@ pub unsafe extern "C" fn dc_is_io_running(context: *mut dc_context_t) -> libc::c
}
let ctx = &*context;
block_on({ ctx.is_io_running() }) as libc::c_int
block_on(ctx.is_io_running()) as libc::c_int
}
#[no_mangle]
@@ -1829,7 +1829,11 @@ pub unsafe extern "C" fn dc_send_locations_to_chat(
}
let ctx = &*context;
block_on({ location::send_locations_to_chat(&ctx, ChatId::new(chat_id), seconds as i64) });
block_on(location::send_locations_to_chat(
&ctx,
ChatId::new(chat_id),
seconds as i64,
));
}
#[no_mangle]

View File

@@ -488,6 +488,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
}
"listchats" | "listarchived" | "chats" => {
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
let time_start = std::time::SystemTime::now();
let chatlist = Chatlist::try_load(
&context,
listflags,
@@ -495,6 +496,9 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
None,
)
.await?;
let time_needed = std::time::SystemTime::now()
.duration_since(time_start)
.unwrap_or_default();
let cnt = chatlist.len();
if cnt > 0 {
@@ -553,6 +557,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
println!("Location streaming enabled.");
}
println!("{} chats", cnt);
println!("{:?} to create this list", time_needed);
}
"chat" => {
if sel_chat.is_none() && arg1.is_empty() {

View File

@@ -187,7 +187,9 @@ class DirectImap:
""" (blocking) wait for next idle message from server. """
assert self._idling
self.account.log("imap-direct: calling idle_check")
res = self.conn.idle_check()
res = self.conn.idle_check(timeout=30)
if len(res) == 0:
raise TimeoutError
if terminate:
self.idle_done()
return res

View File

@@ -850,6 +850,7 @@ class TestOnlineAccount:
lp.sec("mark messages as seen on ac2, wait for changes on ac1")
ac2.direct_imap.idle_start()
ac1.direct_imap.idle_start()
ac2.mark_seen_messages([msg2, msg4])
ac2.direct_imap.idle_check(terminate=True)
lp.step("1")
@@ -858,6 +859,8 @@ class TestOnlineAccount:
assert ev.data1 > const.DC_CHAT_ID_LAST_SPECIAL
assert ev.data2 > const.DC_MSG_ID_LAST_SPECIAL
lp.step("2")
ac1.direct_imap.idle_wait_for_seen() # Check that ac1 marks the read receipt as read
assert msg1.is_out_mdn_received()
assert msg3.is_out_mdn_received()

View File

@@ -14,6 +14,7 @@ use thiserror::Error;
use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
use crate::error::Error;
use crate::events::Event;
use crate::message;
@@ -408,7 +409,13 @@ impl<'a> BlobObject<'a> {
return Ok(());
}
let img = img.thumbnail(img_wh, img_wh);
let mut img = img.thumbnail(img_wh, img_wh);
match self.get_exif_orientation(context) {
Ok(90) => img = img.rotate90(),
Ok(180) => img = img.rotate180(),
Ok(270) => img = img.rotate270(),
_ => {}
}
img.save(&blob_abs).map_err(|err| BlobError::WriteFailure {
blobdir: context.get_blobdir().to_path_buf(),
@@ -418,6 +425,24 @@ impl<'a> BlobObject<'a> {
Ok(())
}
pub fn get_exif_orientation(&self, context: &Context) -> Result<i32, Error> {
let file = std::fs::File::open(self.to_abs_path())?;
let mut bufreader = std::io::BufReader::new(&file);
let exifreader = exif::Reader::new();
let exif = exifreader.read_from_container(&mut bufreader)?;
if let Some(orientation) = exif.get_field(exif::Tag::Orientation, exif::In::PRIMARY) {
// possible orientation values are described at http://sylvana.net/jpegcrop/exif_orientation.html
// we only use rotation, in practise, flipping is not used.
match orientation.value.get_uint(0) {
Some(3) => return Ok(180),
Some(6) => return Ok(90),
Some(8) => return Ok(270),
other => warn!(context, "exif orientation value ignored: {:?}", other),
}
}
Ok(0)
}
}
impl<'a> fmt::Display for BlobObject<'a> {
@@ -472,7 +497,7 @@ mod tests {
#[async_std::test]
async fn test_create() {
let t = dummy_context().await;
let t = TestContext::new().await;
let blob = BlobObject::create(&t.ctx, "foo", b"hello").await.unwrap();
let fname = t.ctx.get_blobdir().join("foo");
let data = fs::read(fname).await.unwrap();
@@ -483,7 +508,7 @@ mod tests {
#[async_std::test]
async fn test_lowercase_ext() {
let t = dummy_context().await;
let t = TestContext::new().await;
let blob = BlobObject::create(&t.ctx, "foo.TXT", b"hello")
.await
.unwrap();
@@ -492,7 +517,7 @@ mod tests {
#[async_std::test]
async fn test_as_file_name() {
let t = dummy_context().await;
let t = TestContext::new().await;
let blob = BlobObject::create(&t.ctx, "foo.txt", b"hello")
.await
.unwrap();
@@ -501,7 +526,7 @@ mod tests {
#[async_std::test]
async fn test_as_rel_path() {
let t = dummy_context().await;
let t = TestContext::new().await;
let blob = BlobObject::create(&t.ctx, "foo.txt", b"hello")
.await
.unwrap();
@@ -510,7 +535,7 @@ mod tests {
#[async_std::test]
async fn test_suffix() {
let t = dummy_context().await;
let t = TestContext::new().await;
let blob = BlobObject::create(&t.ctx, "foo.txt", b"hello")
.await
.unwrap();
@@ -521,7 +546,7 @@ mod tests {
#[async_std::test]
async fn test_create_dup() {
let t = dummy_context().await;
let t = TestContext::new().await;
BlobObject::create(&t.ctx, "foo.txt", b"hello")
.await
.unwrap();
@@ -545,7 +570,7 @@ mod tests {
#[async_std::test]
async fn test_double_ext_preserved() {
let t = dummy_context().await;
let t = TestContext::new().await;
BlobObject::create(&t.ctx, "foo.tar.gz", b"hello")
.await
.unwrap();
@@ -570,7 +595,7 @@ mod tests {
#[async_std::test]
async fn test_create_long_names() {
let t = dummy_context().await;
let t = TestContext::new().await;
let s = "1".repeat(150);
let blob = BlobObject::create(&t.ctx, &s, b"data").await.unwrap();
let blobname = blob.as_name().split('/').last().unwrap();
@@ -579,7 +604,7 @@ mod tests {
#[async_std::test]
async fn test_create_and_copy() {
let t = dummy_context().await;
let t = TestContext::new().await;
let src = t.dir.path().join("src");
fs::write(&src, b"boo").await.unwrap();
let blob = BlobObject::create_and_copy(&t.ctx, &src).await.unwrap();
@@ -595,7 +620,7 @@ mod tests {
#[async_std::test]
async fn test_create_from_path() {
let t = dummy_context().await;
let t = TestContext::new().await;
let src_ext = t.dir.path().join("external");
fs::write(&src_ext, b"boo").await.unwrap();
@@ -613,7 +638,7 @@ mod tests {
}
#[async_std::test]
async fn test_create_from_name_long() {
let t = dummy_context().await;
let t = TestContext::new().await;
let src_ext = t.dir.path().join("autocrypt-setup-message-4137848473.html");
fs::write(&src_ext, b"boo").await.unwrap();
let blob = BlobObject::new_from_path(&t.ctx, &src_ext).await.unwrap();

View File

@@ -424,7 +424,7 @@ impl ChatId {
async fn get_parent_mime_headers(self, context: &Context) -> Option<(String, String, String)> {
let collect =
|row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?));
let (packed, rfc724_mid, mime_in_reply_to, mime_references): (
let (rfc724_mid, mime_in_reply_to, mime_references, error): (
String,
String,
String,
@@ -432,15 +432,14 @@ impl ChatId {
) = self
.parent_query(
context,
"param, rfc724_mid, mime_in_reply_to, mime_references",
"rfc724_mid, mime_in_reply_to, mime_references, error",
collect,
)
.await
.ok()
.flatten()?;
let param = packed.parse::<Params>().ok()?;
if param.exists(Param::Error) {
if !error.is_empty() {
// Do not reply to error messages.
//
// An error message could be a group chat message that we failed to decrypt and
@@ -454,12 +453,13 @@ impl ChatId {
}
async fn parent_is_encrypted(self, context: &Context) -> Result<bool, Error> {
let collect = |row: &rusqlite::Row| Ok(row.get(0)?);
let packed: Option<String> = self.parent_query(context, "param", collect).await?;
let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?));
let res: Option<(String, String)> =
self.parent_query(context, "param, error", collect).await?;
if let Some(ref packed) = packed {
if let Some((ref packed, ref error)) = res {
let param = packed.parse::<Params>()?;
Ok(!param.exists(Param::Error) && param.exists(Param::GuaranteeE2ee))
Ok(error.is_empty() && param.exists(Param::GuaranteeE2ee))
} else {
// No messages
Ok(false)
@@ -1464,7 +1464,7 @@ pub async fn send_msg(
}
}
msg.param.remove(Param::PrepForwards);
msg.save_param_to_disk(context).await;
msg.update_param(context).await;
}
return send_msg_inner(context, chat_id, msg).await;
}
@@ -2596,7 +2596,7 @@ pub async fn forward_msgs(
.set(Param::PrepForwards, new_msg_id.to_u32().to_string());
}
msg.save_param_to_disk(context).await;
msg.update_param(context).await;
msg.param = save_param;
} else {
msg.state = MessageState::OutPending;
@@ -2784,7 +2784,7 @@ pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Resul
pub(crate) async fn add_info_msg(context: &Context, chat_id: ChatId, text: impl AsRef<str>) {
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
if context.sql.execute(
if let Err(e) = context.sql.execute(
"INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);",
paramsv![
chat_id,
@@ -2796,7 +2796,8 @@ pub(crate) async fn add_info_msg(context: &Context, chat_id: ChatId, text: impl
text.as_ref().to_string(),
rfc724_mid,
]
).await.is_err() {
).await {
warn!(context, "Could not add info msg: {}", e);
return;
}
@@ -2820,7 +2821,7 @@ mod tests {
#[async_std::test]
async fn test_chat_info() {
let t = dummy_context().await;
let t = TestContext::new().await;
let bob = Contact::create(&t.ctx, "bob", "bob@example.com")
.await
.unwrap();
@@ -2854,7 +2855,7 @@ mod tests {
#[async_std::test]
async fn test_get_draft_no_draft() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF)
.await
.unwrap();
@@ -2864,7 +2865,7 @@ mod tests {
#[async_std::test]
async fn test_get_draft_special_chat_id() {
let t = dummy_context().await;
let t = TestContext::new().await;
let draft = ChatId::new(DC_CHAT_ID_LAST_SPECIAL)
.get_draft(&t.ctx)
.await
@@ -2876,14 +2877,14 @@ mod tests {
async fn test_get_draft_no_chat() {
// This is a weird case, maybe this should be an error but we
// do not get this info from the database currently.
let t = dummy_context().await;
let t = TestContext::new().await;
let draft = ChatId::new(42).get_draft(&t.ctx).await.unwrap();
assert!(draft.is_none());
}
#[async_std::test]
async fn test_get_draft() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF)
.await
.unwrap();
@@ -2899,7 +2900,7 @@ mod tests {
#[async_std::test]
async fn test_add_contact_to_chat_ex_add_self() {
// Adding self to a contact should succeed, even though it's pointless.
let t = test_context().await;
let t = TestContext::new().await;
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo")
.await
.unwrap();
@@ -2911,7 +2912,7 @@ mod tests {
#[async_std::test]
async fn test_self_talk() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF)
.await
.unwrap();
@@ -2932,7 +2933,7 @@ mod tests {
#[async_std::test]
async fn test_deaddrop_chat() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat = Chat::load_from_db(&t.ctx, ChatId::new(DC_CHAT_ID_DEADDROP))
.await
.unwrap();
@@ -2947,7 +2948,7 @@ mod tests {
#[async_std::test]
async fn test_add_device_msg_unlabelled() {
let t = test_context().await;
let t = TestContext::new().await;
// add two device-messages
let mut msg1 = Message::new(Viewtype::Text);
@@ -2982,7 +2983,7 @@ mod tests {
#[async_std::test]
async fn test_add_device_msg_labelled() {
let t = test_context().await;
let t = TestContext::new().await;
// add two device-messages with the same label (second attempt is not added)
let mut msg1 = Message::new(Viewtype::Text);
@@ -3036,7 +3037,7 @@ mod tests {
#[async_std::test]
async fn test_add_device_msg_label_only() {
let t = test_context().await;
let t = TestContext::new().await;
let res = add_device_msg(&t.ctx, Some(""), None).await;
assert!(res.is_err());
let res = add_device_msg(&t.ctx, Some("some-label"), None).await;
@@ -3056,7 +3057,7 @@ mod tests {
#[async_std::test]
async fn test_was_device_msg_ever_added() {
let t = test_context().await;
let t = TestContext::new().await;
add_device_msg(&t.ctx, Some("some-label"), None).await.ok();
assert!(was_device_msg_ever_added(&t.ctx, "some-label")
.await
@@ -3080,7 +3081,7 @@ mod tests {
#[async_std::test]
async fn test_delete_device_chat() {
let t = test_context().await;
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some("message text".to_string());
@@ -3100,7 +3101,7 @@ mod tests {
#[async_std::test]
async fn test_device_chat_cannot_sent() {
let t = test_context().await;
let t = TestContext::new().await;
t.ctx.update_device_chats().await.unwrap();
let (device_chat_id, _) =
create_or_lookup_by_contact_id(&t.ctx, DC_CONTACT_ID_DEVICE, Blocked::Not)
@@ -3120,7 +3121,7 @@ mod tests {
#[async_std::test]
async fn test_delete_and_reset_all_device_msgs() {
let t = test_context().await;
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some("message text".to_string());
let msg_id1 = add_device_msg(&t.ctx, Some("some-label"), Some(&mut msg))
@@ -3157,7 +3158,7 @@ mod tests {
#[async_std::test]
async fn test_archive() {
// create two chats
let t = dummy_context().await;
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some("foo".to_string());
let msg_id = add_device_msg(&t.ctx, None, Some(&mut msg)).await.unwrap();
@@ -3271,7 +3272,7 @@ mod tests {
#[async_std::test]
async fn test_pinned() {
let t = dummy_context().await;
let t = TestContext::new().await;
// create 3 chats, wait 1 second in between to get a reliable order (we order by time)
let mut msg = Message::new(Viewtype::Text);
@@ -3330,7 +3331,7 @@ mod tests {
#[async_std::test]
async fn test_set_chat_name() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo")
.await
.unwrap();
@@ -3354,7 +3355,7 @@ mod tests {
#[async_std::test]
async fn test_create_same_chat_twice() {
let context = dummy_context().await;
let context = TestContext::new().await;
let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de")
.await
.unwrap();
@@ -3373,7 +3374,7 @@ mod tests {
#[async_std::test]
async fn test_shall_attach_selfavatar() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo")
.await
.unwrap();
@@ -3397,7 +3398,7 @@ mod tests {
#[async_std::test]
async fn test_set_mute_duration() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo")
.await
.unwrap();
@@ -3465,7 +3466,7 @@ mod tests {
#[async_std::test]
async fn test_parent_is_encrypted() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo")
.await
.unwrap();

View File

@@ -147,11 +147,12 @@ impl Chatlist {
FROM chats c
LEFT JOIN msgs m
ON c.id=m.chat_id
AND m.timestamp=(
SELECT MAX(timestamp)
AND m.id=(
SELECT id
FROM msgs
WHERE chat_id=c.id
AND (hidden=0 OR state=?1))
AND (hidden=0 OR state=?1)
ORDER BY timestamp DESC, id DESC LIMIT 1)
WHERE c.id>9
AND c.blocked=0
AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?2)
@@ -173,11 +174,12 @@ impl Chatlist {
FROM chats c
LEFT JOIN msgs m
ON c.id=m.chat_id
AND m.timestamp=(
SELECT MAX(timestamp)
AND m.id=(
SELECT id
FROM msgs
WHERE chat_id=c.id
AND (hidden=0 OR state=?))
AND (hidden=0 OR state=?)
ORDER BY timestamp DESC, id DESC LIMIT 1)
WHERE c.id>9
AND c.blocked=0
AND c.archived=1
@@ -206,11 +208,12 @@ impl Chatlist {
FROM chats c
LEFT JOIN msgs m
ON c.id=m.chat_id
AND m.timestamp=(
SELECT MAX(timestamp)
AND m.id=(
SELECT id
FROM msgs
WHERE chat_id=c.id
AND (hidden=0 OR state=?1))
AND (hidden=0 OR state=?1)
ORDER BY timestamp DESC, id DESC LIMIT 1)
WHERE c.id>9 AND c.id!=?2
AND c.blocked=0
AND c.name LIKE ?3
@@ -236,11 +239,12 @@ impl Chatlist {
FROM chats c
LEFT JOIN msgs m
ON c.id=m.chat_id
AND m.timestamp=(
SELECT MAX(timestamp)
AND m.id=(
SELECT id
FROM msgs
WHERE chat_id=c.id
AND (hidden=0 OR state=?1))
AND (hidden=0 OR state=?1)
ORDER BY timestamp DESC, id DESC LIMIT 1)
WHERE c.id>9 AND c.id!=?2
AND c.blocked=0
AND NOT c.archived=?3
@@ -424,7 +428,7 @@ mod tests {
#[async_std::test]
async fn test_try_load() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id1 = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "a chat")
.await
.unwrap();
@@ -472,7 +476,7 @@ mod tests {
#[async_std::test]
async fn test_sort_self_talk_up_on_forward() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx.update_device_chats().await.unwrap();
create_group_chat(&t.ctx, VerifiedStatus::Unverified, "a chat")
.await
@@ -497,7 +501,7 @@ mod tests {
#[async_std::test]
async fn test_search_special_chat_names() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx.update_device_chats().await.unwrap();
let chats = Chatlist::try_load(&t.ctx, 0, Some("t-1234-s"), None)
@@ -530,7 +534,7 @@ mod tests {
#[async_std::test]
async fn test_get_summary_unwrap() {
let t = dummy_context().await;
let t = TestContext::new().await;
let chat_id1 = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "a chat")
.await
.unwrap();

View File

@@ -286,7 +286,7 @@ mod tests {
#[async_std::test]
async fn test_selfavatar_outside_blobdir() {
let t = dummy_context().await;
let t = TestContext::new().await;
let avatar_src = t.dir.path().join("avatar.jpg");
let avatar_bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg");
File::create(&avatar_src)
@@ -315,7 +315,7 @@ mod tests {
#[async_std::test]
async fn test_selfavatar_in_blobdir() {
let t = dummy_context().await;
let t = TestContext::new().await;
let avatar_src = t.ctx.get_blobdir().join("avatar.png");
let avatar_bytes = include_bytes!("../test-data/image/avatar900x900.png");
File::create(&avatar_src)
@@ -341,7 +341,7 @@ mod tests {
#[async_std::test]
async fn test_selfavatar_copy_without_recode() {
let t = dummy_context().await;
let t = TestContext::new().await;
let avatar_src = t.dir.path().join("avatar.png");
let avatar_bytes = include_bytes!("../test-data/image/avatar64x64.png");
File::create(&avatar_src)
@@ -365,7 +365,7 @@ mod tests {
#[async_std::test]
async fn test_media_quality_config_option() {
let t = dummy_context().await;
let t = TestContext::new().await;
let media_quality = t.ctx.get_config_int(Config::MediaQuality).await;
assert_eq!(media_quality, 0);
let media_quality = constants::MediaQuality::from_i32(media_quality).unwrap_or_default();

View File

@@ -1,5 +1,7 @@
//! Email accounts autoconfiguration process module
#![forbid(clippy::indexing_slicing)]
mod auto_mozilla;
mod auto_outlook;
mod read_url;
@@ -621,7 +623,7 @@ mod tests {
#[async_std::test]
async fn test_no_panic_on_bad_credentials() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_config(Config::Addr, Some("probably@unexistant.addr"))
.await
@@ -635,7 +637,7 @@ mod tests {
#[async_std::test]
async fn test_get_offline_autoconfig() {
let context = dummy_context().await.ctx;
let context = TestContext::new().await.ctx;
let mut params = LoginParam::new();
params.addr = "someone123@example.org".to_string();

View File

@@ -1,5 +1,7 @@
//! Contacts module
#![forbid(clippy::indexing_slicing)]
use async_std::path::PathBuf;
use deltachat_derive::*;
use itertools::Itertools;
@@ -1029,10 +1031,10 @@ pub fn addr_normalize(addr: &str) -> &str {
let norm = addr.trim();
if norm.starts_with("mailto:") {
return &norm[7..];
norm.get(7..).unwrap_or(norm)
} else {
norm
}
norm
}
fn sanitize_name_and_addr(name: impl AsRef<str>, addr: impl AsRef<str>) -> (String, String) {
@@ -1042,11 +1044,15 @@ fn sanitize_name_and_addr(name: impl AsRef<str>, addr: impl AsRef<str>) -> (Stri
if let Some(captures) = ADDR_WITH_NAME_REGEX.captures(addr.as_ref()) {
(
if name.as_ref().is_empty() {
normalize_name(&captures[1])
captures
.get(1)
.map_or("".to_string(), |m| normalize_name(m.as_str()))
} else {
name.as_ref().to_string()
},
captures[2].to_string(),
captures
.get(2)
.map_or("".to_string(), |m| m.as_str().to_string()),
)
} else {
(name.as_ref().to_string(), addr.as_ref().to_string())
@@ -1113,38 +1119,21 @@ pub(crate) async fn set_profile_image(
/// Normalize a name.
///
/// - Remove quotes (come from some bad MUA implementations)
/// - Convert names as "Petersen, Björn" to "Björn Petersen"
/// - Trims the resulting string
///
/// Typically, this function is not needed as it is called implicitly by `Contact::add_address_book`.
pub fn normalize_name(full_name: impl AsRef<str>) -> String {
let mut full_name = full_name.as_ref().trim();
let full_name = full_name.as_ref().trim();
if full_name.is_empty() {
return full_name.into();
}
let len = full_name.len();
if len > 1 {
let firstchar = full_name.as_bytes()[0];
let lastchar = full_name.as_bytes()[len - 1];
if firstchar == b'\'' && lastchar == b'\''
|| firstchar == b'\"' && lastchar == b'\"'
|| firstchar == b'<' && lastchar == b'>'
{
full_name = &full_name[1..len - 1];
}
match full_name.as_bytes() {
[b'\'', .., b'\''] | [b'\"', .., b'\"'] | [b'<', .., b'>'] => full_name
.get(1..full_name.len() - 1)
.map_or("".to_string(), |s| s.trim().into()),
_ => full_name.to_string(),
}
if let Some(p1) = full_name.find(',') {
let (last_name, first_name) = full_name.split_at(p1);
let last_name = last_name.trim();
let first_name = (&first_name[1..]).trim();
return format!("{} {}", first_name, last_name);
}
full_name.trim().into()
}
fn cat_fingerprint(
@@ -1235,7 +1224,6 @@ mod tests {
#[test]
fn test_normalize_name() {
assert_eq!(&normalize_name("Doe, John"), "John Doe");
assert_eq!(&normalize_name(" hello world "), "hello world");
assert_eq!(&normalize_name("<"), "<");
assert_eq!(&normalize_name(">"), ">");
@@ -1270,7 +1258,7 @@ mod tests {
#[async_std::test]
async fn test_get_contacts() {
let context = dummy_context().await;
let context = TestContext::new().await;
let contacts = Contact::get_all(&context.ctx, 0, Some("some2"))
.await
.unwrap();
@@ -1294,10 +1282,10 @@ mod tests {
#[async_std::test]
async fn test_is_self_addr() -> Result<()> {
let t = test_context().await;
let t = TestContext::new().await;
assert!(t.ctx.is_self_addr("me@me.org").await.is_err());
let addr = configure_alice_keypair(&t.ctx).await;
let addr = t.configure_alice().await;
assert_eq!(t.ctx.is_self_addr("me@me.org").await?, false);
assert_eq!(t.ctx.is_self_addr(&addr).await?, true);
@@ -1307,7 +1295,7 @@ mod tests {
#[async_std::test]
async fn test_add_or_lookup() {
// add some contacts, this also tests add_address_book()
let t = dummy_context().await;
let t = TestContext::new().await;
let book = concat!(
" Name one \n one@eins.org \n",
"Name two\ntwo@deux.net\n",
@@ -1400,10 +1388,10 @@ mod tests {
assert!(contact_id > DC_CONTACT_ID_LAST_SPECIAL);
assert_eq!(sth_modified, Modifier::None);
let contact = Contact::load_from_db(&t.ctx, contact_id).await.unwrap();
assert_eq!(contact.get_name(), "Alice Wonderland");
assert_eq!(contact.get_display_name(), "Alice Wonderland");
assert_eq!(contact.get_name(), "Wonderland, Alice");
assert_eq!(contact.get_display_name(), "Wonderland, Alice");
assert_eq!(contact.get_addr(), "alice@w.de");
assert_eq!(contact.get_name_n_addr(), "Alice Wonderland (alice@w.de)");
assert_eq!(contact.get_name_n_addr(), "Wonderland, Alice (alice@w.de)");
// check SELF
let contact = Contact::load_from_db(&t.ctx, DC_CONTACT_ID_SELF)
@@ -1420,7 +1408,7 @@ mod tests {
#[async_std::test]
async fn test_remote_authnames() {
let t = dummy_context().await;
let t = TestContext::new().await;
// incoming mail `From: bob1 <bob@example.org>` - this should init authname and name
let (contact_id, sth_modified) = Contact::add_or_lookup(
@@ -1483,7 +1471,7 @@ mod tests {
#[async_std::test]
async fn test_remote_authnames_create_empty() {
let t = dummy_context().await;
let t = TestContext::new().await;
// manually create "claire@example.org" without a given name
let contact_id = Contact::create(&t.ctx, "", "claire@example.org")
@@ -1530,7 +1518,7 @@ mod tests {
#[async_std::test]
async fn test_remote_authnames_edit_empty() {
let t = dummy_context().await;
let t = TestContext::new().await;
// manually create "dave@example.org"
let contact_id = Contact::create(&t.ctx, "dave1", "dave@example.org")
@@ -1574,7 +1562,7 @@ mod tests {
#[async_std::test]
async fn test_name_in_address() {
let t = dummy_context().await;
let t = TestContext::new().await;
let contact_id = Contact::create(&t.ctx, "", "<dave@example.org>")
.await
@@ -1587,7 +1575,7 @@ mod tests {
.await
.unwrap();
let contact = Contact::load_from_db(&t.ctx, contact_id).await.unwrap();
assert_eq!(contact.get_name(), "Dave Mueller");
assert_eq!(contact.get_name(), "Mueller, Dave");
assert_eq!(contact.get_addr(), "dave@example.org");
let contact_id = Contact::create(&t.ctx, "name1", "name2 <dave@example.org>")

View File

@@ -540,7 +540,7 @@ mod tests {
#[async_std::test]
async fn test_get_fresh_msgs() {
let t = dummy_context().await;
let t = TestContext::new().await;
let fresh = t.ctx.get_fresh_msgs().await;
assert!(fresh.is_empty())
}
@@ -595,13 +595,13 @@ mod tests {
#[async_std::test]
async fn no_crashes_on_context_deref() {
let t = dummy_context().await;
let t = TestContext::new().await;
std::mem::drop(t.ctx);
}
#[async_std::test]
async fn test_get_info() {
let t = dummy_context().await;
let t = TestContext::new().await;
let info = t.ctx.get_info().await;
assert!(info.get("database_dir").is_some());

View File

@@ -45,13 +45,14 @@ pub async fn dc_receive_imf(
) -> Result<()> {
info!(
context,
"Receiving message {}/{}...",
"Receiving message {}/{}, seen={}...",
if !server_folder.as_ref().is_empty() {
server_folder.as_ref()
} else {
"?"
},
server_uid,
seen
);
if std::env::var(crate::DCC_MIME_DEBUG).unwrap_or_default() == "2" {
@@ -227,6 +228,19 @@ pub async fn dc_receive_imf(
context
.do_heuristics_moves(server_folder.as_ref(), insert_msg_id)
.await;
if !mime_parser.mdn_reports.is_empty() && mime_parser.has_chat_version() {
// This is a Delta Chat MDN. Mark as read.
job::add(
context,
job::Job::new(
Action::MarkseenMsgOnImap,
insert_msg_id.to_u32(),
Params::new(),
0,
),
)
.await;
}
}
}
@@ -238,7 +252,7 @@ pub async fn dc_receive_imf(
cleanup(context, &create_event_to_send, created_db_entries);
mime_parser
.handle_reports(context, from_id, sent_timestamp)
.handle_reports(context, from_id, sent_timestamp, &mime_parser.parts)
.await;
Ok(())
@@ -332,7 +346,7 @@ async fn add_parts(
return Ok(());
}
let mut msgrmsg = if mime_parser.has_chat_version() {
let mut is_dc_message = if mime_parser.has_chat_version() {
MessengerMessage::Yes
} else if is_reply_to_messenger_message(context, mime_parser).await {
MessengerMessage::Reply
@@ -344,7 +358,7 @@ async fn add_parts(
let show_emails =
ShowEmails::from_i32(context.get_config_int(Config::ShowEmails).await).unwrap_or_default();
if mime_parser.is_system_message != SystemMessage::AutocryptSetupMessage
&& msgrmsg == MessengerMessage::No
&& is_dc_message == MessengerMessage::No
{
// this message is a classic email not a chat-message nor a reply to one
match show_emails {
@@ -373,7 +387,7 @@ async fn add_parts(
// handshake may mark contacts as verified and must be processed before chats are created
if mime_parser.get(HeaderDef::SecureJoin).is_some() {
msgrmsg = MessengerMessage::Yes; // avoid discarding by show_emails setting
is_dc_message = MessengerMessage::Yes; // avoid discarding by show_emails setting
*chat_id = ChatId::new(0);
allow_creation = true;
match handle_securejoin_handshake(context, mime_parser, from_id).await {
@@ -405,6 +419,14 @@ async fn add_parts(
.await
.unwrap_or_default();
if chat_id.is_unset() && mime_parser.failure_report.is_some() {
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
info!(
context,
"Message belongs to an NDN and is not shown in a chat.",
);
}
// get the chat_id - a chat_id here is no indicator that the chat is displayed in the normal list,
// it might also be blocked and displayed in the deaddrop as a result
if chat_id.is_unset() {
@@ -498,7 +520,7 @@ async fn add_parts(
if Blocked::Not != chat_id_blocked
&& state == MessageState::InFresh
&& !incoming_origin.is_known()
&& msgrmsg == MessengerMessage::No
&& is_dc_message == MessengerMessage::No
&& show_emails != ShowEmails::All
{
state = MessageState::InNoticed;
@@ -513,7 +535,7 @@ async fn add_parts(
// handshake may mark contacts as verified and must be processed before chats are created
if mime_parser.get(HeaderDef::SecureJoin).is_some() {
msgrmsg = MessengerMessage::Yes; // avoid discarding by show_emails setting
is_dc_message = MessengerMessage::Yes; // avoid discarding by show_emails setting
*chat_id = ChatId::new(0);
allow_creation = true;
match observe_securejoin_on_other_device(context, mime_parser, to_id).await {
@@ -552,7 +574,7 @@ async fn add_parts(
}
}
if chat_id.is_unset() && allow_creation {
let create_blocked = if MessengerMessage::No != msgrmsg
let create_blocked = if MessengerMessage::No != is_dc_message
&& !Contact::is_blocked_load(context, to_id).await
{
Blocked::Not
@@ -600,7 +622,13 @@ async fn add_parts(
// correct message_timestamp, it should not be used before,
// however, we cannot do this earlier as we need from_id to be set
let rcvd_timestamp = time();
let sort_timestamp = calc_sort_timestamp(context, *sent_timestamp, *chat_id, !seen).await;
let sort_timestamp = calc_sort_timestamp(
context,
*sent_timestamp,
*chat_id,
state == MessageState::InFresh,
)
.await;
*sent_timestamp = std::cmp::min(*sent_timestamp, rcvd_timestamp);
// unarchive chat
@@ -637,7 +665,7 @@ async fn add_parts(
let sent_timestamp = *sent_timestamp;
let is_hidden = *hidden;
let chat_id = *chat_id;
let is_mdn = !mime_parser.reports.is_empty();
let is_mdn = !mime_parser.mdn_reports.is_empty();
// TODO: can this clone be avoided?
let rfc724_mid = rfc724_mid.to_string();
@@ -654,8 +682,8 @@ async fn add_parts(
"INSERT INTO msgs \
(rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
bytes, hidden, mime_headers, mime_in_reply_to, mime_references, error) \
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?, ?);",
)?;
let is_location_kml = location_kml_is
@@ -689,7 +717,7 @@ async fn add_parts(
rcvd_timestamp,
part.typ,
state,
msgrmsg,
is_dc_message,
part.msg,
// txt_raw might contain invalid utf8
txt_raw,
@@ -699,6 +727,7 @@ async fn add_parts(
mime_headers,
mime_in_reply_to,
mime_references,
part.error,
])?;
drop(stmt);
@@ -1767,7 +1796,7 @@ mod tests {
use crate::chat::ChatVisibility;
use crate::chatlist::Chatlist;
use crate::message::Message;
use crate::test_utils::{configured_offline_context, dummy_context};
use crate::test_utils::*;
#[test]
fn test_hex_hash() {
@@ -1779,7 +1808,7 @@ mod tests {
#[async_std::test]
async fn test_grpid_simple() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"From: hello\n\
Subject: outer-subject\n\
In-Reply-To: <lqkjwelq123@123123>\n\
@@ -1796,7 +1825,7 @@ mod tests {
#[async_std::test]
async fn test_grpid_from_multiple() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"From: hello\n\
Subject: outer-subject\n\
In-Reply-To: <Gr.HcxyMARjyJy.9-qweqwe@asd.net>\n\
@@ -1833,7 +1862,7 @@ mod tests {
#[async_std::test]
async fn test_is_known_rfc724_mid() {
let t = dummy_context().await;
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some("first message".to_string());
let msg_id = chat::add_device_msg(&t.ctx, None, Some(&mut msg))
@@ -1849,7 +1878,7 @@ mod tests {
#[async_std::test]
async fn test_is_msgrmsg_rfc724_mid() {
let t = dummy_context().await;
let t = TestContext::new().await;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some("first message".to_string());
let msg_id = chat::add_device_msg(&t.ctx, None, Some(&mut msg))
@@ -1863,34 +1892,34 @@ mod tests {
assert!(!is_msgrmsg_rfc724_mid(&t.ctx, "nonexistant@message.id").await);
}
static MSGRMSG: &[u8] = b"From: Bob <bob@example.org>\n\
To: alice@example.org\n\
static MSGRMSG: &[u8] = b"From: Bob <bob@example.com>\n\
To: alice@example.com\n\
Chat-Version: 1.0\n\
Subject: Chat: hello\n\
Message-ID: <Mr.1111@example.org>\n\
Message-ID: <Mr.1111@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:55 +0000\n\
\n\
hello\n";
static ONETOONE_NOREPLY_MAIL: &[u8] = b"From: Bob <bob@example.org>\n\
To: alice@example.org\n\
static ONETOONE_NOREPLY_MAIL: &[u8] = b"From: Bob <bob@example.com>\n\
To: alice@example.com\n\
Subject: Chat: hello\n\
Message-ID: <2222@example.org>\n\
Message-ID: <2222@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n";
static GRP_MAIL: &[u8] = b"From: bob@example.org\n\
To: alice@example.org, claire@example.org\n\
static GRP_MAIL: &[u8] = b"From: bob@example.com\n\
To: alice@example.com, claire@example.com\n\
Subject: group with Alice, Bob and Claire\n\
Message-ID: <3333@example.org>\n\
Message-ID: <3333@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
hello\n";
#[async_std::test]
async fn test_adhoc_group_show_chats_only() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
assert_eq!(t.ctx.get_config_int(Config::ShowEmails).await, 0);
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
@@ -1917,7 +1946,7 @@ mod tests {
#[async_std::test]
async fn test_adhoc_group_show_accepted_contact_unknown() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::ShowEmails, Some("1"))
.await
@@ -1933,12 +1962,12 @@ mod tests {
#[async_std::test]
async fn test_adhoc_group_show_accepted_contact_known() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::ShowEmails, Some("1"))
.await
.unwrap();
Contact::create(&t.ctx, "Bob", "bob@example.org")
Contact::create(&t.ctx, "Bob", "bob@example.com")
.await
.unwrap();
dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 1, false)
@@ -1953,7 +1982,7 @@ mod tests {
#[async_std::test]
async fn test_adhoc_group_show_accepted_contact_accepted() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::ShowEmails, Some("1"))
.await
@@ -1999,7 +2028,7 @@ mod tests {
#[async_std::test]
async fn test_adhoc_group_show_all() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::ShowEmails, Some("2"))
.await
@@ -2024,7 +2053,7 @@ mod tests {
#[async_std::test]
async fn test_read_receipt_and_unarchive() {
// create alice's account
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
// create one-to-one with bob, archive one-to-one
let bob_id = Contact::create(&t.ctx, "bob", "bob@exampel.org")
@@ -2067,14 +2096,14 @@ mod tests {
dc_receive_imf(
&t.ctx,
format!(
"From: alice@example.org\n\
To: bob@example.org\n\
"From: alice@example.com\n\
To: bob@example.com\n\
Subject: foo\n\
Message-ID: <Gr.{}.12345678901@example.org>\n\
Message-ID: <Gr.{}.12345678901@example.com>\n\
Chat-Version: 1.0\n\
Chat-Group-ID: {}\n\
Chat-Group-Name: foo\n\
Chat-Disposition-Notification-To: alice@example.org\n\
Chat-Disposition-Notification-To: alice@example.com\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
hello\n",
@@ -2103,12 +2132,12 @@ mod tests {
dc_receive_imf(
&t.ctx,
format!(
"From: bob@example.org\n\
To: alice@example.org\n\
"From: bob@example.com\n\
To: alice@example.com\n\
Subject: message opened\n\
Date: Sun, 22 Mar 2020 23:37:57 +0000\n\
Chat-Version: 1.0\n\
Message-ID: <Mr.12345678902@example.org>\n\
Message-ID: <Mr.12345678902@example.com>\n\
Content-Type: multipart/report; report-type=disposition-notification; boundary=\"SNIPP\"\n\
\n\
\n\
@@ -2122,9 +2151,9 @@ mod tests {
Content-Type: message/disposition-notification\n\
\n\
Reporting-UA: Delta Chat 1.28.0\n\
Original-Recipient: rfc822;bob@example.org\n\
Final-Recipient: rfc822;bob@example.org\n\
Original-Message-ID: <Gr.{}.12345678901@example.org>\n\
Original-Recipient: rfc822;bob@example.com\n\
Final-Recipient: rfc822;bob@example.com\n\
Original-Message-ID: <Gr.{}.12345678901@example.com>\n\
Disposition: manual-action/MDN-sent-automatically; displayed\n\
\n\
\n\
@@ -2164,7 +2193,7 @@ mod tests {
// are very rare, however, we have to add them to the database (they go to the
// "deaddrop" chat) to avoid a re-download from the server. See also [**]
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
let context = &t.ctx;
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
@@ -2172,9 +2201,9 @@ mod tests {
dc_receive_imf(
context,
b"To: bob@example.org\n\
b"To: bob@example.com\n\
Subject: foo\n\
Message-ID: <3924@example.org>\n\
Message-ID: <3924@example.com>\n\
Chat-Version: 1.0\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
@@ -2193,7 +2222,7 @@ mod tests {
#[async_std::test]
async fn test_escaped_from() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
let contact_id = Contact::create(&t.ctx, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -2203,9 +2232,9 @@ mod tests {
dc_receive_imf(
&t.ctx,
b"From: =?UTF-8?B?0JjQvNGPLCDQpNCw0LzQuNC70LjRjw==?= <foobar@example.com>\n\
To: alice@example.org\n\
To: alice@example.com\n\
Subject: foo\n\
Message-ID: <asdklfjjaweofi@example.org>\n\
Message-ID: <asdklfjjaweofi@example.com>\n\
Chat-Version: 1.0\n\
Chat-Disposition-Notification-To: =?UTF-8?B?0JjQvNGPLCDQpNCw0LzQuNC70LjRjw==?= <foobar@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
@@ -2220,7 +2249,7 @@ mod tests {
.await
.unwrap()
.get_authname(),
"Фамилия Имя", // The name was "Имя, Фамилия" and ("lastname, firstname") and should be swapped to "firstname, lastname"
"Имя, Фамилия",
);
let msgs = chat::get_chat_msgs(&t.ctx, chat_id, 0, None).await;
assert_eq!(msgs.len(), 1);
@@ -2235,7 +2264,7 @@ mod tests {
#[async_std::test]
async fn test_escaped_recipients() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
Contact::create(&t.ctx, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -2249,10 +2278,10 @@ mod tests {
dc_receive_imf(
&t.ctx,
b"From: Foobar <foobar@example.com>\n\
To: =?UTF-8?B?0JjQvNGPLCDQpNCw0LzQuNC70LjRjw==?= alice@example.org\n\
To: =?UTF-8?B?0JjQvNGPLCDQpNCw0LzQuNC70LjRjw==?= alice@example.com\n\
Cc: =?utf-8?q?=3Ch2=3E?= <carl@host.tld>\n\
Subject: foo\n\
Message-ID: <asdklfjjaweofi@example.org>\n\
Message-ID: <asdklfjjaweofi@example.com>\n\
Chat-Version: 1.0\n\
Chat-Disposition-Notification-To: <foobar@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
@@ -2283,7 +2312,7 @@ mod tests {
#[async_std::test]
async fn test_cc_to_contact() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
Contact::create(&t.ctx, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -2301,10 +2330,10 @@ mod tests {
dc_receive_imf(
&t.ctx,
b"From: Foobar <foobar@example.com>\n\
To: alice@example.org\n\
To: alice@example.com\n\
Cc: Carl <carl@host.tld>\n\
Subject: foo\n\
Message-ID: <asdklfjjaweofi@example.org>\n\
Message-ID: <asdklfjjaweofi@example.com>\n\
Chat-Version: 1.0\n\
Chat-Disposition-Notification-To: <foobar@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
@@ -2324,4 +2353,184 @@ mod tests {
"Carl"
);
}
#[async_std::test]
async fn test_parse_ndn_tiscali() {
test_parse_ndn(
"alice@tiscali.it",
"shenauithz@testrun.org",
"Mr.un2NYERi1RM.lbQ5F9q-QyJ@tiscali.it",
include_bytes!("../test-data/message/tiscali_ndn.eml"),
"",
)
.await;
}
#[async_std::test]
async fn test_parse_ndn_testrun() {
test_parse_ndn(
"alice@testrun.org",
"hcksocnsofoejx@five.chat",
"Mr.A7pTA5IgrUA.q4bP41vAJOp@testrun.org",
include_bytes!("../test-data/message/testrun_ndn.eml"),
"Undelivered Mail Returned to Sender This is the mail system at host hq5.merlinux.eu.\n\nI\'m sorry to have to inform you that your message could not\nbe delivered to one or more recipients. It\'s attached below.\n\nFor further assistance, please send mail to postmaster.\n\nIf you do so, please include this problem report. You can\ndelete your own text from the attached returned message.\n\n The mail system\n\n<hcksocnsofoejx@five.chat>: host mail.five.chat[195.62.125.103] said: 550 5.1.1\n <hcksocnsofoejx@five.chat>: Recipient address rejected: User unknown in\n virtual mailbox table (in reply to RCPT TO command)"
)
.await;
}
#[async_std::test]
async fn test_parse_ndn_yahoo() {
test_parse_ndn(
"alice@yahoo.com",
"haeclirth.sinoenrat@yahoo.com",
"1680295672.3657931.1591783872936@mail.yahoo.com",
include_bytes!("../test-data/message/yahoo_ndn.eml"),
"Failure Notice Sorry, we were unable to deliver your message to the following address.\n\n<haeclirth.sinoenrat@yahoo.com>:\n554: delivery error: dd Not a valid recipient - atlas117.free.mail.ne1.yahoo.com"
)
.await;
}
#[async_std::test]
async fn test_parse_ndn_gmail() {
test_parse_ndn(
"alice@gmail.com",
"assidhfaaspocwaeofi@gmail.com",
"CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com",
include_bytes!("../test-data/message/gmail_ndn.eml"),
"Delivery Status Notification (Failure) ** Die Adresse wurde nicht gefunden **\n\nIhre Nachricht wurde nicht an assidhfaaspocwaeofi@gmail.com zugestellt, weil die Adresse nicht gefunden wurde oder keine E-Mails empfangen kann.\n\nHier erfahren Sie mehr: https://support.google.com/mail/?p=NoSuchUser\n\nAntwort:\n\n550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient\'s email address for typos or unnecessary spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser i18sor6261697wrs.38 - gsmtp",
)
.await;
}
#[async_std::test]
async fn test_parse_ndn_gmx() {
test_parse_ndn(
"alice@gmx.com",
"snaerituhaeirns@gmail.com",
"9c9c2a32-056b-3592-c372-d7e8f0bd4bc2@gmx.de",
include_bytes!("../test-data/message/gmx_ndn.eml"),
"Mail delivery failed: returning message to sender This message was created automatically by mail delivery software.\n\nA message that you sent could not be delivered to one or more of\nits recipients. This is a permanent error. The following address(es)\nfailed:\n\nsnaerituhaeirns@gmail.com:\nSMTP error from remote server for RCPT TO command, host: gmail-smtp-in.l.google.com (66.102.1.27) reason: 550-5.1.1 The email account that you tried to reach does not exist. Please\n try\n550-5.1.1 double-checking the recipient\'s email address for typos or\n550-5.1.1 unnecessary spaces. Learn more at\n550 5.1.1 https://support.google.com/mail/?p=NoSuchUser f6si2517766wmc.21\n9 - gsmtp"
)
.await;
}
#[async_std::test]
async fn test_parse_ndn_posteo() {
test_parse_ndn(
"alice@posteo.org",
"hanerthaertidiuea@gmx.de",
"04422840-f884-3e37-5778-8192fe22d8e1@posteo.de",
include_bytes!("../test-data/message/posteo_ndn.eml"),
"Undelivered Mail Returned to Sender This is the mail system at host mout01.posteo.de.\n\nI\'m sorry to have to inform you that your message could not\nbe delivered to one or more recipients. It\'s attached below.\n\nFor further assistance, please send mail to postmaster.\n\nIf you do so, please include this problem report. You can\ndelete your own text from the attached returned message.\n\n The mail system\n\n<hanerthaertidiuea@gmx.de>: host mx01.emig.gmx.net[212.227.17.5] said: 550\n Requested action not taken: mailbox unavailable (in reply to RCPT TO\n command)",
)
.await;
}
// ndn = Non Delivery Notification
async fn test_parse_ndn(
self_addr: &str,
foreign_addr: &str,
rfc724_mid_outgoing: &str,
raw_ndn: &[u8],
error_msg: &str,
) {
let t = TestContext::new().await;
t.configure_addr(self_addr).await;
dc_receive_imf(
&t.ctx,
format!(
"From: {}\n\
To: {}\n\
Subject: foo\n\
Message-ID: <{}>\n\
Chat-Version: 1.0\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
hello\n",
self_addr, foreign_addr, rfc724_mid_outgoing
)
.as_bytes(),
"INBOX",
1,
false,
)
.await
.unwrap();
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
let msg_id = chats.get_msg_id(0).unwrap();
// Check that the ndn would be downloaded:
let headers = mailparse::parse_mail(raw_ndn).unwrap().headers;
assert!(
crate::imap::prefetch_should_download(&t.ctx, &headers, ShowEmails::Off)
.await
.unwrap()
);
dc_receive_imf(&t.ctx, raw_ndn, "INBOX", 1, false)
.await
.unwrap();
let msg = Message::load_from_db(&t.ctx, msg_id).await.unwrap();
assert_eq!(msg.state, MessageState::OutFailed);
assert_eq!(msg.error, error_msg);
}
#[async_std::test]
async fn test_parse_ndn_group_msg() {
let t = TestContext::new().await;
t.configure_addr("alice@gmail.com").await;
dc_receive_imf(
&t.ctx,
b"From: alice@gmail.com\n\
To: bob@example.com, assidhfaaspocwaeofi@gmail.com\n\
Subject: foo\n\
Message-ID: <CADWx9Cs32Wa7Gy-gM0bvbq54P_FEHe7UcsAV=yW7sVVW=fiMYQ@mail.gmail.com>\n\
Chat-Version: 1.0\n\
Chat-Group-ID: abcde\n\
Chat-Group-Name: foo\n\
Chat-Disposition-Notification-To: alice@example.com\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
hello\n",
"INBOX",
1,
false,
)
.await
.unwrap();
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
let msg_id = chats.get_msg_id(0).unwrap();
let raw = include_bytes!("../test-data/message/gmail_ndn_group.eml");
dc_receive_imf(&t.ctx, raw, "INBOX", 1, false)
.await
.unwrap();
let msg = Message::load_from_db(&t.ctx, msg_id).await.unwrap();
assert_eq!(msg.state, MessageState::OutFailed);
let msgs = chat::get_chat_msgs(&t.ctx, msg.chat_id, 0, None).await;
let last_msg = Message::load_from_db(&t.ctx, *msgs.last().unwrap())
.await
.unwrap();
assert_eq!(
last_msg.text,
Some(
t.ctx
.stock_string_repl_str(
StockMessage::FailedSendingTo,
"assidhfaaspocwaeofi@gmail.com",
)
.await,
)
);
assert_eq!(last_msg.from_id, DC_CONTACT_ID_INFO);
}
}

View File

@@ -774,7 +774,7 @@ mod tests {
#[async_std::test]
async fn test_file_handling() {
let t = dummy_context().await;
let t = TestContext::new().await;
let context = &t.ctx;
macro_rules! dc_file_exist {
($ctx:expr, $fname:expr) => {
@@ -853,7 +853,7 @@ mod tests {
#[async_std::test]
async fn test_create_smeared_timestamp() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_ne!(
dc_create_smeared_timestamp(&t.ctx).await,
dc_create_smeared_timestamp(&t.ctx).await
@@ -869,7 +869,7 @@ mod tests {
#[async_std::test]
async fn test_create_smeared_timestamps() {
let t = dummy_context().await;
let t = TestContext::new().await;
let count = MAX_SECONDS_TO_LEND_FROM_FUTURE - 1;
let start = dc_create_smeared_timestamps(&t.ctx, count as usize).await;
let next = dc_smeared_time(&t.ctx).await;

View File

@@ -327,14 +327,14 @@ mod tests {
#[async_std::test]
async fn test_prexisting() {
let t = dummy_context().await;
let test_addr = configure_alice_keypair(&t.ctx).await;
let t = TestContext::new().await;
let test_addr = t.configure_alice().await;
assert_eq!(ensure_secret_key_exists(&t.ctx).await.unwrap(), test_addr);
}
#[async_std::test]
async fn test_not_configured() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert!(ensure_secret_key_exists(&t.ctx).await.is_err());
}
}

View File

@@ -21,6 +21,7 @@ pub enum HeaderDef {
References,
InReplyTo,
Precedence,
ContentType,
ChatVersion,
ChatGroupId,
ChatGroupName,

View File

@@ -3,6 +3,8 @@
//! uses [async-email/async-imap](https://github.com/async-email/async-imap)
//! to implement connect, fetch, delete functionality with standard IMAP servers.
#![forbid(clippy::indexing_slicing)]
use std::collections::BTreeMap;
use async_imap::{
@@ -732,9 +734,17 @@ impl Imap {
folder: S,
server_uids: &[u32],
) -> (Option<u32>, usize) {
if server_uids.is_empty() {
return (None, 0);
}
let set = match server_uids {
[] => return (None, 0),
[server_uid] => server_uid.to_string(),
[first_uid, .., last_uid] => {
// XXX: it is assumed that UIDs are sorted and
// contiguous. If UIDs are not contiguous, more
// messages than needed will be downloaded.
debug_assert!(first_uid < last_uid, "uids must be sorted");
format!("{}:{}", first_uid, last_uid)
}
};
if !self.is_connected() {
warn!(context, "Not connected");
@@ -750,15 +760,6 @@ impl Imap {
let session = self.session.as_mut().unwrap();
let set = if server_uids.len() == 1 {
server_uids[0].to_string()
} else {
let first_uid = server_uids[0];
let last_uid = server_uids[server_uids.len() - 1];
assert!(first_uid < last_uid, "uids must be sorted");
format!("{}:{}", first_uid, last_uid)
};
let mut msgs = match session.uid_fetch(&set, BODY_FLAGS).await {
Ok(msgs) => msgs,
Err(err) => {
@@ -811,7 +812,6 @@ impl Imap {
Ok(_) => Some(server_uid),
Err(err) => {
warn!(context, "dc_receive_imf error: {}", err);
read_errors += 1;
None
}
}
@@ -1449,7 +1449,7 @@ async fn prefetch_is_reply_to_chat_message(
false
}
async fn prefetch_should_download(
pub(crate) async fn prefetch_should_download(
context: &Context,
headers: &[mailparse::MailHeader<'_>],
show_emails: ShowEmails,
@@ -1457,6 +1457,13 @@ async fn prefetch_should_download(
let is_chat_message = headers.get_header_value(HeaderDef::ChatVersion).is_some();
let is_reply_to_chat_message = prefetch_is_reply_to_chat_message(context, &headers).await;
let maybe_ndn = if let Some(from) = headers.get_header_value(HeaderDef::From_) {
let from = from.to_ascii_lowercase();
from.contains("mailer-daemon") || from.contains("mail-daemon")
} else {
false
};
// Autocrypt Setup Message should be shown even if it is from non-chat client.
let is_autocrypt_setup_message = headers
.get_header_value(HeaderDef::AutocryptSetupMessage)
@@ -1467,6 +1474,7 @@ async fn prefetch_should_download(
let accepted_contact = origin.is_known();
let show = is_autocrypt_setup_message
|| maybe_ndn
|| match show_emails {
ShowEmails::Off => is_chat_message || is_reply_to_chat_message,
ShowEmails::AcceptedContacts => {

View File

@@ -776,9 +776,9 @@ mod tests {
#[async_std::test]
async fn test_render_setup_file() {
let t = test_context().await;
let t = TestContext::new().await;
configure_alice_keypair(&t.ctx).await;
t.configure_alice().await;
let msg = render_setup_file(&t.ctx, "hello").await.unwrap();
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
@@ -795,12 +795,12 @@ mod tests {
#[async_std::test]
async fn test_render_setup_file_newline_replace() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_stock_translation(StockMessage::AcSetupMsgBody, "hello\r\nthere".to_string())
.await
.unwrap();
configure_alice_keypair(&t.ctx).await;
t.configure_alice().await;
let msg = render_setup_file(&t.ctx, "pw").await.unwrap();
println!("{}", &msg);
assert!(msg.contains("<p>hello<br>there</p>"));
@@ -808,7 +808,7 @@ mod tests {
#[async_std::test]
async fn test_create_setup_code() {
let t = dummy_context().await;
let t = TestContext::new().await;
let setupcode = create_setup_code(&t.ctx);
assert_eq!(setupcode.len(), 44);
assert_eq!(setupcode.chars().nth(4).unwrap(), '-');
@@ -823,7 +823,7 @@ mod tests {
#[async_std::test]
async fn test_export_key_to_asc_file() {
let context = dummy_context().await;
let context = TestContext::new().await;
let key = alice_keypair().public;
let blobdir = "$BLOBDIR";
assert!(export_key_to_asc_file(&context.ctx, blobdir, None, &key)

View File

@@ -806,7 +806,7 @@ pub async fn send_msg_job(context: &Context, msg_id: MsgId) -> Result<Option<Job
if rendered_msg.is_encrypted && !needs_encryption {
msg.param.set_int(Param::GuaranteeE2ee, 1);
msg.save_param_to_disk(context).await;
msg.update_param(context).await;
}
ensure!(!recipients.is_empty(), "no recipients for smtp job set");
@@ -1209,7 +1209,7 @@ mod tests {
// 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().await;
let t = TestContext::new().await;
insert_job(&t.ctx, -1).await; // This can not be loaded into Job struct.
let jobs = load_next(
&t.ctx,
@@ -1231,7 +1231,7 @@ mod tests {
#[async_std::test]
async fn test_load_next_job_one() {
let t = dummy_context().await;
let t = TestContext::new().await;
insert_job(&t.ctx, 1).await;

View File

@@ -550,8 +550,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[async_std::test]
async fn test_load_self_existing() {
let alice = alice_keypair();
let t = dummy_context().await;
configure_alice_keypair(&t.ctx).await;
let t = TestContext::new().await;
t.configure_alice().await;
let pubkey = SignedPublicKey::load_self(&t.ctx).await.unwrap();
assert_eq!(alice.public, pubkey);
let seckey = SignedSecretKey::load_self(&t.ctx).await.unwrap();
@@ -560,7 +560,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[async_std::test]
async fn test_load_self_generate_public() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_config(Config::ConfiguredAddr, Some("alice@example.com"))
.await
@@ -571,7 +571,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[async_std::test]
async fn test_load_self_generate_secret() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_config(Config::ConfiguredAddr, Some("alice@example.com"))
.await
@@ -584,7 +584,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
async fn test_load_self_generate_concurrent() {
use std::thread;
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_config(Config::ConfiguredAddr, Some("alice@example.com"))
.await
@@ -611,7 +611,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
async fn test_save_self_key_twice() {
// Saving the same key twice should result in only one row in
// the keypairs table.
let t = dummy_context().await;
let t = TestContext::new().await;
let ctx = Arc::new(t.ctx);
let ctx1 = ctx.clone();

View File

@@ -79,8 +79,8 @@ mod tests {
#[async_std::test]
async fn test_keyring_load_self() {
// new_self() implies load_self()
let t = dummy_context().await;
configure_alice_keypair(&t.ctx).await;
let t = TestContext::new().await;
t.configure_alice().await;
let alice = alice_keypair();
let pub_ring: Keyring<SignedPublicKey> = Keyring::new_self(&t.ctx).await.unwrap();

View File

@@ -530,7 +530,7 @@ pub async fn save(
accuracy,
..
} = location;
context
let (loc_id, ts) = context
.sql
.with_conn(move |mut conn| {
let mut stmt_test = conn
@@ -569,9 +569,11 @@ pub async fn save(
)?;
}
}
Ok(())
Ok((newest_location_id, newest_timestamp))
})
.await?;
newest_timestamp = ts;
newest_location_id = loc_id;
}
Ok(newest_location_id)
@@ -722,11 +724,11 @@ pub(crate) async fn job_maybe_send_locations_ended(
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::dummy_context;
use crate::test_utils::TestContext;
#[async_std::test]
async fn test_kml_parse() {
let context = dummy_context().await;
let context = TestContext::new().await;
let xml =
b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document addr=\"user@example.org\">\n<Placemark><Timestamp><when>2019-03-06T21:09:57Z</when></Timestamp><Point><coordinates accuracy=\"32.000000\">9.423110,53.790302</coordinates></Point></Placemark>\n<PlaceMARK>\n<Timestamp><WHEN > \n\t2018-12-13T22:11:12Z\t</WHEN></Timestamp><Point><coordinates aCCuracy=\"2.500000\"> 19.423110 \t , \n 63.790302\n </coordinates></Point></PlaceMARK>\n</Document>\n</kml>";

View File

@@ -14,7 +14,7 @@ use crate::error::{ensure, Error};
use crate::events::Event;
use crate::job::{self, Action};
use crate::lot::{Lot, LotState, Meaning};
use crate::mimeparser::SystemMessage;
use crate::mimeparser::{FailureReport, SystemMessage};
use crate::param::*;
use crate::pgp::*;
use crate::stock::StockMessage;
@@ -255,6 +255,7 @@ pub struct Message {
pub(crate) starred: bool,
pub(crate) chat_blocked: Blocked,
pub(crate) location_id: u32,
pub(crate) error: String,
pub(crate) param: Params,
}
@@ -289,6 +290,7 @@ impl Message {
" m.timestamp_rcvd AS timestamp_rcvd,",
" m.type AS type,",
" m.state AS state,",
" m.error AS error,",
" m.msgrmsg AS msgrmsg,",
" m.txt AS txt,",
" m.param AS param,",
@@ -316,6 +318,7 @@ impl Message {
msg.timestamp_rcvd = row.get("timestamp_rcvd")?;
msg.viewtype = row.get("type")?;
msg.state = row.get("state")?;
msg.error = row.get("error")?;
msg.is_dc_message = row.get("msgrmsg")?;
let text;
@@ -390,7 +393,7 @@ impl Message {
}
if !self.id.is_unset() {
self.save_param_to_disk(context).await;
self.update_param(context).await;
}
}
}
@@ -643,10 +646,10 @@ impl Message {
if duration > 0 {
self.param.set_int(Param::Duration, duration);
}
self.save_param_to_disk(context).await;
self.update_param(context).await;
}
pub async fn save_param_to_disk(&mut self, context: &Context) -> bool {
pub async fn update_param(&mut self, context: &Context) -> bool {
context
.sql
.execute(
@@ -763,9 +766,10 @@ impl From<MessageState> for LotState {
impl MessageState {
pub fn can_fail(self) -> bool {
match self {
MessageState::OutPreparing | MessageState::OutPending | MessageState::OutDelivered => {
true
}
MessageState::OutPreparing
| MessageState::OutPending
| MessageState::OutDelivered
| MessageState::OutMdnRcvd => true, // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
_ => false,
}
}
@@ -937,8 +941,9 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> String {
}
ret += "\n";
if let Some(err) = msg.param.get(Param::Error) {
ret += &format!("Error: {}", err)
if !msg.error.is_empty() {
ret += &format!("Error: {}", msg.error);
}
if let Some(path) = msg.get_file(context) {
@@ -1251,33 +1256,38 @@ pub async fn exists(context: &Context, msg_id: MsgId) -> bool {
pub async 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).await {
let error = error.map(|e| e.as_ref().to_string()).unwrap_or_default();
if msg.state.can_fail() {
msg.state = MessageState::OutFailed;
}
if let Some(error) = error {
msg.param.set(Param::Error, error.as_ref());
warn!(context, "Message failed: {}", error.as_ref());
warn!(context, "{} failed: {}", msg_id, error);
} else {
warn!(
context,
"{} seems to have failed ({}), but state is {}", msg_id, error, msg.state
)
}
if context
match context
.sql
.execute(
"UPDATE msgs SET state=?, param=? WHERE id=?;",
paramsv![msg.state, msg.param.to_string(), msg_id],
"UPDATE msgs SET state=?, error=? WHERE id=?;",
paramsv![msg.state, error, msg_id],
)
.await
.is_ok()
{
context.emit_event(Event::MsgFailed {
Ok(_) => context.emit_event(Event::MsgFailed {
chat_id: msg.chat_id,
msg_id,
});
}),
Err(e) => {
warn!(context, "{:?}", e);
}
}
}
}
/// returns Some if an event should be send
pub async fn mdn_from_ext(
pub async fn handle_mdn(
context: &Context,
from_id: u32,
rfc724_mid: &str,
@@ -1318,10 +1328,10 @@ pub async fn mdn_from_ext(
if let Ok((msg_id, chat_id, chat_type, msg_state)) = res {
let mut read_by_all = false;
// if already marked as MDNS_RCVD msgstate_can_fail() returns false.
// however, it is important, that ret_msg_id is set above as this
// will allow the caller eg. to move the message away
if msg_state.can_fail() {
if msg_state == MessageState::OutPreparing
|| msg_state == MessageState::OutPending
|| msg_state == MessageState::OutDelivered
{
let mdn_already_in_table = context
.sql
.exists(
@@ -1384,6 +1394,69 @@ pub async fn mdn_from_ext(
None
}
/// Marks a message as failed after an ndn (non-delivery-notification) arrived.
/// Where appropriate, also adds an info message telling the user which of the recipients of a group message failed.
pub(crate) async fn handle_ndn(
context: &Context,
failed: &FailureReport,
error: Option<impl AsRef<str>>,
) {
if failed.rfc724_mid.is_empty() {
return;
}
let res = context
.sql
.query_row(
concat!(
"SELECT",
" m.id AS msg_id,",
" c.id AS chat_id,",
" c.type AS type",
" FROM msgs m LEFT JOIN chats c ON m.chat_id=c.id",
" WHERE rfc724_mid=? AND from_id=1",
),
paramsv![failed.rfc724_mid],
|row| {
Ok((
row.get::<_, MsgId>("msg_id")?,
row.get::<_, ChatId>("chat_id")?,
row.get::<_, Chattype>("type")?,
))
},
)
.await;
if let Err(ref err) = res {
info!(context, "Failed to select NDN {:?}", err);
}
if let Ok((msg_id, chat_id, chat_type)) = res {
set_msg_failed(context, msg_id, error).await;
if chat_type == Chattype::Group || chat_type == Chattype::VerifiedGroup {
if let Some(failed_recipient) = &failed.failed_recipient {
let contact_id =
Contact::lookup_id_by_addr(context, failed_recipient, Origin::Unknown).await;
if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
// Tell the user which of the recipients failed if we know that (because in a group, this might otherwise be unclear)
chat::add_info_msg(
context,
chat_id,
context
.stock_string_repl_str(
StockMessage::FailedSendingTo,
contact.get_display_name(),
)
.await,
)
.await;
context.emit_event(Event::ChatModified(chat_id));
}
}
}
}
}
/// The number of messages assigned to real chat (!=deaddrop, !=trash)
pub async fn get_real_msg_cnt(context: &Context) -> i32 {
match context
@@ -1572,7 +1645,7 @@ mod tests {
async fn test_prepare_message_and_send() {
use crate::config::Config;
let d = test::dummy_context().await;
let d = test::TestContext::new().await;
let ctx = &d.ctx;
let contact = Contact::create(ctx, "", "dest@example.com")
@@ -1596,7 +1669,7 @@ mod tests {
#[async_std::test]
async fn test_get_summarytext_by_raw() {
let d = test::dummy_context().await;
let d = test::TestContext::new().await;
let ctx = &d.ctx;
let some_text = Some("bla bla".to_string());

View File

@@ -1210,7 +1210,6 @@ mod tests {
use crate::chatlist::Chatlist;
use crate::dc_receive_imf::dc_receive_imf;
use crate::mimeparser::*;
use crate::test_utils::configured_offline_context;
use crate::test_utils::TestContext;
#[test]
@@ -1300,10 +1299,10 @@ mod tests {
// 1.: Receive a mail from an MUA or Delta Chat
assert_eq!(
msg_to_subject_str(
b"From: Bob <bob@example.org>\n\
To: alice@example.org\n\
b"From: Bob <bob@example.com>\n\
To: alice@example.com\n\
Subject: Antw: Chat: hello\n\
Message-ID: <2222@example.org>\n\
Message-ID: <2222@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n"
@@ -1314,10 +1313,10 @@ mod tests {
assert_eq!(
msg_to_subject_str(
b"From: Bob <bob@example.org>\n\
To: alice@example.org\n\
b"From: Bob <bob@example.com>\n\
To: alice@example.com\n\
Subject: Infos: 42\n\
Message-ID: <2222@example.org>\n\
Message-ID: <2222@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n"
@@ -1329,11 +1328,11 @@ mod tests {
// 2. Receive a message from Delta Chat when we did not send any messages before
assert_eq!(
msg_to_subject_str(
b"From: Charlie <charlie@example.org>\n\
To: alice@example.org\n\
b"From: Charlie <charlie@example.com>\n\
To: alice@example.com\n\
Subject: Chat: hello\n\
Chat-Version: 1.0\n\
Message-ID: <2223@example.org>\n\
Message-ID: <2223@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n"
@@ -1343,10 +1342,11 @@ mod tests {
);
// 3. Send the first message to a new contact
let t = configured_offline_context().await;
assert_eq!(first_subject_str(t).await, "Message from alice@example.org");
let t = TestContext::new_alice().await;
let t = configured_offline_context().await;
assert_eq!(first_subject_str(t).await, "Message from alice@example.com");
let t = TestContext::new_alice().await;
t.ctx
.set_config(Config::Displayname, Some("Alice"))
.await
@@ -1355,11 +1355,11 @@ mod tests {
// 4. Receive messages with unicode characters and make sure that we do not panic (we do not care about the result)
msg_to_subject_str(
"From: Charlie <charlie@example.org>\n\
To: alice@example.org\n\
"From: Charlie <charlie@example.com>\n\
To: alice@example.com\n\
Subject: äääää\n\
Chat-Version: 1.0\n\
Message-ID: <2893@example.org>\n\
Message-ID: <2893@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n"
@@ -1368,11 +1368,11 @@ mod tests {
.await;
msg_to_subject_str(
"From: Charlie <charlie@example.org>\n\
To: alice@example.org\n\
"From: Charlie <charlie@example.com>\n\
To: alice@example.com\n\
Subject: aäääää\n\
Chat-Version: 1.0\n\
Message-ID: <2893@example.org>\n\
Message-ID: <2893@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n"
@@ -1383,7 +1383,7 @@ mod tests {
async fn first_subject_str(t: TestContext) -> String {
let contact_id =
Contact::add_or_lookup(&t.ctx, "Dave", "dave@example.org", Origin::ManuallyCreated)
Contact::add_or_lookup(&t.ctx, "Dave", "dave@example.com", Origin::ManuallyCreated)
.await
.unwrap()
.0;
@@ -1407,7 +1407,7 @@ mod tests {
}
async fn msg_to_subject_str(imf_raw: &[u8]) -> String {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
let new_msg = incoming_msg_to_reply_msg(imf_raw, &t.ctx).await;
let mf = MimeFactory::from_msg(&t.ctx, &new_msg, false)
.await
@@ -1445,15 +1445,15 @@ mod tests {
#[async_std::test]
// This test could still be extended
async fn test_render_reply() {
let t = configured_offline_context().await;
let t = TestContext::new_alice().await;
let context = &t.ctx;
let msg = incoming_msg_to_reply_msg(
b"From: Charlie <charlie@example.org>\n\
To: alice@example.org\n\
b"From: Charlie <charlie@example.com>\n\
To: alice@example.com\n\
Subject: Chat: hello\n\
Chat-Version: 1.0\n\
Message-ID: <2223@example.org>\n\
Message-ID: <2223@example.com>\n\
Date: Sun, 22 Mar 2020 22:37:56 +0000\n\
\n\
hello\n",
@@ -1464,7 +1464,7 @@ mod tests {
let mimefactory = MimeFactory::from_msg(&t.ctx, &msg, false).await.unwrap();
let recipients = mimefactory.recipients();
assert_eq!(recipients, vec!["charlie@example.org"]);
assert_eq!(recipients, vec!["charlie@example.com"]);
let rendered_msg = mimefactory.render().await.unwrap();

View File

@@ -3,6 +3,7 @@ use std::future::Future;
use std::pin::Pin;
use deltachat_derive::{FromSql, ToSql};
use lazy_static::lazy_static;
use lettre_email::mime::{self, Mime};
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
@@ -53,7 +54,8 @@ pub struct MimeMessage {
pub message_kml: Option<location::Kml>,
pub(crate) user_avatar: Option<AvatarAction>,
pub(crate) group_avatar: Option<AvatarAction>,
pub(crate) reports: Vec<Report>,
pub(crate) mdn_reports: Vec<Report>,
pub(crate) failure_report: Option<FailureReport>,
}
#[derive(Debug, PartialEq)]
@@ -176,14 +178,16 @@ impl MimeMessage {
signatures,
gossipped_addr,
is_forwarded: false,
reports: Vec::new(),
mdn_reports: Vec::new(),
is_system_message: SystemMessage::Unknown,
location_kml: None,
message_kml: None,
user_avatar: None,
group_avatar: None,
failure_report: None,
};
parser.parse_mime_recursive(context, &mail).await?;
parser.heuristically_parse_ndn(context).await;
parser.parse_headers(context)?;
Ok(parser)
@@ -253,7 +257,8 @@ impl MimeMessage {
self.parts[0].msg = "".to_string();
// swap new with old
std::mem::replace(&mut self.parts[0], filepart);
self.parts.push(filepart); // push to the end
let _ = self.parts.swap_remove(0); // drops first element, replacing it with the last one in O(1)
}
}
}
@@ -353,7 +358,7 @@ impl MimeMessage {
// 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() {
if self.parts.is_empty() && self.mdn_reports.is_empty() {
let mut part = Part::default();
part.typ = Viewtype::Text;
@@ -527,7 +532,7 @@ impl MimeMessage {
part.typ = Viewtype::Text;
part.msg_raw = Some(txt.clone());
part.msg = txt;
part.param.set(Param::Error, "Decryption failed");
part.error = "Decryption failed".to_string();
self.parts.push(part);
@@ -550,10 +555,10 @@ impl MimeMessage {
(mime::MULTIPART, "report") => {
/* RFC 6522: the first part is for humans, the second for machines */
if mail.subparts.len() >= 2 {
if let Some(report_type) = mail.ctype.params.get("report-type") {
if report_type == "disposition-notification" {
match mail.ctype.params.get("report-type").map(|s| s as &str) {
Some("disposition-notification") => {
if let Some(report) = self.process_report(context, mail)? {
self.reports.push(report);
self.mdn_reports.push(report);
}
// Add MDN part so we can track it, avoid
@@ -565,9 +570,21 @@ impl MimeMessage {
self.parts.push(part);
any_part_added = true;
} else {
/* eg. `report-type=delivery-status`;
maybe we should show them as a little error icon */
}
// Some providers, e.g. Tiscali, forget to set the report-type. So, if it's None, assume that it might be delivery-status
Some("delivery-status") | None => {
if let Some(report) = self.process_delivery_status(context, mail)? {
self.failure_report = Some(report);
}
// Add all parts (we need another part, preferrably text/plain, to show as an error message)
for cur_data in mail.subparts.iter() {
if self.parse_mime_recursive(context, cur_data).await? {
any_part_added = true;
}
}
}
Some(_) => {
if let Some(first) = mail.subparts.iter().next() {
any_part_added = self.parse_mime_recursive(context, first).await?;
}
@@ -840,24 +857,118 @@ impl MimeMessage {
Ok(None)
}
/// Handle reports (only MDNs for now)
pub async fn handle_reports(&self, context: &Context, from_id: u32, sent_timestamp: i64) {
if self.reports.is_empty() {
return;
fn process_delivery_status(
&self,
context: &Context,
report: &mailparse::ParsedMail<'_>,
) -> Result<Option<FailureReport>> {
// parse as mailheaders
if let Some(original_msg) = report
.subparts
.iter()
.find(|p| p.ctype.mimetype.contains("rfc822") || p.ctype.mimetype == "message/global")
{
let report_body = original_msg.get_body_raw()?;
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
if let Some(original_message_id) = report_fields
.get_header_value(HeaderDef::MessageId)
.and_then(|v| parse_message_id(&v).ok())
{
let mut to_list = get_all_addresses_from_header(&report.headers, |header_key| {
header_key == "x-failed-recipients"
});
let to = if to_list.len() == 1 {
Some(to_list.pop().unwrap())
} else {
None // We do not know which recipient failed
};
return Ok(Some(FailureReport {
rfc724_mid: original_message_id,
failed_recipient: to.map(|s| s.addr),
}));
}
warn!(
context,
"ignoring unknown ndn-notification, Message-Id: {:?}",
report_fields.get_header_value(HeaderDef::MessageId)
);
}
for report in &self.reports {
Ok(None)
}
/// Some providers like GMX and Yahoo do not send standard NDNs (Non Delivery notifications).
/// If you improve heuristics here you might also have to change prefetch_should_download() in imap/mod.rs.
/// Also you should add a test in dc_receive_imf.rs (there already are lots of test_parse_ndn_* tests).
async fn heuristically_parse_ndn(&mut self, context: &Context) -> Option<()> {
let maybe_ndn = if let Some(from) = self.get(HeaderDef::From_) {
let from = from.to_ascii_lowercase();
from.contains("mailer-daemon") || from.contains("mail-daemon")
} else {
false
};
if maybe_ndn && self.failure_report.is_none() {
lazy_static! {
static ref RE: regex::Regex = regex::Regex::new(r"Message-ID:(.*)").unwrap();
}
for captures in self
.parts
.iter()
.filter_map(|part| part.msg_raw.as_ref())
.flat_map(|part| part.lines())
.filter_map(|line| RE.captures(line))
{
if let Ok(original_message_id) = parse_message_id(&captures[1]) {
if let Ok(Some(_)) =
message::rfc724_mid_exists(context, &original_message_id).await
{
self.failure_report = Some(FailureReport {
rfc724_mid: original_message_id,
failed_recipient: None,
})
}
}
}
}
None // Always return None, we just return anything so that we can use the '?' operator.
}
/// Handle reports
/// (MDNs = Message Disposition Notification, the message was read
/// and NDNs = Non delivery notification, the message could not be delivered)
pub async fn handle_reports(
&self,
context: &Context,
from_id: u32,
sent_timestamp: i64,
parts: &[Part],
) {
for report in &self.mdn_reports {
for original_message_id in
std::iter::once(&report.original_message_id).chain(&report.additional_message_ids)
{
if let Some((chat_id, msg_id)) =
message::mdn_from_ext(context, from_id, original_message_id, sent_timestamp)
.await
message::handle_mdn(context, from_id, original_message_id, sent_timestamp).await
{
context.emit_event(Event::MsgRead { chat_id, msg_id });
}
}
}
if let Some(failure_report) = &self.failure_report {
let error = parts.iter().find(|p| p.typ == Viewtype::Text).map(|p| {
let msg = &p.msg;
match msg.find("\n--- ") {
Some(footer_start) => &msg[..footer_start],
None => msg,
}
.trim()
});
message::handle_ndn(context, failure_report, error).await
}
}
}
@@ -914,6 +1025,12 @@ pub(crate) struct Report {
additional_message_ids: Vec<String>,
}
#[derive(Debug)]
pub(crate) struct FailureReport {
pub rfc724_mid: String,
pub failed_recipient: Option<String>,
}
pub(crate) fn parse_message_ids(ids: &str) -> Result<Vec<String>> {
// take care with mailparse::msgidparse() that is pretty untolerant eg. wrt missing `<` or `>`
let mut msgids = Vec::new();
@@ -957,6 +1074,7 @@ pub struct Part {
pub bytes: usize,
pub param: Params,
org_filename: Option<String>,
pub error: String,
}
/// return mimetype and viewtype for a parsed mail
@@ -1119,7 +1237,7 @@ mod tests {
#[async_std::test]
async fn test_dc_mimeparser_crash() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/issue_523.txt");
let mimeparser = MimeMessage::from_bytes(&context.ctx, &raw[..])
.await
@@ -1131,7 +1249,7 @@ mod tests {
#[async_std::test]
async fn test_get_rfc724_mid_exists() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/mail_with_message_id.txt");
let mimeparser = MimeMessage::from_bytes(&context.ctx, &raw[..])
.await
@@ -1145,7 +1263,7 @@ mod tests {
#[async_std::test]
async fn test_get_rfc724_mid_not_exists() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = include_bytes!("../test-data/message/issue_523.txt");
let mimeparser = MimeMessage::from_bytes(&context.ctx, &raw[..])
.await
@@ -1203,7 +1321,7 @@ mod tests {
#[async_std::test]
async fn test_parse_first_addr() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"From: hello@one.org, world@two.org\n\
Chat-Disposition-Notification-To: wrong\n\
Content-Type: text/plain\n\
@@ -1224,7 +1342,7 @@ mod tests {
#[async_std::test]
async fn test_mimeparser_with_context() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"From: hello\n\
Content-Type: multipart/mixed; boundary=\"==break==\";\n\
Subject: outer-subject\n\
@@ -1274,7 +1392,7 @@ mod tests {
#[async_std::test]
async fn test_mimeparser_with_avatars() {
let t = dummy_context().await;
let t = TestContext::new().await;
let raw = include_bytes!("../test-data/message/mail_attach_txt.eml");
let mimeparser = MimeMessage::from_bytes(&t.ctx, &raw[..]).await.unwrap();
@@ -1317,7 +1435,7 @@ mod tests {
#[async_std::test]
async fn test_mimeparser_message_kml() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"Chat-Version: 1.0\n\
From: foo <foo@example.org>\n\
To: bar <bar@example.org>\n\
@@ -1362,7 +1480,7 @@ Content-Disposition: attachment; filename=\"message.kml\"\n\
#[async_std::test]
async fn test_parse_mdn() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
Date: Mon, 10 Jan 2020 00:00:00 +0000\n\
Chat-Version: 1.0\n\
@@ -1403,7 +1521,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
);
assert_eq!(message.parts.len(), 1);
assert_eq!(message.reports.len(), 1);
assert_eq!(message.mdn_reports.len(), 1);
}
/// Test parsing multiple MDNs combined in a single message.
@@ -1412,7 +1530,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
/// multipart MIME messages.
#[async_std::test]
async fn test_parse_multiple_mdns() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
Date: Mon, 10 Jan 2020 00:00:00 +0000\n\
Chat-Version: 1.0\n\
@@ -1483,12 +1601,12 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
);
assert_eq!(message.parts.len(), 2);
assert_eq!(message.reports.len(), 2);
assert_eq!(message.mdn_reports.len(), 2);
}
#[async_std::test]
async fn test_parse_mdn_with_additional_message_ids() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\
Date: Mon, 10 Jan 2020 00:00:00 +0000\n\
Chat-Version: 1.0\n\
@@ -1530,17 +1648,20 @@ Additional-Message-IDs: <foo@example.com> <foo@example.net>\n\
);
assert_eq!(message.parts.len(), 1);
assert_eq!(message.reports.len(), 1);
assert_eq!(message.reports[0].original_message_id, "foo@example.org");
assert_eq!(message.mdn_reports.len(), 1);
assert_eq!(
&message.reports[0].additional_message_ids,
message.mdn_reports[0].original_message_id,
"foo@example.org"
);
assert_eq!(
&message.mdn_reports[0].additional_message_ids,
&["foo@example.com", "foo@example.net"]
);
}
#[async_std::test]
async fn test_parse_inline_attachment() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = br#"Date: Thu, 13 Feb 2020 22:41:20 +0000 (UTC)
From: sender@example.com
To: receiver@example.com
@@ -1580,7 +1701,7 @@ MDYyMDYxNTE1RTlDOEE4Cj4+CnN0YXJ0eHJlZgo4Mjc4CiUlRU9GCg==
#[async_std::test]
async fn parse_inline_image() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = br#"Message-ID: <foobar@example.org>
From: foo <foo@example.org>
Subject: example
@@ -1626,7 +1747,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I=
#[async_std::test]
async fn parse_thunderbird_html_embedded_image() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = br#"To: Alice <alice@example.org>
From: Bob <bob@example.org>
Subject: Test subject
@@ -1699,7 +1820,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I=
// Outlook specifies filename in the "name" attribute of Content-Type
#[async_std::test]
async fn parse_outlook_html_embedded_image() {
let context = dummy_context().await;
let context = TestContext::new().await;
let raw = br##"From: Anonymous <anonymous@example.org>
To: Anonymous <anonymous@example.org>
Subject: Delta Chat is great stuff!

View File

@@ -1,12 +1,16 @@
//! OAuth 2 module
use regex::Regex;
use std::collections::HashMap;
use async_std_resolver::{config, resolver};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use serde::Deserialize;
use crate::context::Context;
use crate::dc_tools::*;
use crate::provider;
use crate::provider::Oauth2Authorizer;
const OAUTH2_GMAIL: Oauth2 = Oauth2 {
// see https://developers.google.com/identity/protocols/OAuth2InstalledApp
@@ -15,6 +19,7 @@ const OAUTH2_GMAIL: Oauth2 = Oauth2 {
init_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=authorization_code",
refresh_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token",
get_userinfo: Some("https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=$ACCESS_TOKEN"),
mx_pattern: Some(r"^aspmx\.l\.google\.com\.$"),
};
const OAUTH2_YANDEX: Oauth2 = Oauth2 {
@@ -24,8 +29,11 @@ const OAUTH2_YANDEX: Oauth2 = Oauth2 {
init_token: "https://oauth.yandex.com/token?grant_type=authorization_code&code=$CODE&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
refresh_token: "https://oauth.yandex.com/token?grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
get_userinfo: None,
mx_pattern: None,
};
const OAUTH2_PROVIDERS: [Oauth2; 1] = [OAUTH2_GMAIL];
#[derive(Debug, Clone, PartialEq, Eq)]
struct Oauth2 {
client_id: &'static str,
@@ -33,6 +41,7 @@ struct Oauth2 {
init_token: &'static str,
refresh_token: &'static str,
get_userinfo: Option<&'static str>,
mx_pattern: Option<&'static str>,
}
/// OAuth 2 Access Token Response
@@ -53,7 +62,7 @@ pub async fn dc_get_oauth2_url(
addr: impl AsRef<str>,
redirect_uri: impl AsRef<str>,
) -> Option<String> {
if let Some(oauth2) = Oauth2::from_address(addr) {
if let Some(oauth2) = Oauth2::from_address(addr).await {
if context
.sql
.set_raw_config(
@@ -81,7 +90,7 @@ pub async fn dc_get_oauth2_access_token(
code: impl AsRef<str>,
regenerate: bool,
) -> Option<String> {
if let Some(oauth2) = Oauth2::from_address(addr) {
if let Some(oauth2) = Oauth2::from_address(addr).await {
let lock = context.oauth2_mutex.lock().await;
// read generated token
@@ -239,7 +248,7 @@ pub async fn dc_get_oauth2_addr(
addr: impl AsRef<str>,
code: impl AsRef<str>,
) -> Option<String> {
let oauth2 = Oauth2::from_address(addr.as_ref())?;
let oauth2 = Oauth2::from_address(addr.as_ref()).await?;
oauth2.get_userinfo?;
if let Some(access_token) =
@@ -263,23 +272,56 @@ pub async fn dc_get_oauth2_addr(
}
impl Oauth2 {
fn from_address(addr: impl AsRef<str>) -> Option<Self> {
async fn from_address(addr: impl AsRef<str>) -> Option<Self> {
let addr_normalized = normalize_addr(addr.as_ref());
if let Some(domain) = addr_normalized
.find('@')
.map(|index| addr_normalized.split_at(index + 1).1)
{
match domain {
"gmail.com" | "googlemail.com" => Some(OAUTH2_GMAIL),
"yandex.com" | "yandex.by" | "yandex.kz" | "yandex.ru" | "yandex.ua" | "ya.ru"
| "narod.ru" => Some(OAUTH2_YANDEX),
_ => None,
if let Some(provider) = provider::get_provider_info(&addr_normalized) {
match &provider.oauth2_authorizer {
Some(Oauth2Authorizer::Gmail) => Some(OAUTH2_GMAIL),
Some(Oauth2Authorizer::Yandex) => Some(OAUTH2_YANDEX),
None => None, // provider known to not support oauth2, no mx-lookup required
}
} else {
Oauth2::lookup_mx(domain).await
}
} else {
None
}
}
async fn lookup_mx(domain: impl AsRef<str>) -> Option<Self> {
if let Ok(resolver) = resolver(
config::ResolverConfig::default(),
config::ResolverOpts::default(),
)
.await
{
for provider in OAUTH2_PROVIDERS.iter() {
if let Some(pattern) = provider.mx_pattern {
let re = Regex::new(pattern).unwrap();
let mut fqdn: String = String::from(domain.as_ref());
if !fqdn.ends_with('.') {
fqdn.push_str(".");
}
if let Ok(res) = resolver.mx_lookup(fqdn).await {
for rr in res.iter() {
if re.is_match(&rr.exchange().to_lowercase().to_utf8()) {
return Some(provider.clone());
}
}
}
}
}
}
None
}
async fn get_addr(&self, context: &Context, access_token: impl AsRef<str>) -> Option<String> {
let userinfo_url = self.get_userinfo.unwrap_or_else(|| "");
let userinfo_url = replace_in_uri(&userinfo_url, "$ACCESS_TOKEN", access_token);
@@ -362,25 +404,39 @@ mod tests {
);
}
#[test]
fn test_oauth_from_address() {
assert_eq!(Oauth2::from_address("hello@gmail.com"), Some(OAUTH2_GMAIL));
#[async_std::test]
async fn test_oauth_from_address() {
assert_eq!(
Oauth2::from_address("hello@googlemail.com"),
Oauth2::from_address("hello@gmail.com").await,
Some(OAUTH2_GMAIL)
);
assert_eq!(
Oauth2::from_address("hello@yandex.com"),
Oauth2::from_address("hello@googlemail.com").await,
Some(OAUTH2_GMAIL)
);
assert_eq!(
Oauth2::from_address("hello@yandex.com").await,
Some(OAUTH2_YANDEX)
);
assert_eq!(
Oauth2::from_address("hello@yandex.ru").await,
Some(OAUTH2_YANDEX)
);
assert_eq!(Oauth2::from_address("hello@yandex.ru"), Some(OAUTH2_YANDEX));
assert_eq!(Oauth2::from_address("hello@web.de"), None);
assert_eq!(Oauth2::from_address("hello@web.de").await, None);
}
#[async_std::test]
async fn test_oauth_from_mx() {
assert_eq!(
Oauth2::from_address("hello@google.com").await,
Some(OAUTH2_GMAIL)
);
}
#[async_std::test]
async fn test_dc_get_oauth2_addr() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";
let code = "fail";
let res = dc_get_oauth2_addr(&ctx.ctx, addr, code).await;
@@ -390,7 +446,7 @@ mod tests {
#[async_std::test]
async fn test_dc_get_oauth2_url() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";
let redirect_uri = "chat.delta:/com.b44t.messenger";
let res = dc_get_oauth2_url(&ctx.ctx, addr, redirect_uri).await;
@@ -400,7 +456,7 @@ mod tests {
#[async_std::test]
async fn test_dc_get_oauth2_token() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let addr = "dignifiedquire@gmail.com";
let code = "fail";
let res = dc_get_oauth2_access_token(&ctx.ctx, addr, code, false).await;

View File

@@ -65,9 +65,6 @@ pub enum Param {
/// For Messages
Arg4 = b'H',
/// For Messages
Error = b'L',
/// For Messages
AttachGroupImage = b'A',
@@ -417,7 +414,7 @@ mod tests {
#[async_std::test]
async fn test_params_file_fs_path() {
let t = dummy_context().await;
let t = TestContext::new().await;
if let ParamsFile::FsPath(p) = ParamsFile::from_param(&t.ctx, "/foo/bar/baz").unwrap() {
assert_eq!(p, Path::new("/foo/bar/baz"));
} else {
@@ -427,7 +424,7 @@ mod tests {
#[async_std::test]
async fn test_params_file_blob() {
let t = dummy_context().await;
let t = TestContext::new().await;
if let ParamsFile::Blob(b) = ParamsFile::from_param(&t.ctx, "$BLOBDIR/foo").unwrap() {
assert_eq!(b.as_name(), "$BLOBDIR/foo");
} else {
@@ -438,7 +435,7 @@ mod tests {
// Tests for Params::get_file(), Params::get_path() and Params::get_blob().
#[async_std::test]
async fn test_params_get_fileparam() {
let t = dummy_context().await;
let t = TestContext::new().await;
let fname = t.dir.path().join("foo");
let mut p = Params::new();
p.set(Param::File, fname.to_str().unwrap());

View File

@@ -450,14 +450,11 @@ impl<'a> Peerstate<'a> {
}
pub fn has_verified_key(&self, fingerprints: &HashSet<Fingerprint>) -> bool {
if self.verified_key.is_some() && self.verified_key_fingerprint.is_some() {
let vkc = self.verified_key_fingerprint.as_ref().unwrap();
if fingerprints.contains(vkc) {
return true;
}
if let Some(vkc) = &self.verified_key_fingerprint {
fingerprints.contains(vkc) && self.verified_key.is_some()
} else {
false
}
false
}
}
@@ -476,7 +473,7 @@ mod tests {
#[async_std::test]
async fn test_peerstate_save_to_db() {
let ctx = crate::test_utils::dummy_context().await;
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
let pub_key = alice_keypair().public;
@@ -519,7 +516,7 @@ mod tests {
#[async_std::test]
async fn test_peerstate_double_create() {
let ctx = crate::test_utils::dummy_context().await;
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
let pub_key = alice_keypair().public;
@@ -552,7 +549,7 @@ mod tests {
#[async_std::test]
async fn test_peerstate_with_empty_gossip_key_save_to_db() {
let ctx = crate::test_utils::dummy_context().await;
let ctx = crate::test_utils::TestContext::new().await;
let addr = "hello@mail.com";
let pub_key = alice_keypair().public;

View File

@@ -272,6 +272,14 @@ pub async fn pk_encrypt(
.await
}
/// Decrypts the message with keys from the private key keyring.
///
/// Receiver private keys are provided in
/// `private_keys_for_decryption`.
///
/// If `ret_signature_fingerprints` is not `None`, stores fingerprints
/// of all keys from the `public_keys_for_validation` keyring that
/// have valid signatures there.
#[allow(clippy::implicit_hasher)]
pub async fn pk_decrypt(
ctext: Vec<u8>,
@@ -290,36 +298,41 @@ pub async fn pk_decrypt(
})
.await?;
ensure!(!msgs.is_empty(), "No valid messages found");
if let Some(msg) = msgs.into_iter().next() {
// get_content() will decompress the message if needed,
// but this avoids decompressing it again to check signatures
let msg = msg.decompress()?;
let content = match msgs[0].get_content()? {
Some(content) => content,
None => bail!("Decrypted message is empty"),
};
let content = match msg.get_content()? {
Some(content) => content,
None => bail!("The decrypted message is empty"),
};
if let Some(ret_signature_fingerprints) = ret_signature_fingerprints {
if !public_keys_for_validation.is_empty() {
let fingerprints = async_std::task::spawn_blocking(move || {
let dec_msg = &msgs[0];
if let Some(ret_signature_fingerprints) = ret_signature_fingerprints {
if !public_keys_for_validation.is_empty() {
let fingerprints = async_std::task::spawn_blocking(move || {
let pkeys = public_keys_for_validation.keys();
let pkeys = public_keys_for_validation.keys();
let mut fingerprints: Vec<Fingerprint> = Vec::new();
for pkey in pkeys {
if dec_msg.verify(&pkey.primary_key).is_ok() {
let fp = DcKey::fingerprint(pkey);
fingerprints.push(fp);
let mut fingerprints: Vec<Fingerprint> = Vec::new();
if let signed_msg @ pgp::composed::Message::Signed { .. } = msg {
for pkey in pkeys {
if signed_msg.verify(&pkey.primary_key).is_ok() {
let fp = DcKey::fingerprint(pkey);
fingerprints.push(fp);
}
}
}
}
fingerprints
})
.await;
fingerprints
})
.await;
ret_signature_fingerprints.extend(fingerprints);
ret_signature_fingerprints.extend(fingerprints);
}
}
Ok(content)
} else {
bail!("No valid messages found");
}
Ok(content)
}
/// Symmetric encryption.

View File

@@ -20,6 +20,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// aol.md: aol.com
@@ -32,6 +33,22 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// arcor.de.md: arcor.de
static ref P_ARCOR_DE: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/arcor-de",
server: vec![
Server { protocol: IMAP, socket: SSL, hostname: "imap.arcor.de", port: 993, username_pattern: EMAIL },
Server { protocol: SMTP, socket: SSL, hostname: "mail.arcor.de", port: 465, username_pattern: EMAIL },
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// autistici.org.md: autistici.org
@@ -46,6 +63,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// bluewin.ch.md: bluewin.ch
@@ -60,6 +78,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// chello.at.md: chello.at
@@ -74,13 +93,34 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// comcast.md: xfinity.com, comcast.net
// - skipping provider with status OK and no special things to do
static ref P_COMCAST: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/comcast",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// dismail.de.md: dismail.de
// - skipping provider with status OK and no special things to do
static ref P_DISMAIL_DE: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/dismail-de",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// disroot.md: disroot.org
static ref P_DISROOT: Provider = Provider {
@@ -92,6 +132,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// example.com.md: example.com, example.org
@@ -106,6 +147,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// fastmail.md: fastmail.com
@@ -118,6 +160,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// five.chat.md: five.chat
@@ -130,6 +173,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// freenet.de.md: freenet.de
@@ -144,6 +188,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// gmail.md: gmail.com, googlemail.com
@@ -158,6 +203,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: Some(Oauth2Authorizer::Gmail),
};
// gmx.net.md: gmx.net, gmx.de, gmx.at, gmx.ch, gmx.org, gmx.eu, gmx.info, gmx.biz, gmx.com
@@ -173,10 +219,21 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// i.ua.md: i.ua
// - skipping provider with status OK and no special things to do
static ref P_I_UA: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/i-ua",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// icloud.md: icloud.com, me.com, mac.com
static ref P_ICLOUD: Provider = Provider {
@@ -190,16 +247,47 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// kolst.com.md: kolst.com
// - skipping provider with status OK and no special things to do
static ref P_KOLST_COM: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/kolst-com",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// kontent.com.md: kontent.com
// - skipping provider with status OK and no special things to do
static ref P_KONTENT_COM: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/kontent-com",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// mail.ru.md: mail.ru, inbox.ru, bk.ru, list.ru
// - skipping provider with status OK and no special things to do
static ref P_MAIL_RU: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/mail-ru",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// mailbox.org.md: mailbox.org, secure.mailbox.org
static ref P_MAILBOX_ORG: Provider = Provider {
@@ -211,6 +299,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// nauta.cu.md: nauta.cu
@@ -233,6 +322,7 @@ lazy_static::lazy_static! {
ConfigDefault { key: Config::MediaQuality, value: "1" },
]),
strict_tls: false,
oauth2_authorizer: None,
};
// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com
@@ -247,6 +337,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// posteo.md: posteo.de, posteo.af, posteo.at, posteo.be, posteo.ch, posteo.cl, posteo.co, posteo.co.uk, posteo.com.br, posteo.cr, posteo.cz, posteo.dk, posteo.ee, posteo.es, posteo.eu, posteo.fi, posteo.gl, posteo.gr, posteo.hn, posteo.hr, posteo.hu, posteo.ie, posteo.in, posteo.is, posteo.jp, posteo.la, posteo.li, posteo.lt, posteo.lu, posteo.me, posteo.mx, posteo.my, posteo.net, posteo.nl, posteo.no, posteo.nz, posteo.org, posteo.pe, posteo.pl, posteo.pm, posteo.pt, posteo.ro, posteo.ru, posteo.se, posteo.sg, posteo.si, posteo.tn, posteo.uk, posteo.us
@@ -261,6 +352,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// protonmail.md: protonmail.com, protonmail.ch
@@ -273,6 +365,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// riseup.net.md: riseup.net
@@ -285,10 +378,21 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// rogers.com.md: rogers.com
// - skipping provider with status OK and no special things to do
static ref P_ROGERS_COM: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/rogers-com",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// systemli.org.md: systemli.org
static ref P_SYSTEMLI_ORG: Provider = Provider {
@@ -300,6 +404,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// t-online.md: t-online.de, magenta.de
@@ -312,6 +417,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// testrun.md: testrun.org
@@ -327,6 +433,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: None,
};
// tiscali.it.md: tiscali.it
@@ -341,13 +448,34 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// ukr.net.md: ukr.net
// - skipping provider with status OK and no special things to do
static ref P_UKR_NET: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/ukr-net",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// vfemail.md: vfemail.net
// - skipping provider with status OK and no special things to do
static ref P_VFEMAIL: Provider = Provider {
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/vfemail",
server: vec![
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// web.de.md: web.de, email.de, flirt.ms, hallo.ms, kuss.ms, love.ms, magic.ms, singles.ms, cool.ms, kanzler.ms, okay.ms, party.ms, pop.ms, stars.ms, techno.ms, clever.ms, deutschland.ms, genial.ms, ich.ms, online.ms, smart.ms, wichtig.ms, action.ms, fussball.ms, joker.ms, planet.ms, power.ms
static ref P_WEB_DE: Provider = Provider {
@@ -362,6 +490,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, ymail.com, rocketmail.com, yahoodns.net
@@ -376,9 +505,10 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
// yandex.ru.md: yandex.ru, yandex.com
// yandex.ru.md: yandex.com, yandex.by, yandex.kz, yandex.ru, yandex.ua, ya.ru, narod.ru
static ref P_YANDEX_RU: Provider = Provider {
status: Status::PREPARATION,
before_login_hint: "For Yandex accounts, you have to set IMAP protocol option turned on.",
@@ -388,6 +518,7 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: true,
oauth2_authorizer: Some(Oauth2Authorizer::Yandex),
};
// ziggo.nl.md: ziggo.nl
@@ -402,14 +533,19 @@ lazy_static::lazy_static! {
],
config_defaults: None,
strict_tls: false,
oauth2_authorizer: None,
};
pub static ref PROVIDER_DATA: HashMap<&'static str, &'static Provider> = [
("aktivix.org", &*P_AKTIVIX_ORG),
("aol.com", &*P_AOL),
("arcor.de", &*P_ARCOR_DE),
("autistici.org", &*P_AUTISTICI_ORG),
("bluewin.ch", &*P_BLUEWIN_CH),
("chello.at", &*P_CHELLO_AT),
("xfinity.com", &*P_COMCAST),
("comcast.net", &*P_COMCAST),
("dismail.de", &*P_DISMAIL_DE),
("disroot.org", &*P_DISROOT),
("example.com", &*P_EXAMPLE_COM),
("example.org", &*P_EXAMPLE_COM),
@@ -427,9 +563,16 @@ lazy_static::lazy_static! {
("gmx.info", &*P_GMX_NET),
("gmx.biz", &*P_GMX_NET),
("gmx.com", &*P_GMX_NET),
("i.ua", &*P_I_UA),
("icloud.com", &*P_ICLOUD),
("me.com", &*P_ICLOUD),
("mac.com", &*P_ICLOUD),
("kolst.com", &*P_KOLST_COM),
("kontent.com", &*P_KONTENT_COM),
("mail.ru", &*P_MAIL_RU),
("inbox.ru", &*P_MAIL_RU),
("bk.ru", &*P_MAIL_RU),
("list.ru", &*P_MAIL_RU),
("mailbox.org", &*P_MAILBOX_ORG),
("secure.mailbox.org", &*P_MAILBOX_ORG),
("nauta.cu", &*P_NAUTA_CU),
@@ -490,11 +633,14 @@ lazy_static::lazy_static! {
("protonmail.com", &*P_PROTONMAIL),
("protonmail.ch", &*P_PROTONMAIL),
("riseup.net", &*P_RISEUP_NET),
("rogers.com", &*P_ROGERS_COM),
("systemli.org", &*P_SYSTEMLI_ORG),
("t-online.de", &*P_T_ONLINE),
("magenta.de", &*P_T_ONLINE),
("testrun.org", &*P_TESTRUN),
("tiscali.it", &*P_TISCALI_IT),
("ukr.net", &*P_UKR_NET),
("vfemail.net", &*P_VFEMAIL),
("web.de", &*P_WEB_DE),
("email.de", &*P_WEB_DE),
("flirt.ms", &*P_WEB_DE),
@@ -537,8 +683,13 @@ lazy_static::lazy_static! {
("ymail.com", &*P_YAHOO),
("rocketmail.com", &*P_YAHOO),
("yahoodns.net", &*P_YAHOO),
("yandex.ru", &*P_YANDEX_RU),
("yandex.com", &*P_YANDEX_RU),
("yandex.by", &*P_YANDEX_RU),
("yandex.kz", &*P_YANDEX_RU),
("yandex.ru", &*P_YANDEX_RU),
("yandex.ua", &*P_YANDEX_RU),
("ya.ru", &*P_YANDEX_RU),
("narod.ru", &*P_YANDEX_RU),
("ziggo.nl", &*P_ZIGGO_NL),
].iter().copied().collect();
}

View File

@@ -35,6 +35,13 @@ pub enum UsernamePattern {
EMAILLOCALPART = 2,
}
#[derive(Debug, PartialEq)]
#[repr(u8)]
pub enum Oauth2Authorizer {
Yandex = 1,
Gmail = 2,
}
#[derive(Debug)]
pub struct Server {
pub protocol: Protocol,
@@ -73,6 +80,7 @@ pub struct Provider {
pub server: Vec<Server>,
pub config_defaults: Option<Vec<ConfigDefault>>,
pub strict_tls: bool,
pub oauth2_authorizer: Option<Oauth2Authorizer>,
}
impl Provider {

View File

@@ -103,6 +103,9 @@ def process_data(data, file):
strict_tls = data.get("strict_tls", False)
strict_tls = "true" if strict_tls else "false"
oauth2 = data.get("oauth2", "")
oauth2 = "Some(Oauth2Authorizer::" + camel(oauth2) + ")" if oauth2 != "" else "None"
provider = ""
before_login_hint = cleanstr(data.get("before_login_hint", ""))
after_login_hint = cleanstr(data.get("after_login_hint", ""))
@@ -115,6 +118,7 @@ def process_data(data, file):
provider += " server: vec![\n" + server + " ],\n"
provider += " config_defaults: " + config_defaults + ",\n"
provider += " strict_tls: " + strict_tls + ",\n"
provider += " oauth2_authorizer: " + oauth2 + ",\n"
provider += " };\n\n"
else:
raise TypeError("SMTP and IMAP must be specified together or left out both")
@@ -125,11 +129,11 @@ def process_data(data, file):
# finally, add the provider
global out_all, out_domains
out_all += " // " + file[file.rindex("/")+1:] + ": " + comment.strip(", ") + "\n"
if status == "OK" and before_login_hint == "" and after_login_hint == "" and server == "" and config_defaults == "None" and strict_tls == "false":
out_all += " // - skipping provider with status OK and no special things to do\n\n"
else:
out_all += provider
out_domains += domains
# also add provider with no special things to do -
# eg. _not_ supporting oauth2 is also an information and we can skip the mx-lookup in this case
out_all += provider
out_domains += domains
def process_file(file):

View File

@@ -383,11 +383,11 @@ fn normalize_address(addr: &str) -> Result<String, Error> {
mod tests {
use super::*;
use crate::test_utils::dummy_context;
use crate::test_utils::TestContext;
#[async_std::test]
async fn test_decode_http() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(&ctx.ctx, "http://www.hello.com").await;
@@ -399,7 +399,7 @@ mod tests {
#[async_std::test]
async fn test_decode_https() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(&ctx.ctx, "https://www.hello.com").await;
@@ -411,7 +411,7 @@ mod tests {
#[async_std::test]
async fn test_decode_text() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(&ctx.ctx, "I am so cool").await;
@@ -423,7 +423,7 @@ mod tests {
#[async_std::test]
async fn test_decode_vcard() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -441,7 +441,7 @@ mod tests {
#[async_std::test]
async fn test_decode_matmsg() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -459,7 +459,7 @@ mod tests {
#[async_std::test]
async fn test_decode_mailto() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -485,7 +485,7 @@ mod tests {
#[async_std::test]
async fn test_decode_smtp() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(&ctx.ctx, "SMTP:stress@test.local:subjecthello:bodyworld").await;
@@ -499,7 +499,7 @@ mod tests {
#[async_std::test]
async fn test_decode_openpgp_group() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -528,7 +528,7 @@ mod tests {
#[async_std::test]
async fn test_decode_openpgp_secure_join() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -556,7 +556,7 @@ mod tests {
#[async_std::test]
async fn test_decode_openpgp_without_addr() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -591,7 +591,7 @@ mod tests {
#[async_std::test]
async fn test_decode_account() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
@@ -613,7 +613,7 @@ mod tests {
#[async_std::test]
async fn test_decode_account_bad_scheme() {
let ctx = dummy_context().await;
let ctx = TestContext::new().await;
let res = check_qr(
&ctx.ctx,
"DCACCOUNT:http://example.org/new_email?t=1w_7wDjgjelxeX884x96v3",

View File

@@ -1,3 +1,5 @@
#![warn(clippy::indexing_slicing)]
use async_std::prelude::*;
use async_std::sync::{channel, Receiver, Sender};
use async_std::task;

View File

@@ -114,7 +114,7 @@ pub async fn dc_get_securejoin_qr(context: &Context, group_chat_id: ChatId) -> O
Some(format!(
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
fingerprint,
fingerprint.hex(),
self_addr_urlencoded,
&group_name_urlencoded,
&chat.grpid,
@@ -129,7 +129,11 @@ pub async fn dc_get_securejoin_qr(context: &Context, group_chat_id: ChatId) -> O
// parameters used: a=n=i=s=
Some(format!(
"OPENPGP4FPR:{}#a={}&n={}&i={}&s={}",
fingerprint, self_addr_urlencoded, self_name_urlencoded, &invitenumber, &auth,
fingerprint.hex(),
self_addr_urlencoded,
self_name_urlencoded,
&invitenumber,
&auth,
))
};

View File

@@ -1,5 +1,7 @@
//! # SMTP transport module
#![forbid(clippy::indexing_slicing)]
pub mod send;
use std::time::{Duration, Instant};

View File

@@ -1241,6 +1241,15 @@ async fn open(
.await?;
sql.set_raw_config_int(context, "dbversion", 63).await?;
}
if dbversion < 64 {
info!(context, "[migration] v64");
sql.execute(
"ALTER TABLE msgs ADD COLUMN error TEXT DEFAULT '';",
paramsv![],
)
.await?;
sql.set_raw_config_int(context, "dbversion", 64).await?;
}
// (2) updates that require high-level objects
// (the structure is complete now and all objects are usable)

View File

@@ -182,6 +182,9 @@ pub enum StockMessage {
#[strum(props(fallback = "Message from %1$s"))]
SubjectForNewContact = 73,
#[strum(props(fallback = "Failed to send message to %1$s."))]
FailedSendingTo = 74,
}
/*
@@ -406,7 +409,7 @@ mod tests {
#[async_std::test]
async fn test_set_stock_translation() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx
.set_stock_translation(StockMessage::NoMessages, "xyz".to_string())
.await
@@ -416,7 +419,7 @@ mod tests {
#[async_std::test]
async fn test_set_stock_translation_wrong_replacements() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert!(t
.ctx
.set_stock_translation(StockMessage::NoMessages, "xyz %1$s ".to_string())
@@ -431,7 +434,7 @@ mod tests {
#[async_std::test]
async fn test_stock_str() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx.stock_str(StockMessage::NoMessages).await,
"No messages."
@@ -440,7 +443,7 @@ mod tests {
#[async_std::test]
async fn test_stock_string_repl_str() {
let t = dummy_context().await;
let t = TestContext::new().await;
// uses %1$s substitution
assert_eq!(
t.ctx
@@ -453,7 +456,7 @@ mod tests {
#[async_std::test]
async fn test_stock_string_repl_int() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx
.stock_string_repl_int(StockMessage::MsgAddMember, 42)
@@ -464,7 +467,7 @@ mod tests {
#[async_std::test]
async fn test_stock_string_repl_str2() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx
.stock_string_repl_str2(StockMessage::ServerResponse, "foo", "bar")
@@ -475,7 +478,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_simple() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx
.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0)
@@ -486,7 +489,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_add_member_by_me() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx
.stock_system_msg(
@@ -502,7 +505,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_add_member_by_me_with_displayname() {
let t = dummy_context().await;
let t = TestContext::new().await;
Contact::create(&t.ctx, "Alice", "alice@example.com")
.await
.expect("failed to create contact");
@@ -521,7 +524,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_add_member_by_other_with_displayname() {
let t = dummy_context().await;
let t = TestContext::new().await;
let contact_id = {
Contact::create(&t.ctx, "Alice", "alice@example.com")
.await
@@ -545,7 +548,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_grp_name() {
let t = dummy_context().await;
let t = TestContext::new().await;
assert_eq!(
t.ctx
.stock_system_msg(
@@ -561,7 +564,7 @@ mod tests {
#[async_std::test]
async fn test_stock_system_msg_grp_name_other() {
let t = dummy_context().await;
let t = TestContext::new().await;
let id = Contact::create(&t.ctx, "Alice", "alice@example.com")
.await
.expect("failed to create contact");
@@ -576,7 +579,7 @@ mod tests {
#[async_std::test]
async fn test_update_device_chats() {
let t = dummy_context().await;
let t = TestContext::new().await;
t.ctx.update_device_chats().await.ok();
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
assert_eq!(chats.len(), 2);

View File

@@ -18,43 +18,59 @@ pub(crate) struct TestContext {
pub dir: TempDir,
}
/// Create a new, opened [TestContext] using given callback.
///
/// The [Context] will be opened with the SQLite database named
/// "db.sqlite" in the [TestContext.dir] directory.
///
/// [Context]: crate::context::Context
pub(crate) async fn test_context() -> TestContext {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
let ctx = Context::new("FakeOs".into(), dbfile.into()).await.unwrap();
TestContext { ctx, dir }
}
impl TestContext {
/// Create a new [TestContext].
///
/// The [Context] will be created and have an SQLite database named "db.sqlite" in the
/// [TestContext.dir] directory. This directory is cleaned up when the [TestContext] is
/// dropped.
///
/// [Context]: crate::context::Context
pub async fn new() -> Self {
let dir = tempdir().unwrap();
let dbfile = dir.path().join("db.sqlite");
let ctx = Context::new("FakeOS".into(), dbfile.into()).await.unwrap();
Self { ctx, dir }
}
/// Return a dummy [TestContext].
///
/// The context will be opened and use the SQLite database as
/// specified in [test_context] but there is no callback hooked up,
/// i.e. [Context::call_cb] will always return `0`.
pub(crate) async fn dummy_context() -> TestContext {
test_context().await
}
/// Create a new configured [TestContext].
///
/// This is a shortcut which automatically calls [TestContext::configure_alice] after
/// creating the context.
pub async fn new_alice() -> Self {
let t = Self::new().await;
t.configure_alice().await;
t
}
pub(crate) async fn configured_offline_context() -> TestContext {
let t = dummy_context().await;
t.ctx
.set_config(Config::Addr, Some("alice@example.org"))
.await
.unwrap();
t.ctx
.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.await
.unwrap();
t.ctx
.set_config(Config::Configured, Some("1"))
.await
.unwrap();
t
/// Configure with alice@example.com.
///
/// The context will be fake-configured as the alice user, with a pre-generated secret
/// key. The email address of the user is returned as a string.
pub async fn configure_alice(&self) -> String {
let keypair = alice_keypair();
self.configure_addr(&keypair.addr.to_string()).await;
key::store_self_keypair(&self.ctx, &keypair, key::KeyPairUse::Default)
.await
.expect("Failed to save Alice's key");
keypair.addr.to_string()
}
/// Configure as a given email address.
///
/// The context will be configured but the key will not be pre-generated so if a key is
/// used the fingerprint will be different every time.
pub async fn configure_addr(&self, addr: &str) {
self.ctx.set_config(Config::Addr, Some(addr)).await.unwrap();
self.ctx
.set_config(Config::ConfiguredAddr, Some(addr))
.await
.unwrap();
self.ctx
.set_config(Config::Configured, Some("1"))
.await
.unwrap();
}
}
/// Load a pre-generated keypair for alice@example.com from disk.
@@ -77,20 +93,6 @@ pub(crate) fn alice_keypair() -> key::KeyPair {
}
}
/// Creates Alice with a pre-generated keypair.
///
/// Returns the address of the keypair created (alice@example.com).
pub(crate) async fn configure_alice_keypair(ctx: &Context) -> String {
let keypair = alice_keypair();
ctx.set_config(Config::ConfiguredAddr, Some(&keypair.addr.to_string()))
.await
.unwrap();
key::store_self_keypair(&ctx, &keypair, key::KeyPairUse::Default)
.await
.expect("Failed to save Alice's key");
keypair.addr.to_string()
}
/// Load a pre-generated keypair for bob@example.net from disk.
///
/// Like [alice_keypair] but a different key and identity.

View File

@@ -0,0 +1,242 @@
Delivered-To: alice@gmail.com
Received: by 2002:a1c:b4d7:0:0:0:0:0 with SMTP id d206csp3026053wmf;
Mon, 18 May 2020 09:23:25 -0700 (PDT)
X-Received: by 2002:a5d:4651:: with SMTP id j17mr19532177wrs.50.1589819005555;
Mon, 18 May 2020 09:23:25 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1589819005; cv=none;
d=google.com; s=arc-20160816;
b=IZbNnzzuYzTFuqfuZwpd3ehqpYYGpn31c8DsfGbQ8rpbS0OTTROkVYvihQl8Ne/8X/
brEWsrcmaCh9WpFMzpI+cp/TY39uusnI6qdp5rcgrFmFgoANtwf3TBBj1+f7wBPn46BP
dQOUsg/J8KVfvzVgvL1x4uyJ0m9QirDgJeJ/BvrswbTleRQK7oY3fIireUCDxj6r2lCB
1Z0TKw1mgIb1LiFMZz8kvCNn3R4KSFnwS8rIju0hYwnsioNiExVQgumXL+RVkEZ9BMzf
UdoWIAw3VW+MOZFTpfLCEfgIPtLg/gtE0Q1P+a3KKpi8dkPiV2n6DGMecy9lTLtdhCXt
pnaA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=in-reply-to:references:subject:from:date:message-id:auto-submitted
:to:dkim-signature;
bh=5xjZvcHbEGbMY0K2QB+3U6tpm1L1LAVv5h1pd4YXDEE=;
b=nNP0DktrSjdBaFfhhoDi2O9KVKM0iXE5ZgubQ0q0ff68Z6Ke7c8dDBXEsZoToI0s4Y
w90KyJFpgMJLFmP3iVDRqCfohi2y1HGdWg5VXQPTvzM7+YozZRlbNNV9UsuyRY91CXrJ
a2XREBgB+LPMGQivwcHtUMZfyNv/4uiwWivk+92ySNDhxqOiDt4R5Jak/7RkZMFwQpsE
JGwk6asM6VqZlihkF24lKv3pPaob6feyX3wD5N0+Mqiy1kQTj2JkpQk6nkTmdf0gapZe
fOhU1NkbNfbuS3U7m2gEUiyktE+MhV/MgAzgBhm9bgNt2gQLVWju8rHkPndfv1PDmEkC
FsYQ==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@googlemail.com header.s=20161025 header.b=dPisws+O;
spf=pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) smtp.helo=mail-sor-f69.google.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
Return-Path: <>
Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69])
by mx.google.com with SMTPS id s18sor5584435wrb.25.2020.05.18.09.23.25
for <alice@gmail.com>
(Google Transport Security);
Mon, 18 May 2020 09:23:25 -0700 (PDT)
Received-SPF: pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) client-ip=209.85.220.69;
Authentication-Results: mx.google.com;
dkim=pass header.i=@googlemail.com header.s=20161025 header.b=dPisws+O;
spf=pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) smtp.helo=mail-sor-f69.google.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=googlemail.com; s=20161025;
h=to:auto-submitted:message-id:date:from:subject:references
:in-reply-to;
bh=5xjZvcHbEGbMY0K2QB+3U6tpm1L1LAVv5h1pd4YXDEE=;
b=dPisws+OwGFyOy0a612XYZgvz5T71GcJRJtU068/Tce8vN/+ggIQtUsZnZtsphe71v
2NvfP9ULxR4cXvomTvhrYAk19KdxN/S7SeyBbmXv3x/tg+DBVCmmPS/6RXrcl6Ms3Hkw
uPFQ9S3KcvHe/2bcb5LSTA/stIP4tuxxAXvsX2j+MjPYPWKAl50jkSbWK98U0Q0U+MTl
pKaaC9s9iEBafac8BFZCy4DfpumKlemNEyRa3cSV2hw+DYHKA5peModrK1A2tcsfstFF
rZi8yF/D90RIFbE04DI2QCxB3trsChNF1aYF06aSzI//wsfM1+lb+uGPi0YVkw3n4HrX
Xw4w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:to:auto-submitted:message-id:date:from:subject
:references:in-reply-to;
bh=5xjZvcHbEGbMY0K2QB+3U6tpm1L1LAVv5h1pd4YXDEE=;
b=A/NCOtgbpA7VzB1G7ZFo8TA2FfrjuqjGdwMrJr3yXe21FrBFwzssprJwOkynqoVLkK
iJU7uMF/KTcQPDEmOLFThzFfe5GCx7eJtZPhwY+FbBlC5sq4I55/xaQLd0gOZ1BYXwMn
2bk169d2aoukbaLbGSQZF3d9atd+/e48YzkRxpmUoLcrWk2LcHAeQIG7SgT9pfX5DKPr
VpxM5/GMVEBbTRhBIWCeVSfpYCs80l0xEeTC3/B5lzpzMVDE8QCW6Dwh75b4Tb2K6yru
Zsy5ZpRmwv0wrkrb2vM+pl4IMkaF7s8XosIvlIT++fQV5xDFItT4atpykZvSDB92RKV0
8lEA==
X-Gm-Message-State: AOAM532RG/PT3ChZHBCDORGLtAjKvX8TGBuOy+AxrnEaJT6v1ieb+VV1
+ejly+/6UthxHYlkOJYAszCSgL4dKVFotoVaN7LhEA==
X-Google-Smtp-Source: ABdhPJz6veVKWhomCL4gK+whrybuMzHCDCq8AowgQvi7sobpMoM/k9CDw79jo1j3OUcTz6MEeUYLxEXuNIuu4zyoS7kVtsUYryGFHAI=
X-Received: by 2002:a5d:5183:: with SMTP id k3mr20545185wrv.159.1589819005394;
Mon, 18 May 2020 09:23:25 -0700 (PDT)
Content-Type: multipart/report; boundary="00000000000012d63005a5ee9520"; report-type=delivery-status
To: alice@gmail.com
Received: by 2002:a5d:5183:: with SMTP id k3mr13704211wrv.159; Mon, 18 May
2020 09:23:25 -0700 (PDT)
Return-Path: <>
Auto-Submitted: auto-replied
Message-ID: <5ec2b67d.1c69fb81.213af.67a5.GMR@mx.google.com>
Date: Mon, 18 May 2020 09:23:25 -0700 (PDT)
From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
Subject: Delivery Status Notification (Failure)
References: <CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com>
In-Reply-To: <CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com>
X-Failed-Recipients: assidhfaaspocwaeofi@gmail.com
--00000000000012d63005a5ee9520
Content-Type: multipart/related; boundary="00000000000012dc0005a5ee952f"
--00000000000012dc0005a5ee952f
Content-Type: multipart/alternative; boundary="00000000000012dc0705a5ee9530"
--00000000000012dc0705a5ee9530
Content-Type: text/plain; charset="UTF-8"
** Die Adresse wurde nicht gefunden **
Ihre Nachricht wurde nicht an assidhfaaspocwaeofi@gmail.com zugestellt, weil die Adresse nicht gefunden wurde oder keine E-Mails empfangen kann.
Hier erfahren Sie mehr: https://support.google.com/mail/?p=NoSuchUser
Antwort:
550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient's email address for typos or unnecessary spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser i18sor6261697wrs.38 - gsmtp
--00000000000012dc0705a5ee9530
Content-Type: text/html; charset="UTF-8"
<html>
<head>
<style>
* {
font-family:Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
}
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" class="email-wrapper" style="padding-top:32px;background-color:#ffffff;"><tbody>
<tr><td>
<table cellpadding=0 cellspacing=0><tbody>
<tr><td style="max-width:560px;padding:24px 24px 32px;background-color:#fafafa;border:1px solid #e0e0e0;border-radius:2px">
<img style="padding:0 24px 16px 0;float:left" width=72 height=72 alt="Fehlersymbol" src="cid:icon.png">
<table style="min-width:272px;padding-top:8px"><tbody>
<tr><td><h2 style="font-size:20px;color:#212121;font-weight:bold;margin:0">
Die Adresse wurde nicht gefunden
</h2></td></tr>
<tr><td style="padding-top:20px;color:#757575;font-size:16px;font-weight:normal;text-align:left">
Ihre Nachricht wurde nicht an <a style='color:#212121;text-decoration:none'><b>assidhfaaspocwaeofi@gmail.com</b></a> zugestellt, weil die Adresse nicht gefunden wurde oder keine E-Mails empfangen kann.
</td></tr>
<tr><td style="padding-top:24px;color:#4285F4;font-size:14px;font-weight:bold;text-align:left">
<a style="text-decoration:none" href="https://support.google.com/mail/?p=NoSuchUser">WEITERE INFORMATIONEN</a>
</td></tr>
</tbody></table>
</td></tr>
</tbody></table>
</td></tr>
<tr style="border:none;background-color:#fff;font-size:12.8px;width:90%">
<td align="left" style="padding:48px 10px">
Antwort:<br/>
<p style="font-family:monospace">
550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient&#39;s email address for typos or unnecessary spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser i18sor6261697wrs.38 - gsmtp
</p>
</td>
</tr>
</tbody></table>
</body>
</html>
--00000000000012dc0705a5ee9530--
--00000000000012dc0005a5ee952f
Content-Type: image/png; name="icon.png"
Content-Disposition: attachment; filename="icon.png"
Content-Transfer-Encoding: base64
Content-ID: <icon.png>
iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAYAAADnRuK4AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABTdJREFUeNrsnD9sFEcUh5+PRMqZ
yA0SPhAUQAQFUkyTgiBASARo6QApqVIkfdxGFJFSgGhJAUIiBaQB0ZIOKVCkwUgURjIg2fxL4kS+
YDvkbC/388bi8N16Z4/d7J/5PsniuD3fyePP772ZeTsDQRAYQL/UGAJAIEAgQCBAIAAEAgQCBAIE
AkAgyJT3Mv+Eq7vYK8mTE+MDRCAghQECAeRQA5V2ZOpmg5vDx3NPzRbmGRMEcmTrEbNNB8zWfRD+
f/Efs2e3zCZvMjaksBg27TfbcuSNPEKP9ZyuAQKtHX2O9ncNgWC57umMPKvRNb0GEKgnLoUyxTQC
rcns0/6uIRAs8/hGf9cQCJZpTpjdO2f25/03z+mxntM1eLtsZAgiUtX4JcaBCAQIBAgECARQ8CJa
G5jab4J4pm4WZmO3OALVh802fIwcLkyPkcKAGggAgQCBAIEAgQCBABAIEAjKA/1AnahhbO5FdOOY
VsrrDbPBYcYKgf5D2wLaV3p+22xh1u17tO3S+DTcvxvagUDeivPgx/a/95J/73w7Sj26Hn4pKo2M
ehuV/KyBJM6d0f7k6RKx/R63vvL2tmf/ItDdM2ZTP6f7nkp9Y2fDx1v9akmpIU+KSCLVUghUQfSL
zVKeTklbLxGoctw/nzC5rw8L5KRNbkpnKq6pgSqEClzNnFzY+XnYWrt6VpVk1vbwWvg+RKCKMOUw
Q1LEOXA+/MX3mpJvGDHb265xtnzmFoUK1HaKQGlMtePYM+q2KKjXuaS1NJYIEKgI8jhEgqHt4cqy
Ky53j3hyHz2bqSLp2o2LbJ7MxKovkGqXteoWpaOk96O9/yF/dF7NwlS36AuIQIBA5celQK4PIxBE
4LLzrtoLgaALdSy6CJRkWQCBPGLsTHznomZ9nszUECgJ2ml3WWHe+QVFNPSQx6UdZNtxr9pbEShN
eTTz8mQXHoHSlke7+Z+c9m6VGoHSkEfs/trLW3wQKApN1V3lGfnGu2Z6BFoLtYCs3GWBPAiUCLVh
/HoaeRCoT9R873KLM/IgUBfapnCpe5AHgXry4pf412ihEHkQqCdxd5VqrcezhUIESsJMTJ+Pdthp
Z0WgyNlXXPHc2Mc4IVAELl2Gnh8mhUDvCkfbIVAkcbf/aOoO3fMKhqAD3frTa4quwpn0hUDOkQhI
YYBAgECAQAAU0QlYObl+5Ug8NcprZkZxjUCxRPVA6zmtEXHCBykskrhjgHXN09PoEcgFl4M4H11j
nBAoApcj6ZoPGScEAgTKApcDoTw5sgWB+sGlz1n90IBAPdE6j1o21PfcC11jLagL1oFWRyGlKU3p
OxcSJQ7NZAjkhHp/uG2HFAYIBAgECASAQIBAgECAQAAIBOkxEARBtp9wdVfAMOfIifEBIhCQwgCB
ABAI0oV2jhxZ+nfBatuPZfgBCy0Eqqo8c01b+uu51XZvzOgDWoHNTGR+pCwpLEd5svuAZXlO2uEr
PyEQ8hRWHgRCHmqg0sjTnLalv6crJQ8C/U8stqNO0I4+VZOHFIY8COS1PGL2ybd5yUMKK7s8zYmL
dujyd3n+nESgcsvzZd4/KwIhDwIhT35QA6UyE1qyxZnfvJMHgdKS549JC1qvvJOHFIY8CFR5eV5O
XimqPAhUdHnmfx+zgxdOFXkoqIGKKs/cswnb/8Oeog8HEai48nxUhiFBIORBIOShBioskkbySCLk
IQIhDwIhj28p7FApR6b1qlEbHGpkO/rr6215vi/zH1r2x7tApSGFAQIBAgECAQIBIBAgECAQIBBA
LK8FGADCTxYrr+EVJgAAAABJRU5ErkJggg==
--00000000000012dc0005a5ee952f--
--00000000000012d63005a5ee9520
Content-Type: message/delivery-status
Reporting-MTA: dns; googlemail.com
Arrival-Date: Mon, 18 May 2020 09:23:25 -0700 (PDT)
X-Original-Message-ID: <CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com>
Final-Recipient: rfc822; assidhfaaspocwaeofi@gmail.com
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient's email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1 https://support.google.com/mail/?p=NoSuchUser i18sor6261697wrs.38 - gsmtp
Last-Attempt-Date: Mon, 18 May 2020 09:23:25 -0700 (PDT)
--00000000000012d63005a5ee9520
Content-Type: message/rfc822
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20161025;
h=mime-version:from:date:message-id:subject:to;
bh=gtlm3j0shCgZYOVxUt74zkQ69Zq+GTQeHeXLfMlrhlk=;
b=a185ogBcMzF9whNVWvuyUoUunNZk3Vc1kEIFmPkX0IxLpAFcI+fOQajOSromGl7Oyi
yecLwQevpww2Xd0XjZ3UkZvrI9m9koRmh0QeoHvgTRORiVwj08+PVc3N4F9bCO4w9i0J
ir7SSsJqBCDovoIFSFDyNa64vs6Nxno0cH/DaPG7pVTdD+3jfB7nLXIsMQYeX+1eP6rB
UhKxH82r7Mh9CI2PWDQpVtGj63AMUEyHgE9Ou08PWbbKjrQOasoG3Tw8tB1GoN1XYssM
rxOTgWEoTiduZ35AUH6h+eChOn9OHuI3SPECcVob70Qndayia3dMKfHMO6sEx9J0Wpic
29vg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:mime-version:from:date:message-id:subject:to;
bh=gtlm3j0shCgZYOVxUt74zkQ69Zq+GTQeHeXLfMlrhlk=;
b=miGIfL5BgnkD3wQvS34RtGwRRoh+8gJT5sFFfdX/hVyG/dvjXfdwP4yyNWr8ox8iY2
BLlahS4y4VGcbG1e2aYjurnWNytGu6utQcZax/uUngJ0bTOwXW1VaIiEZtqd6gTV+8d/
rrfQ459+4vXqIoQf0+Oi/U6dWwgJvPPjjRiToWdF3vIJE8R1iTRdZbW4lkgxSADbmskg
noT/gWGWblHtR6uuGuKGJ3bkhJKCBnjavKh0LlbWEeFBZfmVNPRvzEFWHjBDdu5wvSL5
0QJ+Qn0Orfn5CJuN3xPfzT1S2rI2iYZx37KX9zyMnZEx0ilkTYqCtBPWkrXRYDSXcxYS
Y1ag==
X-Gm-Message-State: AOAM531vhwpXiK8M12286dOJx0Q5fBl9ZaH6BJKts93GoxvPv0xdryP0
jg9wYmoP5MUHudsxAMCYDFsCUMVx2PEywyIsaQqklw==
X-Google-Smtp-Source: ABdhPJxlVJtTODM3pZZSTbbpAAAQRU8XbmuosDF9fgQZmVwxGZSzRWl22o+moppVRU/r8xMAyf0r3+qXwEBe1vZfjZo=
X-Received: by 2002:a5d:5183:: with SMTP id k3mr20545162wrv.159.1589819005034;
Mon, 18 May 2020 09:23:25 -0700 (PDT)
MIME-Version: 1.0
From: <alice@gmail.com>
Date: Mon, 18 May 2020 18:23:39 +0200
Message-ID: <CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com>
Subject: Kommt sowieso nicht an
To: assidhfaaspocwaeofi@gmail.com
Content-Type: multipart/alternative; boundary="0000000000000d652a05a5ee95df"
--0000000000000d652a05a5ee95df
Content-Type: text/plain; charset="UTF-8"
Wollte nur was testen
--0000000000000d652a05a5ee95df
Content-Type: text/html; charset="UTF-8"
<div dir="ltr">Wollte nur was testen<br></div>
--0000000000000d652a05a5ee95df--
--00000000000012d63005a5ee9520--

View File

@@ -0,0 +1,242 @@
Delivered-To: alice@gmail.com
Received: by 2002:a02:6629:0:0:0:0:0 with SMTP id k41csp368502jac;
Wed, 10 Jun 2020 05:17:57 -0700 (PDT)
X-Received: by 2002:a6b:1448:: with SMTP id 69mr2898530iou.83.1591791475733;
Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1591791475; cv=none;
d=google.com; s=arc-20160816;
b=a0vSKJPbMtGYFnuk1ye/gnnV00Zvva4OOJTMOyfm13xMJD0YAhzGVfa7Z+wn5sQ8dw
VAxpmDHCkjp4jol0C1iutiq2Nl0qma819oFPuuoMLLatKQXHpo8Jt+sL3MnwNR7J5bZC
1c6Fjk75EIsRWhJd1HCkm44A6UYHxqqsTnzQCaNiHbjsRsvbggxwlMGSrZ4silxqSDvo
Pzd/YDLCvsnZNSNIjIckKAwtGmY6sXctZ+JnOTykXAyL32Milfwy1vRL9xm10Q14biTR
+qaIQp4E6WE63g1WHvfAjs0Dru7DalUh4GGl/NAwqVhY1gVyRD5E9/nODyHAfxjvaxDD
4sMw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=in-reply-to:references:subject:from:date:message-id:auto-submitted
:to:dkim-signature;
bh=XaR1H4XeD+InO7mULPJn53omDGmxN+KG6DbSxyyErPM=;
b=OJbgbrktMKyczw25z/ib7lSdRX80PEK3Myh9fj4q6mDlXmPPv//Gv069znRQ4QbadM
HUXZH0WLMZcGyqI6SvGL/noxQ1O8yP0FYJJKTkoX0Gk2hHzfaE3x1scOP/o2FMMQXIFm
S4CgGBD6HHzBJYj/rSL3gzqLzx1Id/z5kTeDvH2cn8JJAcCE2q/nhjTyWUb87geoNlDJ
A1HRrLHK/0JOyRjHfg2zZCqIvSi1xmpiHStMyL9mfVyrQs98tsPxaOkJHjLplFARoPlr
mmmDvsFg7MPvFqkkANzz4JDHidnfKRULCgnrVj1yTU66UagUpQEGjZqz8/99YuU6nt1t
81sQ==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@googlemail.com header.s=20161025 header.b=aO4aNy7C;
spf=pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) smtp.helo=mail-sor-f69.google.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
Return-Path: <>
Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69])
by mx.google.com with SMTPS id w14sor16686480iow.23.2020.06.10.05.17.55
for <alice@gmail.com>
(Google Transport Security);
Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
Received-SPF: pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) client-ip=209.85.220.69;
Authentication-Results: mx.google.com;
dkim=pass header.i=@googlemail.com header.s=20161025 header.b=aO4aNy7C;
spf=pass (google.com: best guess record for domain of postmaster@mail-sor-f69.google.com designates 209.85.220.69 as permitted sender) smtp.helo=mail-sor-f69.google.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=googlemail.com; s=20161025;
h=to:auto-submitted:message-id:date:from:subject:references
:in-reply-to;
bh=XaR1H4XeD+InO7mULPJn53omDGmxN+KG6DbSxyyErPM=;
b=aO4aNy7CUOk9O4Jnsue/DvMFY6Ph0C34AbpoxJH+mLZpOmt/KYGCGYWgunZgamF15U
Vm8JY5yLKGwkTz2m3abDnKNP4fpl6zeZ5fyk5LvXH2Jema0iocHai6pJZBoFGPnonNmd
MscTf1sEltbOxwfOmM1BRHX34c1jW0+8Yd2+Nhg2DPvzuq1brOVin6bUV4VX5EeeuNqT
ZTewjJVPmO/B5NQhdpG81FO5w4hKSQ/VzZXnap2thMf3gOmnaoR+tbsnOIAiklcLdJ7b
57SKUwI041pwSmh9dffs0STl2GvMRSJyGCtBqMnzXgflqoGTcnPflWgR3LXHM/MIA0q8
WqRQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:to:auto-submitted:message-id:date:from:subject
:references:in-reply-to;
bh=XaR1H4XeD+InO7mULPJn53omDGmxN+KG6DbSxyyErPM=;
b=iORAzNvXegQ8oSp4RYb/S168muAiBox769seMk49kDBIvXwI+N8P4mUZq/zDi8DmQd
+wlLzVzowQq6EofiSpjOJWT9IC/k8otk15PMGtgHE4BGSSeKn7L30d3ocQS93HzYnLmA
VBlHBdFTKrsfKhe2+CQyCosTDGRpbkQLuRRyhxChEq8ltvaOHgbu1+eCeb9PsPuh6OxH
kvTHJZeA9A+eLOl26pBmqGIWkr7FlYW0wI6YPoEs9WXX5LSFOQs6fm/9l366eIR7IFFI
ihX5LrZl/Cf0lwwYX7fqIMgnHy1K+QnKuEb+dRQGqLbxdIEls9bXIF98iPQVkEWzgSZy
ip8Q==
X-Gm-Message-State: AOAM531ahfHE6oS9/nuni8pNf9bwC+DXAcaLV0owBwNCj9kcTPLCCNhX
W1JNciK0ivEIVB4dgiyLE/5K7iKbEznQhqyG9Bi1QA==
X-Google-Smtp-Source: ABdhPJygljUXswH0ycJyHmXVthi5IjlDvP8QdYlMdHUPKEtgIZeUk69Acti5LnswGhg63T9/L0PuGZGBM5XE5BsP0mMNNDRZyt+DgnE=
X-Received: by 2002:a05:6638:101c:: with SMTP id r28mr2990163jab.84.1591791475516;
Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
Content-Type: multipart/report; boundary="00000000000074432a05a7b9d512"; report-type=delivery-status
To: alice@gmail.com
Received: by 2002:a05:6638:101c:: with SMTP id r28mr3059870jab.84; Wed, 10 Jun
2020 05:17:55 -0700 (PDT)
Return-Path: <>
Auto-Submitted: auto-replied
Message-ID: <5ee0cf73.1c69fb81.6888.c2f4.GMR@mx.google.com>
Date: Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
Subject: Delivery Status Notification (Failure)
References: <CADWx9Cs32Wa7Gy-gM0bvbq54P_FEHe7UcsAV=yW7sVVW=fiMYQ@mail.gmail.com>
In-Reply-To: <CADWx9Cs32Wa7Gy-gM0bvbq54P_FEHe7UcsAV=yW7sVVW=fiMYQ@mail.gmail.com>
X-Failed-Recipients: assidhfaaspocwaeofi@gmail.com
--00000000000074432a05a7b9d512
Content-Type: multipart/related; boundary="000000000000745e0805a7b9d51b"
--000000000000745e0805a7b9d51b
Content-Type: multipart/alternative; boundary="000000000000745e1705a7b9d51c"
--000000000000745e1705a7b9d51c
Content-Type: text/plain; charset="UTF-8"
** Die Adresse wurde nicht gefunden **
Ihre Nachricht wurde nicht an assidhfaaspocwaeofi@gmail.com zugestellt, weil die Adresse nicht gefunden wurde oder keine E-Mails empfangen kann.
Hier erfahren Sie mehr: https://support.google.com/mail/?p=NoSuchUser
Antwort:
550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient's email address for typos or unnecessary spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser h20sor9401601jar.6 - gsmtp
--000000000000745e1705a7b9d51c
Content-Type: text/html; charset="UTF-8"
<html>
<head>
<style>
* {
font-family:Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
}
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" class="email-wrapper" style="padding-top:32px;background-color:#ffffff;"><tbody>
<tr><td>
<table cellpadding=0 cellspacing=0><tbody>
<tr><td style="max-width:560px;padding:24px 24px 32px;background-color:#fafafa;border:1px solid #e0e0e0;border-radius:2px">
<img style="padding:0 24px 16px 0;float:left" width=72 height=72 alt="Fehlersymbol" src="cid:icon.png">
<table style="min-width:272px;padding-top:8px"><tbody>
<tr><td><h2 style="font-size:20px;color:#212121;font-weight:bold;margin:0">
Die Adresse wurde nicht gefunden
</h2></td></tr>
<tr><td style="padding-top:20px;color:#757575;font-size:16px;font-weight:normal;text-align:left">
Ihre Nachricht wurde nicht an <a style='color:#212121;text-decoration:none'><b>assidhfaaspocwaeofi@gmail.com</b></a> zugestellt, weil die Adresse nicht gefunden wurde oder keine E-Mails empfangen kann.
</td></tr>
<tr><td style="padding-top:24px;color:#4285F4;font-size:14px;font-weight:bold;text-align:left">
<a style="text-decoration:none" href="https://support.google.com/mail/?p=NoSuchUser">WEITERE INFORMATIONEN</a>
</td></tr>
</tbody></table>
</td></tr>
</tbody></table>
</td></tr>
<tr style="border:none;background-color:#fff;font-size:12.8px;width:90%">
<td align="left" style="padding:48px 10px">
Antwort:<br/>
<p style="font-family:monospace">
550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient&#39;s email address for typos or unnecessary spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser h20sor9401601jar.6 - gsmtp
</p>
</td>
</tr>
</tbody></table>
</body>
</html>
--000000000000745e1705a7b9d51c--
--000000000000745e0805a7b9d51b
Content-Type: image/png; name="icon.png"
Content-Disposition: attachment; filename="icon.png"
Content-Transfer-Encoding: base64
Content-ID: <icon.png>
iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAYAAADnRuK4AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABTdJREFUeNrsnD9sFEcUh5+PRMqZ
yA0SPhAUQAQFUkyTgiBASARo6QApqVIkfdxGFJFSgGhJAUIiBaQB0ZIOKVCkwUgURjIg2fxL4kS+
YDvkbC/388bi8N16Z4/d7J/5PsniuD3fyePP772ZeTsDQRAYQL/UGAJAIEAgQCBAIAAEAgQCBAIE
AkAgyJT3Mv+Eq7vYK8mTE+MDRCAghQECAeRQA5V2ZOpmg5vDx3NPzRbmGRMEcmTrEbNNB8zWfRD+
f/Efs2e3zCZvMjaksBg27TfbcuSNPEKP9ZyuAQKtHX2O9ncNgWC57umMPKvRNb0GEKgnLoUyxTQC
rcns0/6uIRAs8/hGf9cQCJZpTpjdO2f25/03z+mxntM1eLtsZAgiUtX4JcaBCAQIBAgECARQ8CJa
G5jab4J4pm4WZmO3OALVh802fIwcLkyPkcKAGggAgQCBAIEAgQCBABAIEAjKA/1AnahhbO5FdOOY
VsrrDbPBYcYKgf5D2wLaV3p+22xh1u17tO3S+DTcvxvagUDeivPgx/a/95J/73w7Sj26Hn4pKo2M
ehuV/KyBJM6d0f7k6RKx/R63vvL2tmf/ItDdM2ZTP6f7nkp9Y2fDx1v9akmpIU+KSCLVUghUQfSL
zVKeTklbLxGoctw/nzC5rw8L5KRNbkpnKq6pgSqEClzNnFzY+XnYWrt6VpVk1vbwWvg+RKCKMOUw
Q1LEOXA+/MX3mpJvGDHb265xtnzmFoUK1HaKQGlMtePYM+q2KKjXuaS1NJYIEKgI8jhEgqHt4cqy
Ky53j3hyHz2bqSLp2o2LbJ7MxKovkGqXteoWpaOk96O9/yF/dF7NwlS36AuIQIBA5celQK4PIxBE
4LLzrtoLgaALdSy6CJRkWQCBPGLsTHznomZ9nszUECgJ2ml3WWHe+QVFNPSQx6UdZNtxr9pbEShN
eTTz8mQXHoHSlke7+Z+c9m6VGoHSkEfs/trLW3wQKApN1V3lGfnGu2Z6BFoLtYCs3GWBPAiUCLVh
/HoaeRCoT9R873KLM/IgUBfapnCpe5AHgXry4pf412ihEHkQqCdxd5VqrcezhUIESsJMTJ+Pdthp
Z0WgyNlXXPHc2Mc4IVAELl2Gnh8mhUDvCkfbIVAkcbf/aOoO3fMKhqAD3frTa4quwpn0hUDOkQhI
YYBAgECAQAAU0QlYObl+5Ug8NcprZkZxjUCxRPVA6zmtEXHCBykskrhjgHXN09PoEcgFl4M4H11j
nBAoApcj6ZoPGScEAgTKApcDoTw5sgWB+sGlz1n90IBAPdE6j1o21PfcC11jLagL1oFWRyGlKU3p
OxcSJQ7NZAjkhHp/uG2HFAYIBAgECASAQIBAgECAQAAIBOkxEARBtp9wdVfAMOfIifEBIhCQwgCB
ABAI0oV2jhxZ+nfBatuPZfgBCy0Eqqo8c01b+uu51XZvzOgDWoHNTGR+pCwpLEd5svuAZXlO2uEr
PyEQ8hRWHgRCHmqg0sjTnLalv6crJQ8C/U8stqNO0I4+VZOHFIY8COS1PGL2ybd5yUMKK7s8zYmL
dujyd3n+nESgcsvzZd4/KwIhDwIhT35QA6UyE1qyxZnfvJMHgdKS549JC1qvvJOHFIY8CFR5eV5O
XimqPAhUdHnmfx+zgxdOFXkoqIGKKs/cswnb/8Oeog8HEai48nxUhiFBIORBIOShBioskkbySCLk
IQIhDwIhj28p7FApR6b1qlEbHGpkO/rr6215vi/zH1r2x7tApSGFAQIBAgECAQIBIBAgECAQIBBA
LK8FGADCTxYrr+EVJgAAAABJRU5ErkJggg==
--000000000000745e0805a7b9d51b--
--00000000000074432a05a7b9d512
Content-Type: message/delivery-status
Reporting-MTA: dns; googlemail.com
Arrival-Date: Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
X-Original-Message-ID: <CADWx9Cs32Wa7Gy-gM0bvbq54P_FEHe7UcsAV=yW7sVVW=fiMYQ@mail.gmail.com>
Final-Recipient: rfc822; assidhfaaspocwaeofi@gmail.com
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient's email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1 https://support.google.com/mail/?p=NoSuchUser h20sor9401601jar.6 - gsmtp
Last-Attempt-Date: Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
--00000000000074432a05a7b9d512
Content-Type: message/rfc822
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20161025;
h=mime-version:from:date:message-id:subject:to;
bh=Y1ylbv3YC5frF/LtF2it4tQQ0OVZstDdWqivvggIOB0=;
b=eyr60XbgOrgHoZFpRYzw9WQIR7aEBaYKWhiEcqdnugB+hn0W2KVcTkKiL2C6zSF+jh
l+lM+dNZZTUcMqWx4kVgTVtqwUNea8OUqe+WLqx04ULwdKZn1okbKYovaiavCLKOKDnf
ZP5mNz3Ka/ywpCGoq8rdgnXc7NunnkWeaBpYY/BWOmLU4WNXX8zS7etXXhQE4YPQEJT4
Sh2o/YIIjDLncJFMyE+25n3tbd2mIoLt4sjaCHE5ibm9w7zojyHM+LDCQ37cM74FEAAa
88KTn0gSnCFBCfojhfxOH78CpySHG3FFfTlpCefwP2A5J9MQlb6QdSVa9STYSx3IntJ4
L7Tg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:mime-version:from:date:message-id:subject:to;
bh=Y1ylbv3YC5frF/LtF2it4tQQ0OVZstDdWqivvggIOB0=;
b=pBL4/bKUDw5E2zo1uR2Tl69h2iTlMgIAcnzQgodPCbU4jZ9kH+F5H9rfbzXCjT06J7
L72SYpdfgc5fOwM4GhRcdYnyK3wiXQ8ugpL19nbYt2iWo/vRF3GidawXXDGb2GUYpkzX
1Mz531cy2/HOsmQbUQ7304KV+OUghtcg8eLNnFuhQch7n12Kk3yy3AOzjrLoktcdgIsy
/HxBjyut0Au+A2t6si+PVwTHvC647a0BioeV0tUYLigzu3/jgP9Hb8eRZaXTX5VC6iZi
9QMH/+rXp05IK7OpGWh22xDpeV8CDkQ2sLFaBhKxtJ+nYoerM64t8EJXBBsVQb18ojGz
pW/A==
X-Gm-Message-State: AOAM5330q6kn/TKataMNEVigNfNdr/xii/PQgHXzJyMbwLvsETlNfLoy
1rM9JBIGrcHeEDRx4qhZfl5S4bircceU7c3i6Fyn2fRO
X-Google-Smtp-Source: ABdhPJwysG+S90b/g+9mK7LgeHhmJTBowst6JMhL16+a0coTi7P1NVp9jjaNHJfhvhLodYG6eHIvWdbQGJnAP2brEzI=
X-Received: by 2002:a05:6638:101c:: with SMTP id r28mr2990137jab.84.1591791475066;
Wed, 10 Jun 2020 05:17:55 -0700 (PDT)
MIME-Version: 1.0
From: Deltachat Test <alice@gmail.com>
Date: Wed, 10 Jun 2020 14:18:26 +0200
Message-ID: <CADWx9Cs32Wa7Gy-gM0bvbq54P_FEHe7UcsAV=yW7sVVW=fiMYQ@mail.gmail.com>
Subject: test
To: bob@example.org, assidhfaaspocwaeofi@gmail.com
Content-Type: multipart/alternative; boundary="0000000000006d8d7d05a7b9d5b3"
--0000000000006d8d7d05a7b9d5b3
Content-Type: text/plain; charset="UTF-8"
test
--0000000000006d8d7d05a7b9d5b3
Content-Type: text/html; charset="UTF-8"
<div dir="ltr">test<br></div>
--0000000000006d8d7d05a7b9d5b3--
--00000000000074432a05a7b9d512--

View File

@@ -0,0 +1,113 @@
Return-Path: <>
Received: from mout-bounce.gmx.net ([212.227.15.44]) by mx-ha.gmx.net
(mxgmx101 [212.227.17.5]) with ESMTPS (Nemesis) id 1Mr97m-1jC6Y01o86-00oEqk
for <alice@gmx.de>; Tue, 09 Jun 2020 14:35:30 +0200
Received: from localhost by mout-bounce.gmx.net id 0LhiZF-1jDTj11ZoH-00msO3
Tue, 09 Jun 2020 14:35:30 +0200
Date: Tue, 09 Jun 2020 14:35:30 +0200
From: "GMX Mailer Daemon" <mailer-daemon@gmx.de>
To: alice@gmx.de
Subject: Mail delivery failed: returning message to sender
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-UI-Out-Filterresults: unknown:0;V03:K0:O8yx6kuPaGQ=:0wIDPNXEr0wX2oNsLnXaWA
==
Envelope-To: <alice@gmx.de>
X-GMX-Antispam: 0 (Mail was not recognized as spam); Detail=V3;
X-Spam-Flag: NO
X-UI-Filterresults: notjunk:1;V03:K0:QcE43EBhMmU=:IC5vvzi9jhPS/698Wuubzw1Q4N
h87X9j9B3CBN0ZKXB67KepwyNHmh9pxmFIUOMimylv7UK9np+j3X55roOd0nX9BmaaZ3Twvqf
UaSsxmyU+cNr6m3+oOb3udJBLe2pJEZDk1cOwACb5NXzYPSaIj4APfGCyvrzIx3FGkNuScNBb
tCbbKUJ0GB/VmJLB34XfF6dNN+Iwv9IQ9Yrvw/VXv9vWKsi3qRGGUt3yRw5jUKhQlBY21Pnoq
m0LqoMbAKfH1tKEQ/5TymH1ei50YKyWzZ89ISkQwkbYLaqN+6meGACpY18j43VCU9Fk4WQR7y
3XvBYh2CO0CnCn+M9VsnasYag2sNrySe9nzyKfRTaxEg8qlJtl7kS4GX/FsxhHPavkqnU62Gl
9V5TxIG7tmIR0Bf11sPzG/WGegoOHxrfz+qYR81llLMOHznpdDRKjsYDtO/rFBGZzYTiCZsrW
dZPVXV25SVcrDGZOaop3JoCbglmXLcSLLhmfE5MzyJEGte3I+6EiZJNeIe8qN3wMDTsRtJL9S
J6b2F/5/kTGVAWnXtNlf69BholCrxvjC4Snt3Xjc+7WIO8iw2c5YjmWy+4bAwd4uWll529hZd
6pUYGwjFRnKleivCaJIt7DqbvbE7GZSbQH8fXm3zYqYTrrxiWdlykdoOA1OGbeM06RHJt3mJB
osZPU8BZKt0OiBOW64vg6gyAsNC0f02EA7dvRWYgFYqlSogfWZQIOKDKibMVHpIaA0foXg4BG
TEQDlsTIL0n2WC9WVqkMdm6xUXHgpArCrAsUhw3mEqPywEfJeBHn60tP2vQ9+pDIQAj5dQCDV
y96qSiCX4p31HfrWwAXB9mHfl4OO/tPcKUGBclj2rZ/NMc4O+7yDedLWXQnRzQExfOJLBbBh3
xgiNlWFHvDLn0pKG9EI1+3wJ7m2GF2jzDtbQTBv9z26DuAq5WbHZHupzeyfP7VCVXcKuB6sG1
3+LWcdYtcXfqT58HwcvDLwowC4uJpiHfHwtVdiGMtHnmYLysp0V425g+vofQfNzBgR3d9JC15
G+HS44o6x6Legm6KnHYH3k0KhR7fgcgswJv/S+I/ryppUhGb2jezVZIUzgvAplzIUDAWnrHdF
KVqZ5wBJ0acShIfgMlsIxnBmcnIQ4R4jq3zAyj4XTFxVUFanU8ySiXubxV5PzJqj+GsVa2sjx
9n/xQRJLwgMC4BYqzP6lEPwg/g5AneDAnl7ZlcQPC4SCMblC8N1KZyyIDTXPOI/o4lfdMYb9P
7DmBp2S8aA2yuDe5XT20OmX3kVWeBOsBaAGvVFpIn7gwIDqnFh9WSMP6mkCwfChN3D1yLquYB
KAODgRZV5lVNmK+eOjW8m2oiRxmfxrjXLtw5PEhn3RkiRN4HnoePJeoYC7SG4EUwg+wYPu3M6
exP/YigoE6bjuBS5d0imUTRDMiwg469GyrFo1J1GkRVvj3lXSF4Nt11j6waqu1l0ReDYfU+QM
EMPGLEh1vRChCaqz4L7YI5FlSAVXxfmst0JRyE4k5r9CToEbZuYlPQ+jbcvptwBSaqzMb/YfT
cCrU2RWHUfmYIy8x8A/t8ScRbYPzs1lTK3yn1hYeXpw8Fgkip6DIIXAJwUUp+2SLcELICIo+p
uumMN0P/OZHH3V/hZ0dPr9xsYi7gdd/vyRIRPUwiL1rSp2WJGi+w4atun8kQBgnbAznRObDh1
4zzKhApX9jo5gtFN6640QDEI5KpsMuPoty4rj9OK163ntKWGR451n+5ZX2FilTlpZYlIPO9Hy
SrjHzBog4texceR1OLh4pb/WFB0XFSjQchPAltXCYQFs82aDDk/A0nOPk=
This message was created automatically by mail delivery software.
A message that you sent could not be delivered to one or more of
its recipients. This is a permanent error. The following address(es)
failed:
snaerituhaeirns@gmail.com:
SMTP error from remote server for RCPT TO command, host: gmail-smtp-in.l.google.com (66.102.1.27) reason: 550-5.1.1 The email account that you tried to reach does not exist. Please
try
550-5.1.1 double-checking the recipient's email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1 https://support.google.com/mail/?p=NoSuchUser f6si2517766wmc.21
9 - gsmtp
--- The header of the original message is following. ---
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net;
s=badeba3b8450; t=1591706130;
bh=g3zLYH4xKxcPrHOD18z9YfpQcnk/GaJedfustWU5uGs=;
h=X-UI-Sender-Class:To:From:Subject:Date;
b=NwY6W33mI1bAq6lpr6kbY+LD2hO9cDJBItTgY3NRIT94A6rKTVlSmhFM3AxYgFnj0
Db0hncsNRDqcdtRoOo8Emcah5NJURvEQohG37lkug3GqneB4+FNTdYCeQbOKlZn6on
pYYD/T9CmeL2HG3+8voeBjZIUenyXrF2WXG37hFY=
X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c
Received: from [192.168.178.30] ([84.57.126.154]) by mail.gmx.com (mrgmx005
[212.227.17.190]) with ESMTPSA (Nemesis) id 1MKbkM-1jNoq60HKm-00KyL2 for
<snaerituhaeirns@gmail.com>; Tue, 09 Jun 2020 14:35:30 +0200
To: snaerituhaeirns@gmail.com
From: Alice <alice@gmx.de>
Subject: test
Message-ID: <9c9c2a32-056b-3592-c372-d7e8f0bd4bc2@gmx.de>
Date: Tue, 9 Jun 2020 14:36:10 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101
Thunderbird/68.8.1
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Content-Language: de-DE
X-Provags-ID: V03:K1:7awoptmynaF5MqxCAincdsa7zFCwQFNkFb6xRxigK06uEiGN00b
Mv2wJU91CEd4mvCCWzrTtaWLZDLH8pjAWaT4+HvYIUbpwNx2jC6WHTppkYYRMVJnm4lG9pr
SUx1OlIcp0kbsnl3mB9xYNFwm9jzpR9Kx8QEHwIbZiiSFBcH56498UGQi//kKXVMos8C14o
I7cmwYmr8xB09DwLMKXfg==
X-Spam-Flag: NO
X-UI-Out-Filterresults: notjunk:1;V03:K0:NWQAUbhAkBc=:yAaolOnVCDWEZhgUwwvtEs
wXbSJ/GfMvDRpCkYpFBvHXOTpGm6hjdjQ0vLK2hvu/Hz22UdlWbIdc1J2oO9S5U20mIdc+1bS
TPSSpqPFc7ICPx4Wbvv2SEp9ZqH2q7ORC52UvUWfI6OjAJEPDNrXQFdUiZAa72hLj1NPeG6Qi
4AbL2HwLfJ8s6TeOCm6TXRRuD+w1o/ASFOqQmoao2dFyZ2BaoAgOKPKxXYfwVGceuUygpchyS
0d2bZYOXSLR+6rUYevjZAq1OCi9AIC6/wlkOe5yIRk4gJFMfPauaICsdnq3uZ9ikCAX83VWun
PJVMxTLTP54lgo2h0jMBX3uKk10+/wzXWplllxX9NnSa3x1V28n6raslNF0IoC6Pm72kC6Jzr
GkC22viCm3/Y4uHlPMOXbY5WFrQe/D9GKeJeXBLoGciNwIFkUG12a+iqWtoT+h5HVObTW8LxM
+UtEl97nAwxYSM+sGfIpasRpZc7r/SgN3JWGO9R9WaXpW4Cc1dH7RI+hzuZDsDUBEGTUTVPDo
0SvjKHiJ6sUqGDyfv4HUgVutus6EYP27LALND4ekfom2DPRFopZhbtV5fZT7CL1Q1NogU7tYf
/FdmR1T1J1zCAZSFvyR5LBkfglZlHzgdnTF2heuxyqKq4dm0hnLFSULB1+CVWsg8hzrruvO5q
XzA6qIhBQUZmWo7wBpqpkBPxzjgTGGtXc5y5e6+crxYbbuQdnUWEnyw2xI4d6pJPqtHDA2/vT
ZgvNDUGceavTR5Rtyb14hhX4Q6dWK3ATy16j4hs9Aq+q/IKyVAX3A5nFYbJRIz+2YnoLr2YOa
IrScEorXjvTxjw+aBy73SZBe2REPzJ+O6k7chVrYjV9Q28FiGVuRYJYxWw/59Pes7IAbmfQBV
4vqGCQQr4eG78gVwjw+SNdp4/6jdNkIHDqR4XW9id/r5wYxKKj4UUkSor3/+h9Rd9srh+GApy
uOxw/ejFvbRcxFIjvadpq1KLnO7nM27nJ4lp44ul3i7VUGefLM/45TCsuds2HM1iQWhPFQ54y
SA5sYjf73EUJdkHchaf5i+4uSOmbOWQ4Yvmd8+IoyoXAxvEzY2Xh53nWi8ZPY1Tu4Bw8GRrz7
L+VK0QiWCg3/hM7wRlFFyshmMrScMk5fOf9ynqd0JbHB7u+n4/GUwx3im/w8+NgSd3YOz7wNU
KD1snDWoMUO8f23Ik1Osym688OLWNwKYT+mZbMIMXcz1fB+olRZn4czMhN5DiSb8hyOxRI8NE
PNfaoN87CXiRkgazV6U1eiRkfcK2AvI7zOJF1tclUHZ9awyYoXtxfEzZ+J/2TCXiC7V2iSkUF
EjwgPxlJmccccjsxc46v1ajnTxLo0tJbZ0+DJXWkCgQ0d/iiScQ=

View File

@@ -0,0 +1,113 @@
Return-Path: <>
Delivered-To: alice@posteo.org
Received: from proxy02.posteo.name ([127.0.0.1])
by dovecot03.posteo.local (Dovecot) with LMTP id zvCFJRzX317LGQIA+3EWog
for <alice@posteo.org>; Tue, 09 Jun 2020 20:44:24 +0200
Received: from proxy02.posteo.de ([127.0.0.1])
by proxy02.posteo.name (Dovecot) with LMTP id mhNkNAnR316xBQMAGFAyLg
; Tue, 09 Jun 2020 20:44:23 +0200
Received: from mailin06.posteo.de (unknown [10.0.1.6])
by proxy02.posteo.de (Postfix) with ESMTPS id 49hJtv3RRcz11m7
for <alice@posteo.org>; Tue, 9 Jun 2020 20:44:23 +0200 (CEST)
Received: from mx04.posteo.de (mailin06.posteo.de [127.0.0.1])
by mailin06.posteo.de (Postfix) with ESMTPS id 6935920DD2
for <alice@posteo.org>; Tue, 9 Jun 2020 20:44:23 +0200 (CEST)
X-Virus-Scanned: amavisd-new at posteo.de
X-Spam-Flag: NO
X-Spam-Score: -1
X-Spam-Level:
X-Spam-Status: No, score=-1 tagged_above=-1000 required=8
tests=[ALL_TRUSTED=-1] autolearn=disabled
Received: from mout01.posteo.de (mout01.posteo.de [185.67.36.65])
by mx04.posteo.de (Postfix) with ESMTPS id 49hJtv001Vz10kT
for <alice@posteo.org>; Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
Authentication-Results: mx04.posteo.de; dmarc=none (p=none dis=none) header.from=mout01.posteo.de
Received: by mout01.posteo.de (Postfix)
id DCB6B1200DD; Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
Date: Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
From: MAILER-DAEMON@mout01.posteo.de (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: alice@posteo.org
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="B39111200B9.1591728262/mout01.posteo.de"
Content-Transfer-Encoding: 7bit
Message-Id: <20200609184422.DCB6B1200DD@mout01.posteo.de>
This is a MIME-encapsulated message.
--B39111200B9.1591728262/mout01.posteo.de
Content-Description: Notification
Content-Type: text/plain; charset=us-ascii
This is the mail system at host mout01.posteo.de.
I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.
For further assistance, please send mail to postmaster.
If you do so, please include this problem report. You can
delete your own text from the attached returned message.
The mail system
<hanerthaertidiuea@gmx.de>: host mx01.emig.gmx.net[212.227.17.5] said: 550
Requested action not taken: mailbox unavailable (in reply to RCPT TO
command)
--B39111200B9.1591728262/mout01.posteo.de
Content-Description: Delivery report
Content-Type: message/delivery-status
Reporting-MTA: dns; mout01.posteo.de
X-Postfix-Queue-ID: B39111200B9
X-Postfix-Sender: rfc822; alice@posteo.org
Arrival-Date: Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
Final-Recipient: rfc822; hanerthaertidiuea@gmx.de
Original-Recipient: rfc822;hanerthaertidiuea@gmx.de
Action: failed
Status: 5.0.0
Remote-MTA: dns; mx01.emig.gmx.net
Diagnostic-Code: smtp; 550 Requested action not taken: mailbox unavailable
--B39111200B9.1591728262/mout01.posteo.de
Content-Description: Undelivered Message Headers
Content-Type: text/rfc822-headers
Return-Path: <alice@posteo.org>
Received: from mout01.posteo.de (unknown [10.0.0.65])
by mout01.posteo.de (Postfix) with ESMTPS id B39111200B9
for <hanerthaertidiuea@gmx.de>; Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
Received: from submission-encrypt01.posteo.de (unknown [10.0.0.75])
by mout01.posteo.de (Postfix) with ESMTPS id 8A684160060
for <hanerthaertidiuea@gmx.de>; Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017;
t=1591728262; bh=g3zLYH4xKxcPrHOD18z9YfpQcnk/GaJedfustWU5uGs=;
h=To:From:Subject:Date:From;
b=brJnt4PLAX3Tda1RHCo91aB1kMAL/Ku9dmO7D2DD41Zu5ShNsyqqyDkyxb1DsDn3O
6KuBZe3/8gemBuCJ/mxzwd9v8sBnlrV+5afIk0Ye9VvthZsc4HoG79+FiVOi9F38o0
DtJJFYFw/X7mAc5Xyt0B0JvtiTPpBdRAkluUQm+QW6cW6GGlwicVW19qvebzq+sHyP
X2bZ8wpo78yVgvjPBK3DLaXa+pKFMBjLdDUcIE2bZnY6u6F1x8SXGKGBoxVwdJipJx
v14so5IejNsf4LYJjH3Qb8xgK1aAi6e6nQn4YXV0INL6ahzgALiT9N6vwunNKYVJNi
fPPKvBWDfUS4Q==
Received: from customer (localhost [127.0.0.1])
by submission (posteo.de) with ESMTPSA id 49hJtt1WPbz6tmV
for <hanerthaertidiuea@gmx.de>; Tue, 9 Jun 2020 20:44:22 +0200 (CEST)
To: hanerthaertidiuea@gmx.de
From: deltachat <alice@posteo.org>
Subject: test
Message-ID: <04422840-f884-3e37-5778-8192fe22d8e1@posteo.de>
Date: Tue, 9 Jun 2020 20:45:02 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101
Thunderbird/68.8.1
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Content-Language: de-DE
Posteo-User: alice@posteo.org
Posteo-Dkim: ok
--B39111200B9.1591728262/mout01.posteo.de--

View File

@@ -0,0 +1,107 @@
Return-Path: <>
Delivered-To: alice@testrun.org
Received: from hq5.merlinux.eu
by hq5.merlinux.eu (Dovecot) with LMTP id Ye02K6PB5F43cQAAPzvFDg
for <alice@testrun.org>; Sat, 13 Jun 2020 14:08:03 +0200
Received: by hq5.merlinux.eu (Postfix)
id 9EBE627A0B2E; Sat, 13 Jun 2020 14:08:03 +0200 (CEST)
Date: Sat, 13 Jun 2020 14:08:03 +0200 (CEST)
From: MAILER-DAEMON@hq5.merlinux.eu (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
To: alice@testrun.org
Auto-Submitted: auto-replied
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
boundary="CDB8D27A0B2C.1592050083/hq5.merlinux.eu"
Content-Transfer-Encoding: 8bit
Message-Id: <20200613120803.9EBE627A0B2E@hq5.merlinux.eu>
This is a MIME-encapsulated message.
--CDB8D27A0B2C.1592050083/hq5.merlinux.eu
Content-Description: Notification
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
This is the mail system at host hq5.merlinux.eu.
I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.
For further assistance, please send mail to postmaster.
If you do so, please include this problem report. You can
delete your own text from the attached returned message.
The mail system
<hcksocnsofoejx@five.chat>: host mail.five.chat[195.62.125.103] said: 550 5.1.1
<hcksocnsofoejx@five.chat>: Recipient address rejected: User unknown in
virtual mailbox table (in reply to RCPT TO command)
--CDB8D27A0B2C.1592050083/hq5.merlinux.eu
Content-Description: Delivery report
Content-Type: message/global-delivery-status
Content-Transfer-Encoding: 8bit
Reporting-MTA: dns; hq5.merlinux.eu
X-Postfix-Queue-ID: CDB8D27A0B2C
X-Postfix-Sender: rfc822; alice@testrun.org
Arrival-Date: Sat, 13 Jun 2020 14:08:01 +0200 (CEST)
Final-Recipient: rfc822; hcksocnsofoejx@five.chat
Original-Recipient: rfc822;hcksocnsofoejx@five.chat
Action: failed
Status: 5.1.1
Remote-MTA: dns; mail.five.chat
Diagnostic-Code: smtp; 550 5.1.1 <hcksocnsofoejx@five.chat>: Recipient address
rejected: User unknown in virtual mailbox table
--CDB8D27A0B2C.1592050083/hq5.merlinux.eu
Content-Description: Undelivered Message
Content-Type: message/global
Content-Transfer-Encoding: 8bit
Return-Path: <alice@testrun.org>
Received: from localhost (p200300edb723070079835ce22985a199.dip0.t-ipconnect.de [IPv6:2003:ed:b723:700:7983:5ce2:2985:a199])
by hq5.merlinux.eu (Postfix) with UTF8SMTPSA id CDB8D27A0B2C;
Sat, 13 Jun 2020 14:08:01 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=testrun.org;
s=testrun; t=1592050082;
bh=Kvhta0OMsTRVC7OlaAqo68TBE0KuGBv4vUBp6Ez/7VY=;
h=Subject:References:In-Reply-To:Date:To:From:From;
b=Ql60JEGFXLNvjsyihATw2z34ct++8xZvTPNw0snXe6+oqdqsRZJ9tWNDTxOgx8Iqf
HQ4puBVGcWjIlszYQVLlq3APi04o2ep3GrD8EF0J0GpDdW8yw6wCos6Q8r+TWmXwET
kGXHTRPVaUIqZF2i/utypxMfd1ua0S3jBDnIXTe/p2+XvfC3Cf3hZGW+FQ/Zd7G8Vh
/U2rgX5BTIGf26ZCbmcMaXWkftgv6+yns0AmzorV9yB+EhTkWIUjk+C25bRtMbJ5mZ
93dwdr+sXrrSZLSi+LBqc57Dv9j4p/SUmB4zPlvfUv7/bqLi36pypvtCJ5Ul8UEXSb
XNFZPaEl+mwjA==
Content-Type: text/plain; charset=utf-8
Chat-Disposition-Notification-To: alice@testrun.org
Subject: =?utf-8?q?Message_from_hocuri1=40testrun=2Eorg?=
MIME-Version: 1.0
References: <Mr.VSg3KXFUOTG.9sn7JBxZn1W@testrun.org>
<Mr.F4nR4LnXb6v.gqVbCJRgsmn@testrun.org>
In-Reply-To: <Mr.F4nR4LnXb6v.gqVbCJRgsmn@testrun.org>
Date: Sat, 13 Jun 2020 12:08:01 +0000
X-Mailer: Delta Chat Core 1.35.0/Android 1.9.5
Chat-Version: 1.0
Autocrypt: addr=alice@testrun.org; prefer-encrypt=mutual;
keydata=xjMEXt3z1xYJKwYBBAHaRw8BAQdAf6MctU/8cmEqwEN9VFZ3gHBFIxKiEaARZl1DFUkI7e
rNFTxob2N1cmkxQHRlc3RydW4ub3JnPsKLBBAWCAAzAhkBBQJe3fPXAhsDBAsJCAcGFQgJCgsCAxYC
ARYhBIZ3ajRUkki89+04sgctAtaIXygAAAoJEActAtaIXygAG2IA/1nTmmmkHAc1Bjtx2FOstbaS+N
XHjxaK+hkoWllsyhz0AQDJJ1++u7jVZPRn/j1LlByrT3Jv/D1aY14J5rjj+ADVBM44BF7d89cSCisG
AQQBl1UBBQEBB0DpSTaZ30dAVwM9PkBe2h+gFyxn9HSorP4XCHJu/lIdPAMBCAfCeAQYFggAIAUCXt
3z1wIbDBYhBIZ3ajRUkki89+04sgctAtaIXygAAAoJEActAtaIXygA2QkA/16toWCtseYKw8G1X2j7
xYR3Cyabq37hgbesDOThIIzNAP0UCUS8mnunmkS5adEbftRaDi2JZoGxDw46jtJJ2+13Cw==
Message-ID: <Mr.A7pTA5IgrUA.q4bP41vAJOp@testrun.org>
To: <hcksocnsofoejx@five.chat>
From: <alice@testrun.org>
F
--
Sent with my Delta Chat Messenger: https://delta.chat
--CDB8D27A0B2C.1592050083/hq5.merlinux.eu--

View File

@@ -0,0 +1,91 @@
Return-Path: <>
Delivered-To: alice@tiscali.it
Received: from director-5.mail.tiscali.sys ([10.39.80.174])
by dovecot-08.mail.tiscali.sys with LMTP id SBRfEpGb517VAgAAd2fHbg
for <alice@tiscali.it>; Mon, 15 Jun 2020 16:02:25 +0000
Received: from cmgw-4.mail.tiscali.it ([10.39.80.174])
by director-5.mail.tiscali.sys with LMTP id MFUPL5Cb516tawAArQJVuQ
; Mon, 15 Jun 2020 16:02:25 +0000
Received: from michael.mail.tiscali.it ([213.205.33.246])
by cmgw-4.mail.tiscali.it with
id rTtS2200V5JdeUd01U2RlV; Mon, 15 Jun 2020 16:02:25 +0000
x-cnfs-analysis: v=2.3 cv=ZdPMyfdA c=1 sm=1 tr=0 cx=a_idp_d
a=AfTPebshMYb+aQOCLa9q3Q==:117 a=HpEJnUlJZJkA:10 a=jmdcTMp_Gj4A:10
a=r77TgQKjGQsHNAKrUKIA:9 a=b8iBRs35AAAA:8 a=NMdB-582e605uxHDr_AA:9
a=QEXdDO2ut3YA:10 a=MhhPCb74-dYA:10 a=HXlsH_Kov2KnitTn7A4A:9
a=BkuCPOF3BOzethIN9HQA:9 a=qG5HpJ6ZyD35YNEB:21 a=kvHihYffoorsyJbA:21
a=xD8EQi6zkreDqSNPYj5l:22
Date: Mon, 15 Jun 2020 16:02:25 +0000
From: Mail Delivery System <mail-daemon@smtp.tiscali.it>
To: alice@tiscali.it
Subject: Delivery status notification
MIME-Version: 1.0
Content-Type: multipart/report; boundary="------------I305M09060309060P_896715922369450"
This is a multi-part message in MIME format.
--------------I305M09060309060P_896715922369450
Content-Type: text/plain; charset=UTF-8;
Content-Transfer-Encoding: 8bit
This is an automatically generated Delivery Status Notification.
Delivery to the following recipients was aborted after 2 second(s):
* shenauithz@testrun.org
--------------I305M09060309060P_896715922369450
Content-Type: message/delivery-status; charset=UTF-8;
Content-Transfer-Encoding: 8bit
Reporting-MTA: dns; michael.mail.tiscali.it [213.205.33.13]
Received-From-MTA: dns; localhost [146.241.100.150]
Arrival-Date: Mon, 15 Jun 2020 16:02:23 +0000
Final-recipient: rfc822; shenauithz@testrun.org
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 <shenauithz@testrun.org>: Recipient address rejected: User unknown in virtual mailbox table
Last-attempt-Date: Mon, 15 Jun 2020 16:02:25 +0000
--------------I305M09060309060P_896715922369450
Content-Type: text/rfc822-headers; Content-Transfer-Encoding: 8bit
Content-Disposition: attachment
x-auth-user: alice@tiscali.it
Chat-Disposition-Notification-To: alice@tiscali.it
Chat-User-Avatar: avatar.jpg
Subject: =?utf-8?q?Message_from_=F0=9F=8F=9E=EF=B8=8F_Mefiscali?=
MIME-Version: 1.0
Date: Mon, 15 Jun 2020 16:02:22 +0000
X-Mailer: Delta Chat Core 1.35.0/Android 1.9.5
Chat-Version: 1.0
Autocrypt: addr=alice@tiscali.it; prefer-encrypt=mutual;
keydata=xjMEXtFRUBYJKwYBBAHaRw8BAQdA5sqHJqkWlveCgsNd0rtwtZrT1mmo1gwaGC5+WheYk5
nNHTxhbmRyZWFzLmxhdHRtYW5uQHRpc2NhbGkuaXQ+wosEEBYIADMCGQEFAl7RUXoCGwMECwkIBwYV
CAkKCwIDFgIBFiEEJUsbRIjZEaRNAs1p1Z5M1vshkrAACgkQ1Z5M1vshkrAAaAEA4wssXeU2IXnowv
iu3zmcNzDgE4HdmW4RFyqJC6bgxXQA/3aTfE/PhQgZvi6RrKMvP4zygXpD9y+3ydIZP88Bp8kIzjgE
XtFRUBIKKwYBBAGXVQEFAQEHQKaAwlP0j9m0aYsCtO+qD9+foH0kiTN5BWDe5YcZrckVAwEIB8J4BB
gWCAAgBQJe0VF6AhsMFiEEJUsbRIjZEaRNAs1p1Z5M1vshkrAACgkQ1Z5M1vshkrA1JgEAkscCQlps
h3ZxlLqBlbf2+85f4S4aGQfFPtIYEkKKhYEBAJbQulNNp9UarvhfyBiIdvkBVDcCnJZwzbORqp8RM0 gC
Message-ID: <Mr.un2NYERi1RM.lbQ5F9q-QyJ@tiscali.it>
To: <shenauithz@testrun.org>
From: =?utf-8?b?8J+Pnu+4jyBNZWZpc2NhbGk=?= <alice@tiscali.it>
Content-Type: multipart/mixed; boundary="5uAmYQux1HZxxriijTjjKSp4DMoJwq"
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tiscali.it; s=smtp;
t=1592236943; bh=C3taz+zuSre1ko5Q5CzGPmbyrgegKYBClx/3Dv7t/Xw=;
h=Subject:Date:To:From;
b=LrcfLfrQoemOkHTQsqR8MExqNlx5KPYNFWhwlBWylvVc5GlmlhzqM6SAVKd0NVsKE
gVRlBId5FvnlwoJ2WZnXaw/+3lWKilMTuzzQ1oFGvLnZ1XUaUEfuliIv+9NI79dJWX
+S3jsSgzJMJc9+fO6s9bJsX1EHQ2a8GXNbwDtLXs=
--------------I305M09060309060P_896715922369450--

View File

@@ -0,0 +1,100 @@
X-Atlas-Received: from 10.218.250.153 by atlas222.free.mail.ne1.yahoo.com with http; Wed, 10 Jun 2020 10:11:23 +0000
Return-Path: <>
Received: from 77.238.177.145 (EHLO sonic314-19.consmr.mail.ir2.yahoo.com)
by atlas222.free.mail.ne1.yahoo.com with SMTPs; Wed, 10 Jun 2020 10:11:23 +0000
X-Originating-Ip: [77.238.177.145]
Received-SPF: none (domain of sonic314-19.consmr.mail.ir2.yahoo.com does not designate permitted sender hosts)
Authentication-Results: atlas222.free.mail.ne1.yahoo.com;
dkim=pass header.i=@yahoo.com header.s=@bounce;
spf=none smtp.mailfrom=sonic314-19.consmr.mail.ir2.yahoo.com;
dmarc=success(p=REJECT) header.from=yahoo.com;
X-Apparently-To: alice@yahoo.com; Wed, 10 Jun 2020 10:11:23 +0000
X-YMailISG: RT5ZnycWLDvIW52uqHS_EWNgl31NdJPyLLB2F4SYb1GCAoo9
pcninuVU5GDMBZykeMT4cSUt4ZqXxS5FdEeWJqtGIAtbEGbIL8Uhcoszqm4m
JuMJiQZwEE7W_fsS_9MUK5gZtMkhKkSnAuaeaOLKNYAwFZdBqA0uEYA5EmVf
EC9J4RGQ4hZvrMqMj_W.cj4pvbEC.pyirLxTfkICuUkZVguYoxG16y1EOJPw
B48fhXvF5ErU7WAHKxyRM3bMOg7b5pXHKn1dtRSVAXEuqBAQrWig1pePpYH1
wO54sYT7cgmdiFvfLY5rR7YcBzopmKJBycKzBVoRLCY4gvoNyTLPKx9o3AAz
WU4B7TGejDBElYSLpfnyvQg8wU27zzo2IVBZWUNztP0Ca8CQ07Y7TxUZAO.f
DNO5c7nd81PHMRDbSeaw1BTV2Yd9vlBc7syYmwGvtVBJQwRU7qPN.DpFO2jC
9j9DytVhm5231gdBBRSzW78yG.VvaIdJgq_YViKNM9VxFseTz3Sjt3TaYznP
gAVq.MxpopNsSZf_tedwAhXDWyrjKsRPK.v2ANivmuWGPednniEaMYhxJ05M
_5SnJ.hAU.l6h3HCEfiU.SH390_3tZgYNfxCo4GPPFMfnNPmKa3.rgpChBCz
9CRexJ8BSFyCEeAhuqQ8vSJfSuittJmXvS6Tk8Rxd9HUJAtKzZ.xCWZQ4tA6
Yp2aRG23_rK_C6hH8ArkkvbG.uVQTt6DltSX6avJLObBfIhBH0x64RoFjGee
vYXxM741Okm0jH7r79c8GhnAwas_bwfkaTW9e1nhYP0eyI36z_QwLYgOH3Mm
LrUcejpOMDR60QWDuDyRbWXOJdr3Q2K0ERhuAy6YnINq0sL3HX7t5wjsFLvp
_7Ri_eruTfIst4C7DZwERwui6aDSEAdF1Z8oZukBVmiyZsHmhJQCUik646iy
3ASMR3lX7R3q2PBHQo2oC3qte8Fzz1FhKoMtfCGtIpeCazlkhDEJ6eTBSQ3R
Pe7M_GPiv3QNp7qu5CWHlzy6hWEKIkNwx.WRGYzfxkyJMmJm4UrhQYUfa4lG
Wb8n.mfYnS_KGYtzyRFNqAL0IGo.1MB9aG6qQk456Fz9GJgbHLWrMXVtyfrr
Uo7mKih8FCrdUKv5X6KBnpY0vvyoH5jrWyrvo3DW0bq_JvZ9U51JwUhoGY5U
c1t.yCSJbs8tnrGZHuUTOvouWzpCAJsk34AqRyH0wDJZQsAwBW5UZ3jx8ARA
FicoSqZCa4wEP9WaaXvfzFbmLW0-
X-Originating-IP: [77.238.177.145]
Received: from 10.217.135.165 (EHLO sonic314-19.consmr.mail.ir2.yahoo.com) (77.238.177.145)
by mta4277.mail.ne1.yahoo.com with SMTPS; Wed, 10 Jun 2020 10:11:21 +0000
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=bounce; t=1591783879; bh=4BmZzBC/nu0AJ9r0i0xNuCENks2KZcuXCbjSHdzbg9Y=; h=Date:From:To:Subject:From:Subject; b=lPxu8goOGOLVgnwbndfdptZ7zI5VEo0lSSr+ONGxwdtuhrySKDU6Sp41/g6jWbAiVPT1947j/B5wOlPfa5tv4XkWrGf0JCbT1I20ZJIkNfNwt4F0qPnbJAiHFIDPxcY68utjC9IgPWJd0cGqJNXbFwbJBu88rtrbMoInzLakh5I=
Received: from sonic.gate.mail.ne1.yahoo.com by sonic314.consmr.mail.ir2.yahoo.com with HTTP; Wed, 10 Jun 2020 10:11:19 +0000
Date: Wed, 10 Jun 2020 10:11:19 +0000
From: MAILER-DAEMON@yahoo.com
To: alice@yahoo.com
Message-ID: <1713051795.39992.1591783879940@sonic314.consmr.mail.ir2.yahoo.com>
Subject: Failure Notice
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-Length: 3347
Sorry, we were unable to deliver your message to the following address.
<haeclirth.sinoenrat@yahoo.com>:
554: delivery error: dd Not a valid recipient - atlas117.free.mail.ne1.yahoo.com
--- Below this line is a copy of the message.
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1591783876; bh=kXD6TZuQDjqZf/AEAJ2HCX32Titkj3IywytG6GSm4yQ=; h=Date:From:To:Subject:References:From:Subject; b=PexnIBxnVSkyutv/jVn+Wlt5QPuVHnWleP3baWlvqkXaKR51pCaZIoGJggMEonitEeJkcYpgplBawEBz0hlGf63NqOHHkxUk6U1olwc0y9kj5kDH5lrORgXrf7U4z5t+i5n0II36MxbG9n/5tDRXoiabLFoWx//3O9x/ZJvVWPlq8RBFzVG8aoL2TkBQAVcqX/vW1f3WJuopaUYWB4AzR3TyuC2kVQPFqbPMk+G/VmyuZFmZesh1bSBva5hdKYLxES5v8hvTIDRqSYZrnZ4V67MqicZ8m229Xf4Za8qOE+a2Z+Vv5VrQ+CjjPZwRAcmKHkLY80VCSkpeL2R2YG4APg==
X-YMail-OSG: 4spnw98VM1k_g51CM6oepdNEMiPFRtZ0ZG_zOBGIlhcNvS1mkzr8l8VTB0CY_Q0
dR52ikl7QVYESerRQgcGqBfLwKpem7i1XSrCl2HuyHeWzF6Gu5MqFPMCak.v8GyDXNO075NEwNt1
i18CJ29cEjiHthoamgmj0oqerAglglKRhTuuAFy4wUmZZm7VyvaW4wHUD1g7DeWGijQsCglSYMUK
CmoFcKsWOZBSYPMkp7iRwUp52pXHFin3qf4uQ27K_Sh.6s7KLAfWVkV7L_5AR3MyCPAVzm71.1yG
G7Vy5HSBgGMQ90B7VbcjOkCg3F4JNl4Z_P2ejV1KZ.tNoPLgO.FmsfFy1OXBGf3m2mDmRcuEO4K2
mTRhsjZf.2iiWpx02b3tY.oUtYrIBXBVIFPbTB9sBMn_9Z_qdVmO3gjD6gCPEBzuVvEO0eZIrgaw
EDTZt8Z9tSRDm1.4gV8LWQBYShF7XuMV0togiLYIO8s_iTHcTbhKhPlwxP.mxr06xcx_9kzReVTL
9lB1FkB5Jm0WccWHGhLBqeMjGDoaNqPxLqJ.1tI58tLXsPoR6m1NFVEdzI1G.4AVBeXZ_9BjgUhm
KY33sEg.GwIjUlWWWuSyRZ1q1K2nqi1z29wH2R1Glmdmx0lyqfMg9Xe8HV7YZu2CuZ8SlDLLB.rX
NU4PwMsNfU6pK2HejQPsJuyOlI5Q824rXRF5xTLYKsYcQptoFXyLe6MXKW1ThBLQV2nWYDRs_V.e
SBmt22TfuOwu4Y5ju0sXmztZ8zpiIC8_rnAa5bVBEHxzkic64UZdukDX9V12Pk3G2sGYRyPTH472
wBX33JpDuq6BtrKr4FXjCLeVppARTHpiKM0jHMjmNf1bF0TvrcCsC9zAYtitAqgcGZNFETNuV3KM
57XifdDEwUPOuww0ApSWO.iwP2POvIRBVlrxdgA8MbLmuuX4UxNCw23z1f7MVY6F3L60LUrX5GZO
aKaMmD1XTzx32J6c_TUmyuViT5vphqpEooTzHG2X7ALb4xC8yHlE4wDKyaEDARZ.8P2lO9T18oCz
OQvJjwDaLOkeAmo23yRMn70bYJK3tP9Z5cS1C0TE8PEtz4sd1syQUIZZ2g8JG_AQcE4lUZSZlIKN
AHjB8h8Uin35zKe0Le1DBjdQUmpgAETlmYE7V0nJDEmagB3dtpbokgRBuuBfhXlFpxHcnAmBFFFm
XOSLWEPnmxu2o8CCjjz3QUBy2fr3EI_D2VFpy..MuZgRwtES.l24m_95xtQxI28R4SWZN6LsS_rr
1S33BJCCCAfXtCAFzCfz5.qSzHRYbLdY5do6yKj0pPLQTUTjlMwmCUGPcSJhsyxkkEVIK1W_Z16R
ZRls-
Received: from sonic.gate.mail.ne1.yahoo.com by sonic314.consmr.mail.ir2.yahoo.com with HTTP; Wed, 10 Jun 2020 10:11:16 +0000
Date: Wed, 10 Jun 2020 10:11:12 +0000 (UTC)
From: Delta Chat Test <alice@yahoo.com>
To: "haeclirth.sinoenrat@yahoo.com" <haeclirth.sinoenrat@yahoo.com>
Message-ID: <1680295672.3657931.1591783872936@mail.yahoo.com>
Subject: test
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_3657930_145367320.1591783872935"
References: <1680295672.3657931.1591783872936.ref@mail.yahoo.com>
X-Mailer: WebService/1.1.16072 YMailNorrin Mozilla/5.0 (X11; Linux x86_64; rv:77.0) Gecko/20100101 Firefox/77.0
Content-Length: 494
------=_Part_3657930_145367320.1591783872935
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
test
------=_Part_3657930_145367320.1591783872935
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
<html><head></head><body><div class="yahoo-style-wrap" style="font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:16px;"><div dir="ltr" data-setdir="false">test<br></div></div></body></html>
------=_Part_3657930_145367320.1591783872935--