mirror of
https://github.com/chatmail/core.git
synced 2026-04-06 15:42:10 +03:00
Compare commits
30 Commits
v1.139.3
...
hpk-gh-pyt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e454ede4c | ||
|
|
029f60df27 | ||
|
|
20c82b324a | ||
|
|
e7ebb40cd1 | ||
|
|
bca8094fcb | ||
|
|
7ab5d36b5b | ||
|
|
58ad14d9c3 | ||
|
|
e539bddc3b | ||
|
|
2fc1d21959 | ||
|
|
b43d9d2ffe | ||
|
|
5b73951b9b | ||
|
|
8595b92fcf | ||
|
|
6054b90975 | ||
|
|
b8427ab56e | ||
|
|
02f72eea61 | ||
|
|
a5a20078f0 | ||
|
|
7383094b33 | ||
|
|
e225a6fb17 | ||
|
|
6bdc207277 | ||
|
|
101141c67a | ||
|
|
d07afe5bd6 | ||
|
|
00e22d4339 | ||
|
|
91c8f48c21 | ||
|
|
3d76d21925 | ||
|
|
3349c0e9dc | ||
|
|
7b35104b83 | ||
|
|
22b6e8f6e2 | ||
|
|
ad118aa0df | ||
|
|
9044b80b9f | ||
|
|
b948e973c5 |
@@ -15,7 +15,7 @@ restore-workspace: &restore-workspace
|
|||||||
restore-cache: &restore-cache
|
restore-cache: &restore-cache
|
||||||
restore_cache:
|
restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
- cargo-v3-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||||
- repo-source-{{ .Branch }}-{{ .Revision }}
|
- repo-source-{{ .Branch }}-{{ .Revision }}
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
command: cargo generate-lockfile
|
command: cargo generate-lockfile
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
- cargo-v3-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||||
- run: rustup install $(cat rust-toolchain)
|
- run: rustup install $(cat rust-toolchain)
|
||||||
- run: rustup default $(cat rust-toolchain)
|
- run: rustup default $(cat rust-toolchain)
|
||||||
- run: rustup component add --toolchain $(cat rust-toolchain) rustfmt
|
- run: rustup component add --toolchain $(cat rust-toolchain) rustfmt
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
paths:
|
paths:
|
||||||
- crate
|
- crate
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: cargo-v2-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
key: cargo-v3-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
|
||||||
paths:
|
paths:
|
||||||
- "~/.cargo"
|
- "~/.cargo"
|
||||||
- "~/.rustup"
|
- "~/.rustup"
|
||||||
@@ -121,7 +121,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: bash ci_scripts/run-doxygen.sh
|
- run: bash ci_scripts/run-doxygen.sh
|
||||||
- run: mkdir -p workspace/c-docs
|
- run: mkdir -p workspace/c-docs
|
||||||
- run: cp -av deltachat-ffi/{html,xml} workspace/c-docs/
|
- run: cp -av deltachat-ffi/{html,xml} workspace/c-docs/
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: workspace
|
root: workspace
|
||||||
@@ -189,7 +189,7 @@ workflows:
|
|||||||
- upload_docs_wheels:
|
- upload_docs_wheels:
|
||||||
requires:
|
requires:
|
||||||
- build_test_docs_wheel
|
- build_test_docs_wheel
|
||||||
- build_doxygen
|
- build_doxygen
|
||||||
- rustfmt:
|
- rustfmt:
|
||||||
requires:
|
requires:
|
||||||
- cargo_fetch
|
- cargo_fetch
|
||||||
|
|||||||
33
.github/workflows/rust.yml
vendored
33
.github/workflows/rust.yml
vendored
@@ -1,15 +1,30 @@
|
|||||||
name: Rust
|
name: CI
|
||||||
|
|
||||||
on: [push]
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -Dwarnings
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
name: 3.7 python tests against core
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@master
|
||||||
- name: Build
|
|
||||||
run: cargo build --verbose
|
- uses: actions-rs/toolchain@v1
|
||||||
- name: Run tests
|
with:
|
||||||
run: cargo test --verbose
|
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
|
||||||
|
|||||||
954
Cargo.lock
generated
954
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
15
Cargo.toml
15
Cargo.toml
@@ -15,12 +15,13 @@ hex = "0.3.2"
|
|||||||
sha2 = "0.8.0"
|
sha2 = "0.8.0"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
smallvec = "0.6.9"
|
smallvec = "0.6.9"
|
||||||
reqwest = "0.9.15"
|
reqwest = { version = "0.9.15", default-features = false, features = ["rustls-tls"] }
|
||||||
num-derive = "0.2.5"
|
num-derive = "0.2.5"
|
||||||
num-traits = "0.2.6"
|
num-traits = "0.2.6"
|
||||||
native-tls = "0.2.3"
|
lettre = { git = "https://github.com/deltachat/lettre", branch = "feat/rustls" }
|
||||||
lettre = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
async-imap = "0.1"
|
||||||
imap = { git = "https://github.com/deltachat/rust-imap", branch = "master" }
|
async-tls = "0.6"
|
||||||
|
async-std = { version = "1.0", features = ["unstable"] }
|
||||||
base64 = "0.10"
|
base64 = "0.10"
|
||||||
charset = "0.1"
|
charset = "0.1"
|
||||||
percent-encoding = "2.0"
|
percent-encoding = "2.0"
|
||||||
@@ -49,6 +50,10 @@ bitflags = "1.1.0"
|
|||||||
jetscii = "0.4.4"
|
jetscii = "0.4.4"
|
||||||
debug_stub_derive = "0.3.0"
|
debug_stub_derive = "0.3.0"
|
||||||
sanitize-filename = "0.2.1"
|
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]
|
[dev-dependencies]
|
||||||
tempfile = "3.0"
|
tempfile = "3.0"
|
||||||
@@ -74,6 +79,6 @@ path = "examples/repl/main.rs"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nightly", "ringbuf"]
|
default = ["nightly", "ringbuf"]
|
||||||
vendored = ["native-tls/vendored", "reqwest/default-tls-vendored"]
|
vendored = []
|
||||||
nightly = ["pgp/nightly"]
|
nightly = ["pgp/nightly"]
|
||||||
ringbuf = ["pgp/ringbuf"]
|
ringbuf = ["pgp/ringbuf"]
|
||||||
|
|||||||
@@ -5,16 +5,6 @@ RUN echo /usr/local/lib64 > /etc/ld.so.conf.d/local.conf && \
|
|||||||
echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf
|
echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf
|
||||||
ENV PKG_CONFIG_PATH /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig
|
ENV PKG_CONFIG_PATH /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig
|
||||||
|
|
||||||
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
|
|
||||||
|
|
||||||
# Install python tools (auditwheels,tox, ...)
|
|
||||||
ADD deps/build_python.sh /builder/build_python.sh
|
|
||||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_python.sh && cd .. && rm -r tmp1
|
|
||||||
|
|
||||||
# Install Rust nightly
|
|
||||||
ADD deps/build_rust.sh /builder/build_rust.sh
|
|
||||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_rust.sh && cd .. && rm -r tmp1
|
|
||||||
|
|
||||||
# Install a recent Perl, needed to install OpenSSL
|
# Install a recent Perl, needed to install OpenSSL
|
||||||
ADD deps/build_perl.sh /builder/build_perl.sh
|
ADD deps/build_perl.sh /builder/build_perl.sh
|
||||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_perl.sh && cd .. && rm -r tmp1
|
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_perl.sh && cd .. && rm -r tmp1
|
||||||
@@ -23,3 +13,12 @@ RUN mkdir tmp1 && cd tmp1 && bash /builder/build_perl.sh && cd .. && rm -r tmp1
|
|||||||
ADD deps/build_openssl.sh /builder/build_openssl.sh
|
ADD deps/build_openssl.sh /builder/build_openssl.sh
|
||||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_openssl.sh && cd .. && rm -r tmp1
|
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_openssl.sh && cd .. && rm -r tmp1
|
||||||
|
|
||||||
|
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
|
||||||
|
|
||||||
|
# Install python tools (auditwheels,tox, ...)
|
||||||
|
ADD deps/build_python.sh /builder/build_python.sh
|
||||||
|
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_python.sh && cd .. && rm -r tmp1
|
||||||
|
|
||||||
|
# Install Rust nightly
|
||||||
|
ADD deps/build_rust.sh /builder/build_rust.sh
|
||||||
|
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_rust.sh && cd .. && rm -r tmp1
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
PERL_VERSION=5.28.0
|
PERL_VERSION=5.30.0
|
||||||
PERL_SHA256=7e929f64d4cb0e9d1159d4a59fc89394e27fa1f7004d0836ca0d514685406ea8
|
# PERL_SHA256=7e929f64d4cb0e9d1159d4a59fc89394e27fa1f7004d0836ca0d514685406ea8
|
||||||
curl -O https://www.cpan.org/src/5.0/perl-${PERL_VERSION}.tar.gz
|
curl -O https://www.cpan.org/src/5.0/perl-${PERL_VERSION}.tar.gz
|
||||||
echo "${PERL_SHA256} perl-${PERL_VERSION}.tar.gz" | sha256sum -c -
|
# echo "${PERL_SHA256} perl-${PERL_VERSION}.tar.gz" | sha256sum -c -
|
||||||
tar xzf perl-${PERL_VERSION}.tar.gz
|
tar -xzf perl-${PERL_VERSION}.tar.gz
|
||||||
cd perl-${PERL_VERSION}
|
cd perl-${PERL_VERSION}
|
||||||
|
|
||||||
./Configure -de
|
./Configure -de
|
||||||
make
|
make
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e -x
|
set -e -x
|
||||||
|
|
||||||
# Install Rust
|
# Install Rust
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-07-10 -y
|
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-09-12 -y
|
||||||
export PATH=/root/.cargo/bin:$PATH
|
export PATH=/root/.cargo/bin:$PATH
|
||||||
rustc --version
|
rustc --version
|
||||||
|
|
||||||
# remove some 300-400 MB that we don't need for automated builds
|
|
||||||
rm -rf /root/.rustup/toolchains/nightly-2019-07-10-x86_64-unknown-linux-gnu/share/
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ export TOXWORKDIR=.docker-tox
|
|||||||
|
|
||||||
export PATH=/root/.cargo/bin:$PATH
|
export PATH=/root/.cargo/bin:$PATH
|
||||||
cargo build --release -p deltachat_ffi
|
cargo build --release -p deltachat_ffi
|
||||||
# cargo test --all --all-features
|
|
||||||
|
|
||||||
# Statically link against libdeltachat.a.
|
# Statically link against libdeltachat.a.
|
||||||
export DCC_RS_DEV=$(pwd)
|
export DCC_RS_DEV=$(pwd)
|
||||||
@@ -22,36 +21,27 @@ export DCC_RS_DEV=$(pwd)
|
|||||||
# needed by tox below.
|
# needed by tox below.
|
||||||
export PATH=$PATH:/opt/python/cp35-cp35m/bin
|
export PATH=$PATH:/opt/python/cp35-cp35m/bin
|
||||||
export PYTHONDONTWRITEBYTECODE=1
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
pushd /bin
|
|
||||||
ln -s /opt/python/cp27-cp27m/bin/python2.7
|
pushd python
|
||||||
ln -s /opt/python/cp36-cp36m/bin/python3.6
|
# prepare a clean tox run
|
||||||
ln -s /opt/python/cp37-cp37m/bin/python3.7
|
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
|
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
|
# if [ -n "$DOCS" ]; then
|
||||||
# echo -----------------------
|
# echo -----------------------
|
||||||
# echo generating python docs
|
# echo generating python docs
|
||||||
|
|||||||
@@ -675,7 +675,6 @@ class TestOnlineAccount:
|
|||||||
assert len(messages) == 1
|
assert len(messages) == 1
|
||||||
assert messages[0].text == "msg1"
|
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
|
# wait until a second passed since last backup
|
||||||
# because get_latest_backupfile() shall return the latest backup
|
# because get_latest_backupfile() shall return the latest backup
|
||||||
# from a UI it's unlikely anyone manages to export two
|
# from a UI it's unlikely anyone manages to export two
|
||||||
@@ -896,7 +895,7 @@ class TestOnlineConfigureFails:
|
|||||||
ac1.start_threads()
|
ac1.start_threads()
|
||||||
wait_configuration_progress(ac1, 500)
|
wait_configuration_progress(ac1, 500)
|
||||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||||
assert "authentication failed" in ev1[2].lower()
|
assert "cannot login" in ev1[2].lower()
|
||||||
wait_configuration_progress(ac1, 0, 0)
|
wait_configuration_progress(ac1, 0, 0)
|
||||||
|
|
||||||
def test_invalid_user(self, acfactory):
|
def test_invalid_user(self, acfactory):
|
||||||
@@ -905,7 +904,7 @@ class TestOnlineConfigureFails:
|
|||||||
ac1.start_threads()
|
ac1.start_threads()
|
||||||
wait_configuration_progress(ac1, 500)
|
wait_configuration_progress(ac1, 500)
|
||||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||||
assert "authentication failed" in ev1[2].lower()
|
assert "cannot login" in ev1[2].lower()
|
||||||
wait_configuration_progress(ac1, 0, 0)
|
wait_configuration_progress(ac1, 0, 0)
|
||||||
|
|
||||||
def test_invalid_domain(self, acfactory):
|
def test_invalid_domain(self, acfactory):
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
nightly-2019-08-13
|
nightly-2019-11-06
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ fn try_smtp_one_param(context: &Context, param: &LoginParam) -> Option<bool> {
|
|||||||
pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_int {
|
pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_int {
|
||||||
let mut ret_connected = 0;
|
let mut ret_connected = 0;
|
||||||
|
|
||||||
if imap.is_connected() {
|
if async_std::task::block_on(async move { imap.is_connected().await }) {
|
||||||
ret_connected = 1
|
ret_connected = 1
|
||||||
} else if !context.sql.get_raw_config_bool(context, "configured") {
|
} else if !context.sql.get_raw_config_bool(context, "configured") {
|
||||||
warn!(context, "Not configured, cannot connect.",);
|
warn!(context, "Not configured, cannot connect.",);
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ fn decrypt_if_autocrypt_message(
|
|||||||
public_keyring_for_validate: &Keyring,
|
public_keyring_for_validate: &Keyring,
|
||||||
ret_valid_signatures: &mut HashSet<String>,
|
ret_valid_signatures: &mut HashSet<String>,
|
||||||
ret_gossip_headers: *mut *mut mailimf_fields,
|
ret_gossip_headers: *mut *mut mailimf_fields,
|
||||||
) -> Result<(bool)> {
|
) -> Result<bool> {
|
||||||
/* The returned bool is true if we detected an Autocrypt-encrypted
|
/* The returned bool is true if we detected an Autocrypt-encrypted
|
||||||
message and successfully decrypted it. Decryption then modifies the
|
message and successfully decrypted it. Decryption then modifies the
|
||||||
passed in mime structure in place. The returned bool is false
|
passed in mime structure in place. The returned bool is false
|
||||||
|
|||||||
1696
src/imap.rs
1696
src/imap.rs
File diff suppressed because it is too large
Load Diff
294
src/imap_client.rs
Normal file
294
src/imap_client.rs
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
use async_imap::{
|
||||||
|
error::{Error as ImapError, Result as ImapResult},
|
||||||
|
extensions::idle::Handle as ImapIdleHandle,
|
||||||
|
types::{Capabilities, Fetch, Mailbox, Name},
|
||||||
|
Client as ImapClient, Session as ImapSession,
|
||||||
|
};
|
||||||
|
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};
|
||||||
|
|
||||||
|
const DCC_IMAP_DEBUG: &str = "DCC_IMAP_DEBUG";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum Client {
|
||||||
|
Secure(ImapClient<TlsStream<TcpStream>>),
|
||||||
|
Insecure(ImapClient<TcpStream>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum Session {
|
||||||
|
Secure(ImapSession<TlsStream<TcpStream>>),
|
||||||
|
Insecure(ImapSession<TcpStream>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum IdleHandle {
|
||||||
|
Secure(ImapIdleHandle<TlsStream<TcpStream>>),
|
||||||
|
Insecure(ImapIdleHandle<TcpStream>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn connect_secure<A: net::ToSocketAddrs, S: AsRef<str>>(
|
||||||
|
addr: A,
|
||||||
|
domain: S,
|
||||||
|
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 mut client = ImapClient::new(tls_stream);
|
||||||
|
if std::env::var(DCC_IMAP_DEBUG).is_ok() {
|
||||||
|
client.debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _greeting = client
|
||||||
|
.read_response()
|
||||||
|
.await
|
||||||
|
.expect("failed to read greeting");
|
||||||
|
|
||||||
|
Ok(Client::Secure(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn connect_insecure<A: net::ToSocketAddrs>(addr: A) -> ImapResult<Self> {
|
||||||
|
let stream = TcpStream::connect(addr).await?;
|
||||||
|
|
||||||
|
let mut client = ImapClient::new(stream);
|
||||||
|
if std::env::var(DCC_IMAP_DEBUG).is_ok() {
|
||||||
|
client.debug = true;
|
||||||
|
}
|
||||||
|
let _greeting = client
|
||||||
|
.read_response()
|
||||||
|
.await
|
||||||
|
.expect("failed to read greeting");
|
||||||
|
|
||||||
|
Ok(Client::Insecure(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn secure<S: AsRef<str>>(
|
||||||
|
self,
|
||||||
|
domain: S,
|
||||||
|
_certificate_checks: CertificateChecks,
|
||||||
|
) -> ImapResult<Client> {
|
||||||
|
match self {
|
||||||
|
Client::Insecure(client) => {
|
||||||
|
let tls = async_tls::TlsConnector::new();
|
||||||
|
|
||||||
|
let client_sec = client.secure(domain, &tls).await?;
|
||||||
|
|
||||||
|
Ok(Client::Secure(client_sec))
|
||||||
|
}
|
||||||
|
// Nothing to do
|
||||||
|
Client::Secure(_) => Ok(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn authenticate<A: async_imap::Authenticator, S: AsRef<str>>(
|
||||||
|
self,
|
||||||
|
auth_type: S,
|
||||||
|
authenticator: &A,
|
||||||
|
) -> Result<Session, (ImapError, Client)> {
|
||||||
|
match self {
|
||||||
|
Client::Secure(i) => match i.authenticate(auth_type, authenticator).await {
|
||||||
|
Ok(session) => Ok(Session::Secure(session)),
|
||||||
|
Err((err, c)) => Err((err, Client::Secure(c))),
|
||||||
|
},
|
||||||
|
Client::Insecure(i) => match i.authenticate(auth_type, authenticator).await {
|
||||||
|
Ok(session) => Ok(Session::Insecure(session)),
|
||||||
|
Err((err, c)) => Err((err, Client::Insecure(c))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn login<U: AsRef<str>, P: AsRef<str>>(
|
||||||
|
self,
|
||||||
|
username: U,
|
||||||
|
password: P,
|
||||||
|
) -> Result<Session, (ImapError, Client)> {
|
||||||
|
match self {
|
||||||
|
Client::Secure(i) => match i.login(username, password).await {
|
||||||
|
Ok(session) => Ok(Session::Secure(session)),
|
||||||
|
Err((err, c)) => Err((err, Client::Secure(c))),
|
||||||
|
},
|
||||||
|
Client::Insecure(i) => match i.login(username, password).await {
|
||||||
|
Ok(session) => Ok(Session::Insecure(session)),
|
||||||
|
Err((err, c)) => Err((err, Client::Insecure(c))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Session {
|
||||||
|
pub async fn capabilities(&mut self) -> ImapResult<Capabilities> {
|
||||||
|
let res = match self {
|
||||||
|
Session::Secure(i) => i.capabilities().await?,
|
||||||
|
Session::Insecure(i) => i.capabilities().await?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list(
|
||||||
|
&mut self,
|
||||||
|
reference_name: Option<&str>,
|
||||||
|
mailbox_pattern: Option<&str>,
|
||||||
|
) -> ImapResult<Vec<Name>> {
|
||||||
|
let res = match self {
|
||||||
|
Session::Secure(i) => {
|
||||||
|
i.list(reference_name, mailbox_pattern)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Session::Insecure(i) => {
|
||||||
|
i.list(reference_name, mailbox_pattern)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create<S: AsRef<str>>(&mut self, mailbox_name: S) -> ImapResult<()> {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => i.create(mailbox_name).await?,
|
||||||
|
Session::Insecure(i) => i.create(mailbox_name).await?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn subscribe<S: AsRef<str>>(&mut self, mailbox: S) -> ImapResult<()> {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => i.subscribe(mailbox).await?,
|
||||||
|
Session::Insecure(i) => i.subscribe(mailbox).await?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn close(&mut self) -> ImapResult<()> {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => i.close().await?,
|
||||||
|
Session::Insecure(i) => i.close().await?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn select<S: AsRef<str>>(&mut self, mailbox_name: S) -> ImapResult<Mailbox> {
|
||||||
|
let mbox = match self {
|
||||||
|
Session::Secure(i) => i.select(mailbox_name).await?,
|
||||||
|
Session::Insecure(i) => i.select(mailbox_name).await?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(mbox)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn fetch<S1, S2>(&mut self, sequence_set: S1, query: S2) -> ImapResult<Vec<Fetch>>
|
||||||
|
where
|
||||||
|
S1: AsRef<str>,
|
||||||
|
S2: AsRef<str>,
|
||||||
|
{
|
||||||
|
let res = match self {
|
||||||
|
Session::Secure(i) => {
|
||||||
|
i.fetch(sequence_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Session::Insecure(i) => {
|
||||||
|
i.fetch(sequence_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn uid_fetch<S1, S2>(&mut self, uid_set: S1, query: S2) -> ImapResult<Vec<Fetch>>
|
||||||
|
where
|
||||||
|
S1: AsRef<str>,
|
||||||
|
S2: AsRef<str>,
|
||||||
|
{
|
||||||
|
let res = match self {
|
||||||
|
Session::Secure(i) => {
|
||||||
|
i.uid_fetch(uid_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Session::Insecure(i) => {
|
||||||
|
i.uid_fetch(uid_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn idle(self) -> IdleHandle {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => {
|
||||||
|
let h = i.idle();
|
||||||
|
IdleHandle::Secure(h)
|
||||||
|
}
|
||||||
|
Session::Insecure(i) => {
|
||||||
|
let h = i.idle();
|
||||||
|
IdleHandle::Insecure(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn uid_store<S1, S2>(&mut self, uid_set: S1, query: S2) -> ImapResult<Vec<Fetch>>
|
||||||
|
where
|
||||||
|
S1: AsRef<str>,
|
||||||
|
S2: AsRef<str>,
|
||||||
|
{
|
||||||
|
let res = match self {
|
||||||
|
Session::Secure(i) => {
|
||||||
|
i.uid_store(uid_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
Session::Insecure(i) => {
|
||||||
|
i.uid_store(uid_set, query)
|
||||||
|
.await?
|
||||||
|
.collect::<ImapResult<_>>()
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn uid_mv<S1: AsRef<str>, S2: AsRef<str>>(
|
||||||
|
&mut self,
|
||||||
|
uid_set: S1,
|
||||||
|
mailbox_name: S2,
|
||||||
|
) -> ImapResult<()> {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => i.uid_mv(uid_set, mailbox_name).await?,
|
||||||
|
Session::Insecure(i) => i.uid_mv(uid_set, mailbox_name).await?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn uid_copy<S1: AsRef<str>, S2: AsRef<str>>(
|
||||||
|
&mut self,
|
||||||
|
uid_set: S1,
|
||||||
|
mailbox_name: S2,
|
||||||
|
) -> ImapResult<()> {
|
||||||
|
match self {
|
||||||
|
Session::Secure(i) => i.uid_copy(uid_set, mailbox_name).await?,
|
||||||
|
Session::Insecure(i) => i.uid_copy(uid_set, mailbox_name).await?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/job.rs
18
src/job.rs
@@ -245,10 +245,10 @@ impl Job {
|
|||||||
&dest_folder,
|
&dest_folder,
|
||||||
&mut dest_uid,
|
&mut dest_uid,
|
||||||
) {
|
) {
|
||||||
ImapResult::RetryLater => {
|
ImapActionResult::RetryLater => {
|
||||||
self.try_again_later(3i32, None);
|
self.try_again_later(3i32, None);
|
||||||
}
|
}
|
||||||
ImapResult::Success => {
|
ImapActionResult::Success => {
|
||||||
message::update_server_uid(
|
message::update_server_uid(
|
||||||
context,
|
context,
|
||||||
&msg.rfc724_mid,
|
&msg.rfc724_mid,
|
||||||
@@ -256,7 +256,7 @@ impl Job {
|
|||||||
dest_uid,
|
dest_uid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ImapResult::Failed | ImapResult::AlreadyDone => {}
|
ImapActionResult::Failed | ImapActionResult::AlreadyDone => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ impl Job {
|
|||||||
let mid = msg.rfc724_mid;
|
let mid = msg.rfc724_mid;
|
||||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||||
let res = inbox.delete_msg(context, &mid, server_folder, &mut msg.server_uid);
|
let res = inbox.delete_msg(context, &mid, server_folder, &mut msg.server_uid);
|
||||||
if res == ImapResult::RetryLater {
|
if res == ImapActionResult::RetryLater {
|
||||||
self.try_again_later(-1i32, None);
|
self.try_again_later(-1i32, None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -313,11 +313,11 @@ impl Job {
|
|||||||
if let Ok(msg) = Message::load_from_db(context, MsgId::new(self.foreign_id)) {
|
if let Ok(msg) = Message::load_from_db(context, MsgId::new(self.foreign_id)) {
|
||||||
let folder = msg.server_folder.as_ref().unwrap();
|
let folder = msg.server_folder.as_ref().unwrap();
|
||||||
match inbox.set_seen(context, folder, msg.server_uid) {
|
match inbox.set_seen(context, folder, msg.server_uid) {
|
||||||
ImapResult::RetryLater => {
|
ImapActionResult::RetryLater => {
|
||||||
self.try_again_later(3i32, None);
|
self.try_again_later(3i32, None);
|
||||||
}
|
}
|
||||||
ImapResult::AlreadyDone => {}
|
ImapActionResult::AlreadyDone => {}
|
||||||
ImapResult::Success | ImapResult::Failed => {
|
ImapActionResult::Success | ImapActionResult::Failed => {
|
||||||
// XXX the message might just have been moved
|
// XXX the message might just have been moved
|
||||||
// we want to send out an MDN anyway
|
// we want to send out an MDN anyway
|
||||||
// The job will not be retried so locally
|
// The job will not be retried so locally
|
||||||
@@ -343,7 +343,7 @@ impl Job {
|
|||||||
.to_string();
|
.to_string();
|
||||||
let uid = self.param.get_int(Param::ServerUid).unwrap_or_default() as u32;
|
let uid = self.param.get_int(Param::ServerUid).unwrap_or_default() as u32;
|
||||||
let inbox = context.inbox.read().unwrap();
|
let inbox = context.inbox.read().unwrap();
|
||||||
if inbox.set_seen(context, &folder, uid) == ImapResult::RetryLater {
|
if inbox.set_seen(context, &folder, uid) == ImapActionResult::RetryLater {
|
||||||
self.try_again_later(3i32, None);
|
self.try_again_later(3i32, None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ impl Job {
|
|||||||
.get_raw_config(context, "configured_mvbox_folder");
|
.get_raw_config(context, "configured_mvbox_folder");
|
||||||
if let Some(dest_folder) = dest_folder {
|
if let Some(dest_folder) = dest_folder {
|
||||||
let mut dest_uid = 0;
|
let mut dest_uid = 0;
|
||||||
if ImapResult::RetryLater
|
if ImapActionResult::RetryLater
|
||||||
== inbox.mv(context, &folder, uid, &dest_folder, &mut dest_uid)
|
== inbox.mv(context, &folder, uid, &dest_folder, &mut dest_uid)
|
||||||
{
|
{
|
||||||
self.try_again_later(3, None);
|
self.try_again_later(3, None);
|
||||||
|
|||||||
@@ -107,12 +107,17 @@ impl JobThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn connect_to_imap(&self, context: &Context) -> bool {
|
fn connect_to_imap(&self, context: &Context) -> bool {
|
||||||
if self.imap.is_connected() {
|
if async_std::task::block_on(async move { self.imap.is_connected().await }) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
let watch_folder_name = match context.sql.get_raw_config(context, self.folder_config_name) {
|
||||||
|
Some(name) => name,
|
||||||
|
None => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut ret_connected = dc_connect_to_configured_imap(context, &self.imap) != 0;
|
let ret_connected = dc_connect_to_configured_imap(context, &self.imap) != 0;
|
||||||
|
|
||||||
if ret_connected {
|
if ret_connected {
|
||||||
if context
|
if context
|
||||||
.sql
|
.sql
|
||||||
@@ -123,12 +128,7 @@ impl JobThread {
|
|||||||
self.imap.configure_folders(context, 0x1);
|
self.imap.configure_folders(context, 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mvbox_name) = context.sql.get_raw_config(context, self.folder_config_name) {
|
self.imap.set_watch_folder(watch_folder_name);
|
||||||
self.imap.set_watch_folder(mvbox_name);
|
|
||||||
} else {
|
|
||||||
self.imap.disconnect(context);
|
|
||||||
ret_connected = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_connected
|
ret_connected
|
||||||
@@ -170,10 +170,18 @@ impl JobThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.connect_to_imap(context);
|
if self.connect_to_imap(context) {
|
||||||
info!(context, "{}-IDLE started...", self.name,);
|
info!(context, "{}-IDLE started...", self.name,);
|
||||||
self.imap.idle(context);
|
self.imap.idle(context);
|
||||||
info!(context, "{}-IDLE ended.", self.name);
|
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.state.0.lock().unwrap().using_handle = false;
|
self.state.0.lock().unwrap().using_handle = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ pub mod contact;
|
|||||||
pub mod context;
|
pub mod context;
|
||||||
mod e2ee;
|
mod e2ee;
|
||||||
mod imap;
|
mod imap;
|
||||||
|
mod imap_client;
|
||||||
pub mod imex;
|
pub mod imex;
|
||||||
pub mod job;
|
pub mod job;
|
||||||
mod job_thread;
|
mod job_thread;
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ use std::fmt;
|
|||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use async_std::sync::Arc;
|
||||||
|
use rustls;
|
||||||
|
use webpki;
|
||||||
|
use webpki_roots;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Display, FromPrimitive)]
|
#[derive(Copy, Clone, Debug, Display, FromPrimitive)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
@@ -251,27 +255,49 @@ fn get_readable_flags(flags: i32) -> String {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_build_tls(
|
pub struct NoCertificateVerification {}
|
||||||
certificate_checks: CertificateChecks,
|
|
||||||
) -> Result<native_tls::TlsConnector, native_tls::Error> {
|
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||||
let mut tls_builder = native_tls::TlsConnector::builder();
|
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 {
|
match certificate_checks {
|
||||||
|
CertificateChecks::Strict => {}
|
||||||
CertificateChecks::Automatic => {
|
CertificateChecks::Automatic => {
|
||||||
// Same as AcceptInvalidCertificates for now.
|
// Same as AcceptInvalidCertificates for now.
|
||||||
// TODO: use provider database when it becomes available
|
// TODO: use provider database when it becomes available
|
||||||
tls_builder
|
config
|
||||||
.danger_accept_invalid_hostnames(true)
|
.dangerous()
|
||||||
.danger_accept_invalid_certs(true)
|
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||||
|
}
|
||||||
|
CertificateChecks::AcceptInvalidCertificates => {
|
||||||
|
// TODO: only accept invalid certs
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||||
}
|
}
|
||||||
CertificateChecks::Strict => &mut tls_builder,
|
|
||||||
CertificateChecks::AcceptInvalidHostnames => {
|
CertificateChecks::AcceptInvalidHostnames => {
|
||||||
tls_builder.danger_accept_invalid_hostnames(true)
|
// TODO: only accept invalid hostnames
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||||
}
|
}
|
||||||
CertificateChecks::AcceptInvalidCertificates => tls_builder
|
|
||||||
.danger_accept_invalid_hostnames(true)
|
|
||||||
.danger_accept_invalid_certs(true),
|
|
||||||
}
|
}
|
||||||
.build()
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::constants::*;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use crate::login_param::{dc_build_tls, LoginParam};
|
use crate::login_param::{dc_build_tls_config, LoginParam};
|
||||||
use crate::oauth2::*;
|
use crate::oauth2::*;
|
||||||
|
|
||||||
#[derive(DebugStub)]
|
#[derive(DebugStub)]
|
||||||
@@ -65,8 +65,8 @@ impl Smtp {
|
|||||||
let domain = &lp.send_server;
|
let domain = &lp.send_server;
|
||||||
let port = lp.send_port as u16;
|
let port = lp.send_port as u16;
|
||||||
|
|
||||||
let tls = dc_build_tls(lp.smtp_certificate_checks).unwrap();
|
let tls_config = dc_build_tls_config(lp.smtp_certificate_checks);
|
||||||
let tls_parameters = ClientTlsParameters::new(domain.to_string(), tls);
|
let tls_parameters = ClientTlsParameters::new(domain.to_string(), tls_config);
|
||||||
|
|
||||||
let (creds, mechanism) = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
|
let (creds, mechanism) = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
|
||||||
// oauth2
|
// oauth2
|
||||||
|
|||||||
Reference in New Issue
Block a user