mirror of
https://github.com/chatmail/core.git
synced 2026-04-04 06:22:16 +03:00
Compare commits
11 Commits
hpk-gh-pyt
...
fix/async-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55ada1cd89 | ||
|
|
1077cf5e99 | ||
|
|
ca698f9164 | ||
|
|
99201027e2 | ||
|
|
d607d35abc | ||
|
|
3d790cbfca | ||
|
|
68b2707d12 | ||
|
|
6066821b50 | ||
|
|
fe695c0f95 | ||
|
|
7bf13f3f89 | ||
|
|
3b3992daed |
@@ -138,6 +138,8 @@ jobs:
|
||||
steps:
|
||||
- *restore-workspace
|
||||
- *restore-cache
|
||||
- run: rustup install $(cat rust-toolchain)
|
||||
- run: rustup default $(cat rust-toolchain)
|
||||
- run:
|
||||
name: build docs, run tests and build wheels
|
||||
command: ci_scripts/run-python.sh
|
||||
|
||||
30
.github/workflows/rust.yml
vendored
30
.github/workflows/rust.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: 3.7 python tests against core
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.x
|
||||
architecture: x64
|
||||
|
||||
- run: bash ci_scripts/run-python.sh
|
||||
41
Cargo.lock
generated
41
Cargo.lock
generated
@@ -90,17 +90,17 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "async-imap"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/dignifiedquire/async-imap#1d3cbafaa87203d71b4f8e6ed282079511439dd7"
|
||||
dependencies = [
|
||||
"async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-std 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-tls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-std 0.99.12 (git+https://github.com/async-rs/async-std)",
|
||||
"async-tls 0.5.0 (git+https://github.com/async-rs/async-tls)",
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures_codec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"imap-proto 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"imap-proto 0.9.1 (git+https://github.com/dignifiedquire/tokio-imap?branch=async-imap)",
|
||||
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rental 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -119,7 +119,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "0.99.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/async-rs/async-std#122e87364bef463c5afbf7681ec3ce35a3a7f577"
|
||||
dependencies = [
|
||||
"async-macros 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-task 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -144,7 +144,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.0.0"
|
||||
version = "0.99.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"async-macros 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -178,8 +178,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/async-rs/async-tls#cd44fd7adfc24632c07a941c2daf4e05dc68be9e"
|
||||
dependencies = [
|
||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -636,9 +636,9 @@ dependencies = [
|
||||
name = "deltachat"
|
||||
version = "1.0.0-beta.7"
|
||||
dependencies = [
|
||||
"async-imap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-std 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-tls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-imap 0.1.0 (git+https://github.com/dignifiedquire/async-imap)",
|
||||
"async-std 0.99.12 (git+https://github.com/async-rs/async-std)",
|
||||
"async-tls 0.5.0 (git+https://github.com/async-rs/async-tls)",
|
||||
"backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -684,7 +684,6 @@ dependencies = [
|
||||
"strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -903,7 +902,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.13"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1294,7 +1293,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "imap-proto"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/dignifiedquire/tokio-imap?branch=async-imap#b03e5e07aa066c6a27a55e465a9660cdc99bf1c3"
|
||||
dependencies = [
|
||||
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1784,7 +1783,7 @@ dependencies = [
|
||||
"ed25519-dalek 1.0.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2198,7 +2197,7 @@ dependencies = [
|
||||
"cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3285,12 +3284,12 @@ dependencies = [
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
|
||||
"checksum async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "efd3d156917d94862e779f356c5acae312b08fd3121e792c857d7928c8088423"
|
||||
"checksum async-imap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11beae75596af5c2c44f08dc1ef666bc0982e65646fd59f70af800709a6028a8"
|
||||
"checksum async-imap 0.1.0 (git+https://github.com/dignifiedquire/async-imap)" = "<none>"
|
||||
"checksum async-macros 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e421d59b24c1feea2496e409b3e0a8de23e5fc130a2ddc0b012e551f3b272bba"
|
||||
"checksum async-std 0.99.12 (git+https://github.com/async-rs/async-std)" = "<none>"
|
||||
"checksum async-std 0.99.12 (registry+https://github.com/rust-lang/crates.io-index)" = "44501a9f7961bb539b67be0c428b3694e26557046a52759ca7eaf790030a64cc"
|
||||
"checksum async-std 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80fd70c8b0cbd985275dc70448d5b6b76338ead5350d1774d81585ab8f826673"
|
||||
"checksum async-task 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de6bd58f7b9cc49032559422595c81cbfcf04db2f2133592f70af19e258a1ced"
|
||||
"checksum async-tls 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce6977f57fa68da77ffe5542950d47e9c23d65f5bc7cb0a9f8700996913eec7"
|
||||
"checksum async-tls 0.5.0 (git+https://github.com/async-rs/async-tls)" = "<none>"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
@@ -3367,7 +3366,7 @@ dependencies = [
|
||||
"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
"checksum fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
|
||||
"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f"
|
||||
"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
@@ -3410,7 +3409,7 @@ dependencies = [
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
|
||||
"checksum image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b00861cbbb254a627d8acc0cec786b484297d896ab8f20fdc8e28536a3e918ef"
|
||||
"checksum imap-proto 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e0690d689f8afe8111dfe1daedd9ef0d232868c7819da3c1f9252fd260aff7f7"
|
||||
"checksum imap-proto 0.9.1 (git+https://github.com/dignifiedquire/tokio-imap?branch=async-imap)" = "<none>"
|
||||
"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
|
||||
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e"
|
||||
|
||||
@@ -19,9 +19,9 @@ reqwest = { version = "0.9.15", default-features = false, features = ["rustls-tl
|
||||
num-derive = "0.2.5"
|
||||
num-traits = "0.2.6"
|
||||
lettre = { git = "https://github.com/deltachat/lettre", branch = "feat/rustls" }
|
||||
async-imap = "0.1"
|
||||
async-tls = "0.6"
|
||||
async-std = { version = "1.0", features = ["unstable"] }
|
||||
async-imap = { git = "https://github.com/dignifiedquire/async-imap", branch = "master" }
|
||||
async-tls = { git = "https://github.com/async-rs/async-tls", branch = "master" }
|
||||
async-std = { git = "https://github.com/async-rs/async-std", branch = "master", features = ["unstable"] }
|
||||
base64 = "0.10"
|
||||
charset = "0.1"
|
||||
percent-encoding = "2.0"
|
||||
@@ -53,7 +53,6 @@ sanitize-filename = "0.2.1"
|
||||
stop-token = { version = "0.1.1", features = ["unstable"] }
|
||||
rustls = "0.16.0"
|
||||
webpki-roots = "0.18.0"
|
||||
webpki = "0.21.0"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0"
|
||||
|
||||
@@ -13,6 +13,7 @@ export TOXWORKDIR=.docker-tox
|
||||
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
cargo build --release -p deltachat_ffi
|
||||
# cargo test --all --all-features
|
||||
|
||||
# Statically link against libdeltachat.a.
|
||||
export DCC_RS_DEV=$(pwd)
|
||||
@@ -21,27 +22,36 @@ export DCC_RS_DEV=$(pwd)
|
||||
# needed by tox below.
|
||||
export PATH=$PATH:/opt/python/cp35-cp35m/bin
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
pushd python
|
||||
# prepare a clean tox run
|
||||
rm -rf tests/__pycache__
|
||||
rm -rf src/deltachat/__pycache__
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# run tox. The circle-ci project env-var-setting DCC_PY_LIVECONFIG
|
||||
# allows running of "liveconfig" tests but for speed reasons
|
||||
# we run them only for the highest python version we support
|
||||
|
||||
# we split out qr-tests run to minimize likelyness of flaky tests
|
||||
# (some qr tests are pretty heavy in terms of send/received
|
||||
# messages and rust's imap code likely has concurrency problems)
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "qr"
|
||||
unset DCC_PY_LIVECONFIG
|
||||
#tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
|
||||
#tox --workdir "$TOXWORKDIR" -e auditwheels
|
||||
pushd /bin
|
||||
ln -s /opt/python/cp27-cp27m/bin/python2.7
|
||||
ln -s /opt/python/cp36-cp36m/bin/python3.6
|
||||
ln -s /opt/python/cp37-cp37m/bin/python3.7
|
||||
popd
|
||||
|
||||
if [ -n "$TESTS" ]; then
|
||||
|
||||
pushd python
|
||||
# prepare a clean tox run
|
||||
rm -rf tests/__pycache__
|
||||
rm -rf src/deltachat/__pycache__
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# run tox. The circle-ci project env-var-setting DCC_PY_LIVECONFIG
|
||||
# allows running of "liveconfig" tests but for speed reasons
|
||||
# we run them only for the highest python version we support
|
||||
|
||||
# we split out qr-tests run to minimize likelyness of flaky tests
|
||||
# (some qr tests are pretty heavy in terms of send/received
|
||||
# messages and rust's imap code likely has concurrency problems)
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- --reruns 3 -k "qr"
|
||||
unset DCC_PY_LIVECONFIG
|
||||
tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
|
||||
tox --workdir "$TOXWORKDIR" -e auditwheels
|
||||
popd
|
||||
fi
|
||||
|
||||
|
||||
# if [ -n "$DOCS" ]; then
|
||||
# echo -----------------------
|
||||
# echo generating python docs
|
||||
|
||||
@@ -427,15 +427,19 @@ class TestOnlineAccount:
|
||||
assert self_addr not in ev[2]
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
|
||||
|
||||
def test_mvbox_sentbox_threads(self, acfactory):
|
||||
def test_mvbox_sentbox_threads(self, acfactory, lp):
|
||||
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
wait_configuration_progress(ac2, 1000)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
lp.sec("configuration completed for both accounts")
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
lp.sec("ac1: send text to chat with ac2")
|
||||
chat.send_text("message1")
|
||||
lp.sec("ac2: wait for incoming message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
lp.sec("message arrived, test ends")
|
||||
|
||||
def test_move_works(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
@@ -675,6 +679,7 @@ class TestOnlineAccount:
|
||||
assert len(messages) == 1
|
||||
assert messages[0].text == "msg1"
|
||||
|
||||
pytest.xfail("cannot export twice yet, probably due to interrupt_idle failing")
|
||||
# wait until a second passed since last backup
|
||||
# because get_latest_backupfile() shall return the latest backup
|
||||
# from a UI it's unlikely anyone manages to export two
|
||||
@@ -895,7 +900,7 @@ class TestOnlineConfigureFails:
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "cannot login" in ev1[2].lower()
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_user(self, acfactory):
|
||||
@@ -904,7 +909,7 @@ class TestOnlineConfigureFails:
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "cannot login" in ev1[2].lower()
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_domain(self, acfactory):
|
||||
|
||||
227
src/imap.rs
227
src/imap.rs
@@ -45,7 +45,7 @@ pub struct Imap {
|
||||
session: Arc<Mutex<Option<Session>>>,
|
||||
connected: Arc<Mutex<bool>>,
|
||||
interrupt: Arc<Mutex<Option<stop_token::StopSource>>>,
|
||||
skip_next_idle_wait: AtomicBool,
|
||||
|
||||
should_reconnect: AtomicBool,
|
||||
}
|
||||
|
||||
@@ -119,7 +119,6 @@ impl Imap {
|
||||
config: Arc::new(RwLock::new(ImapConfig::default())),
|
||||
interrupt: Arc::new(Mutex::new(None)),
|
||||
connected: Arc::new(Mutex::new(false)),
|
||||
skip_next_idle_wait: AtomicBool::new(false),
|
||||
should_reconnect: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
@@ -312,21 +311,18 @@ impl Imap {
|
||||
return false;
|
||||
}
|
||||
|
||||
let teardown = match &mut *self.session.lock().await {
|
||||
let (teardown, can_idle, has_xlist) = match &mut *self.session.lock().await {
|
||||
Some(ref mut session) => match session.capabilities().await {
|
||||
Ok(caps) => {
|
||||
if !context.sql.is_open() {
|
||||
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
|
||||
true
|
||||
(true, false, false)
|
||||
} else {
|
||||
let can_idle = caps.has_str("IDLE");
|
||||
let has_xlist = caps.has_str("XLIST");
|
||||
let caps_list = caps
|
||||
.iter()
|
||||
.fold(String::new(), |s, c| s + &format!(" {:?}", c));
|
||||
self.config.write().await.can_idle = can_idle;
|
||||
self.config.write().await.has_xlist = has_xlist;
|
||||
*self.connected.lock().await = true;
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ImapConnected(format!(
|
||||
@@ -334,22 +330,25 @@ impl Imap {
|
||||
lp.mail_user, caps_list,
|
||||
))
|
||||
);
|
||||
false
|
||||
(false, can_idle, has_xlist)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
info!(context, "CAPABILITY command error: {}", err);
|
||||
true
|
||||
(true, false, false)
|
||||
}
|
||||
},
|
||||
None => true,
|
||||
None => (true, false, false),
|
||||
};
|
||||
|
||||
if teardown {
|
||||
self.disconnect(context);
|
||||
|
||||
self.unsetup_handle(context).await;
|
||||
self.free_connect_params().await;
|
||||
false
|
||||
} else {
|
||||
self.config.write().await.can_idle = can_idle;
|
||||
self.config.write().await.has_xlist = has_xlist;
|
||||
*self.connected.lock().await = true;
|
||||
true
|
||||
}
|
||||
})
|
||||
@@ -397,16 +396,13 @@ impl Imap {
|
||||
})
|
||||
}
|
||||
|
||||
async fn select_folder<S: AsRef<str>>(
|
||||
&self,
|
||||
context: &Context,
|
||||
folder: Option<S>,
|
||||
) -> ImapActionResult {
|
||||
async fn select_folder<S: AsRef<str>>(&self, context: &Context, folder: Option<S>) -> usize {
|
||||
if self.session.lock().await.is_none() {
|
||||
info!(context, "select_folder detects there is a shutdown ongoing");
|
||||
let mut cfg = self.config.write().await;
|
||||
cfg.selected_folder = None;
|
||||
cfg.selected_folder_needs_expunge = false;
|
||||
return ImapActionResult::Failed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if there is a new folder and the new folder is equal to the selected one, there's nothing to do.
|
||||
@@ -414,7 +410,7 @@ impl Imap {
|
||||
if let Some(ref folder) = folder {
|
||||
if let Some(ref selected_folder) = self.config.read().await.selected_folder {
|
||||
if folder.as_ref() == selected_folder {
|
||||
return ImapActionResult::AlreadyDone;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,11 +430,11 @@ impl Imap {
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, "failed to close session: {:?}", err);
|
||||
return ImapActionResult::Failed;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ImapActionResult::Failed;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
self.config.write().await.selected_folder_needs_expunge = false;
|
||||
@@ -454,7 +450,7 @@ impl Imap {
|
||||
config.selected_mailbox = Some(mailbox);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
info!(
|
||||
context,
|
||||
"Cannot select folder: {}; {:?}.",
|
||||
folder.as_ref(),
|
||||
@@ -463,7 +459,7 @@ impl Imap {
|
||||
|
||||
self.config.write().await.selected_folder = None;
|
||||
self.should_reconnect.store(true, Ordering::Relaxed);
|
||||
return ImapActionResult::Failed;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -471,7 +467,7 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
ImapActionResult::Success
|
||||
1
|
||||
}
|
||||
|
||||
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
|
||||
@@ -497,16 +493,24 @@ impl Imap {
|
||||
}
|
||||
|
||||
async fn fetch_from_single_folder<S: AsRef<str>>(&self, context: &Context, folder: S) -> usize {
|
||||
match self.select_folder(context, Some(&folder)).await {
|
||||
ImapActionResult::Failed | ImapActionResult::RetryLater => {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot select folder \"{}\" for fetching.",
|
||||
folder.as_ref()
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
ImapActionResult::Success | ImapActionResult::AlreadyDone => {}
|
||||
if !self.is_connected().await {
|
||||
info!(
|
||||
context,
|
||||
"Cannot fetch from \"{}\" - not connected.",
|
||||
folder.as_ref()
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if self.select_folder(context, Some(&folder)).await == 0 {
|
||||
info!(
|
||||
context,
|
||||
"Cannot select folder \"{}\" for fetching.",
|
||||
folder.as_ref()
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// compare last seen UIDVALIDITY against the current one
|
||||
@@ -745,34 +749,25 @@ impl Imap {
|
||||
|
||||
pub fn idle(&self, context: &Context) {
|
||||
task::block_on(async move {
|
||||
if self.config.read().await.selected_folder.is_none() {
|
||||
// this probably means that we are in teardown
|
||||
// in any case we can't perform any idling
|
||||
return;
|
||||
}
|
||||
|
||||
info!(context, "imap.idle entered");
|
||||
if !self.config.read().await.can_idle {
|
||||
self.fake_idle(context, true).await;
|
||||
self.fake_idle(context).await;
|
||||
return;
|
||||
}
|
||||
|
||||
info!(context, "setting up handle if needed");
|
||||
self.setup_handle_if_needed(context);
|
||||
|
||||
info!(context, "select watch folder");
|
||||
let watch_folder = self.config.read().await.watch_folder.clone();
|
||||
match self.select_folder(context, watch_folder.as_ref()).await {
|
||||
ImapActionResult::Success | ImapActionResult::AlreadyDone => {}
|
||||
if self.select_folder(context, watch_folder.as_ref()).await == 0 {
|
||||
warn!(context, "IMAP-IDLE not setup.");
|
||||
|
||||
ImapActionResult::Failed | ImapActionResult::RetryLater => {
|
||||
warn!(
|
||||
context,
|
||||
"idle select_folder failed {:?}",
|
||||
watch_folder.as_ref()
|
||||
);
|
||||
self.fake_idle(context, true).await;
|
||||
return;
|
||||
}
|
||||
self.fake_idle(context).await;
|
||||
return;
|
||||
}
|
||||
|
||||
info!(context, "starting to enter idle loop");
|
||||
let session = self.session.lock().await.take();
|
||||
let timeout = Duration::from_secs(23 * 60);
|
||||
if let Some(session) = session {
|
||||
@@ -785,17 +780,8 @@ impl Imap {
|
||||
let (idle_wait, interrupt) = handle.wait_with_timeout(timeout);
|
||||
*self.interrupt.lock().await = Some(interrupt);
|
||||
|
||||
if self.skip_next_idle_wait.load(Ordering::Relaxed) {
|
||||
// interrupt_idle has happened before we
|
||||
// provided self.interrupt
|
||||
self.skip_next_idle_wait.store(false, Ordering::Relaxed);
|
||||
std::mem::drop(idle_wait);
|
||||
info!(context, "Idle wait was skipped");
|
||||
} else {
|
||||
info!(context, "Idle entering wait-on-remote state");
|
||||
let res = idle_wait.await;
|
||||
info!(context, "Idle finished wait-on-remote: {:?}", res);
|
||||
}
|
||||
let res = idle_wait.await;
|
||||
info!(context, "Idle finished: {:?}", res);
|
||||
match handle.done().await {
|
||||
Ok(session) => {
|
||||
*self.session.lock().await = Some(Session::Secure(session));
|
||||
@@ -813,18 +799,8 @@ impl Imap {
|
||||
let (idle_wait, interrupt) = handle.wait_with_timeout(timeout);
|
||||
*self.interrupt.lock().await = Some(interrupt);
|
||||
|
||||
if self.skip_next_idle_wait.load(Ordering::Relaxed) {
|
||||
// interrupt_idle has happened before we
|
||||
// provided self.interrupt
|
||||
self.skip_next_idle_wait.store(false, Ordering::Relaxed);
|
||||
std::mem::drop(idle_wait);
|
||||
info!(context, "Idle wait was skipped");
|
||||
} else {
|
||||
info!(context, "Idle entering wait-on-remote state");
|
||||
let res = idle_wait.await;
|
||||
info!(context, "Idle finished wait-on-remote: {:?}", res);
|
||||
}
|
||||
|
||||
let res = idle_wait.await;
|
||||
info!(context, "Idle finished: {:?}", res);
|
||||
match handle.done().await {
|
||||
Ok(session) => {
|
||||
*self.session.lock().await = Some(Session::Insecure(session));
|
||||
@@ -839,7 +815,7 @@ impl Imap {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) async fn fake_idle(&self, context: &Context, use_network: bool) {
|
||||
async fn fake_idle(&self, context: &Context) {
|
||||
// Idle using timeouts. This is also needed if we're not yet configured -
|
||||
// in this case, we're waiting for a configure job
|
||||
let fake_idle_start_time = SystemTime::now();
|
||||
@@ -849,20 +825,13 @@ impl Imap {
|
||||
task::block_on(async move {
|
||||
let interrupt = stop_token::StopSource::new();
|
||||
|
||||
// we use 1000 minutes if we are told to not try network
|
||||
// which can happen because the watch_folder is not defined
|
||||
// but clients are still calling us in a loop.
|
||||
// if we are to use network, we check every minute if there
|
||||
// is new mail -- TODO: make this more flexible
|
||||
let secs = if use_network { 60 } else { 60000 };
|
||||
let interval = async_std::stream::interval(Duration::from_secs(secs));
|
||||
// TODO: More flexible interval
|
||||
let interval = async_std::stream::interval(Duration::from_secs(10));
|
||||
let mut interrupt_interval = interrupt.stop_token().stop_stream(interval);
|
||||
*self.interrupt.lock().await = Some(interrupt);
|
||||
|
||||
while let Some(_) = interrupt_interval.next().await {
|
||||
if !use_network {
|
||||
continue;
|
||||
}
|
||||
// check if we want to finish fake-idling.
|
||||
if !self.is_connected().await {
|
||||
// try to connect with proper login params
|
||||
// (setup_handle_if_needed might not know about them if we
|
||||
@@ -899,13 +868,7 @@ impl Imap {
|
||||
|
||||
pub fn interrupt_idle(&self) {
|
||||
task::block_on(async move {
|
||||
if self.interrupt.lock().await.take().is_none() {
|
||||
// idle wait is not running, signal it needs to skip
|
||||
self.skip_next_idle_wait.store(true, Ordering::Relaxed);
|
||||
|
||||
// meanwhile idle-wait may have produced the interrupter
|
||||
let _ = self.interrupt.lock().await.take();
|
||||
}
|
||||
let _ = self.interrupt.lock().await.take();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1041,16 +1004,14 @@ impl Imap {
|
||||
return Some(ImapActionResult::RetryLater);
|
||||
}
|
||||
}
|
||||
match self.select_folder(context, Some(&folder)).await {
|
||||
ImapActionResult::Success | ImapActionResult::AlreadyDone => None,
|
||||
res => {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot select folder {} for preparing IMAP operation", folder
|
||||
);
|
||||
|
||||
Some(res)
|
||||
}
|
||||
if self.select_folder(context, Some(&folder)).await == 0 {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot select folder {} for preparing IMAP operation", folder
|
||||
);
|
||||
Some(ImapActionResult::RetryLater)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1164,6 +1125,13 @@ impl Imap {
|
||||
.list_folders(session, context)
|
||||
.await
|
||||
.expect("no folders found");
|
||||
let delimiter = self.config.read().await.imap_delimiter;
|
||||
let fallback_folder = format!("INBOX{}DeltaChat", delimiter);
|
||||
|
||||
let mut mvbox_folder = folders
|
||||
.iter()
|
||||
.find(|folder| folder.name() == "DeltaChat" || folder.name() == fallback_folder)
|
||||
.map(|n| n.name().to_string());
|
||||
|
||||
let sentbox_folder =
|
||||
folders
|
||||
@@ -1172,15 +1140,6 @@ impl Imap {
|
||||
FolderMeaning::SentObjects => true,
|
||||
_ => false,
|
||||
});
|
||||
info!(context, "sentbox folder is {:?}", sentbox_folder);
|
||||
|
||||
let delimiter = self.config.read().await.imap_delimiter;
|
||||
let fallback_folder = format!("INBOX{}DeltaChat", delimiter);
|
||||
|
||||
let mut mvbox_folder = folders
|
||||
.iter()
|
||||
.find(|folder| folder.name() == "DeltaChat" || folder.name() == fallback_folder)
|
||||
.map(|n| n.name().to_string());
|
||||
|
||||
if mvbox_folder.is_none() && 0 != (flags as usize & DC_CREATE_MVBOX) {
|
||||
info!(context, "Creating MVBOX-folder \"DeltaChat\"...",);
|
||||
@@ -1271,34 +1230,26 @@ impl Imap {
|
||||
task::block_on(async move {
|
||||
info!(context, "emptying folder {}", folder);
|
||||
|
||||
if folder.is_empty() {
|
||||
warn!(context, "cannot perform empty, folder not set");
|
||||
if folder.is_empty() || self.select_folder(context, Some(&folder)).await == 0 {
|
||||
warn!(context, "Cannot select folder '{}' for emptying", folder);
|
||||
return;
|
||||
}
|
||||
match self.select_folder(context, Some(&folder)).await {
|
||||
ImapActionResult::Success | ImapActionResult::AlreadyDone => {
|
||||
if !self
|
||||
.add_flag_finalized_with_set(context, SELECT_ALL, "\\Deleted")
|
||||
.await
|
||||
{
|
||||
warn!(context, "Cannot empty folder {}", folder);
|
||||
} else {
|
||||
// we now trigger expunge to actually delete messages
|
||||
self.config.write().await.selected_folder_needs_expunge = true;
|
||||
if self.select_folder::<String>(context, None).await
|
||||
== ImapActionResult::Success
|
||||
{
|
||||
emit_event!(context, Event::ImapFolderEmptied(folder.to_string()));
|
||||
} else {
|
||||
warn!(
|
||||
context,
|
||||
"could not perform expunge on empty-marked folder {}", folder
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImapActionResult::Failed | ImapActionResult::RetryLater => {
|
||||
warn!(context, "could not select folder {}", folder);
|
||||
|
||||
if !self
|
||||
.add_flag_finalized_with_set(context, SELECT_ALL, "\\Deleted")
|
||||
.await
|
||||
{
|
||||
warn!(context, "Cannot empty folder {}", folder);
|
||||
} else {
|
||||
// we now trigger expunge to actually delete messages
|
||||
self.config.write().await.selected_folder_needs_expunge = true;
|
||||
if self.select_folder::<String>(context, None).await == 0 {
|
||||
warn!(
|
||||
context,
|
||||
"could not perform expunge on empty-marked folder {}", folder
|
||||
);
|
||||
} else {
|
||||
emit_event!(context, Event::ImapFolderEmptied(folder.to_string()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,10 +6,9 @@ use async_imap::{
|
||||
};
|
||||
use async_std::net::{self, TcpStream};
|
||||
use async_std::prelude::*;
|
||||
use async_std::sync::Arc;
|
||||
use async_tls::client::TlsStream;
|
||||
|
||||
use crate::login_param::{dc_build_tls_config, CertificateChecks};
|
||||
use crate::login_param::CertificateChecks;
|
||||
|
||||
const DCC_IMAP_DEBUG: &str = "DCC_IMAP_DEBUG";
|
||||
|
||||
@@ -35,12 +34,13 @@ impl Client {
|
||||
pub async fn connect_secure<A: net::ToSocketAddrs, S: AsRef<str>>(
|
||||
addr: A,
|
||||
domain: S,
|
||||
certificate_checks: CertificateChecks,
|
||||
_certificate_checks: CertificateChecks,
|
||||
) -> ImapResult<Self> {
|
||||
let stream = TcpStream::connect(addr).await?;
|
||||
let tls_config = dc_build_tls_config(certificate_checks);
|
||||
let tls_connector: async_tls::TlsConnector = Arc::new(tls_config).into();
|
||||
let tls_stream = tls_connector.connect(domain.as_ref(), stream)?.await?;
|
||||
let tls = async_tls::TlsConnector::new();
|
||||
|
||||
let tls_stream = tls.connect(domain.as_ref(), stream)?.await?;
|
||||
|
||||
let mut client = ImapClient::new(tls_stream);
|
||||
if std::env::var(DCC_IMAP_DEBUG).is_ok() {
|
||||
client.debug = true;
|
||||
|
||||
@@ -110,14 +110,9 @@ impl JobThread {
|
||||
if async_std::task::block_on(async move { self.imap.is_connected().await }) {
|
||||
return true;
|
||||
}
|
||||
let watch_folder_name = match context.sql.get_raw_config(context, self.folder_config_name) {
|
||||
Some(name) => name,
|
||||
None => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let ret_connected = dc_connect_to_configured_imap(context, &self.imap) != 0;
|
||||
let mut ret_connected = dc_connect_to_configured_imap(context, &self.imap) != 0;
|
||||
|
||||
if ret_connected {
|
||||
if context
|
||||
.sql
|
||||
@@ -128,7 +123,12 @@ impl JobThread {
|
||||
self.imap.configure_folders(context, 0x1);
|
||||
}
|
||||
|
||||
self.imap.set_watch_folder(watch_folder_name);
|
||||
if let Some(mvbox_name) = context.sql.get_raw_config(context, self.folder_config_name) {
|
||||
self.imap.set_watch_folder(mvbox_name);
|
||||
} else {
|
||||
self.imap.disconnect(context);
|
||||
ret_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
ret_connected
|
||||
@@ -170,18 +170,10 @@ impl JobThread {
|
||||
}
|
||||
}
|
||||
|
||||
if self.connect_to_imap(context) {
|
||||
info!(context, "{}-IDLE started...", self.name,);
|
||||
self.imap.idle(context);
|
||||
info!(context, "{}-IDLE ended.", self.name);
|
||||
} else {
|
||||
// It's probably wrong that the thread even runs
|
||||
// but let's call fake_idle and tell it to not try network at all.
|
||||
// (once we move to rust-managed threads this problem goes away)
|
||||
info!(context, "{}-IDLE not connected, fake-idling", self.name);
|
||||
async_std::task::block_on(async move { self.imap.fake_idle(context, false).await });
|
||||
info!(context, "{}-IDLE fake-idling finished", self.name);
|
||||
}
|
||||
self.connect_to_imap(context);
|
||||
info!(context, "{}-IDLE started...", self.name,);
|
||||
self.imap.idle(context);
|
||||
info!(context, "{}-IDLE ended.", self.name);
|
||||
|
||||
self.state.0.lock().unwrap().using_handle = false;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,6 @@ use std::fmt;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use async_std::sync::Arc;
|
||||
use rustls;
|
||||
use webpki;
|
||||
use webpki_roots;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Display, FromPrimitive)]
|
||||
#[repr(i32)]
|
||||
@@ -255,50 +251,28 @@ fn get_readable_flags(flags: i32) -> String {
|
||||
res
|
||||
}
|
||||
|
||||
pub struct NoCertificateVerification {}
|
||||
|
||||
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_roots: &rustls::RootCertStore,
|
||||
_presented_certs: &[rustls::Certificate],
|
||||
_dns_name: webpki::DNSNameRef<'_>,
|
||||
_ocsp: &[u8],
|
||||
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||
Ok(rustls::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_build_tls_config(certificate_checks: CertificateChecks) -> rustls::ClientConfig {
|
||||
let mut config = rustls::ClientConfig::new();
|
||||
config
|
||||
.root_store
|
||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||
|
||||
match certificate_checks {
|
||||
CertificateChecks::Strict => {}
|
||||
CertificateChecks::Automatic => {
|
||||
// Same as AcceptInvalidCertificates for now.
|
||||
// TODO: use provider database when it becomes available
|
||||
config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||
}
|
||||
CertificateChecks::AcceptInvalidCertificates => {
|
||||
// TODO: only accept invalid certs
|
||||
config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||
}
|
||||
CertificateChecks::AcceptInvalidHostnames => {
|
||||
// TODO: only accept invalid hostnames
|
||||
config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
// pub fn dc_build_tls(
|
||||
// certificate_checks: CertificateChecks,
|
||||
// ) -> Result<native_tls::TlsConnector, native_tls::Error> {
|
||||
// let mut tls_builder = native_tls::TlsConnector::builder();
|
||||
// match certificate_checks {
|
||||
// CertificateChecks::Automatic => {
|
||||
// // Same as AcceptInvalidCertificates for now.
|
||||
// // TODO: use provider database when it becomes available
|
||||
// tls_builder
|
||||
// .danger_accept_invalid_hostnames(true)
|
||||
// .danger_accept_invalid_certs(true)
|
||||
// }
|
||||
// CertificateChecks::Strict => &mut tls_builder,
|
||||
// CertificateChecks::AcceptInvalidHostnames => {
|
||||
// tls_builder.danger_accept_invalid_hostnames(true)
|
||||
// }
|
||||
// CertificateChecks::AcceptInvalidCertificates => tls_builder
|
||||
// .danger_accept_invalid_hostnames(true)
|
||||
// .danger_accept_invalid_certs(true),
|
||||
// }
|
||||
// .build()
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::login_param::{dc_build_tls_config, LoginParam};
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::oauth2::*;
|
||||
|
||||
#[derive(DebugStub)]
|
||||
@@ -65,7 +65,10 @@ impl Smtp {
|
||||
let domain = &lp.send_server;
|
||||
let port = lp.send_port as u16;
|
||||
|
||||
let tls_config = dc_build_tls_config(lp.smtp_certificate_checks);
|
||||
let mut tls_config = rustls::ClientConfig::new();
|
||||
tls_config
|
||||
.root_store
|
||||
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||
let tls_parameters = ClientTlsParameters::new(domain.to_string(), tls_config);
|
||||
|
||||
let (creds, mechanism) = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
|
||||
|
||||
Reference in New Issue
Block a user