mirror of
https://github.com/chatmail/core.git
synced 2026-04-10 09:32:11 +03:00
Compare commits
59 Commits
1.55.0
...
export_cha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b5c900cb9 | ||
|
|
b87ca6e747 | ||
|
|
850f7e1174 | ||
|
|
9f2b5feda2 | ||
|
|
b8cbcc6648 | ||
|
|
584d28f807 | ||
|
|
241111470f | ||
|
|
4bf07ccc71 | ||
|
|
897d2f4a08 | ||
|
|
a81096aa36 | ||
|
|
b1c9342631 | ||
|
|
0c8aad2102 | ||
|
|
82253e1e30 | ||
|
|
aa953687bf | ||
|
|
9f2f2ca1c0 | ||
|
|
54637004cd | ||
|
|
da9f45d9ff | ||
|
|
d8ba466c6a | ||
|
|
0c2a3c8347 | ||
|
|
e3e2adeea5 | ||
|
|
46e901be78 | ||
|
|
d899a38d17 | ||
|
|
b60994b313 | ||
|
|
8b19b6f9fe | ||
|
|
ea88a567f9 | ||
|
|
38c23104da | ||
|
|
2a83147d90 | ||
|
|
7e3bfd38f0 | ||
|
|
8b78e12b36 | ||
|
|
15660f2741 | ||
|
|
03520fbd4b | ||
|
|
b1228cbbe5 | ||
|
|
09f5b015bb | ||
|
|
67ca93b093 | ||
|
|
dabf31204c | ||
|
|
c22580e07f | ||
|
|
0028f579b6 | ||
|
|
9522240992 | ||
|
|
8ab3415c58 | ||
|
|
e858fca356 | ||
|
|
7d4affcc8d | ||
|
|
60d596bb0e | ||
|
|
c57bfde010 | ||
|
|
afd7e7eaac | ||
|
|
cfc324c95b | ||
|
|
aa5d6077a8 | ||
|
|
4a2beac6fc | ||
|
|
b5dc954408 | ||
|
|
a9f5077cf9 | ||
|
|
09280508bc | ||
|
|
4391835a8d | ||
|
|
05f9ac0583 | ||
|
|
fd9d632cd6 | ||
|
|
c9e626322b | ||
|
|
f343ec47b4 | ||
|
|
efb1534d5c | ||
|
|
6ec765cad6 | ||
|
|
372a4ee539 | ||
|
|
418b591602 |
@@ -27,7 +27,10 @@ jobs:
|
||||
- checkout
|
||||
# the following commands on success produces
|
||||
# workspace/{wheelhouse,py-docs} as artefact directories
|
||||
- run: bash scripts/remote_python_packaging.sh
|
||||
- run:
|
||||
# building aarch64 packages under qemu is very slow
|
||||
no_output_timeout: 60m
|
||||
command: bash scripts/remote_python_packaging.sh
|
||||
- persist_to_workspace:
|
||||
root: workspace
|
||||
paths:
|
||||
@@ -51,18 +54,24 @@ workflows:
|
||||
jobs:
|
||||
- remote_python_packaging:
|
||||
filters:
|
||||
tags:
|
||||
only: /.+/
|
||||
branches:
|
||||
only: master
|
||||
ignore: /.*/
|
||||
|
||||
- build_doxygen:
|
||||
filters:
|
||||
tags:
|
||||
only: /.+/
|
||||
branches:
|
||||
ignore: /.*/
|
||||
|
||||
- upload_docs_wheels:
|
||||
requires:
|
||||
- remote_python_packaging
|
||||
- build_doxygen
|
||||
filters:
|
||||
tags:
|
||||
only: /.+/
|
||||
branches:
|
||||
only: master
|
||||
|
||||
- build_doxygen:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
ignore: /.*/
|
||||
|
||||
52
.github/workflows/ci.yml
vendored
52
.github/workflows/ci.yml
vendored
@@ -65,26 +65,16 @@ jobs:
|
||||
|
||||
build_and_test:
|
||||
name: Build and test
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
strategy:
|
||||
matrix:
|
||||
# macOS disabled due to random failures related to caching
|
||||
#os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
rust: [1.50.0]
|
||||
experimental: [false]
|
||||
# include:
|
||||
# - os: ubuntu-latest
|
||||
# rust: nightly
|
||||
# experimental: true
|
||||
# - os: windows-latest
|
||||
# rust: nightly
|
||||
# experimental: true
|
||||
# - os: macOS-latest
|
||||
# rust: nightly
|
||||
# experimental: true
|
||||
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
rust: 1.50.0
|
||||
python: 3.6
|
||||
- os: windows-latest
|
||||
rust: 1.50.0
|
||||
python: false # Python bindings compilation on Windows is not supported.
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
@@ -125,3 +115,29 @@ jobs:
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
|
||||
- name: install python
|
||||
if: ${{ matrix.python }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: install tox
|
||||
if: ${{ matrix.python }}
|
||||
run: pip install tox
|
||||
|
||||
- name: build C library
|
||||
if: ${{ matrix.python }}
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: -p deltachat_ffi
|
||||
|
||||
- name: run python tests
|
||||
if: ${{ matrix.python }}
|
||||
env:
|
||||
DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }}
|
||||
DCC_RS_TARGET: debug
|
||||
DCC_RS_DEV: ${{ github.workspace }}
|
||||
working-directory: python
|
||||
run: tox -e lint,doc,py3
|
||||
|
||||
18
.github/workflows/remote_tests.yml
vendored
18
.github/workflows/remote_tests.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Remote tests
|
||||
on: [push]
|
||||
jobs:
|
||||
remote_tests_python:
|
||||
name: Remote Python tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DCC_NEW_TMP_EMAIL: ${{ secrets.DCC_NEW_TMP_EMAIL }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: mkdir -m 700 -p ~/.ssh
|
||||
- run: touch ~/.ssh/id_ed25519
|
||||
- run: chmod 600 ~/.ssh/id_ed25519
|
||||
- run: 'echo "$SSH_KEY" | base64 -d > ~/.ssh/id_ed25519'
|
||||
shell: bash
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
||||
- run: scripts/remote_tests_python.sh "deltachat-core/python/${{ github.ref }}/${{ github.run_number }}"
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(deltachat)
|
||||
project(deltachat LANGUAGES C)
|
||||
|
||||
find_program(CARGO cargo)
|
||||
|
||||
|
||||
175
Cargo.lock
generated
175
Cargo.lock
generated
@@ -374,9 +374,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-std-resolver"
|
||||
version = "0.20.2"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d613d619c2886fc0f4b5a777eceab405b23de82d73f0fc61ae402fdb9bc6fb2"
|
||||
checksum = "ed4e2c3da14d8ad45acb1e3191db7a918e9505b6f155b218e70a7c9a1a48c638"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
@@ -637,6 +637,27 @@ version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.10+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.1.1"
|
||||
@@ -748,6 +769,17 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "4.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8"
|
||||
dependencies = [
|
||||
"error-code",
|
||||
"str-buf",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
@@ -815,9 +847,12 @@ checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cd5a7748210e7ec1a9696610b1015e6e31fbf58f77a160801f124bd1c36592a"
|
||||
checksum = "dec1028182c380cc45a2e2c5ec841134f2dfd0f8f5f0a5bcd68004f81b5efdf4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpuid-bool"
|
||||
@@ -1161,6 +1196,7 @@ dependencies = [
|
||||
"toml",
|
||||
"url",
|
||||
"uuid",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1452,6 +1488,16 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-code"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"str-buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "escaper"
|
||||
version = "0.1.1"
|
||||
@@ -1497,6 +1543,16 @@ dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fd-lock"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0010f02effd88c702318c5dde0463206be67495d0b4d906ba7c0a8f166cc7f06"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.14"
|
||||
@@ -1552,21 +1608,11 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
|
||||
checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1579,9 +1625,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
|
||||
checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -1589,15 +1635,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
|
||||
checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d"
|
||||
checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1606,9 +1652,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
|
||||
checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -1627,10 +1673,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b"
|
||||
checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1639,22 +1686,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
|
||||
checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc"
|
||||
checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.14"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
|
||||
checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
@@ -2102,9 +2150,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.94"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@@ -3154,14 +3202,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustyline"
|
||||
version = "8.0.0"
|
||||
version = "8.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e1b597fcd1eeb1d6b25b493538e5aa19629eb08932184b85fef931ba87e893"
|
||||
checksum = "fbd4eaf7a7738f76c98e4f0395253ae853be3eb018f7b0bb57fe1b6c17e31874"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"clipboard-win",
|
||||
"dirs-next",
|
||||
"fs2",
|
||||
"fd-lock",
|
||||
"libc",
|
||||
"log",
|
||||
"memchr",
|
||||
@@ -3271,9 +3320,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.125"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -3290,9 +3339,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.125"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3336,9 +3385,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.5"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b659df5fc3ce22274daac600ffb845300bd2125bcfaec047823075afdab81c00"
|
||||
checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -3355,9 +3404,9 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f6b75b17576b792bef0db1bcc4b8b8bcdf9506744cf34b974195487af6cff2"
|
||||
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -3542,6 +3591,12 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "str-buf"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
|
||||
|
||||
[[package]]
|
||||
name = "stream-cipher"
|
||||
version = "0.7.1"
|
||||
@@ -3658,18 +3713,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
||||
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3771,9 +3826,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-proto"
|
||||
version = "0.20.2"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "952a078337565ba39007de99b151770f41039253a31846f0a3d5cd5a4ac8eedf"
|
||||
checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -3795,9 +3850,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-resolver"
|
||||
version = "0.20.2"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da9c97f7d103e0f94dbe384a57908833505ae5870126492f166821b7cf685589"
|
||||
checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"futures-util",
|
||||
@@ -4179,3 +4234,17 @@ dependencies = [
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"thiserror",
|
||||
"time 0.1.44",
|
||||
]
|
||||
|
||||
15
Cargo.toml
15
Cargo.toml
@@ -19,7 +19,7 @@ anyhow = "1.0.40"
|
||||
async-imap = "0.5.0"
|
||||
async-native-tls = { version = "0.3.3" }
|
||||
async-smtp = { git = "https://github.com/async-email/async-smtp", rev="2275fd8d13e39b2c58d6605c786ff06ff9e05708" }
|
||||
async-std-resolver = "0.20.2"
|
||||
async-std-resolver = "0.20.3"
|
||||
async-std = { version = "~1.9.0", features = ["unstable"] }
|
||||
async-tar = "0.3.0"
|
||||
async-trait = "0.1.50"
|
||||
@@ -33,14 +33,14 @@ dirs = { version = "3.0.2", optional=true }
|
||||
email = { git = "https://github.com/deltachat/rust-email", branch = "master" }
|
||||
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
|
||||
escaper = "0.1.1"
|
||||
futures = "0.3.14"
|
||||
futures = "0.3.15"
|
||||
hex = "0.4.0"
|
||||
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
|
||||
indexmap = "1.3.0"
|
||||
itertools = "0.10.0"
|
||||
kamadak-exif = "0.5"
|
||||
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
||||
libc = "0.2.51"
|
||||
libc = "0.2.95"
|
||||
log = {version = "0.4.8", optional = true }
|
||||
mailparse = "0.13.4"
|
||||
native-tls = "0.2.3"
|
||||
@@ -58,21 +58,22 @@ rand = "0.7.0"
|
||||
regex = "1.4.6"
|
||||
rusqlite = "0.25"
|
||||
rust-hsluv = "0.1.4"
|
||||
rustyline = { version = "8.0.0", optional = true }
|
||||
rustyline = { version = "8.2.0", optional = true }
|
||||
sanitize-filename = "0.3.0"
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sha-1 = "0.9.5"
|
||||
sha2 = "0.9.4"
|
||||
sha-1 = "0.9.6"
|
||||
sha2 = "0.9.5"
|
||||
smallvec = "1.0.0"
|
||||
stop-token = "0.2.0"
|
||||
strum = "0.20.0"
|
||||
strum_macros = "0.20.1"
|
||||
surf = { version = "2.0.0-alpha.4", default-features = false, features = ["h1-client"] }
|
||||
thiserror = "1.0.14"
|
||||
thiserror = "1.0.25"
|
||||
toml = "0.5.6"
|
||||
url = "2.2.2"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
zip = "0.5.12"
|
||||
|
||||
[dev-dependencies]
|
||||
ansi_term = "0.12.0"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
> Deltachat-core written in Rust
|
||||
|
||||
[](https://github.com/deltachat/deltachat-core-rust/actions/workflows/ci.yml)
|
||||
[](https://github.com/deltachat/deltachat-core-rust/actions/workflows/remote_tests.yml)
|
||||
[](https://circleci.com/gh/deltachat/deltachat-core-rust/)
|
||||
|
||||
## Installing Rust and Cargo
|
||||
|
||||
@@ -17,7 +17,7 @@ async fn address_book_benchmark(n: u32, read_count: u32) {
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
|
||||
Contact::add_address_book(&context, book).await.unwrap();
|
||||
Contact::add_address_book(&context, &book).await.unwrap();
|
||||
|
||||
let query: Option<&str> = None;
|
||||
for _ in 0..read_count {
|
||||
|
||||
@@ -22,7 +22,7 @@ num-traits = "0.2.6"
|
||||
serde_json = "1.0"
|
||||
async-std = "1.9.0"
|
||||
anyhow = "1.0.40"
|
||||
thiserror = "1.0.14"
|
||||
thiserror = "1.0.25"
|
||||
rand = "0.7.3"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -13,6 +13,8 @@ use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_receive_imf::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::error::Error;
|
||||
use deltachat::export_chat::export_chat_to_zip;
|
||||
use deltachat::imex::*;
|
||||
use deltachat::location;
|
||||
use deltachat::log::LogExt;
|
||||
@@ -387,6 +389,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
protect <chat-id>\n\
|
||||
unprotect <chat-id>\n\
|
||||
delchat <chat-id>\n\
|
||||
export-chat <chat-id> <destination-file>\n\
|
||||
===========================Contact requests==\n\
|
||||
decidestartchat <msg-id>\n\
|
||||
decideblock <msg-id>\n\
|
||||
@@ -1022,6 +1025,13 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
let chat_id = ChatId::new(arg1.parse()?);
|
||||
chat_id.delete(&context).await?;
|
||||
}
|
||||
"export-chat" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
|
||||
ensure!(!arg2.is_empty(), "Argument <destination file> missing.");
|
||||
let chat_id = ChatId::new(arg1.parse()?);
|
||||
// todo check if path is valid (dest dir exists) and ends in .zip
|
||||
export_chat_to_zip(&context, chat_id, arg2).await;
|
||||
}
|
||||
"msginfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let id = MsgId::new(arg1.parse()?);
|
||||
|
||||
@@ -169,7 +169,7 @@ const DB_COMMANDS: [&str; 9] = [
|
||||
"housekeeping",
|
||||
];
|
||||
|
||||
const CHAT_COMMANDS: [&str; 34] = [
|
||||
const CHAT_COMMANDS: [&str; 35] = [
|
||||
"listchats",
|
||||
"listarchived",
|
||||
"chat",
|
||||
@@ -204,6 +204,7 @@ const CHAT_COMMANDS: [&str; 34] = [
|
||||
"protect",
|
||||
"unprotect",
|
||||
"delchat",
|
||||
"export-chat",
|
||||
];
|
||||
const MESSAGE_COMMANDS: [&str; 6] = [
|
||||
"listmsgs",
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
assert len(sys.argv) == 2
|
||||
workspacedir = sys.argv[1]
|
||||
arch = platform.machine()
|
||||
for relpath in os.listdir(workspacedir):
|
||||
if relpath.startswith("deltachat"):
|
||||
p = os.path.join(workspacedir, relpath)
|
||||
subprocess.check_call(
|
||||
["auditwheel", "repair", p, "-w", workspacedir,
|
||||
"--plat", "manylinux2014_x86_64"])
|
||||
"--plat", "manylinux2014_" + arch])
|
||||
|
||||
@@ -1033,6 +1033,33 @@ class TestOnlineAccount:
|
||||
except queue.Empty:
|
||||
pass # mark_seen_messages() has generated events before it returns
|
||||
|
||||
def test_moved_markseen(self, acfactory, lp):
|
||||
"""Test that message already moved to DeltaChat folder is marked as seen."""
|
||||
ac1 = acfactory.get_online_configuring_account(mvbox=True, config={"inbox_watch": "0"})
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
acfactory.wait_configure_and_start_io([ac1, ac2])
|
||||
ac1.set_config("bcc_self", "1")
|
||||
|
||||
ac1.direct_imap.idle_start()
|
||||
ac1.create_chat(ac2).send_text("Hello!")
|
||||
ac1.direct_imap.idle_check(terminate=True)
|
||||
ac1.stop_io()
|
||||
|
||||
# Emulate moving of the message to DeltaChat folder by Sieve rule.
|
||||
# mailcow server contains this rule by default.
|
||||
ac1.direct_imap.conn.move(["*"], "DeltaChat")
|
||||
|
||||
ac1.direct_imap.select_folder("DeltaChat")
|
||||
ac1.direct_imap.idle_start()
|
||||
ac1.start_io()
|
||||
ac1.direct_imap.idle_wait_for_seen()
|
||||
ac1.direct_imap.idle_done()
|
||||
|
||||
fetch = list(ac1.direct_imap.conn.fetch("*", b'FLAGS').values())
|
||||
flags = fetch[-1][b'FLAGS']
|
||||
is_seen = b'\\Seen' in flags
|
||||
assert is_seen
|
||||
|
||||
def test_message_override_sender_name(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
chat = acfactory.get_accepted_chat(ac1, ac2)
|
||||
@@ -1071,10 +1098,10 @@ class TestOnlineAccount:
|
||||
# We had so many problems with markseen, if in doubt, rather create another test, it can't harm.
|
||||
ac1 = acfactory.get_online_configuring_account(move=mvbox_move, mvbox=mvbox_move)
|
||||
ac2 = acfactory.get_online_configuring_account(move=mvbox_move, mvbox=mvbox_move)
|
||||
acfactory.wait_configure_and_start_io()
|
||||
|
||||
acfactory.get_accepted_chat(ac1, ac2).send_text("hi")
|
||||
msg = ac2._evtracker.wait_next_incoming_message()
|
||||
acfactory.wait_configure_and_start_io()
|
||||
# Do not send BCC to self, we only want to test MDN on ac1.
|
||||
ac1.set_config("bcc_self", "0")
|
||||
|
||||
folder = "mvbox" if mvbox_move else "inbox"
|
||||
ac1.direct_imap.select_config_folder(folder)
|
||||
@@ -1082,6 +1109,9 @@ class TestOnlineAccount:
|
||||
ac1.direct_imap.idle_start()
|
||||
ac2.direct_imap.idle_start()
|
||||
|
||||
acfactory.get_accepted_chat(ac1, ac2).send_text("hi")
|
||||
msg = ac2._evtracker.wait_next_incoming_message()
|
||||
|
||||
ac2.mark_seen_messages([msg])
|
||||
|
||||
ac1.direct_imap.idle_wait_for_seen() # Check that the mdn is marked as seen
|
||||
@@ -2396,26 +2426,31 @@ class TestOnlineAccount:
|
||||
assert received_reply.quoted_text == "hello"
|
||||
assert received_reply.quote.id == out_msg.id
|
||||
|
||||
@pytest.mark.parametrize("folder,move,expected_destination,", [
|
||||
("xyz", False, "xyz"), # Test that emails are recognized in a random folder but not moved
|
||||
("xyz", True, "DeltaChat"), # ...emails are found in a random folder and moved to DeltaChat
|
||||
("Spam", False, "INBOX") # ...emails are moved from the spam folder to the Inbox
|
||||
@pytest.mark.parametrize("folder,move,expected_destination,inbox_watch,", [
|
||||
("xyz", False, "xyz", "1"), # Test that emails are recognized in a random folder but not moved
|
||||
("xyz", True, "DeltaChat", "1"), # ...emails are found in a random folder and moved to DeltaChat
|
||||
("Spam", False, "INBOX", "1"), # ...emails are moved from the spam folder to the Inbox
|
||||
("INBOX", False, "INBOX", "0"), # ...emails are found in the `Inbox` folder even if `inbox_watch` is "0"
|
||||
])
|
||||
# Testrun.org does not support the CREATE-SPECIAL-USE capability, which means that we can't create a folder with
|
||||
# the "\Junk" flag (see https://tools.ietf.org/html/rfc6154). So, we can't test spam folder detection by flag.
|
||||
def test_scan_folders(self, acfactory, lp, folder, move, expected_destination):
|
||||
def test_scan_folders(self, acfactory, lp, folder, move, expected_destination, inbox_watch):
|
||||
"""Delta Chat periodically scans all folders for new messages to make sure we don't miss any."""
|
||||
variant = folder + "-" + str(move) + "-" + expected_destination
|
||||
lp.sec("Testing variant " + variant)
|
||||
ac1 = acfactory.get_online_configuring_account(move=move)
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
ac1.set_config("inbox_watch", inbox_watch)
|
||||
|
||||
acfactory.wait_configure(ac1)
|
||||
ac1.direct_imap.create_folder(folder)
|
||||
|
||||
acfactory.wait_configure_and_start_io()
|
||||
# Wait until each folder was selected once and we are IDLEing:
|
||||
ac1._evtracker.get_info_contains("INBOX: Idle entering wait-on-remote state")
|
||||
if inbox_watch == "1":
|
||||
ac1._evtracker.get_info_contains("INBOX: Idle entering wait-on-remote state")
|
||||
else:
|
||||
ac1._evtracker.get_info_contains("IMAP-fake-IDLE: no folder, waiting for interrupt")
|
||||
ac1.stop_io()
|
||||
|
||||
# Send a message to ac1 and move it to the mvbox:
|
||||
@@ -2432,7 +2467,10 @@ class TestOnlineAccount:
|
||||
assert msg.text == "hello"
|
||||
|
||||
# Wait until the message was moved (if at all) and we are IDLEing again:
|
||||
ac1._evtracker.get_info_contains("INBOX: Idle entering wait-on-remote state")
|
||||
if inbox_watch == "1":
|
||||
ac1._evtracker.get_info_contains("INBOX: Idle entering wait-on-remote state")
|
||||
else:
|
||||
ac1._evtracker.get_info_contains("IMAP-fake-IDLE: no folder, waiting for interrupt")
|
||||
ac1.direct_imap.select_folder(expected_destination)
|
||||
assert len(ac1.direct_imap.get_all_messages()) == 1
|
||||
if folder != expected_destination:
|
||||
|
||||
@@ -48,3 +48,7 @@ to avoid the relatively large download::
|
||||
cd scripts # where all CI things are
|
||||
docker build -t deltachat/coredeps docker-coredeps
|
||||
docker build -t deltachat/doxygen docker-doxygen
|
||||
|
||||
Additionally, you can install qemu and build arm64 docker image:
|
||||
apt-get install qemu binfmt-support qemu-user-static
|
||||
docker build -t deltachat/coredeps-arm64 docker-coredeps-arm64
|
||||
|
||||
21
scripts/docker-coredeps-arm64/Dockerfile
Normal file
21
scripts/docker-coredeps-arm64/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM quay.io/pypa/manylinux2014_aarch64
|
||||
|
||||
# Configure ld.so/ldconfig and pkg-config
|
||||
RUN echo /usr/local/lib64 > /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
|
||||
|
||||
# Install a recent Perl, needed to install the openssl crate
|
||||
ADD deps/build_perl.sh /builder/build_perl.sh
|
||||
RUN rm /usr/bin/perl
|
||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_perl.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
|
||||
ADD deps/build_rust.sh /builder/build_rust.sh
|
||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_rust.sh && cd .. && rm -r tmp1
|
||||
21
scripts/docker-coredeps-arm64/deps/build_openssl.sh
Executable file
21
scripts/docker-coredeps-arm64/deps/build_openssl.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -x
|
||||
|
||||
OPENSSL_VERSION=1.1.1a
|
||||
OPENSSL_SHA256=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41
|
||||
|
||||
curl -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
|
||||
echo "${OPENSSL_SHA256} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c -
|
||||
tar xzf openssl-${OPENSSL_VERSION}.tar.gz
|
||||
cd openssl-${OPENSSL_VERSION}
|
||||
./config shared no-ssl2 no-ssl3 -fPIC --prefix=/usr/local
|
||||
|
||||
sed -i "s/^SHLIB_MAJOR=.*/SHLIB_MAJOR=200/" Makefile && \
|
||||
sed -i "s/^SHLIB_MINOR=.*/SHLIB_MINOR=0.0/" Makefile && \
|
||||
sed -i "s/^SHLIB_VERSION_NUMBER=.*/SHLIB_VERSION_NUMBER=200.0.0/" Makefile
|
||||
|
||||
make depend
|
||||
make
|
||||
make install_sw install_ssldirs
|
||||
ldconfig -v | grep ssl
|
||||
12
scripts/docker-coredeps-arm64/deps/build_perl.sh
Executable file
12
scripts/docker-coredeps-arm64/deps/build_perl.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
PERL_VERSION=5.30.0
|
||||
# PERL_SHA256=7e929f64d4cb0e9d1159d4a59fc89394e27fa1f7004d0836ca0d514685406ea8
|
||||
curl -O https://www.cpan.org/src/5.0/perl-${PERL_VERSION}.tar.gz
|
||||
# echo "${PERL_SHA256} perl-${PERL_VERSION}.tar.gz" | sha256sum -c -
|
||||
tar -xzf perl-${PERL_VERSION}.tar.gz
|
||||
cd perl-${PERL_VERSION}
|
||||
|
||||
./Configure -de
|
||||
make
|
||||
make install
|
||||
14
scripts/docker-coredeps-arm64/deps/build_python.sh
Executable file
14
scripts/docker-coredeps-arm64/deps/build_python.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x -e
|
||||
|
||||
# we use the python3.6 environment as the base environment
|
||||
/opt/python/cp36-cp36m/bin/pip install tox devpi-client auditwheel
|
||||
|
||||
pushd /usr/bin
|
||||
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/tox
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/devpi
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/auditwheel
|
||||
|
||||
popd
|
||||
16
scripts/docker-coredeps-arm64/deps/build_rust.sh
Executable file
16
scripts/docker-coredeps-arm64/deps/build_rust.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -x
|
||||
|
||||
# Install Rust
|
||||
#
|
||||
# Path from https://forge.rust-lang.org/infra/other-installation-methods.html
|
||||
#
|
||||
# Avoid using rustup here as it depends on reading /proc/self/exe and
|
||||
# has problems running under QEMU.
|
||||
curl "https://static.rust-lang.org/dist/rust-1.52.1-$(uname -m)-unknown-linux-gnu.tar.gz" | tar xz
|
||||
cd "rust-1.52.1-$(uname -m)-unknown-linux-gnu"
|
||||
./install.sh --prefix=/usr --components=rustc,cargo,"rust-std-$(uname -m)-unknown-linux-gnu"
|
||||
rustc --version
|
||||
cd ..
|
||||
rm -fr "rust-1.52.1-$(uname -m)-unknown-linux-gnu"
|
||||
@@ -5,7 +5,7 @@ RUN echo /usr/local/lib64 > /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
|
||||
|
||||
# Install a recent Perl, needed to install the openssl crate
|
||||
# Install a recent Perl, needed to install the openssl crate
|
||||
ADD deps/build_perl.sh /builder/build_perl.sh
|
||||
RUN rm /usr/bin/perl
|
||||
RUN mkdir tmp1 && cd tmp1 && bash /builder/build_perl.sh && cd .. && rm -r tmp1
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
set -x -e
|
||||
|
||||
# we use the python3.5 environment as the base environment
|
||||
/opt/python/cp35-cp35m/bin/pip install tox devpi-client auditwheel
|
||||
# we use the python3.6 environment as the base environment
|
||||
/opt/python/cp36-cp36m/bin/pip install tox devpi-client auditwheel
|
||||
|
||||
pushd /usr/bin
|
||||
|
||||
ln -s /opt/_internal/cpython-3.5.*/bin/tox
|
||||
ln -s /opt/_internal/cpython-3.5.*/bin/devpi
|
||||
ln -s /opt/_internal/cpython-3.5.*/bin/auditwheel
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/tox
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/devpi
|
||||
ln -s /opt/_internal/cpython-3.6.*/bin/auditwheel
|
||||
|
||||
popd
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
set -e -x
|
||||
|
||||
# Install Rust
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.50.0-x86_64-unknown-linux-gnu -y
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain "1.50.0-$(uname -m)-unknown-linux-gnu" -y
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
rustc --version
|
||||
|
||||
# remove some 300-400 MB that we don't need for automated builds
|
||||
rm -rf /root/.rustup/toolchains/1.50.0-x86_64-unknown-linux-gnu/share
|
||||
rm -rf "/root/.rustup/toolchains/1.50.0-$(uname -m)-unknown-linux-gnu/share"
|
||||
|
||||
@@ -15,6 +15,7 @@ git ls-files >.rsynclist
|
||||
# we seem to need .git for setuptools_scm versioning
|
||||
find .git >>.rsynclist
|
||||
rsync --delete --files-from=.rsynclist -az ./ "$SSHTARGET:$BUILDDIR"
|
||||
rsync --delete --files-from=.rsynclist -az ./ "$SSHTARGET:$BUILDDIR-arm64"
|
||||
|
||||
set +x
|
||||
|
||||
@@ -26,24 +27,41 @@ set +x
|
||||
# everything is terminated/cleaned up and we have no orphaned
|
||||
# useless still-running docker-containers consuming resources.
|
||||
|
||||
ssh $SSHTARGET bash -c "cat >$BUILDDIR/exec_docker_run" <<_HERE
|
||||
for arch in "" "-arm64"; do
|
||||
|
||||
ssh $SSHTARGET bash -c "cat >${BUILDDIR}${arch}/exec_docker_run" <<_HERE
|
||||
set +x -e
|
||||
shopt -s huponexit
|
||||
cd $BUILDDIR
|
||||
cd ${BUILDDIR}${arch}
|
||||
export DCC_NEW_TMP_EMAIL=$DCC_NEW_TMP_EMAIL
|
||||
set -x
|
||||
|
||||
# run everything else inside docker
|
||||
docker run -e DCC_NEW_TMP_EMAIL \
|
||||
--rm -it -v \$(pwd):/mnt -w /mnt \
|
||||
deltachat/coredeps scripts/run_all.sh
|
||||
deltachat/coredeps${arch} scripts/run_all.sh
|
||||
|
||||
_HERE
|
||||
|
||||
done
|
||||
|
||||
echo "--- Running $CIRCLE_JOB remotely"
|
||||
|
||||
ssh -t $SSHTARGET bash "$BUILDDIR/exec_docker_run"
|
||||
echo "--- Building aarch64 wheels"
|
||||
ssh -o ServerAliveInterval=30 -t $SSHTARGET bash "$BUILDDIR-arm64/exec_docker_run"
|
||||
|
||||
echo "--- Building x86_64 wheels"
|
||||
ssh -o ServerAliveInterval=30 -t $SSHTARGET bash "$BUILDDIR/exec_docker_run"
|
||||
|
||||
mkdir -p workspace
|
||||
rsync -avz "$SSHTARGET:$BUILDDIR/python/.docker-tox/wheelhouse/*manylinux201*" workspace/wheelhouse/
|
||||
rsync -avz "$SSHTARGET:$BUILDDIR/python/.docker-tox/dist/*" workspace/wheelhouse/
|
||||
|
||||
# Wheels
|
||||
for arch in "" "-arm64"; do
|
||||
rsync -avz "$SSHTARGET:$BUILDDIR${arch}/python/.docker-tox/wheelhouse/*manylinux201*" workspace/wheelhouse/
|
||||
done
|
||||
|
||||
# Source packages
|
||||
rsync -avz "$SSHTARGET:$BUILDDIR${arch}/python/.docker-tox/dist/*" workspace/wheelhouse/
|
||||
|
||||
# Documentation
|
||||
rsync -avz "$SSHTARGET:$BUILDDIR/python/doc/_build/" workspace/py-docs
|
||||
|
||||
@@ -19,14 +19,17 @@ export DCC_RS_TARGET=release
|
||||
|
||||
# Configure access to a base python and to several python interpreters
|
||||
# needed by tox below.
|
||||
export PATH=$PATH:/opt/python/cp35-cp35m/bin
|
||||
export PATH=$PATH:/opt/python/cp36-cp36m/bin
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
pushd /bin
|
||||
rm -f python3.5
|
||||
ln -s /opt/python/cp35-cp35m/bin/python3.5
|
||||
rm -f python3.6
|
||||
ln -s /opt/python/cp36-cp36m/bin/python3.6
|
||||
rm -f python3.7
|
||||
ln -s /opt/python/cp37-cp37m/bin/python3.7
|
||||
rm -f python3.8
|
||||
ln -s /opt/python/cp38-cp38/bin/python3.8
|
||||
rm -f python3.9
|
||||
ln -s /opt/python/cp39-cp39/bin/python3.9
|
||||
popd
|
||||
|
||||
pushd python
|
||||
@@ -40,7 +43,7 @@ mkdir -p $TOXWORKDIR
|
||||
# Note that the independent remote_tests_python step does all kinds of
|
||||
# live-testing already.
|
||||
unset DCC_NEW_TMP_EMAIL
|
||||
tox --workdir "$TOXWORKDIR" -e py35,py36,py37,py38,auditwheels
|
||||
tox --workdir "$TOXWORKDIR" -e py37,py38,py39,auditwheels
|
||||
popd
|
||||
|
||||
|
||||
|
||||
@@ -3986,4 +3986,33 @@ YEAAAAAA!.
|
||||
.await,
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_dont_show_all_outgoing_msgs_in_self_chat() {
|
||||
// Regression test for https://github.com/deltachat/deltachat-android/issues/1940:
|
||||
// Some servers add a `Bcc: <Self>` header, which caused all outgoing messages to
|
||||
// be shown in the self-chat.
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
dc_receive_imf(
|
||||
&t,
|
||||
b"Bcc: alice@example.com
|
||||
Received: from [127.0.0.1]
|
||||
Subject: s
|
||||
Chat-Version: 1.0
|
||||
Message-ID: <abcd@gmail.com>
|
||||
To: <me@other.maildomain.com>
|
||||
From: <alice@example.com>
|
||||
|
||||
Message content",
|
||||
"Inbox",
|
||||
1,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let msg = t.get_last_msg().await;
|
||||
assert_ne!(msg.chat_id, t.get_self_chat().await.id);
|
||||
}
|
||||
}
|
||||
|
||||
339
src/export_chat.rs
Normal file
339
src/export_chat.rs
Normal file
@@ -0,0 +1,339 @@
|
||||
//! Export chats module
|
||||
//!
|
||||
//! ## Export Format
|
||||
//! The format of an exported chat is a zip file with the following structure:
|
||||
//! ```text
|
||||
//! ├── blobs/ # all files that are referenced by the chat
|
||||
//! ├── msg_info/
|
||||
//! │ └── [msg_id].txt # message info
|
||||
//! ├── msg_source/
|
||||
//! │ └── [msg_id].eml # email sourcecode of messages if availible¹
|
||||
//! └── chat.json # chat info, messages and message authors
|
||||
//! ```
|
||||
//! ##### ¹ Saving Mime header
|
||||
//! To save the mime header you need to have the config option [`SaveMimeHeaders`] enabled.
|
||||
//! This option saves the mime headers on future messages. Normaly the original email source code is discarded to save space.
|
||||
//! You can use the repl tool to do this job:
|
||||
//! ```sh
|
||||
//! $ cargo run --example repl --features=repl /path/to/account/db.sqlite
|
||||
//! > set save_mime_headers 1
|
||||
//! ```
|
||||
//! [`SaveMimeHeaders`]: ../config/enum.Config.html#variant.SaveMimeHeaders
|
||||
|
||||
use crate::chat::*;
|
||||
use crate::constants::Viewtype;
|
||||
use crate::constants::DC_GCM_ADDDAYMARKER;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
// use crate::error::Error;
|
||||
use crate::dc_tools::time;
|
||||
use crate::message::*;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use zip::write::FileOptions;
|
||||
|
||||
use crate::location::Location;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExportChatResult {
|
||||
chat_json: String,
|
||||
// locations_geo_json: String,
|
||||
message_ids: Vec<MsgId>,
|
||||
referenced_blobs: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn export_chat_to_zip(context: &Context, chat_id: ChatId, filename: &str) {
|
||||
let res = export_chat_data(&context, chat_id).await;
|
||||
let destination = std::path::Path::new(filename);
|
||||
let pack_res = pack_exported_chat(&context, res, destination).await;
|
||||
match &pack_res {
|
||||
Ok(()) => println!("Exported chat successfully to {}", filename),
|
||||
Err(err) => println!("Error {:?}", err),
|
||||
};
|
||||
}
|
||||
|
||||
async fn pack_exported_chat(
|
||||
context: &Context,
|
||||
artifact: ExportChatResult,
|
||||
destination: &Path,
|
||||
) -> zip::result::ZipResult<()> {
|
||||
let file = std::fs::File::create(&destination).unwrap();
|
||||
|
||||
let mut zip = zip::ZipWriter::new(file);
|
||||
|
||||
zip.start_file("chat.json", Default::default())?;
|
||||
zip.write_all(artifact.chat_json.as_bytes())?;
|
||||
|
||||
zip.add_directory("blobs/", Default::default())?;
|
||||
|
||||
let options = FileOptions::default();
|
||||
for blob_name in artifact.referenced_blobs {
|
||||
let path = context.get_blobdir().join(&blob_name);
|
||||
|
||||
// println!("adding file {:?} as {:?} ...", path, &blob_name);
|
||||
zip.start_file(format!("blobs/{}", &blob_name), options)?;
|
||||
let mut f = File::open(path)?;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
f.read_to_end(&mut buffer)?;
|
||||
zip.write_all(&*buffer)?;
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
zip.add_directory("msg_info/", Default::default())?;
|
||||
zip.add_directory("msg_source/", Default::default())?;
|
||||
for id in artifact.message_ids {
|
||||
zip.start_file(format!("msg_info/{}.txt", id.to_u32()), options)?;
|
||||
zip.write_all((get_msg_info(&context, id).await).as_bytes())?;
|
||||
if let Some(mime_headers) = get_mime_headers(&context, id).await {
|
||||
zip.start_file(format!("msg_source/{}.eml", id.to_u32()), options)?;
|
||||
zip.write_all((mime_headers).as_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
zip.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ChatJSON {
|
||||
chat_json_version: u8,
|
||||
export_timestamp: i64,
|
||||
name: String,
|
||||
color: String,
|
||||
profile_img: Option<String>,
|
||||
contacts: HashMap<u32, ContactJSON>,
|
||||
referenced_external_messages:Vec<ChatItemJSON>,
|
||||
messages: Vec<ChatItemJSON>,
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ContactJSON {
|
||||
name: String,
|
||||
email: String,
|
||||
color: String,
|
||||
profile_img: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct FileReference {
|
||||
name: String,
|
||||
filesize: u64,
|
||||
mime: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Qoute {
|
||||
quoted_text: String,
|
||||
message_id: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
enum ChatItemJSON {
|
||||
Message {
|
||||
id: u32,
|
||||
author_id: u32, // from_id
|
||||
view_type: Viewtype,
|
||||
timestamp_sort: i64,
|
||||
timestamp_sent: i64,
|
||||
timestamp_rcvd: i64,
|
||||
text: Option<String>,
|
||||
attachment: Option<FileReference>,
|
||||
location_id: Option<u32>,
|
||||
is_info_message: bool,
|
||||
show_padlock: bool,
|
||||
state: MessageState,
|
||||
is_forwarded: bool,
|
||||
quote: Option<Qoute>
|
||||
},
|
||||
MessageError {
|
||||
id: u32,
|
||||
error: String,
|
||||
},
|
||||
DayMarker {
|
||||
timestamp: i64,
|
||||
},
|
||||
}
|
||||
|
||||
impl ChatItemJSON {
|
||||
pub async fn from_message(message: &Message, context: &Context) -> ChatItemJSON {
|
||||
let msg_id = message.get_id();
|
||||
ChatItemJSON::Message {
|
||||
id: msg_id.to_u32(),
|
||||
author_id: message.get_from_id(), // from_id
|
||||
view_type: message.get_viewtype(),
|
||||
timestamp_sort: message.timestamp_sort,
|
||||
timestamp_sent: message.timestamp_sent,
|
||||
timestamp_rcvd: message.timestamp_rcvd,
|
||||
text: message.get_text(),
|
||||
attachment: match message.get_file(context) {
|
||||
Some(file) => Some(FileReference {
|
||||
name: message.get_filename().unwrap_or_else(|| "".to_owned()),
|
||||
filesize: message.get_filebytes(context).await,
|
||||
mime: message.get_filemime().unwrap_or_else(|| "".to_owned()),
|
||||
path: format!(
|
||||
"blobs/{}",
|
||||
file.file_name()
|
||||
.unwrap_or_else(|| std::ffi::OsStr::new(""))
|
||||
.to_str()
|
||||
.unwrap()
|
||||
),
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
location_id: match message.has_location() {
|
||||
true => Some(message.location_id),
|
||||
false => None,
|
||||
},
|
||||
is_info_message: message.is_info(),
|
||||
show_padlock: message.get_showpadlock(),
|
||||
state: message.get_state(),
|
||||
is_forwarded: message.is_forwarded(),
|
||||
quote: match message.quoted_text() {
|
||||
Some(text) => match message.quoted_message(&context).await {
|
||||
Ok(Some(msg)) => Some(Qoute {
|
||||
quoted_text: text,
|
||||
message_id: Some(msg.get_id().to_u32())
|
||||
}),
|
||||
Err(_) | Ok(None) => Some(Qoute {
|
||||
quoted_text: text,
|
||||
message_id: None
|
||||
})
|
||||
}
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn export_chat_data(context: &Context, chat_id: ChatId) -> ExportChatResult {
|
||||
let mut blobs = Vec::new();
|
||||
let mut chat_author_ids = Vec::new();
|
||||
// message_ids var is used for writing message info to files
|
||||
let mut message_ids: Vec<MsgId> = Vec::new();
|
||||
let mut message_json: Vec<ChatItemJSON> = Vec::new();
|
||||
let mut referenced_external_messages: Vec<ChatItemJSON> = Vec::new();
|
||||
|
||||
for item in get_chat_msgs(context, chat_id, DC_GCM_ADDDAYMARKER, None).await {
|
||||
if let Some(json_item) = match item {
|
||||
ChatItem::Message { msg_id } => match Message::load_from_db(context, msg_id).await {
|
||||
Ok(message) => {
|
||||
let filename = message.get_filename();
|
||||
if let Some(file) = filename {
|
||||
// push referenced blobs (attachments)
|
||||
blobs.push(file);
|
||||
}
|
||||
message_ids.push(message.id);
|
||||
// populate contactid list
|
||||
chat_author_ids.push(message.from_id);
|
||||
|
||||
if let Ok(Some(ex_msg)) = message.quoted_message(&context).await {
|
||||
if ex_msg.get_chat_id() != chat_id {
|
||||
// if external add it to the file
|
||||
referenced_external_messages.push(ChatItemJSON::from_message(&ex_msg, &context).await)
|
||||
// contacts don't need to be referenced, because these should only be private replies
|
||||
}
|
||||
}
|
||||
|
||||
Some(ChatItemJSON::from_message(&message, &context).await)
|
||||
}
|
||||
Err(error_message) => Some(ChatItemJSON::MessageError {
|
||||
id: msg_id.to_u32(),
|
||||
error: error_message.to_string(),
|
||||
}),
|
||||
},
|
||||
ChatItem::DayMarker { timestamp } => Some(ChatItemJSON::DayMarker { timestamp }),
|
||||
ChatItem::Marker1 => None,
|
||||
} {
|
||||
message_json.push(json_item)
|
||||
}
|
||||
}
|
||||
|
||||
// deduplicate contact list and load the contacts
|
||||
chat_author_ids.sort();
|
||||
chat_author_ids.dedup();
|
||||
// load information about the authors
|
||||
let mut chat_authors: HashMap<u32, ContactJSON> = HashMap::new();
|
||||
chat_authors.insert(
|
||||
0,
|
||||
ContactJSON {
|
||||
name: "Err: Contact not found".to_owned(),
|
||||
email: "error@localhost".to_owned(),
|
||||
profile_img: None,
|
||||
color: "grey".to_owned(),
|
||||
},
|
||||
);
|
||||
for author_id in chat_author_ids {
|
||||
let contact = Contact::get_by_id(context, author_id).await;
|
||||
if let Ok(c) = contact {
|
||||
let profile_img_path: String;
|
||||
if let Some(path) = c.get_profile_image(context).await {
|
||||
profile_img_path = path
|
||||
.file_name()
|
||||
.unwrap_or_else(|| std::ffi::OsStr::new(""))
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
// push referenced blobs (avatars)
|
||||
blobs.push(profile_img_path.clone());
|
||||
} else {
|
||||
profile_img_path = "".to_owned();
|
||||
}
|
||||
chat_authors.insert(
|
||||
author_id,
|
||||
ContactJSON {
|
||||
name: c.get_display_name().to_owned(),
|
||||
email: c.get_addr().to_owned(),
|
||||
profile_img: match profile_img_path != "" {
|
||||
true => Some(profile_img_path),
|
||||
false => None,
|
||||
},
|
||||
color: format!("{:#}", c.get_color()), // TODO
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Load information about the chat
|
||||
let chat: Chat = Chat::load_from_db(context, chat_id).await.unwrap();
|
||||
let chat_avatar = match chat.get_profile_image(context).await {
|
||||
Some(img) => {
|
||||
let path = img
|
||||
.file_name()
|
||||
.unwrap_or_else(|| std::ffi::OsStr::new(""))
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
blobs.push(path.clone());
|
||||
Some(format!("blobs/{}", path))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let chat_json = ChatJSON {
|
||||
chat_json_version: 1,
|
||||
export_timestamp: time(),
|
||||
name: chat.get_name().to_owned(),
|
||||
color: format!("{:#}", chat.get_color(&context).await),
|
||||
profile_img: chat_avatar,
|
||||
contacts: chat_authors,
|
||||
referenced_external_messages,
|
||||
messages: message_json,
|
||||
locations: crate::location::get_range(&context, chat_id, 0, 0, crate::dc_tools::time())
|
||||
.await,
|
||||
};
|
||||
|
||||
blobs.sort();
|
||||
blobs.dedup();
|
||||
ExportChatResult {
|
||||
chat_json: serde_json::to_string(&chat_json).unwrap(),
|
||||
message_ids,
|
||||
referenced_blobs: blobs,
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ impl Imap {
|
||||
}
|
||||
info!(context, "Starting full folder scan");
|
||||
|
||||
self.setup_handle(context).await?;
|
||||
self.connect_configured(context).await?;
|
||||
let session = self.session.as_mut();
|
||||
let session = session.context("scan_folders(): IMAP No Connection established")?;
|
||||
let folders: Vec<_> = session.list(Some(""), Some("*")).await?.collect().await;
|
||||
|
||||
@@ -51,6 +51,7 @@ pub mod contact;
|
||||
pub mod context;
|
||||
mod e2ee;
|
||||
pub mod ephemeral;
|
||||
pub mod export_chat;
|
||||
mod imap;
|
||||
pub mod imex;
|
||||
mod scheduler;
|
||||
|
||||
@@ -16,9 +16,8 @@ use crate::message::{Message, MsgId};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::Params;
|
||||
use crate::stock_str;
|
||||
|
||||
/// Location record
|
||||
#[derive(Debug, Clone, Default)]
|
||||
use serde::Serialize;
|
||||
#[derive(Debug, Clone, Default, Serialize)]
|
||||
pub struct Location {
|
||||
pub location_id: u32,
|
||||
pub latitude: f64,
|
||||
|
||||
@@ -1585,7 +1585,7 @@ fn get_attachment_filename(
|
||||
/// Returned addresses are normalized and lowercased.
|
||||
pub(crate) fn get_recipients(headers: &[MailHeader]) -> Vec<SingleInfo> {
|
||||
get_all_addresses_from_header(headers, |header_key| {
|
||||
header_key == "to" || header_key == "cc" || header_key == "bcc"
|
||||
header_key == "to" || header_key == "cc"
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,6 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
|
||||
None
|
||||
};
|
||||
|
||||
// what is up with that param name?
|
||||
let name = if let Some(encoded_name) = param.get("n") {
|
||||
let encoded_name = encoded_name.replace("+", "%20"); // sometimes spaces are encoded as `+`
|
||||
match percent_decode_str(&encoded_name).decode_utf8() {
|
||||
|
||||
Reference in New Issue
Block a user