mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 21:42:10 +03:00
Compare commits
137 Commits
ci/python-
...
safe-imex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38e2cb97ea | ||
|
|
f28a971b96 | ||
|
|
18808d0a61 | ||
|
|
86369148ee | ||
|
|
f45ee2ab4d | ||
|
|
2b73fab913 | ||
|
|
e0d750ac64 | ||
|
|
bb57c6e7b7 | ||
|
|
f346a052c1 | ||
|
|
3933353b5f | ||
|
|
6c9c21c135 | ||
|
|
d02a721eed | ||
|
|
8ffb4ae127 | ||
|
|
96fbeb583b | ||
|
|
33b98a15d3 | ||
|
|
e523ebe3c1 | ||
|
|
e17c671b7c | ||
|
|
e7565e1a2a | ||
|
|
b73d6377fc | ||
|
|
31f5fffc45 | ||
|
|
64c518c2f2 | ||
|
|
1ed543b0e8 | ||
|
|
8b7cd2dd1a | ||
|
|
8520b5211a | ||
|
|
03661e2a71 | ||
|
|
20b82b3638 | ||
|
|
cb499ae502 | ||
|
|
02b73207f9 | ||
|
|
53b5cbc12a | ||
|
|
f4c6decd2d | ||
|
|
69f1497986 | ||
|
|
2b46f01fe3 | ||
|
|
dd4adb57cf | ||
|
|
452bce07e1 | ||
|
|
8d702d0b77 | ||
|
|
e1dc4b69f5 | ||
|
|
6cd3580263 | ||
|
|
d5383aecc9 | ||
|
|
71cbbab2c9 | ||
|
|
8518d8f456 | ||
|
|
adc0db04bc | ||
|
|
c61fc59003 | ||
|
|
40f9072250 | ||
|
|
ea30bb351e | ||
|
|
b93550f6c8 | ||
|
|
60bd053095 | ||
|
|
8165b76001 | ||
|
|
efc563f5ff | ||
|
|
e52acc994c | ||
|
|
646833d3ec | ||
|
|
fd72c27afe | ||
|
|
c13bcc25c6 | ||
|
|
21c9ff6c85 | ||
|
|
4d6b367654 | ||
|
|
e2fd22a78e | ||
|
|
0759bdde01 | ||
|
|
faa03e0e14 | ||
|
|
f70897a6d3 | ||
|
|
ba231d2c5f | ||
|
|
095cb759ed | ||
|
|
5cbcb76039 | ||
|
|
3388b42f20 | ||
|
|
e1d541b02e | ||
|
|
cb784615ee | ||
|
|
321c5e049b | ||
|
|
ed7cf218f8 | ||
|
|
74d8368525 | ||
|
|
dcbfa272f9 | ||
|
|
42dd600e0c | ||
|
|
9689df601f | ||
|
|
f6019583b7 | ||
|
|
2d50a3335d | ||
|
|
202bfa987d | ||
|
|
93f9c7cfbd | ||
|
|
8f6a0bbf09 | ||
|
|
1a47c148e5 | ||
|
|
2435ba1ea0 | ||
|
|
9ba57a923b | ||
|
|
90e2b6f26b | ||
|
|
05f9f454c3 | ||
|
|
b85f59798c | ||
|
|
e80345a05b | ||
|
|
0bdcc3d616 | ||
|
|
987f12740e | ||
|
|
1265016a55 | ||
|
|
48d1de3678 | ||
|
|
43f6db3252 | ||
|
|
5b917e7d10 | ||
|
|
0523868a88 | ||
|
|
26f176eb7e | ||
|
|
ad32b5ca8f | ||
|
|
dbf14179dc | ||
|
|
45b0a4ec27 | ||
|
|
1969ee02a5 | ||
|
|
266b205c75 | ||
|
|
7dd3bad8bd | ||
|
|
4b45be7cda | ||
|
|
497ffd86fa | ||
|
|
0bdcc4269f | ||
|
|
e583c99f94 | ||
|
|
e22e50c3fa | ||
|
|
e9c9a3e1ce | ||
|
|
fa7bb71f3f | ||
|
|
34a3ad82e0 | ||
|
|
2f5d74dbf4 | ||
|
|
4bf5ba594c | ||
|
|
6e2da27f45 | ||
|
|
6ee9465d43 | ||
|
|
391a6bf422 | ||
|
|
5001a0e37d | ||
|
|
fd8d16a7db | ||
|
|
f3ac9306f3 | ||
|
|
59740d0b56 | ||
|
|
fb05a6c26f | ||
|
|
7943b708d2 | ||
|
|
04e37d1eca | ||
|
|
91b98e8c6d | ||
|
|
70234e5b19 | ||
|
|
ceff85d892 | ||
|
|
9f914dd42e | ||
|
|
24f5d68fef | ||
|
|
735fc325b1 | ||
|
|
178b216e48 | ||
|
|
5d0481f7a2 | ||
|
|
711bc69750 | ||
|
|
7263c9490d | ||
|
|
0c88bc6ac7 | ||
|
|
fda8d0a2e2 | ||
|
|
14bdf7fae8 | ||
|
|
d4ff7ecbaa | ||
|
|
030aec7373 | ||
|
|
6a351de4f9 | ||
|
|
bbff1c9c3e | ||
|
|
bbb8144129 | ||
|
|
83f3e23297 | ||
|
|
4f880932ae | ||
|
|
62e8c2497c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ python/.tox
|
||||
*.egg-info
|
||||
__pycache__
|
||||
python/src/deltachat/capi*.so
|
||||
python/.venv/
|
||||
|
||||
python/liveconfig*
|
||||
|
||||
|
||||
168
Cargo.lock
generated
168
Cargo.lock
generated
@@ -84,7 +84,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.37"
|
||||
version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -130,7 +130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -317,7 +317,7 @@ name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -419,7 +419,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -481,11 +481,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -502,13 +502,12 @@ dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mmime 0.1.2-alpha.0 (git+https://github.com/dignifiedquire/mmime?rev=bccd2c2)",
|
||||
"mmime 0.1.2",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -524,21 +523,20 @@ dependencies = [
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-provider-overview"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211#366b41a7503973e4ffac3aa5173b419f2f03c211"
|
||||
name = "deltachat-provider-database"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -552,10 +550,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.5"
|
||||
dependencies = [
|
||||
"deltachat 1.0.0-alpha.4",
|
||||
"deltachat-provider-overview 0.1.0 (git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211)",
|
||||
"deltachat 1.0.0-alpha.5",
|
||||
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -688,7 +686,7 @@ name = "error-chain"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -705,7 +703,7 @@ name = "failure"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -781,7 +779,7 @@ name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -902,7 +900,7 @@ name = "human-panic"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"os_type 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1090,7 +1088,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1258,8 +1256,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mmime"
|
||||
version = "0.1.2-alpha.0"
|
||||
source = "git+https://github.com/dignifiedquire/mmime?rev=bccd2c2#bccd2c2c89e9241e05f321c963f638affdccad96"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1302,7 +1299,7 @@ name = "nix"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1328,7 +1325,7 @@ name = "nom"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lexical-core 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1411,7 +1408,7 @@ name = "openssl"
|
||||
version = "0.10.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1603,46 +1600,6 @@ dependencies = [
|
||||
"x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.7.24"
|
||||
source = "git+https://github.com/sfackler/rust-phf?rev=0d00821#0d0082178568036736bb6d51cb91f95ca5a616c3"
|
||||
dependencies = [
|
||||
"phf_macros 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"phf_shared 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.7.24"
|
||||
source = "git+https://github.com/sfackler/rust-phf?rev=0d00821#0d0082178568036736bb6d51cb91f95ca5a616c3"
|
||||
dependencies = [
|
||||
"phf_shared 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.7.24"
|
||||
source = "git+https://github.com/sfackler/rust-phf?rev=0d00821#0d0082178568036736bb6d51cb91f95ca5a616c3"
|
||||
dependencies = [
|
||||
"phf_generator 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"phf_shared 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)",
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.7.24"
|
||||
source = "git+https://github.com/sfackler/rust-phf?rev=0d00821#0d0082178568036736bb6d51cb91f95ca5a616c3"
|
||||
dependencies = [
|
||||
"siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.16"
|
||||
@@ -1659,7 +1616,7 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1674,16 +1631,6 @@ dependencies = [
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
@@ -1694,7 +1641,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1706,7 +1653,7 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1736,7 +1683,7 @@ name = "pulldown-cmark"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1774,7 +1721,7 @@ name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1837,7 +1784,6 @@ dependencies = [
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1935,15 +1881,6 @@ dependencies = [
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
@@ -2065,7 +2002,7 @@ name = "rusqlite"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2215,7 +2152,7 @@ name = "serde_derive"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2275,11 +2212,6 @@ dependencies = [
|
||||
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "skeptic"
|
||||
version = "0.13.4"
|
||||
@@ -2348,18 +2280,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2402,7 +2334,7 @@ name = "syn"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2928,13 +2860,13 @@ dependencies = [
|
||||
"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
|
||||
"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
|
||||
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
|
||||
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
|
||||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
||||
"checksum bitfield 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
|
||||
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
|
||||
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||
@@ -2969,13 +2901,13 @@ dependencies = [
|
||||
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
|
||||
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6b2f4752cc29efbfd03474c532ce8f916f2d44ec5bb8c21f93bc76e5365528"
|
||||
"checksum ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3e061727ebef83bbccac7c27b9a5ff9fd83094d34cb20f4005440a9562a27de7"
|
||||
"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d"
|
||||
"checksum darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6"
|
||||
"checksum darling_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6afc018370c3bff3eb51f89256a6bdb18b4fdcda72d577982a14954a7a0b402c"
|
||||
"checksum darling_macro 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1"
|
||||
"checksum debug_stub_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "496b7f8a2f853313c3ca370641d7ff3e42c32974fdccda8f0684599ed0a3ff6b"
|
||||
"checksum deltachat-provider-overview 0.1.0 (git+https://github.com/deltachat/provider-overview?rev=366b41a7503973e4ffac3aa5173b419f2f03c211)" = "<none>"
|
||||
"checksum deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "814dba060d9fdc7a989fccdc4810ada9d1c7a1f09131c78e42412bc6c634b93b"
|
||||
"checksum derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ac53fa6a3cda160df823a9346442525dcaf1e171999a1cf23e67067e4fd64d4"
|
||||
"checksum derive_builder_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0288a23da9333c246bb18c143426074a6ae96747995c5819d2947b64cd942b37"
|
||||
"checksum derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d944ac6003ed268757ef1ee686753b57efc5fcf0ebe7b64c9fc81e7e32ff839"
|
||||
@@ -3037,7 +2969,7 @@ dependencies = [
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728"
|
||||
"checksum lexical-core 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d11f3928ffd249baadf9f083cdea16d7cf317b2a8be6227e1169102432a36d2"
|
||||
"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
|
||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||
"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25"
|
||||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||
@@ -3057,7 +2989,6 @@ dependencies = [
|
||||
"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10"
|
||||
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum mmime 0.1.2-alpha.0 (git+https://github.com/dignifiedquire/mmime?rev=bccd2c2)" = "<none>"
|
||||
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
||||
@@ -3089,17 +3020,12 @@ dependencies = [
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb80b37b7debf9a98dc0caca3ed40ddf1d383691208763d0458df0b91521020f"
|
||||
"checksum phf 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)" = "<none>"
|
||||
"checksum phf_generator 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)" = "<none>"
|
||||
"checksum phf_macros 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)" = "<none>"
|
||||
"checksum phf_shared 0.7.24 (git+https://github.com/sfackler/rust-phf?rev=0d00821)" = "<none>"
|
||||
"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea"
|
||||
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
|
||||
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
||||
"checksum pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074"
|
||||
"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
|
||||
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
|
||||
"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
|
||||
"checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
|
||||
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
||||
@@ -3124,7 +3050,6 @@ dependencies = [
|
||||
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
@@ -3159,7 +3084,6 @@ dependencies = [
|
||||
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
|
||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
|
||||
"checksum siphasher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9913c75df657d84a03fa689c016b0bb2863ff0b497b26a8d6e9703f8d5df03a8"
|
||||
"checksum skeptic 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fb8ed853fdc19ce09752d63f3a2e5b5158aeb261520cd75eb618bd60305165"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7"
|
||||
@@ -3169,8 +3093,8 @@ dependencies = [
|
||||
"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c"
|
||||
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1c33039533f051704951680f1adfd468fd37ac46816ded0d9ee068e60f05f"
|
||||
"checksum strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47cd23f5c7dee395a00fa20135e2ec0fffcdfa151c56182966d7a3261343432e"
|
||||
"checksum strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
|
||||
"checksum strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81"
|
||||
"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
|
||||
11
Cargo.toml
11
Cargo.toml
@@ -1,18 +1,19 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.5"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MPL"
|
||||
|
||||
[dependencies]
|
||||
deltachat_derive = { path = "./deltachat_derive" }
|
||||
mmime = { version = "0.1.2", path = "./mmime" }
|
||||
|
||||
libc = "0.2.51"
|
||||
pgp = { version = "0.2", default-features = false }
|
||||
hex = "0.3.2"
|
||||
sha2 = "0.8.0"
|
||||
rand = "0.6.5"
|
||||
phf = { git = "https://github.com/sfackler/rust-phf", rev = "0d00821", features = ["macros"] }
|
||||
smallvec = "0.6.9"
|
||||
reqwest = "0.9.15"
|
||||
num-derive = "0.2.5"
|
||||
@@ -20,7 +21,6 @@ num-traits = "0.2.6"
|
||||
native-tls = "0.2.3"
|
||||
lettre = "0.9.0"
|
||||
imap = { git = "https://github.com/jonhoo/rust-imap", rev = "281d2eb8ab50dc656ceff2ae749ca5045f334e15" }
|
||||
mmime = { git = "https://github.com/dignifiedquire/mmime", rev = "bccd2c2" }
|
||||
base64 = "0.10"
|
||||
charset = "0.1"
|
||||
percent-encoding = "2.0"
|
||||
@@ -36,8 +36,8 @@ regex = "1.1.6"
|
||||
rusqlite = { version = "0.20", features = ["bundled"] }
|
||||
r2d2_sqlite = "0.12.0"
|
||||
r2d2 = "0.8.5"
|
||||
strum = "0.15.0"
|
||||
strum_macros = "0.15.0"
|
||||
strum = "0.16.0"
|
||||
strum_macros = "0.16.0"
|
||||
thread-local-object = "0.1.0"
|
||||
backtrace = "0.3.33"
|
||||
byteorder = "1.3.1"
|
||||
@@ -59,6 +59,7 @@ proptest = "0.9.4"
|
||||
members = [
|
||||
"deltachat-ffi",
|
||||
"deltachat_derive",
|
||||
"mmime",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -13,7 +13,7 @@ install:
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --release
|
||||
- cargo test --release --all
|
||||
|
||||
cache:
|
||||
- target
|
||||
|
||||
@@ -39,8 +39,12 @@ if [ -n "$TESTS" ]; then
|
||||
# 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
|
||||
|
||||
tox --workdir "$TOXWORKDIR" -e py37
|
||||
|
||||
# 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 -- -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- -k "qr"
|
||||
unset DCC_PY_LIVECONFIG
|
||||
tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
|
||||
tox --workdir "$TOXWORKDIR" -e auditwheels
|
||||
|
||||
@@ -31,7 +31,7 @@ fi
|
||||
if [[ $NORUN == "1" ]]; then
|
||||
export CARGO_SUBCMD="build"
|
||||
else
|
||||
export CARGO_SUBCMD="test"
|
||||
export CARGO_SUBCMD="test --all"
|
||||
export OPT="${OPT} "
|
||||
export OPT_RELEASE="${OPT_RELEASE} "
|
||||
export OPT_RELEASE_IGNORED="${OPT_RELEASE} -- --ignored"
|
||||
@@ -39,4 +39,5 @@ fi
|
||||
|
||||
# Run all the test configurations:
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT_RELEASE
|
||||
$CARGO_CMD $CARGO_SUBCMD $OPT_RELEASE_IGNORED
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.4"
|
||||
version = "1.0.0-alpha.5"
|
||||
description = "Deltachat FFI"
|
||||
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
|
||||
edition = "2018"
|
||||
@@ -16,7 +16,7 @@ crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
deltachat = { path = "../", default-features = false }
|
||||
deltachat-provider-overview = { git = "https://github.com/deltachat/provider-overview", rev = "366b41a7503973e4ffac3aa5173b419f2f03c211" }
|
||||
deltachat-provider-database = "0.2.1"
|
||||
libc = "0.2"
|
||||
human-panic = "1.0.1"
|
||||
num-traits = "0.2.6"
|
||||
|
||||
@@ -11,6 +11,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct _dc_context dc_context_t;
|
||||
typedef struct _dc_array dc_array_t;
|
||||
typedef struct _dc_chatlist dc_chatlist_t;
|
||||
typedef struct _dc_chat dc_chat_t;
|
||||
typedef struct _dc_msg dc_msg_t;
|
||||
typedef struct _dc_contact dc_contact_t;
|
||||
typedef struct _dc_lot dc_lot_t;
|
||||
typedef struct _dc_provider dc_provider_t;
|
||||
|
||||
|
||||
/**
|
||||
* @mainpage Getting started
|
||||
*
|
||||
@@ -189,13 +199,6 @@ extern "C" {
|
||||
* SQLite database for offline functionality and for account-related
|
||||
* settings.
|
||||
*/
|
||||
typedef struct _dc_context dc_context_t;
|
||||
typedef struct _dc_array dc_array_t;
|
||||
typedef struct _dc_chatlist dc_chatlist_t;
|
||||
typedef struct _dc_chat dc_chat_t;
|
||||
typedef struct _dc_msg dc_msg_t;
|
||||
typedef struct _dc_contact dc_contact_t;
|
||||
typedef struct _dc_lot dc_lot_t;
|
||||
|
||||
|
||||
/**
|
||||
@@ -402,9 +405,14 @@ char* dc_get_config (dc_context_t* context, const char*
|
||||
|
||||
/**
|
||||
* Get information about the context.
|
||||
*
|
||||
* The information is returned by a multi-line string
|
||||
* and contains information about the current configuration.
|
||||
*
|
||||
* If the context is not open or configured only a subset of the information
|
||||
* will be available. There is no guarantee about which information will be
|
||||
* included when however.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return String which must be free()'d after usage. Never returns NULL.
|
||||
@@ -442,112 +450,6 @@ char* dc_get_info (dc_context_t* context);
|
||||
*/
|
||||
char* dc_get_oauth2_url (dc_context_t* context, const char* addr, const char* redirect_uri);
|
||||
|
||||
/**
|
||||
* Opaque object containing information about one single email provider.
|
||||
*/
|
||||
typedef struct _dc_provider dc_provider_t;
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given domain.
|
||||
*
|
||||
* @param doamin The domain to get provider info for.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_domain (char* domain);
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given email address.
|
||||
*
|
||||
* The provider is extracted from the email address and it's information is returned.
|
||||
*
|
||||
* @param email The user's email address to extract the provider info form.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_email (char* email);
|
||||
|
||||
/**
|
||||
* URL of the overview page.
|
||||
*
|
||||
* This URL allows linking to the providers page on providers.delta.chat.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* The provider's name.
|
||||
*
|
||||
* The name of the provider, e.g. "POSTEO".
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* The markdown content of the providers page.
|
||||
*
|
||||
* This contains the preparation steps or additional information if the status
|
||||
* is DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Date of when the state was last checked/updated.
|
||||
*
|
||||
* This is returned as a string.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Whether DC works with this provider.
|
||||
*
|
||||
* Can be one of @ref DC_PROVIDER_STATUS_OK, @ref
|
||||
* DC_PROVIDER_STATUS_PREPARATION and @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return The status as a constant number.
|
||||
*/
|
||||
int dc_provider_get_status (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Free the provider info struct.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
*/
|
||||
void dc_provider_unref (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works right out of the box without any preperation steps needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_OK 1
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works, but preparation steps are needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_PREPARATION 2
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Doesn't work (too unstable to use falls also in this category)
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_BROKEN 3
|
||||
|
||||
// connect
|
||||
|
||||
@@ -713,12 +615,8 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch new messages from the MVBOX, if any.
|
||||
* The MVBOX is a folder on the account where chat messages are moved to.
|
||||
* The moving is done to not disturb shared accounts that are used by both,
|
||||
* Delta Chat and a classical MUA.
|
||||
*
|
||||
* This function and dc_perform_mvbox_idle()
|
||||
* Execute pending mvbox-jobs.
|
||||
* This function and dc_perform_mvbox_fetch() and dc_perform_mvbox_idle()
|
||||
* must be called from the same thread, typically in a loop.
|
||||
*
|
||||
* Example:
|
||||
@@ -726,6 +624,7 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
* void* mvbox_thread_func(void* context)
|
||||
* {
|
||||
* while (true) {
|
||||
* dc_perform_mvbox_jobs(context);
|
||||
* dc_perform_mvbox_fetch(context);
|
||||
* dc_perform_mvbox_idle(context);
|
||||
* }
|
||||
@@ -739,13 +638,26 @@ void dc_interrupt_imap_idle (dc_context_t* context);
|
||||
*
|
||||
* // network becomes available again -
|
||||
* // the interrupt causes dc_perform_mvbox_idle() in the thread above
|
||||
* // to return so that and messages are fetched.
|
||||
* // to return so that jobs are executed and messages are fetched.
|
||||
* dc_maybe_network(context);
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_mvbox_jobs (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch new messages from the MVBOX, if any.
|
||||
* The MVBOX is a folder on the account where chat messages are moved to.
|
||||
* The moving is done to not disturb shared accounts that are used by both,
|
||||
* Delta Chat and a classical MUA.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_mvbox_fetch (dc_context_t* context);
|
||||
|
||||
|
||||
@@ -782,6 +694,39 @@ void dc_perform_mvbox_idle (dc_context_t* context);
|
||||
*/
|
||||
void dc_interrupt_mvbox_idle (dc_context_t* context);
|
||||
|
||||
/**
|
||||
* Execute pending sentbox-jobs.
|
||||
* This function and dc_perform_sentbox_fetch() and dc_perform_sentbox_idle()
|
||||
* must be called from the same thread, typically in a loop.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* void* sentbox_thread_func(void* context)
|
||||
* {
|
||||
* while (true) {
|
||||
* dc_perform_sentbox_jobs(context);
|
||||
* dc_perform_sentbox_fetch(context);
|
||||
* dc_perform_sentbox_idle(context);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // start sentbox-thread that runs forever
|
||||
* pthread_t sentbox_thread;
|
||||
* pthread_create(&sentbox_thread, NULL, sentbox_thread_func, context);
|
||||
*
|
||||
* ... program runs ...
|
||||
*
|
||||
* // network becomes available again -
|
||||
* // the interrupt causes dc_perform_sentbox_idle() in the thread above
|
||||
* // to return so that jobs are executed and messages are fetched.
|
||||
* dc_maybe_network(context);
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context as created by dc_context_new().
|
||||
* @return None.
|
||||
*/
|
||||
void dc_perform_sentbox_jobs (dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Fetch new messages from the Sent folder, if any.
|
||||
@@ -3524,6 +3469,110 @@ int dc_contact_is_blocked (const dc_contact_t* contact);
|
||||
int dc_contact_is_verified (dc_contact_t* contact);
|
||||
|
||||
|
||||
/**
|
||||
* @class dc_provider_t
|
||||
*
|
||||
* Opaque object containing information about one single email provider.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given domain.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param domain The domain to get provider info for.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_domain (char* domain);
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given email address.
|
||||
*
|
||||
* The provider is extracted from the email address and it's information is returned.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param email The user's email address to extract the provider info form.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_email (char* email);
|
||||
|
||||
|
||||
/**
|
||||
* URL of the overview page.
|
||||
*
|
||||
* This URL allows linking to the providers page on providers.delta.chat.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The provider's name.
|
||||
*
|
||||
* The name of the provider, e.g. "POSTEO".
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The markdown content of the providers page.
|
||||
*
|
||||
* This contains the preparation steps or additional information if the status
|
||||
* is @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Date of when the state was last checked/updated.
|
||||
*
|
||||
* This is returned as a string.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Whether DC works with this provider.
|
||||
*
|
||||
* Can be one of @ref DC_PROVIDER_STATUS_OK, @ref
|
||||
* DC_PROVIDER_STATUS_PREPARATION and @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return The status as a constant number.
|
||||
*/
|
||||
int dc_provider_get_status (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Free the provider info struct.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
*/
|
||||
void dc_provider_unref (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* @class dc_lot_t
|
||||
*
|
||||
@@ -4131,6 +4180,41 @@ void dc_array_add_id (dc_array_t*, uint32_t); // depreca
|
||||
#define DC_SHOW_EMAILS_ALL 2
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup DC_PROVIDER_STATUS DC_PROVIDER_STATUS
|
||||
*
|
||||
* These constants are used as return values for dc_provider_get_status().
|
||||
*
|
||||
* @addtogroup DC_PROVIDER_STATUS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works right out of the box without any preperation steps needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_OK 1
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works, but preparation steps are needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_PREPARATION 2
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Doesn't work (too unstable to use falls also in this category)
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_BROKEN 3
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Strings need some doumentation about used placeholders.
|
||||
*
|
||||
|
||||
@@ -24,7 +24,9 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
use deltachat::contact::Contact;
|
||||
use deltachat::context::Context;
|
||||
use deltachat::dc_tools::{as_path, as_str, dc_strdup, to_string, OsStrExt, StrExt};
|
||||
use deltachat::dc_tools::{
|
||||
as_path, as_str, dc_strdup, to_string, to_string_lossy, OsStrExt, StrExt,
|
||||
};
|
||||
use deltachat::*;
|
||||
|
||||
// as C lacks a good and portable error handling,
|
||||
@@ -186,7 +188,7 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
let os_name = if os_name.is_null() {
|
||||
String::from("DcFFI")
|
||||
} else {
|
||||
dc_tools::to_string_lossy(os_name)
|
||||
to_string_lossy(os_name)
|
||||
};
|
||||
let ffi_ctx = ContextWrapper {
|
||||
cb,
|
||||
@@ -273,11 +275,11 @@ pub unsafe extern "C" fn dc_is_open(context: *mut dc_context_t) -> libc::c_int {
|
||||
eprintln!("ignoring careless call to dc_is_open()");
|
||||
return 0;
|
||||
}
|
||||
let ffi_context = &mut *context;
|
||||
let ffi_context = &*context;
|
||||
let inner_guard = ffi_context.inner.read().unwrap();
|
||||
match *inner_guard {
|
||||
Some(_) => 0,
|
||||
None => 1,
|
||||
Some(_) => 1,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,9 +347,12 @@ pub unsafe extern "C" fn dc_get_info(context: *mut dc_context_t) -> *mut libc::c
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| render_info(ctx.get_info()).unwrap_or_default().strdup())
|
||||
.unwrap_or_else(|_| "".strdup())
|
||||
let guard = ffi_context.inner.read().unwrap();
|
||||
let info = match guard.as_ref() {
|
||||
Some(ref ctx) => ctx.get_info(),
|
||||
None => context::get_info(),
|
||||
};
|
||||
render_info(info).unwrap_or_default().strdup()
|
||||
}
|
||||
|
||||
fn render_info(
|
||||
@@ -471,6 +476,18 @@ pub unsafe extern "C" fn dc_perform_mvbox_fetch(context: *mut dc_context_t) {
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_mvbox_jobs(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_perform_mvbox_jobs()");
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| job::perform_mvbox_jobs(ctx))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_mvbox_idle(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
@@ -507,6 +524,18 @@ pub unsafe extern "C" fn dc_perform_sentbox_fetch(context: *mut dc_context_t) {
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_sentbox_jobs(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_perform_sentbox_jobs()");
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| job::perform_sentbox_jobs(ctx))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_perform_sentbox_idle(context: *mut dc_context_t) {
|
||||
if context.is_null() {
|
||||
@@ -711,7 +740,7 @@ pub unsafe extern "C" fn dc_send_text_msg(
|
||||
return 0;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
let text_to_send = dc_tools::to_string_lossy(text_to_send);
|
||||
let text_to_send = to_string_lossy(text_to_send);
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
chat::send_text_msg(ctx, chat_id, text_to_send)
|
||||
@@ -912,6 +941,12 @@ pub unsafe extern "C" fn dc_get_next_media(
|
||||
eprintln!("ignoring careless call to dc_get_next_media()");
|
||||
return 0;
|
||||
}
|
||||
let direction = if dir < 0 {
|
||||
chat::Direction::Backward
|
||||
} else {
|
||||
chat::Direction::Forward
|
||||
};
|
||||
|
||||
let ffi_context = &*context;
|
||||
let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {}", msg_type));
|
||||
let or_msg_type2 =
|
||||
@@ -920,7 +955,7 @@ pub unsafe extern "C" fn dc_get_next_media(
|
||||
from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {}", or_msg_type3));
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
chat::get_next_media(ctx, msg_id, dir, msg_type, or_msg_type2, or_msg_type3)
|
||||
chat::get_next_media(ctx, msg_id, direction, msg_type, or_msg_type2, or_msg_type3)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
@@ -1052,7 +1087,8 @@ pub unsafe extern "C" fn dc_is_contact_in_chat(
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| chat::is_contact_in_chat(ctx, chat_id, contact_id))
|
||||
.unwrap_or(0)
|
||||
.unwrap_or_default()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1148,7 +1184,7 @@ pub unsafe extern "C" fn dc_get_msg_info(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_get_msg_info(ctx, msg_id))
|
||||
.with_inner(|ctx| message::get_msg_info(ctx, msg_id).strdup())
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1163,7 +1199,11 @@ pub unsafe extern "C" fn dc_get_mime_headers(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_get_mime_headers(ctx, msg_id))
|
||||
.with_inner(|ctx| {
|
||||
message::get_mime_headers(ctx, msg_id)
|
||||
.map(|s| s.strdup())
|
||||
.unwrap_or_else(|| ptr::null_mut())
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1178,8 +1218,11 @@ pub unsafe extern "C" fn dc_delete_msgs(
|
||||
return;
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_delete_msgs(ctx, msg_ids, msg_cnt))
|
||||
.with_inner(|ctx| message::delete_msgs(ctx, ids))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
@@ -1198,9 +1241,11 @@ pub unsafe extern "C" fn dc_forward_msgs(
|
||||
eprintln!("ignoring careless call to dc_forward_msgs()");
|
||||
return;
|
||||
}
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| chat::forward_msgs(ctx, msg_ids, msg_cnt, chat_id))
|
||||
.with_inner(|ctx| chat::forward_msgs(ctx, ids, chat_id))
|
||||
.unwrap_or(())
|
||||
}
|
||||
|
||||
@@ -1226,9 +1271,11 @@ pub unsafe extern "C" fn dc_markseen_msgs(
|
||||
eprintln!("ignoring careless call to dc_markseen_msgs()");
|
||||
return;
|
||||
}
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_markseen_msgs(ctx, msg_ids, msg_cnt as usize))
|
||||
.with_inner(|ctx| message::markseen_msgs(ctx, ids))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1243,9 +1290,12 @@ pub unsafe extern "C" fn dc_star_msgs(
|
||||
eprintln!("ignoring careless call to dc_star_msgs()");
|
||||
return;
|
||||
}
|
||||
|
||||
let ids = std::slice::from_raw_parts(msg_ids, msg_cnt as usize);
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_star_msgs(ctx, msg_ids, msg_cnt, star))
|
||||
.with_inner(|ctx| message::star_msgs(ctx, ids, star == 1))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1258,7 +1308,7 @@ pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) ->
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
let message = match message::dc_get_msg(ctx, msg_id) {
|
||||
let message = match message::Message::load_from_db(ctx, msg_id) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
error!(ctx, "Error getting msg #{}: {}", msg_id, e);
|
||||
@@ -1472,15 +1522,23 @@ pub unsafe extern "C" fn dc_imex(
|
||||
context: *mut dc_context_t,
|
||||
what: libc::c_int,
|
||||
param1: *mut libc::c_char,
|
||||
param2: *mut libc::c_char,
|
||||
_param2: *mut libc::c_char,
|
||||
) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_imex()");
|
||||
return;
|
||||
}
|
||||
let what = match imex::ImexMode::from_i32(what as i32) {
|
||||
Some(what) => what,
|
||||
None => {
|
||||
eprintln!("ignoring invalid argument {} to dc_imex", what);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| dc_imex::dc_imex(ctx, what, as_opt_str(param1), param2))
|
||||
.with_inner(|ctx| imex::imex(ctx, what, as_opt_str(param1)))
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1495,7 +1553,13 @@ pub unsafe extern "C" fn dc_imex_has_backup(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| dc_imex::dc_imex_has_backup(ctx, as_str(dir)))
|
||||
.with_inner(|ctx| match imex::has_backup(ctx, as_str(dir)) {
|
||||
Ok(res) => res.strdup(),
|
||||
Err(err) => {
|
||||
error!(ctx, "dc_imex_has_backup: {}", err);
|
||||
ptr::null_mut()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1507,7 +1571,13 @@ pub unsafe extern "C" fn dc_initiate_key_transfer(context: *mut dc_context_t) ->
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| dc_imex::dc_initiate_key_transfer(ctx))
|
||||
.with_inner(|ctx| match imex::initiate_key_transfer(ctx) {
|
||||
Ok(res) => res.strdup(),
|
||||
Err(err) => {
|
||||
error!(ctx, "dc_initiate_key_transfer(): {}", err);
|
||||
ptr::null_mut()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
}
|
||||
|
||||
@@ -1526,7 +1596,15 @@ pub unsafe extern "C" fn dc_continue_key_transfer(
|
||||
}
|
||||
let ffi_context = &*context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| dc_imex::dc_continue_key_transfer(ctx, msg_id, setup_code) as libc::c_int)
|
||||
.with_inner(
|
||||
|ctx| match imex::continue_key_transfer(ctx, msg_id, as_str(setup_code)) {
|
||||
Ok(()) => 1,
|
||||
Err(err) => {
|
||||
error!(ctx, "dc_continue_key_transfer: {}", err);
|
||||
0
|
||||
}
|
||||
},
|
||||
)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
@@ -2152,7 +2230,7 @@ pub unsafe extern "C" fn dc_msg_new(
|
||||
let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {}", viewtype));
|
||||
let msg = MessageWrapper {
|
||||
context,
|
||||
message: message::dc_msg_new(viewtype),
|
||||
message: message::Message::new(viewtype),
|
||||
};
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
@@ -2174,7 +2252,7 @@ pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_id(&ffi_msg.message)
|
||||
ffi_msg.message.get_id()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2184,7 +2262,7 @@ pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_from_id(&ffi_msg.message)
|
||||
ffi_msg.message.get_from_id()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2194,7 +2272,7 @@ pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg_t) -> u32 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_chat_id(&ffi_msg.message)
|
||||
ffi_msg.message.get_chat_id()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2204,7 +2282,9 @@ pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_viewtype(&ffi_msg.message)
|
||||
ffi_msg
|
||||
.message
|
||||
.get_viewtype()
|
||||
.to_i64()
|
||||
.expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int
|
||||
}
|
||||
@@ -2216,7 +2296,7 @@ pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_state(&ffi_msg.message) as libc::c_int
|
||||
ffi_msg.message.get_state() as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2226,7 +2306,7 @@ pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg_t) -> i64 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_timestamp(&ffi_msg.message)
|
||||
ffi_msg.message.get_timestamp()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2236,7 +2316,7 @@ pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg_t) -> i6
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_received_timestamp(&ffi_msg.message)
|
||||
ffi_msg.message.get_received_timestamp()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2246,7 +2326,7 @@ pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg_t) -> i64 {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_sort_timestamp(&ffi_msg.message)
|
||||
ffi_msg.message.get_sort_timestamp()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2256,7 +2336,7 @@ pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg_t) -> *mut libc::c_cha
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_text(&ffi_msg.message)
|
||||
ffi_msg.message.get_text().unwrap_or_default().strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2269,7 +2349,9 @@ pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg_t) -> *mut libc::c_cha
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
message::dc_msg_get_file(ctx, &ffi_msg.message)
|
||||
ffi_msg
|
||||
.message
|
||||
.get_file(ctx)
|
||||
.and_then(|p| p.to_c_string().ok())
|
||||
.map(|cs| dc_strdup(cs.as_ptr()))
|
||||
.unwrap_or_else(|| "".strdup())
|
||||
@@ -2284,7 +2366,7 @@ pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_filename(&ffi_msg.message)
|
||||
ffi_msg.message.get_filename().unwrap_or_default().strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2294,7 +2376,11 @@ pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg_t) -> *mut libc::c
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_filemime(&ffi_msg.message).strdup()
|
||||
if let Some(x) = ffi_msg.message.get_filemime() {
|
||||
x.strdup()
|
||||
} else {
|
||||
return dc_strdup(ptr::null());
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2306,7 +2392,7 @@ pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg_t) -> u64 {
|
||||
let ffi_msg = &*msg;
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_msg_get_filebytes(ctx, &ffi_msg.message))
|
||||
.with_inner(|ctx| ffi_msg.message.get_filebytes(ctx))
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
@@ -2317,7 +2403,7 @@ pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_width(&ffi_msg.message)
|
||||
ffi_msg.message.get_width()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2327,7 +2413,7 @@ pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_height(&ffi_msg.message)
|
||||
ffi_msg.message.get_height()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2337,7 +2423,7 @@ pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_duration(&ffi_msg.message)
|
||||
ffi_msg.message.get_duration()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2347,7 +2433,7 @@ pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg_t) -> libc::c_i
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_get_showpadlock(&ffi_msg.message) as libc::c_int
|
||||
ffi_msg.message.get_showpadlock() as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2369,7 +2455,7 @@ pub unsafe extern "C" fn dc_msg_get_summary(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
let lot = message::dc_msg_get_summary(ctx, &mut ffi_msg.message, maybe_chat);
|
||||
let lot = ffi_msg.message.get_summary(ctx, maybe_chat);
|
||||
Box::into_raw(Box::new(lot))
|
||||
})
|
||||
.unwrap_or_else(|_| ptr::null_mut())
|
||||
@@ -2388,13 +2474,12 @@ pub unsafe extern "C" fn dc_msg_get_summarytext(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
message::dc_msg_get_summarytext(
|
||||
ctx,
|
||||
&mut ffi_msg.message,
|
||||
approx_characters.try_into().unwrap(),
|
||||
)
|
||||
ffi_msg
|
||||
.message
|
||||
.get_summarytext(ctx, approx_characters.try_into().unwrap())
|
||||
})
|
||||
.unwrap_or_else(|_| "".strdup())
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2404,7 +2489,7 @@ pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg_t) -> l
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_has_deviating_timestamp(&ffi_msg.message)
|
||||
ffi_msg.message.has_deviating_timestamp().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2414,7 +2499,7 @@ pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_has_location(&ffi_msg.message) as libc::c_int
|
||||
ffi_msg.message.has_location() as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2424,7 +2509,7 @@ pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_sent(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_sent().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2434,7 +2519,7 @@ pub unsafe extern "C" fn dc_msg_is_starred(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_starred(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_starred().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2444,7 +2529,7 @@ pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_forwarded(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_forwarded().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2454,7 +2539,7 @@ pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg_t) -> libc::c_int {
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_info(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_info().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2464,7 +2549,7 @@ pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg_t) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_increation(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_increation().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2474,7 +2559,7 @@ pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_i
|
||||
return 0;
|
||||
}
|
||||
let ffi_msg = &*msg;
|
||||
message::dc_msg_is_setupmessage(&ffi_msg.message).into()
|
||||
ffi_msg.message.is_setupmessage().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2486,8 +2571,9 @@ pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut l
|
||||
let ffi_msg = &*msg;
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| message::dc_msg_get_setupcodebegin(ctx, &ffi_msg.message))
|
||||
.unwrap_or_else(|_| "".strdup())
|
||||
.with_inner(|ctx| ffi_msg.message.get_setupcodebegin(ctx).unwrap_or_default())
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2498,7 +2584,7 @@ pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg_t, text: *mut libc::c_
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
// TODO: {text} equal to NULL is treated as "", which is strange. Does anyone rely on it?
|
||||
message::dc_msg_set_text(&mut ffi_msg.message, text)
|
||||
ffi_msg.message.set_text(as_opt_str(text).map(Into::into))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2507,12 +2593,12 @@ pub unsafe extern "C" fn dc_msg_set_file(
|
||||
file: *mut libc::c_char,
|
||||
filemime: *mut libc::c_char,
|
||||
) {
|
||||
if msg.is_null() {
|
||||
if msg.is_null() || file.is_null() {
|
||||
eprintln!("ignoring careless call to dc_msg_set_file()");
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
message::dc_msg_set_file(&mut ffi_msg.message, file, filemime)
|
||||
ffi_msg.message.set_file(as_str(file), as_opt_str(filemime))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2526,7 +2612,7 @@ pub unsafe extern "C" fn dc_msg_set_dimension(
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
message::dc_msg_set_dimension(&mut ffi_msg.message, width, height)
|
||||
ffi_msg.message.set_dimension(width, height)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2536,7 +2622,7 @@ pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc:
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
message::dc_msg_set_duration(&mut ffi_msg.message, duration)
|
||||
ffi_msg.message.set_duration(duration)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2550,7 +2636,7 @@ pub unsafe extern "C" fn dc_msg_set_location(
|
||||
return;
|
||||
}
|
||||
let ffi_msg = &mut *msg;
|
||||
message::dc_msg_set_location(&mut ffi_msg.message, latitude, longitude)
|
||||
ffi_msg.message.set_location(latitude, longitude)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -2568,7 +2654,9 @@ pub unsafe extern "C" fn dc_msg_latefiling_mediasize(
|
||||
let ffi_context = &*ffi_msg.context;
|
||||
ffi_context
|
||||
.with_inner(|ctx| {
|
||||
message::dc_msg_latefiling_mediasize(ctx, &mut ffi_msg.message, width, height, duration)
|
||||
ffi_msg
|
||||
.message
|
||||
.latefiling_mediasize(ctx, width, height, duration)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -2810,7 +2898,7 @@ fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(dc_tools::as_str(s))
|
||||
Some(as_str(s))
|
||||
}
|
||||
|
||||
pub mod providers;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
extern crate deltachat_provider_overview;
|
||||
extern crate deltachat_provider_database;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use deltachat::dc_tools::{as_str, StrExt};
|
||||
use deltachat_provider_overview::StatusState;
|
||||
use deltachat_provider_database::StatusState;
|
||||
|
||||
#[no_mangle]
|
||||
pub type dc_provider_t = deltachat_provider_overview::Provider;
|
||||
pub type dc_provider_t = deltachat_provider_database::Provider;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_new_from_domain(
|
||||
domain: *const libc::c_char,
|
||||
) -> *const dc_provider_t {
|
||||
match deltachat_provider_overview::get_provider_info(as_str(domain)) {
|
||||
match deltachat_provider_database::get_provider_info(as_str(domain)) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null(),
|
||||
}
|
||||
@@ -22,8 +22,8 @@ pub unsafe extern "C" fn dc_provider_new_from_domain(
|
||||
pub unsafe extern "C" fn dc_provider_new_from_email(
|
||||
email: *const libc::c_char,
|
||||
) -> *const dc_provider_t {
|
||||
let domain = deltachat_provider_overview::get_domain_from_email(as_str(email));
|
||||
match deltachat_provider_overview::get_provider_info(domain) {
|
||||
let domain = deltachat_provider_database::get_domain_from_email(as_str(email));
|
||||
match deltachat_provider_database::get_provider_info(domain) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null(),
|
||||
}
|
||||
@@ -44,7 +44,7 @@ pub unsafe extern "C" fn dc_provider_get_overview_page(
|
||||
null_guard!(provider);
|
||||
format!(
|
||||
"{}/{}",
|
||||
deltachat_provider_overview::PROVIDER_OVERVIEW_URL,
|
||||
deltachat_provider_database::PROVIDER_OVERVIEW_URL,
|
||||
(*provider).overview_page
|
||||
)
|
||||
.strdup()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use deltachat::chat::{self, Chat};
|
||||
@@ -9,19 +8,19 @@ use deltachat::configure::*;
|
||||
use deltachat::constants::*;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_imex::*;
|
||||
use deltachat::dc_receive_imf::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::error::Error;
|
||||
use deltachat::imex::*;
|
||||
use deltachat::job::*;
|
||||
use deltachat::location;
|
||||
use deltachat::lot::LotState;
|
||||
use deltachat::message::*;
|
||||
use deltachat::message::{self, Message, MessageState};
|
||||
use deltachat::peerstate::*;
|
||||
use deltachat::qr::*;
|
||||
use deltachat::sql;
|
||||
use deltachat::x::*;
|
||||
use deltachat::Event;
|
||||
use libc::free;
|
||||
|
||||
/// Reset database tables. This function is called from Core cmdline.
|
||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||
@@ -94,170 +93,128 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) -> libc::c_int {
|
||||
/* mainly for testing, may be called by dc_import_spec() */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut data: *mut libc::c_char = ptr::null_mut();
|
||||
let mut data_bytes = 0;
|
||||
if !(dc_read_file(
|
||||
context,
|
||||
filename,
|
||||
&mut data as *mut *mut libc::c_char as *mut *mut libc::c_void,
|
||||
&mut data_bytes,
|
||||
) == 0i32)
|
||||
{
|
||||
dc_receive_imf(context, data, data_bytes, "import", 0, 0);
|
||||
success = 1;
|
||||
}
|
||||
free(data as *mut libc::c_void);
|
||||
fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
||||
let data = dc_read_file(context, filename)?;
|
||||
|
||||
success
|
||||
unsafe { dc_receive_imf(context, &data, "import", 0, 0) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Import a file to the database.
|
||||
/// For testing, import a folder with eml-files, a single eml-file, e-mail plus public key and so on.
|
||||
/// For normal importing, use dc_imex().
|
||||
/// For normal importing, use imex().
|
||||
///
|
||||
/// @private @memberof Context
|
||||
/// @param context The context as created by dc_context_new().
|
||||
/// @param spec The file or directory to import. NULL for the last command.
|
||||
/// @return 1=success, 0=error.
|
||||
unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
if !context.sql.is_open() {
|
||||
error!(context, "Import: Database not opened.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let ok_to_continue;
|
||||
let mut success: libc::c_int = 0;
|
||||
let real_spec: *mut libc::c_char;
|
||||
let mut suffix: *mut libc::c_char = ptr::null_mut();
|
||||
let mut read_cnt: libc::c_int = 0;
|
||||
let real_spec: String;
|
||||
let mut read_cnt = 0;
|
||||
|
||||
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
||||
if !spec.is_null() {
|
||||
real_spec = dc_strdup(spec);
|
||||
real_spec = to_string(spec);
|
||||
context
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
||||
.set_config(context, "import_spec", Some(&real_spec))
|
||||
.unwrap();
|
||||
ok_to_continue = true;
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
if rs.is_none() {
|
||||
error!(context, "Import: No file or folder given.");
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
return 0;
|
||||
}
|
||||
real_spec = rs.unwrap_or_default().strdup();
|
||||
real_spec = rs.unwrap();
|
||||
}
|
||||
if ok_to_continue {
|
||||
let ok_to_continue2;
|
||||
suffix = dc_get_filesuffix_lc(as_str(real_spec));
|
||||
if !suffix.is_null() && strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
||||
if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
|
||||
if suffix == "eml" {
|
||||
if dc_poke_eml_file(context, &real_spec).is_ok() {
|
||||
read_cnt += 1
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
}
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(&real_spec);
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
|
||||
return 0;
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(
|
||||
context,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
ok_to_continue2 = false;
|
||||
} else {
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
read_cnt += 1
|
||||
}
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", &real_spec, name);
|
||||
info!(context, "Import: {}", path_plus_name);
|
||||
if dc_poke_eml_file(context, path_plus_name).is_ok() {
|
||||
read_cnt += 1
|
||||
}
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
}
|
||||
}
|
||||
if ok_to_continue2 {
|
||||
info!(
|
||||
context,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id: 0,
|
||||
msg_id: 0,
|
||||
});
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
free(real_spec as *mut libc::c_void);
|
||||
free(suffix as *mut libc::c_void);
|
||||
success
|
||||
info!(
|
||||
context,
|
||||
"Import: {} items read from \"{}\".", read_cnt, &real_spec
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id: 0,
|
||||
msg_id: 0,
|
||||
});
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||
let contact = Contact::get_by_id(context, dc_msg_get_from_id(msg)).expect("invalid contact");
|
||||
let contact = Contact::get_by_id(context, msg.get_from_id()).expect("invalid contact");
|
||||
let contact_name = contact.get_name();
|
||||
let contact_id = contact.get_id();
|
||||
|
||||
let statestr = match dc_msg_get_state(msg) {
|
||||
let statestr = match msg.get_state() {
|
||||
MessageState::OutPending => " o",
|
||||
MessageState::OutDelivered => " √",
|
||||
MessageState::OutMdnRcvd => " √√",
|
||||
MessageState::OutFailed => " !!",
|
||||
_ => "",
|
||||
};
|
||||
let temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg));
|
||||
let msgtext = dc_msg_get_text(msg);
|
||||
let temp2 = dc_timestamp_to_str(msg.get_timestamp());
|
||||
let msgtext = msg.get_text();
|
||||
info!(
|
||||
context,
|
||||
"{}#{}{}{}: {} (Contact#{}): {} {}{}{}{} [{}]",
|
||||
prefix.as_ref(),
|
||||
dc_msg_get_id(msg) as libc::c_int,
|
||||
if dc_msg_get_showpadlock(msg) {
|
||||
"🔒"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if dc_msg_has_location(msg) { "📍" } else { "" },
|
||||
msg.get_id() as libc::c_int,
|
||||
if msg.get_showpadlock() { "🔒" } else { "" },
|
||||
if msg.has_location() { "📍" } else { "" },
|
||||
&contact_name,
|
||||
contact_id,
|
||||
as_str(msgtext),
|
||||
if dc_msg_is_starred(msg) { "★" } else { "" },
|
||||
if dc_msg_get_from_id(msg) == 1 as libc::c_uint {
|
||||
msgtext.unwrap_or_default(),
|
||||
if msg.is_starred() { "★" } else { "" },
|
||||
if msg.get_from_id() == 1 as libc::c_uint {
|
||||
""
|
||||
} else if dc_msg_get_state(msg) == MessageState::InSeen {
|
||||
} else if msg.get_state() == MessageState::InSeen {
|
||||
"[SEEN]"
|
||||
} else if dc_msg_get_state(msg) == MessageState::InNoticed {
|
||||
} else if msg.get_state() == MessageState::InNoticed {
|
||||
"[NOTICED]"
|
||||
} else {
|
||||
"[FRESH]"
|
||||
},
|
||||
if dc_msg_is_info(msg) { "[INFO]" } else { "" },
|
||||
if msg.is_info() { "[INFO]" } else { "" },
|
||||
statestr,
|
||||
&temp2,
|
||||
);
|
||||
free(msgtext as *mut libc::c_void);
|
||||
}
|
||||
|
||||
unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error> {
|
||||
@@ -278,7 +235,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<u32>) -> Result<(), Error
|
||||
);
|
||||
lines_out += 1
|
||||
}
|
||||
let msg = dc_get_msg(context, msg_id)?;
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
log_msg(context, "Msg", &msg);
|
||||
}
|
||||
}
|
||||
@@ -360,12 +317,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
arg1.strdup() as *const _
|
||||
};
|
||||
let arg2 = args.next().unwrap_or_default();
|
||||
let arg2_c = if arg2.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg2.strdup() as *const _
|
||||
};
|
||||
|
||||
let blobdir = context.get_blobdir();
|
||||
match arg0 {
|
||||
"help" | "?" => match arg1 {
|
||||
// TODO: reuse commands definition in main.rs.
|
||||
@@ -452,30 +405,24 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
============================================="
|
||||
),
|
||||
},
|
||||
"initiate-key-transfer" => {
|
||||
let setup_code = dc_initiate_key_transfer(context);
|
||||
if !setup_code.is_null() {
|
||||
println!(
|
||||
"Setup code for the transferred setup message: {}",
|
||||
as_str(setup_code),
|
||||
);
|
||||
free(setup_code as *mut libc::c_void);
|
||||
} else {
|
||||
bail!("Failed to generate setup code");
|
||||
};
|
||||
}
|
||||
"initiate-key-transfer" => match initiate_key_transfer(context) {
|
||||
Ok(setup_code) => println!(
|
||||
"Setup code for the transferred setup message: {}",
|
||||
setup_code,
|
||||
),
|
||||
Err(err) => bail!("Failed to generate setup code: {}", err),
|
||||
},
|
||||
"get-setupcodebegin" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let msg_id: u32 = arg1.parse()?;
|
||||
let msg = dc_get_msg(context, msg_id)?;
|
||||
if dc_msg_is_setupmessage(&msg) {
|
||||
let setupcodebegin = dc_msg_get_setupcodebegin(context, &msg);
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
if msg.is_setupmessage() {
|
||||
let setupcodebegin = msg.get_setupcodebegin(context);
|
||||
println!(
|
||||
"The setup code for setup message Msg#{} starts with: {}",
|
||||
msg_id,
|
||||
as_str(setupcodebegin),
|
||||
setupcodebegin.unwrap_or_default(),
|
||||
);
|
||||
free(setupcodebegin as *mut libc::c_void);
|
||||
} else {
|
||||
bail!("Msg#{} is no setup message.", msg_id,);
|
||||
}
|
||||
@@ -485,33 +432,28 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
!arg1.is_empty() && !arg2.is_empty(),
|
||||
"Arguments <msg-id> <setup-code> expected"
|
||||
);
|
||||
if !dc_continue_key_transfer(context, arg1.parse()?, arg2_c) {
|
||||
bail!("Continue key transfer failed");
|
||||
}
|
||||
continue_key_transfer(context, arg1.parse()?, &arg2)?;
|
||||
}
|
||||
"has-backup" => {
|
||||
let ret = dc_imex_has_backup(context, context.get_blobdir());
|
||||
if ret.is_null() {
|
||||
println!("No backup found.");
|
||||
}
|
||||
has_backup(context, blobdir)?;
|
||||
}
|
||||
"export-backup" => {
|
||||
dc_imex(context, 11, Some(context.get_blobdir()), ptr::null());
|
||||
imex(context, ImexMode::ExportBackup, Some(blobdir));
|
||||
}
|
||||
"import-backup" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
|
||||
dc_imex(context, 12, Some(arg1), ptr::null());
|
||||
imex(context, ImexMode::ImportBackup, Some(arg1));
|
||||
}
|
||||
"export-keys" => {
|
||||
dc_imex(context, 1, Some(context.get_blobdir()), ptr::null());
|
||||
imex(context, ImexMode::ExportSelfKeys, Some(blobdir));
|
||||
}
|
||||
"import-keys" => {
|
||||
dc_imex(context, 2, Some(context.get_blobdir()), ptr::null());
|
||||
imex(context, ImexMode::ImportSelfKeys, Some(blobdir));
|
||||
}
|
||||
"export-setup" => {
|
||||
let setup_code = dc_create_setup_code(context);
|
||||
let file_name = context.get_blobdir().join("autocrypt-setup-message.html");
|
||||
let file_content = dc_render_setup_file(context, &setup_code)?;
|
||||
let setup_code = create_setup_code(context);
|
||||
let file_name = blobdir.join("autocrypt-setup-message.html");
|
||||
let file_content = render_setup_file(context, &setup_code)?;
|
||||
std::fs::write(&file_name, file_content)?;
|
||||
println!(
|
||||
"Setup message written to: {}\nSetup code: {}",
|
||||
@@ -825,14 +767,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||
ensure!(!arg1.is_empty(), "No file given.");
|
||||
|
||||
let mut msg = dc_msg_new(if arg0 == "sendimage" {
|
||||
let mut msg = Message::new(if arg0 == "sendimage" {
|
||||
Viewtype::Image
|
||||
} else {
|
||||
Viewtype::File
|
||||
});
|
||||
dc_msg_set_file(&mut msg, arg1_c, ptr::null());
|
||||
msg.set_file(arg1, None);
|
||||
if !arg2.is_empty() {
|
||||
dc_msg_set_text(&mut msg, arg2_c);
|
||||
msg.set_text(Some(arg2.to_string()));
|
||||
}
|
||||
chat::send_msg(context, sel_chat.as_ref().unwrap().get_id(), &mut msg)?;
|
||||
}
|
||||
@@ -854,8 +796,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||
|
||||
if !arg1.is_empty() {
|
||||
let mut draft = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut draft, arg1_c);
|
||||
let mut draft = Message::new(Viewtype::Text);
|
||||
draft.set_text(Some(arg1.to_string()));
|
||||
chat::set_draft(
|
||||
context,
|
||||
sel_chat.as_ref().unwrap().get_id(),
|
||||
@@ -904,8 +846,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"msginfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let id = arg1.parse()?;
|
||||
let res = dc_get_msg_info(context, id);
|
||||
println!("{}", as_str(res));
|
||||
let res = message::get_msg_info(context, id);
|
||||
println!("{}", res);
|
||||
}
|
||||
"listfresh" => {
|
||||
let msglist = context.get_fresh_msgs();
|
||||
@@ -922,30 +864,25 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
let mut msg_ids = [0; 1];
|
||||
let chat_id = arg2.parse()?;
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
chat::forward_msgs(context, msg_ids.as_mut_ptr(), 1, chat_id);
|
||||
chat::forward_msgs(context, &msg_ids, chat_id);
|
||||
}
|
||||
"markseen" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut msg_ids = [0; 1];
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
dc_markseen_msgs(context, msg_ids.as_mut_ptr(), 1);
|
||||
message::markseen_msgs(context, &msg_ids);
|
||||
}
|
||||
"star" | "unstar" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut msg_ids = [0; 1];
|
||||
msg_ids[0] = arg1.parse()?;
|
||||
dc_star_msgs(
|
||||
context,
|
||||
msg_ids.as_mut_ptr(),
|
||||
1,
|
||||
if arg0 == "star" { 1 } else { 0 },
|
||||
);
|
||||
message::star_msgs(context, &msg_ids, arg0 == "star");
|
||||
}
|
||||
"delmsg" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||
let mut ids = [0; 1];
|
||||
ids[0] = arg1.parse()?;
|
||||
dc_delete_msgs(context, ids.as_mut_ptr(), 1);
|
||||
message::delete_msgs(context, &ids);
|
||||
}
|
||||
"listcontacts" | "contacts" | "listverified" => {
|
||||
let contacts = Contact::get_all(
|
||||
@@ -1028,7 +965,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"fileinfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
||||
|
||||
if let Some(buf) = dc_read_file_safe(context, &arg1) {
|
||||
if let Ok(buf) = dc_read_file(context, &arg1) {
|
||||
let (width, height) = dc_get_filemeta(&buf)?;
|
||||
println!("width={}, height={}", width, height);
|
||||
} else {
|
||||
@@ -1040,7 +977,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
free(arg2_c as *mut _);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,11 +23,9 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||
use deltachat::config;
|
||||
use deltachat::configure::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_tools::*;
|
||||
use deltachat::job::*;
|
||||
use deltachat::oauth2::*;
|
||||
use deltachat::securejoin::*;
|
||||
use deltachat::x::*;
|
||||
use deltachat::Event;
|
||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||
use rustyline::config::OutputStreamType;
|
||||
@@ -441,11 +439,6 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
let mut args = line.splitn(2, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
let arg1_c = if arg1.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg1.strdup()
|
||||
};
|
||||
|
||||
match arg0 {
|
||||
"connect" => {
|
||||
@@ -521,8 +514,6 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
|
||||
Ok(ExitResult::Continue)
|
||||
}
|
||||
|
||||
|
||||
42
mmime/.circleci/config.yml
Normal file
42
mmime/.circleci/config.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
# copied from http://koushiro.me/2019/04/30/Building-and-Testing-Rust-projects-on-CircleCI/
|
||||
|
||||
version: 2.1
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
|
||||
working_directory: ~/deltachat-core-rust
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Setup build environment
|
||||
command: |
|
||||
apt update
|
||||
apt install -y curl build-essential autoconf libtool git python pkg-config
|
||||
# this will pick default toolchain from `rust-toolchain` file
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --no-modify-path --default-toolchain none -y;
|
||||
source $HOME/.cargo/env
|
||||
no_output_timeout: 1800s
|
||||
|
||||
- run:
|
||||
name: Format
|
||||
command: |
|
||||
export PATH=~/.cargo/bin:$PATH
|
||||
rustup component add rustfmt
|
||||
cargo fmt -- --check
|
||||
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
export PATH=~/.cargo/bin:$PATH
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
build:
|
||||
jobs:
|
||||
- build
|
||||
23
mmime/Cargo.toml
Normal file
23
mmime/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "mmime"
|
||||
version = "0.1.2"
|
||||
authors = ["dignifiedquire <dignifiedquire@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://github.com/deltachat/deltachat-core-rust"
|
||||
repository = "https://github.com/deltachat/deltachat-core-rust"
|
||||
readme = "README.md"
|
||||
description = "Mime parsing for email"
|
||||
|
||||
|
||||
keywords = ["mail", "mim", "email", "imap", "smtp"]
|
||||
categories = ["std", "email"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.54"
|
||||
charset = "0.1.2"
|
||||
memmap = "0.7.0"
|
||||
lazy_static = "1.3.0"
|
||||
rand = "0.6.5"
|
||||
chrono = "0.4.6"
|
||||
hex = "0.3.2"
|
||||
201
mmime/LICENSE-APACHE
Normal file
201
mmime/LICENSE-APACHE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
23
mmime/LICENSE-MIT
Normal file
23
mmime/LICENSE-MIT
Normal file
@@ -0,0 +1,23 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
4
mmime/LICENSE.md
Normal file
4
mmime/LICENSE.md
Normal file
@@ -0,0 +1,4 @@
|
||||
This library is primarly distributed under the terms of both the MIT license and
|
||||
the Apache License (Version 2.0).
|
||||
|
||||
See LICENSE-MIT and LICENSE-APACHE for details.
|
||||
16
mmime/README.md
Normal file
16
mmime/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# mmime
|
||||
|
||||
[![CircleCI build status][circle-shield]][circle] [![Appveyor build status][appveyor-shield]][appveyor] [![License][license-shield]][license]
|
||||
|
||||
> mmmmmmime parsing
|
||||
|
||||
Base code was compiled using c2rust from libetpan.
|
||||
|
||||
|
||||
|
||||
[circle-shield]: https://img.shields.io/circleci/project/github/dignifiedquire/mmime/master.svg?style=flat-square
|
||||
[circle]: https://circleci.com/gh/dignifiedquire/mmime/
|
||||
[appveyor-shield]: https://ci.appveyor.com/api/projects/status/l26co5rba32knrlu/branch/master?style=flat-square
|
||||
[appveyor]: https://ci.appveyor.com/project/dignifiedquire/mmime/branch/master
|
||||
[license-shield]: https://img.shields.io/badge/License-MIT%2FApache2.0-green.svg?style=flat-square
|
||||
[license]: https://github.com/rpgp/rpgp/blob/master/LICENSE.md
|
||||
32
mmime/src/charconv.rs
Normal file
32
mmime/src/charconv.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use crate::other::*;
|
||||
use libc;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
pub const MAIL_CHARCONV_ERROR_CONV: libc::c_uint = 3;
|
||||
pub const MAIL_CHARCONV_ERROR_MEMORY: libc::c_uint = 2;
|
||||
pub const MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET: libc::c_uint = 1;
|
||||
pub const MAIL_CHARCONV_NO_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn charconv(
|
||||
tocode: *const libc::c_char,
|
||||
fromcode: *const libc::c_char,
|
||||
s: *const libc::c_char,
|
||||
length: size_t,
|
||||
result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
assert!(!fromcode.is_null(), "invalid fromcode");
|
||||
assert!(!s.is_null(), "invalid input string");
|
||||
if let Some(encoding) =
|
||||
charset::Charset::for_label(CStr::from_ptr(fromcode).to_str().unwrap().as_bytes())
|
||||
{
|
||||
let data = std::slice::from_raw_parts(s as *const u8, strlen(s));
|
||||
|
||||
let (res, _, _) = encoding.decode(data);
|
||||
let res_c = CString::new(res.as_bytes()).unwrap();
|
||||
*result = strdup(res_c.as_ptr()) as *mut _;
|
||||
|
||||
MAIL_CHARCONV_NO_ERROR as libc::c_int
|
||||
} else {
|
||||
MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET as libc::c_int
|
||||
}
|
||||
}
|
||||
427
mmime/src/chash.rs
Normal file
427
mmime/src/chash.rs
Normal file
@@ -0,0 +1,427 @@
|
||||
use libc;
|
||||
|
||||
use crate::other::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chashdatum {
|
||||
pub data: *mut libc::c_void,
|
||||
pub len: libc::c_uint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chash {
|
||||
pub size: libc::c_uint,
|
||||
pub count: libc::c_uint,
|
||||
pub copyvalue: libc::c_int,
|
||||
pub copykey: libc::c_int,
|
||||
pub cells: *mut *mut chashcell,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chashcell {
|
||||
pub func: libc::c_uint,
|
||||
pub key: chashdatum,
|
||||
pub value: chashdatum,
|
||||
pub next: *mut chashcell,
|
||||
}
|
||||
|
||||
pub type chashiter = chashcell;
|
||||
/* Allocates a new (empty) hash using this initial size and the given flags,
|
||||
specifying which data should be copied in the hash.
|
||||
CHASH_COPYNONE : Keys/Values are not copied.
|
||||
CHASH_COPYKEY : Keys are dupped and freed as needed in the hash.
|
||||
CHASH_COPYVALUE : Values are dupped and freed as needed in the hash.
|
||||
CHASH_COPYALL : Both keys and values are dupped in the hash.
|
||||
*/
|
||||
pub unsafe fn chash_new(mut size: libc::c_uint, mut flags: libc::c_int) -> *mut chash {
|
||||
let mut h: *mut chash = 0 as *mut chash;
|
||||
h = malloc(::std::mem::size_of::<chash>() as libc::size_t) as *mut chash;
|
||||
if h.is_null() {
|
||||
return 0 as *mut chash;
|
||||
}
|
||||
if size < 13i32 as libc::c_uint {
|
||||
size = 13i32 as libc::c_uint
|
||||
}
|
||||
(*h).count = 0i32 as libc::c_uint;
|
||||
(*h).cells = calloc(
|
||||
size as libc::size_t,
|
||||
::std::mem::size_of::<*mut chashcell>() as libc::size_t,
|
||||
) as *mut *mut chashcell;
|
||||
if (*h).cells.is_null() {
|
||||
free(h as *mut libc::c_void);
|
||||
return 0 as *mut chash;
|
||||
}
|
||||
(*h).size = size;
|
||||
(*h).copykey = flags & 1i32;
|
||||
(*h).copyvalue = flags & 2i32;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Frees a hash */
|
||||
pub unsafe fn chash_free(mut hash: *mut chash) {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
free((*hash).cells as *mut libc::c_void);
|
||||
free(hash as *mut libc::c_void);
|
||||
}
|
||||
|
||||
/* Removes all elements from a hash */
|
||||
pub unsafe fn chash_clear(mut hash: *mut chash) {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
memset(
|
||||
(*hash).cells as *mut libc::c_void,
|
||||
0i32,
|
||||
((*hash).size as libc::size_t)
|
||||
.wrapping_mul(::std::mem::size_of::<*mut chashcell>() as libc::size_t),
|
||||
);
|
||||
(*hash).count = 0i32 as libc::c_uint;
|
||||
}
|
||||
/* Adds an entry in the hash table.
|
||||
Length can be 0 if key/value are strings.
|
||||
If an entry already exists for this key, it is replaced, and its value
|
||||
is returned. Otherwise, the data pointer will be NULL and the length
|
||||
field be set to TRUE or FALSe to indicate success or failure. */
|
||||
pub unsafe fn chash_set(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut value: *mut chashdatum,
|
||||
mut oldvalue: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut cell: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut r: libc::c_int = 0;
|
||||
if (*hash).count > (*hash).size.wrapping_mul(3i32 as libc::c_uint) {
|
||||
r = chash_resize(
|
||||
hash,
|
||||
(*hash)
|
||||
.count
|
||||
.wrapping_div(3i32 as libc::c_uint)
|
||||
.wrapping_mul(2i32 as libc::c_uint)
|
||||
.wrapping_add(1i32 as libc::c_uint),
|
||||
);
|
||||
if r < 0i32 {
|
||||
current_block = 17701753836843438419;
|
||||
} else {
|
||||
current_block = 7095457783677275021;
|
||||
}
|
||||
} else {
|
||||
current_block = 7095457783677275021;
|
||||
}
|
||||
match current_block {
|
||||
7095457783677275021 => {
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
indx = func.wrapping_rem((*hash).size);
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
loop {
|
||||
if iter.is_null() {
|
||||
current_block = 17788412896529399552;
|
||||
break;
|
||||
}
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
/* found, replacing entry */
|
||||
if 0 != (*hash).copyvalue {
|
||||
let mut data: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
data = chash_dup((*value).data, (*value).len);
|
||||
if data.is_null() {
|
||||
current_block = 17701753836843438419;
|
||||
break;
|
||||
}
|
||||
free((*iter).value.data);
|
||||
(*iter).value.data = data as *mut libc::c_void;
|
||||
(*iter).value.len = (*value).len
|
||||
} else {
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*iter).value.data;
|
||||
(*oldvalue).len = (*iter).value.len
|
||||
}
|
||||
(*iter).value.data = (*value).data;
|
||||
(*iter).value.len = (*value).len
|
||||
}
|
||||
if 0 == (*hash).copykey {
|
||||
(*iter).key.data = (*key).data
|
||||
}
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*value).data;
|
||||
(*oldvalue).len = (*value).len
|
||||
}
|
||||
return 0i32;
|
||||
} else {
|
||||
iter = (*iter).next
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
17701753836843438419 => {}
|
||||
_ => {
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = 0 as *mut libc::c_void;
|
||||
(*oldvalue).len = 0i32 as libc::c_uint
|
||||
}
|
||||
cell = malloc(::std::mem::size_of::<chashcell>() as libc::size_t)
|
||||
as *mut chashcell;
|
||||
if !cell.is_null() {
|
||||
if 0 != (*hash).copykey {
|
||||
(*cell).key.data =
|
||||
chash_dup((*key).data, (*key).len) as *mut libc::c_void;
|
||||
if (*cell).key.data.is_null() {
|
||||
current_block = 4267898785354516004;
|
||||
} else {
|
||||
current_block = 7226443171521532240;
|
||||
}
|
||||
} else {
|
||||
(*cell).key.data = (*key).data;
|
||||
current_block = 7226443171521532240;
|
||||
}
|
||||
match current_block {
|
||||
7226443171521532240 => {
|
||||
(*cell).key.len = (*key).len;
|
||||
if 0 != (*hash).copyvalue {
|
||||
(*cell).value.data =
|
||||
chash_dup((*value).data, (*value).len) as *mut libc::c_void;
|
||||
if (*cell).value.data.is_null() {
|
||||
if 0 != (*hash).copykey {
|
||||
free((*cell).key.data);
|
||||
}
|
||||
current_block = 4267898785354516004;
|
||||
} else {
|
||||
current_block = 6717214610478484138;
|
||||
}
|
||||
} else {
|
||||
(*cell).value.data = (*value).data;
|
||||
current_block = 6717214610478484138;
|
||||
}
|
||||
match current_block {
|
||||
4267898785354516004 => {}
|
||||
_ => {
|
||||
(*cell).value.len = (*value).len;
|
||||
(*cell).func = func;
|
||||
(*cell).next = *(*hash).cells.offset(indx as isize);
|
||||
let ref mut fresh0 = *(*hash).cells.offset(indx as isize);
|
||||
*fresh0 = cell;
|
||||
(*hash).count = (*hash).count.wrapping_add(1);
|
||||
return 0i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(cell as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn chash_dup(mut data: *const libc::c_void, mut len: libc::c_uint) -> *mut libc::c_char {
|
||||
let mut r: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
r = malloc(len as libc::size_t) as *mut libc::c_char as *mut libc::c_void;
|
||||
if r.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
memcpy(r, data, len as libc::size_t);
|
||||
return r as *mut libc::c_char;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn chash_func(mut key: *const libc::c_char, mut len: libc::c_uint) -> libc::c_uint {
|
||||
let mut c: libc::c_uint = 5381i32 as libc::c_uint;
|
||||
let mut k: *const libc::c_char = key;
|
||||
loop {
|
||||
let fresh1 = len;
|
||||
len = len.wrapping_sub(1);
|
||||
if !(0 != fresh1) {
|
||||
break;
|
||||
}
|
||||
let fresh2 = k;
|
||||
k = k.offset(1);
|
||||
c = (c << 5i32)
|
||||
.wrapping_add(c)
|
||||
.wrapping_add(*fresh2 as libc::c_uint)
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Resizes the hash table to the passed size. */
|
||||
pub unsafe fn chash_resize(mut hash: *mut chash, mut size: libc::c_uint) -> libc::c_int {
|
||||
let mut cells: *mut *mut chashcell = 0 as *mut *mut chashcell;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut nindx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
if (*hash).size == size {
|
||||
return 0i32;
|
||||
}
|
||||
cells = calloc(
|
||||
size as libc::size_t,
|
||||
::std::mem::size_of::<*mut chashcell>() as libc::size_t,
|
||||
) as *mut *mut chashcell;
|
||||
if cells.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
nindx = (*iter).func.wrapping_rem(size);
|
||||
(*iter).next = *cells.offset(nindx as isize);
|
||||
let ref mut fresh3 = *cells.offset(nindx as isize);
|
||||
*fresh3 = iter;
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
free((*hash).cells as *mut libc::c_void);
|
||||
(*hash).size = size;
|
||||
(*hash).cells = cells;
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
/* Retrieves the data associated to the key if it is found in the hash table.
|
||||
The data pointer and the length will be NULL if not found*/
|
||||
pub unsafe fn chash_get(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut result: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
iter = *(*hash)
|
||||
.cells
|
||||
.offset(func.wrapping_rem((*hash).size) as isize);
|
||||
while !iter.is_null() {
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
*result = (*iter).value;
|
||||
return 0i32;
|
||||
}
|
||||
iter = (*iter).next
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
/* Removes the entry associated to this key if it is found in the hash table,
|
||||
and returns its contents if not dupped (otherwise, pointer will be NULL
|
||||
and len TRUE). If entry is not found both pointer and len will be NULL. */
|
||||
pub unsafe fn chash_delete(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut oldvalue: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
/* chashdatum result = { NULL, TRUE }; */
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut old: *mut chashiter = 0 as *mut chashiter;
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
indx = func.wrapping_rem((*hash).size);
|
||||
old = 0 as *mut chashiter;
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
if !old.is_null() {
|
||||
(*old).next = (*iter).next
|
||||
} else {
|
||||
let ref mut fresh4 = *(*hash).cells.offset(indx as isize);
|
||||
*fresh4 = (*iter).next
|
||||
}
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
} else if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*iter).value.data;
|
||||
(*oldvalue).len = (*iter).value.len
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
(*hash).count = (*hash).count.wrapping_sub(1);
|
||||
return 0i32;
|
||||
}
|
||||
old = iter;
|
||||
iter = (*iter).next
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
/* Returns an iterator to the first non-empty entry of the hash table */
|
||||
pub unsafe fn chash_begin(mut hash: *mut chash) -> *mut chashiter {
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut indx: libc::c_uint = 0i32 as libc::c_uint;
|
||||
iter = *(*hash).cells.offset(0isize);
|
||||
while iter.is_null() {
|
||||
indx = indx.wrapping_add(1);
|
||||
if indx >= (*hash).size {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
iter = *(*hash).cells.offset(indx as isize)
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
/* Returns the next non-empty entry of the hash table */
|
||||
pub unsafe fn chash_next(mut hash: *mut chash, mut iter: *mut chashiter) -> *mut chashiter {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
if iter.is_null() {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
indx = (*iter).func.wrapping_rem((*hash).size);
|
||||
iter = (*iter).next;
|
||||
while iter.is_null() {
|
||||
indx = indx.wrapping_add(1);
|
||||
if indx >= (*hash).size {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
iter = *(*hash).cells.offset(indx as isize)
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
202
mmime/src/clist.rs
Normal file
202
mmime/src/clist.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
use libc;
|
||||
|
||||
use crate::other::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct clistcell {
|
||||
pub data: *mut libc::c_void,
|
||||
pub previous: *mut clistcell,
|
||||
pub next: *mut clistcell,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct clist {
|
||||
pub first: *mut clistcell,
|
||||
pub last: *mut clistcell,
|
||||
pub count: libc::c_int,
|
||||
}
|
||||
|
||||
impl Default for clist {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
first: std::ptr::null_mut(),
|
||||
last: std::ptr::null_mut(),
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for clist {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let mut l1 = self.first;
|
||||
while !l1.is_null() {
|
||||
let l2 = (*l1).next;
|
||||
free(l1 as *mut libc::c_void);
|
||||
l1 = l2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type clistiter = clistcell;
|
||||
pub struct CListIterator {
|
||||
cur: *mut clistiter,
|
||||
}
|
||||
impl Iterator for CListIterator {
|
||||
type Item = *mut libc::c_void;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
if self.cur.is_null() {
|
||||
None
|
||||
} else {
|
||||
let data = (*self.cur).data;
|
||||
self.cur = (*self.cur).next;
|
||||
Some(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &clist {
|
||||
type Item = *mut libc::c_void;
|
||||
type IntoIter = CListIterator;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
return CListIterator { cur: self.first };
|
||||
}
|
||||
}
|
||||
|
||||
pub type clist_func =
|
||||
Option<unsafe extern "C" fn(_: *mut libc::c_void, _: *mut libc::c_void) -> ()>;
|
||||
|
||||
/* Allocate a new pointer list */
|
||||
pub fn clist_new() -> *mut clist {
|
||||
Box::into_raw(Box::new(Default::default()))
|
||||
}
|
||||
/* Destroys a list. Data pointed by data pointers is NOT freed. */
|
||||
pub unsafe fn clist_free(mut lst: *mut clist) {
|
||||
Box::from_raw(lst);
|
||||
}
|
||||
/* Inserts this data pointer after the element pointed by the iterator */
|
||||
pub unsafe fn clist_insert_after(
|
||||
mut lst: *mut clist,
|
||||
mut iter: *mut clistiter,
|
||||
mut data: *mut libc::c_void,
|
||||
) -> libc::c_int {
|
||||
let mut c: *mut clistcell = 0 as *mut clistcell;
|
||||
c = malloc(::std::mem::size_of::<clistcell>() as libc::size_t) as *mut clistcell;
|
||||
if c.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
(*c).data = data;
|
||||
(*lst).count += 1;
|
||||
if (*lst).first == (*lst).last && (*lst).last.is_null() {
|
||||
(*c).next = 0 as *mut clistcell;
|
||||
(*c).previous = (*c).next;
|
||||
(*lst).last = c;
|
||||
(*lst).first = (*lst).last;
|
||||
return 0i32;
|
||||
}
|
||||
if iter.is_null() {
|
||||
(*c).previous = (*lst).last;
|
||||
(*(*c).previous).next = c;
|
||||
(*c).next = 0 as *mut clistcell;
|
||||
(*lst).last = c;
|
||||
return 0i32;
|
||||
}
|
||||
(*c).previous = iter;
|
||||
(*c).next = (*iter).next;
|
||||
if !(*c).next.is_null() {
|
||||
(*(*c).next).previous = c
|
||||
} else {
|
||||
(*lst).last = c
|
||||
}
|
||||
(*(*c).previous).next = c;
|
||||
return 0i32;
|
||||
}
|
||||
/* Deletes the element pointed by the iterator.
|
||||
Returns an iterator to the next element. */
|
||||
pub unsafe fn clist_delete(mut lst: *mut clist, mut iter: *mut clistiter) -> *mut clistiter {
|
||||
let mut ret: *mut clistiter = 0 as *mut clistiter;
|
||||
if iter.is_null() {
|
||||
return 0 as *mut clistiter;
|
||||
}
|
||||
if !(*iter).previous.is_null() {
|
||||
(*(*iter).previous).next = (*iter).next
|
||||
} else {
|
||||
(*lst).first = (*iter).next
|
||||
}
|
||||
if !(*iter).next.is_null() {
|
||||
(*(*iter).next).previous = (*iter).previous;
|
||||
ret = (*iter).next
|
||||
} else {
|
||||
(*lst).last = (*iter).previous;
|
||||
ret = 0 as *mut clistiter
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
(*lst).count -= 1;
|
||||
return ret;
|
||||
}
|
||||
pub unsafe fn clist_foreach(
|
||||
mut lst: *mut clist,
|
||||
mut func: clist_func,
|
||||
mut data: *mut libc::c_void,
|
||||
) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*lst).first;
|
||||
while !cur.is_null() {
|
||||
func.expect("non-null function pointer")((*cur).data, data);
|
||||
cur = (*cur).next
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn clist_nth_data(mut lst: *mut clist, mut indx: libc::c_int) -> *mut libc::c_void {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = internal_clist_nth(lst, indx);
|
||||
if cur.is_null() {
|
||||
return 0 as *mut libc::c_void;
|
||||
}
|
||||
return (*cur).data;
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn internal_clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*lst).first;
|
||||
while indx > 0i32 && !cur.is_null() {
|
||||
cur = (*cur).next;
|
||||
indx -= 1
|
||||
}
|
||||
if cur.is_null() {
|
||||
return 0 as *mut clistiter;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
pub unsafe fn clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter {
|
||||
return internal_clist_nth(lst, indx);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ptr;
|
||||
#[test]
|
||||
fn test_clist_iterator() {
|
||||
unsafe {
|
||||
let mut c = clist_new();
|
||||
assert!(!c.is_null());
|
||||
clist_insert_after(c, ptr::null_mut(), clist_nth as _);
|
||||
assert_eq!((*c).count, 1);
|
||||
|
||||
/* Only one iteration */
|
||||
for data in &*c {
|
||||
assert_eq!(data, clist_nth as _);
|
||||
}
|
||||
assert_eq!((*c).count, 1);
|
||||
|
||||
clist_free(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
mmime/src/constants.rs
Normal file
71
mmime/src/constants.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
pub const MAIL_ERROR_SSL: libc::c_uint = 58;
|
||||
pub const MAIL_ERROR_FOLDER: libc::c_uint = 57;
|
||||
pub const MAIL_ERROR_UNABLE: libc::c_uint = 56;
|
||||
pub const MAIL_ERROR_SYSTEM: libc::c_uint = 55;
|
||||
pub const MAIL_ERROR_COMMAND: libc::c_uint = 54;
|
||||
pub const MAIL_ERROR_SEND: libc::c_uint = 53;
|
||||
pub const MAIL_ERROR_CHAR_ENCODING_FAILED: libc::c_uint = 52;
|
||||
pub const MAIL_ERROR_SUBJECT_NOT_FOUND: libc::c_uint = 51;
|
||||
/* 50 */
|
||||
pub const MAIL_ERROR_PROGRAM_ERROR: libc::c_uint = 50;
|
||||
pub const MAIL_ERROR_NO_PERMISSION: libc::c_uint = 49;
|
||||
pub const MAIL_ERROR_COMMAND_NOT_SUPPORTED: libc::c_uint = 48;
|
||||
pub const MAIL_ERROR_NO_APOP: libc::c_uint = 47;
|
||||
pub const MAIL_ERROR_READONLY: libc::c_uint = 46;
|
||||
pub const MAIL_ERROR_FATAL: libc::c_uint = 45;
|
||||
pub const MAIL_ERROR_CLOSE: libc::c_uint = 44;
|
||||
pub const MAIL_ERROR_CAPABILITY: libc::c_uint = 43;
|
||||
pub const MAIL_ERROR_PROTOCOL: libc::c_uint = 42;
|
||||
/* misc errors */
|
||||
pub const MAIL_ERROR_MISC: libc::c_uint = 41;
|
||||
/* 40 */
|
||||
pub const MAIL_ERROR_EXPUNGE: libc::c_uint = 40;
|
||||
pub const MAIL_ERROR_NO_TLS: libc::c_uint = 39;
|
||||
pub const MAIL_ERROR_CACHE_MISS: libc::c_uint = 38;
|
||||
pub const MAIL_ERROR_STARTTLS: libc::c_uint = 37;
|
||||
pub const MAIL_ERROR_MOVE: libc::c_uint = 36;
|
||||
pub const MAIL_ERROR_FOLDER_NOT_FOUND: libc::c_uint = 35;
|
||||
pub const MAIL_ERROR_REMOVE: libc::c_uint = 34;
|
||||
pub const MAIL_ERROR_PART_NOT_FOUND: libc::c_uint = 33;
|
||||
pub const MAIL_ERROR_INVAL: libc::c_uint = 32;
|
||||
pub const MAIL_ERROR_PARSE: libc::c_uint = 31;
|
||||
/* 30 */
|
||||
pub const MAIL_ERROR_MSG_NOT_FOUND: libc::c_uint = 30;
|
||||
pub const MAIL_ERROR_DISKSPACE: libc::c_uint = 29;
|
||||
pub const MAIL_ERROR_SEARCH: libc::c_uint = 28;
|
||||
pub const MAIL_ERROR_STORE: libc::c_uint = 27;
|
||||
pub const MAIL_ERROR_FETCH: libc::c_uint = 26;
|
||||
pub const MAIL_ERROR_COPY: libc::c_uint = 25;
|
||||
pub const MAIL_ERROR_APPEND: libc::c_uint = 24;
|
||||
pub const MAIL_ERROR_LSUB: libc::c_uint = 23;
|
||||
pub const MAIL_ERROR_LIST: libc::c_uint = 22;
|
||||
pub const MAIL_ERROR_UNSUBSCRIBE: libc::c_uint = 21;
|
||||
/* 20 */
|
||||
pub const MAIL_ERROR_SUBSCRIBE: libc::c_uint = 20;
|
||||
pub const MAIL_ERROR_STATUS: libc::c_uint = 19;
|
||||
pub const MAIL_ERROR_MEMORY: libc::c_uint = 18;
|
||||
pub const MAIL_ERROR_SELECT: libc::c_uint = 17;
|
||||
pub const MAIL_ERROR_EXAMINE: libc::c_uint = 16;
|
||||
pub const MAIL_ERROR_CHECK: libc::c_uint = 15;
|
||||
pub const MAIL_ERROR_RENAME: libc::c_uint = 14;
|
||||
pub const MAIL_ERROR_NOOP: libc::c_uint = 13;
|
||||
pub const MAIL_ERROR_LOGOUT: libc::c_uint = 12;
|
||||
pub const MAIL_ERROR_DELETE: libc::c_uint = 11;
|
||||
/* 10 */
|
||||
pub const MAIL_ERROR_CREATE: libc::c_uint = 10;
|
||||
pub const MAIL_ERROR_LOGIN: libc::c_uint = 9;
|
||||
pub const MAIL_ERROR_STREAM: libc::c_uint = 8;
|
||||
pub const MAIL_ERROR_FILE: libc::c_uint = 7;
|
||||
pub const MAIL_ERROR_BAD_STATE: libc::c_uint = 6;
|
||||
pub const MAIL_ERROR_CONNECT: libc::c_uint = 5;
|
||||
pub const MAIL_ERROR_UNKNOWN: libc::c_uint = 4;
|
||||
pub const MAIL_ERROR_NOT_IMPLEMENTED: libc::c_uint = 3;
|
||||
pub const MAIL_NO_ERROR_NON_AUTHENTICATED: libc::c_uint = 2;
|
||||
pub const MAIL_NO_ERROR_AUTHENTICATED: libc::c_uint = 1;
|
||||
pub const MAIL_NO_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub const MAILIMF_ERROR_FILE: libc::c_uint = 4;
|
||||
pub const MAILIMF_ERROR_INVAL: libc::c_uint = 3;
|
||||
pub const MAILIMF_ERROR_MEMORY: libc::c_uint = 2;
|
||||
pub const MAILIMF_ERROR_PARSE: libc::c_uint = 1;
|
||||
pub const MAILIMF_NO_ERROR: libc::c_uint = 0;
|
||||
386
mmime/src/display.rs
Normal file
386
mmime/src/display.rs
Normal file
@@ -0,0 +1,386 @@
|
||||
use crate::clist::*;
|
||||
|
||||
use crate::mailimf::types::*;
|
||||
use crate::mailmime::types::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
pub unsafe fn display_mime(mut mime: *mut Mailmime) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
println!("{}", (*mime).mm_type);
|
||||
|
||||
match (*mime).mm_type as u32 {
|
||||
MAILMIME_SINGLE => {
|
||||
println!("single part");
|
||||
}
|
||||
MAILMIME_MULTIPLE => {
|
||||
println!("multipart");
|
||||
}
|
||||
MAILMIME_MESSAGE => println!("message"),
|
||||
_ => {}
|
||||
}
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
if !(*(*(*mime).mm_mime_fields).fld_list).first.is_null() {
|
||||
print!("MIME headers begin");
|
||||
display_mime_fields((*mime).mm_mime_fields);
|
||||
println!("MIME headers end");
|
||||
}
|
||||
}
|
||||
display_mime_content((*mime).mm_content_type);
|
||||
match (*mime).mm_type as u32 {
|
||||
MAILMIME_SINGLE => {
|
||||
display_mime_data((*mime).mm_data.mm_single);
|
||||
}
|
||||
MAILMIME_MULTIPLE => {
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
display_mime(
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut Mailmime,
|
||||
);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
MAILMIME_MESSAGE => {
|
||||
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
|
||||
if !(*(*(*mime).mm_data.mm_message.mm_fields).fld_list)
|
||||
.first
|
||||
.is_null()
|
||||
{
|
||||
println!("headers begin");
|
||||
display_fields((*mime).mm_data.mm_message.mm_fields);
|
||||
println!("headers end");
|
||||
}
|
||||
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
|
||||
display_mime((*mime).mm_data.mm_message.mm_msg_mime);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn display_mime_content(mut content_type: *mut mailmime_content) {
|
||||
print!("type: ");
|
||||
display_mime_type((*content_type).ct_type);
|
||||
println!(
|
||||
"/{}",
|
||||
CStr::from_ptr((*content_type).ct_subtype).to_str().unwrap()
|
||||
);
|
||||
}
|
||||
unsafe fn display_mime_type(mut type_0: *mut mailmime_type) {
|
||||
match (*type_0).tp_type {
|
||||
1 => {
|
||||
display_mime_discrete_type((*type_0).tp_data.tp_discrete_type);
|
||||
}
|
||||
2 => {
|
||||
display_mime_composite_type((*type_0).tp_data.tp_composite_type);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_composite_type(mut ct: *mut mailmime_composite_type) {
|
||||
match (*ct).ct_type {
|
||||
1 => {
|
||||
print!("message");
|
||||
}
|
||||
2 => {
|
||||
print!("multipart");
|
||||
}
|
||||
3 => {
|
||||
print!("{}", CStr::from_ptr((*ct).ct_token).to_str().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_discrete_type(mut discrete_type: *mut mailmime_discrete_type) {
|
||||
match (*discrete_type).dt_type {
|
||||
1 => {
|
||||
print!("text");
|
||||
}
|
||||
2 => {
|
||||
print!("image");
|
||||
}
|
||||
3 => {
|
||||
print!("audio");
|
||||
}
|
||||
4 => {
|
||||
print!("video");
|
||||
}
|
||||
5 => {
|
||||
print!("application");
|
||||
}
|
||||
6 => {
|
||||
print!("{}", (*discrete_type).dt_extension as u8 as char);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_data(mut data: *mut mailmime_data) {
|
||||
match (*data).dt_type {
|
||||
0 => {
|
||||
println!(
|
||||
"data : {} bytes",
|
||||
(*data).dt_data.dt_text.dt_length as libc::c_uint,
|
||||
);
|
||||
}
|
||||
1 => {
|
||||
println!(
|
||||
"data (file) : {}",
|
||||
CStr::from_ptr((*data).dt_data.dt_filename)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_dsp_parm(mut param: *mut mailmime_disposition_parm) {
|
||||
match (*param).pa_type {
|
||||
0 => {
|
||||
println!(
|
||||
"filename: {}",
|
||||
CStr::from_ptr((*param).pa_data.pa_filename)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_disposition(mut disposition: *mut mailmime_disposition) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*disposition).dsp_parms).first;
|
||||
while !cur.is_null() {
|
||||
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
param = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime_disposition_parm;
|
||||
display_mime_dsp_parm(param);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_mime_field(mut field: *mut mailmime_field) {
|
||||
match (*field).fld_type {
|
||||
1 => {
|
||||
print!("content-type: ");
|
||||
display_mime_content((*field).fld_data.fld_content);
|
||||
println!("");
|
||||
}
|
||||
6 => {
|
||||
display_mime_disposition((*field).fld_data.fld_disposition);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_fields(mut fields: *mut mailmime_fields) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*fields).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
|
||||
field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime_field;
|
||||
display_mime_field(field);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_date_time(mut d: *mut mailimf_date_time) {
|
||||
print!(
|
||||
"{:02}/{:02}/{:02} {:02}:{:02}:{:02} +{:04}",
|
||||
(*d).dt_day,
|
||||
(*d).dt_month,
|
||||
(*d).dt_year,
|
||||
(*d).dt_hour,
|
||||
(*d).dt_min,
|
||||
(*d).dt_sec,
|
||||
(*d).dt_zone,
|
||||
);
|
||||
}
|
||||
unsafe fn display_orig_date(mut orig_date: *mut mailimf_orig_date) {
|
||||
display_date_time((*orig_date).dt_date_time);
|
||||
}
|
||||
unsafe fn display_mailbox(mut mb: *mut mailimf_mailbox) {
|
||||
if !(*mb).mb_display_name.is_null() {
|
||||
print!(
|
||||
"{}",
|
||||
CStr::from_ptr((*mb).mb_display_name).to_str().unwrap()
|
||||
);
|
||||
}
|
||||
print!("<{}>", CStr::from_ptr((*mb).mb_addr_spec).to_str().unwrap());
|
||||
}
|
||||
unsafe fn display_mailbox_list(mut mb_list: *mut mailimf_mailbox_list) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*mb_list).mb_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
|
||||
mb = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_mailbox;
|
||||
display_mailbox(mb);
|
||||
if !if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
.is_null()
|
||||
{
|
||||
print!(", ");
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_group(mut group: *mut mailimf_group) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
print!(
|
||||
"{}: ",
|
||||
CStr::from_ptr((*group).grp_display_name).to_str().unwrap()
|
||||
);
|
||||
cur = (*(*(*group).grp_mb_list).mb_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
|
||||
mb = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_mailbox;
|
||||
display_mailbox(mb);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
print!("; ");
|
||||
}
|
||||
unsafe fn display_address(mut a: *mut mailimf_address) {
|
||||
match (*a).ad_type {
|
||||
2 => {
|
||||
display_group((*a).ad_data.ad_group);
|
||||
}
|
||||
1 => {
|
||||
display_mailbox((*a).ad_data.ad_mailbox);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_address_list(mut addr_list: *mut mailimf_address_list) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*addr_list).ad_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut addr: *mut mailimf_address = 0 as *mut mailimf_address;
|
||||
addr = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_address;
|
||||
display_address(addr);
|
||||
if !if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
.is_null()
|
||||
{
|
||||
print!(", ");
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_from(mut from: *mut mailimf_from) {
|
||||
display_mailbox_list((*from).frm_mb_list);
|
||||
}
|
||||
unsafe fn display_to(mut to: *mut mailimf_to) {
|
||||
display_address_list((*to).to_addr_list);
|
||||
}
|
||||
unsafe fn display_cc(mut cc: *mut mailimf_cc) {
|
||||
display_address_list((*cc).cc_addr_list);
|
||||
}
|
||||
unsafe fn display_subject(mut subject: *mut mailimf_subject) {
|
||||
print!("{}", CStr::from_ptr((*subject).sbj_value).to_str().unwrap());
|
||||
}
|
||||
unsafe fn display_field(mut field: *mut mailimf_field) {
|
||||
match (*field).fld_type {
|
||||
9 => {
|
||||
print!("Date: ");
|
||||
display_orig_date((*field).fld_data.fld_orig_date);
|
||||
println!("");
|
||||
}
|
||||
10 => {
|
||||
print!("From: ");
|
||||
display_from((*field).fld_data.fld_from);
|
||||
println!("");
|
||||
}
|
||||
13 => {
|
||||
print!("To: ");
|
||||
display_to((*field).fld_data.fld_to);
|
||||
println!("");
|
||||
}
|
||||
14 => {
|
||||
print!("Cc: ");
|
||||
display_cc((*field).fld_data.fld_cc);
|
||||
println!("");
|
||||
}
|
||||
19 => {
|
||||
print!("Subject: ");
|
||||
display_subject((*field).fld_data.fld_subject);
|
||||
println!("");
|
||||
}
|
||||
16 => {
|
||||
println!(
|
||||
"Message-ID: {}",
|
||||
CStr::from_ptr((*(*field).fld_data.fld_message_id).mid_value)
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_fields(mut fields: *mut mailimf_fields) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*fields).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut f: *mut mailimf_field = 0 as *mut mailimf_field;
|
||||
f = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_field;
|
||||
display_field(f);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
78
mmime/src/lib.rs
Normal file
78
mmime/src/lib.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
#![deny(clippy::correctness)]
|
||||
// TODO: make all of these errors, such that clippy actually passes.
|
||||
#![warn(clippy::all, clippy::perf, clippy::not_unsafe_ptr_arg_deref)]
|
||||
// This is nice, but for now just annoying.
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
#![feature(ptr_wrapping_offset_from)]
|
||||
#![allow(unused_attributes)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(mutable_transmutes)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused_assignments)]
|
||||
#![allow(unused_mut)]
|
||||
#![allow(unused_must_use)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(const_raw_ptr_to_usize_cast)]
|
||||
|
||||
pub mod charconv;
|
||||
pub mod chash;
|
||||
pub mod clist;
|
||||
pub mod display;
|
||||
pub mod mailimf;
|
||||
pub mod mailmime;
|
||||
pub mod mmapstring;
|
||||
pub mod other;
|
||||
|
||||
pub use self::charconv::*;
|
||||
pub use self::chash::*;
|
||||
pub use self::clist::*;
|
||||
pub use self::display::*;
|
||||
pub use self::mailimf::*;
|
||||
pub use self::mailmime::*;
|
||||
pub use self::mmapstring::*;
|
||||
pub use self::other::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mailmime_parse_test() {
|
||||
unsafe {
|
||||
let data = "MIME-Version: 1.0\
|
||||
Content-Type: multipart/mixed; boundary=frontier\
|
||||
\
|
||||
This is a message with multiple parts in MIME format.\
|
||||
--frontier\
|
||||
Content-Type: text/plain\
|
||||
\
|
||||
This is the body of the message.\
|
||||
--frontier\
|
||||
Content-Type: application/octet-stream\
|
||||
Content-Transfer-Encoding: base64\
|
||||
\
|
||||
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg\
|
||||
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==\
|
||||
--frontier--";
|
||||
let c_data = std::ffi::CString::new(data).unwrap();
|
||||
|
||||
let mut current_index = 0;
|
||||
let mut mime = std::ptr::null_mut();
|
||||
let res = crate::mailmime::content::mailmime_parse(
|
||||
c_data.as_ptr(),
|
||||
data.len() as usize,
|
||||
&mut current_index,
|
||||
&mut mime,
|
||||
);
|
||||
|
||||
assert_eq!(res, MAIL_NO_ERROR as libc::c_int);
|
||||
assert!(!mime.is_null());
|
||||
|
||||
display_mime(mime);
|
||||
|
||||
mailmime::types::mailmime_free(mime);
|
||||
}
|
||||
}
|
||||
}
|
||||
5921
mmime/src/mailimf/mod.rs
Normal file
5921
mmime/src/mailimf/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
1181
mmime/src/mailimf/types.rs
Normal file
1181
mmime/src/mailimf/types.rs
Normal file
File diff suppressed because it is too large
Load Diff
89
mmime/src/mailimf/types_helper.rs
Normal file
89
mmime/src/mailimf/types_helper.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::types::*;
|
||||
use crate::other::*;
|
||||
|
||||
/*
|
||||
this function creates a new mailimf_fields structure with no fields
|
||||
*/
|
||||
pub unsafe fn mailimf_fields_new_empty() -> *mut mailimf_fields {
|
||||
let mut list: *mut clist = 0 as *mut clist;
|
||||
let mut fields_list: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
list = clist_new();
|
||||
if list.is_null() {
|
||||
return 0 as *mut mailimf_fields;
|
||||
}
|
||||
fields_list = mailimf_fields_new(list);
|
||||
if fields_list.is_null() {
|
||||
return 0 as *mut mailimf_fields;
|
||||
}
|
||||
return fields_list;
|
||||
}
|
||||
/*
|
||||
this function adds a field to the mailimf_fields structure
|
||||
|
||||
@return MAILIMF_NO_ERROR will be returned on success,
|
||||
other code will be returned otherwise
|
||||
*/
|
||||
pub unsafe fn mailimf_fields_add(
|
||||
mut fields: *mut mailimf_fields,
|
||||
mut field: *mut mailimf_field,
|
||||
) -> libc::c_int {
|
||||
let mut r: libc::c_int = 0;
|
||||
r = clist_insert_after(
|
||||
(*fields).fld_list,
|
||||
(*(*fields).fld_list).last,
|
||||
field as *mut libc::c_void,
|
||||
);
|
||||
if r < 0i32 {
|
||||
return MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
}
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
/*
|
||||
mailimf_field_new_custom creates a new field of type optional
|
||||
|
||||
@param name should be allocated with malloc()
|
||||
@param value should be allocated with malloc()
|
||||
*/
|
||||
pub unsafe fn mailimf_field_new_custom(
|
||||
mut name: *mut libc::c_char,
|
||||
mut value: *mut libc::c_char,
|
||||
) -> *mut mailimf_field {
|
||||
let mut opt_field: *mut mailimf_optional_field = 0 as *mut mailimf_optional_field;
|
||||
let mut field: *mut mailimf_field = 0 as *mut mailimf_field;
|
||||
opt_field = mailimf_optional_field_new(name, value);
|
||||
if !opt_field.is_null() {
|
||||
field = mailimf_field_new(
|
||||
MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int,
|
||||
0 as *mut mailimf_return,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_reply_to,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_in_reply_to,
|
||||
0 as *mut mailimf_references,
|
||||
0 as *mut mailimf_subject,
|
||||
0 as *mut mailimf_comments,
|
||||
0 as *mut mailimf_keywords,
|
||||
opt_field,
|
||||
);
|
||||
if field.is_null() {
|
||||
mailimf_optional_field_free(opt_field);
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return 0 as *mut mailimf_field;
|
||||
}
|
||||
1985
mmime/src/mailimf/write_generic.rs
Normal file
1985
mmime/src/mailimf/write_generic.rs
Normal file
File diff suppressed because it is too large
Load Diff
2357
mmime/src/mailmime/content.rs
Normal file
2357
mmime/src/mailmime/content.rs
Normal file
File diff suppressed because it is too large
Load Diff
860
mmime/src/mailmime/decode.rs
Normal file
860
mmime/src/mailmime/decode.rs
Normal file
@@ -0,0 +1,860 @@
|
||||
use libc;
|
||||
use libc::toupper;
|
||||
|
||||
use crate::charconv::*;
|
||||
use crate::mailimf::*;
|
||||
use crate::mailmime::content::*;
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const TYPE_WORD: libc::c_uint = 1;
|
||||
pub const TYPE_ENCODED_WORD: libc::c_uint = 2;
|
||||
pub const MAILMIME_ENCODING_Q: libc::c_uint = 1;
|
||||
pub const MAILMIME_ENCODING_B: libc::c_uint = 0;
|
||||
pub const TYPE_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn mailmime_encoded_phrase_parse(
|
||||
mut default_fromcode: *const libc::c_char,
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut tocode: *const libc::c_char,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut gphrase: *mut MMAPString = 0 as *mut MMAPString;
|
||||
let mut word: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
let mut first: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut str: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut wordutf8: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut missing_closing_quote: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
gphrase = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
if gphrase.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
first = 1i32;
|
||||
type_0 = TYPE_ERROR as libc::c_int;
|
||||
loop {
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
word = 0 as *mut mailmime_encoded_word;
|
||||
r = mailmime_encoded_word_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut word,
|
||||
&mut has_fwd,
|
||||
&mut missing_closing_quote,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
if 0 == first && 0 != has_fwd {
|
||||
if type_0 != TYPE_ENCODED_WORD as libc::c_int {
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
type_0 = TYPE_ENCODED_WORD as libc::c_int;
|
||||
wordutf8 = 0 as *mut libc::c_char;
|
||||
r = charconv(
|
||||
tocode,
|
||||
(*word).wd_charset,
|
||||
(*word).wd_text,
|
||||
strlen((*word).wd_text),
|
||||
&mut wordutf8,
|
||||
);
|
||||
match r {
|
||||
2 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
1 => {
|
||||
r = charconv(
|
||||
tocode,
|
||||
b"iso-8859-1\x00" as *const u8 as *const libc::c_char,
|
||||
(*word).wd_text,
|
||||
strlen((*word).wd_text),
|
||||
&mut wordutf8,
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match r {
|
||||
2 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
3 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if !wordutf8.is_null() {
|
||||
if mmap_string_append(gphrase, wordutf8).is_null() {
|
||||
mailmime_encoded_word_free(word);
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
mailmime_encoded_word_free(word);
|
||||
first = 0i32
|
||||
}
|
||||
}
|
||||
} else if !(r == MAILIMF_ERROR_PARSE as libc::c_int) {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
if !(r == MAILIMF_ERROR_PARSE as libc::c_int) {
|
||||
continue;
|
||||
}
|
||||
let mut raw_word: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
raw_word = 0 as *mut libc::c_char;
|
||||
r = mailmime_non_encoded_word_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut raw_word,
|
||||
&mut has_fwd,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
if 0 == first && 0 != has_fwd {
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
type_0 = TYPE_WORD as libc::c_int;
|
||||
wordutf8 = 0 as *mut libc::c_char;
|
||||
r = charconv(
|
||||
tocode,
|
||||
default_fromcode,
|
||||
raw_word,
|
||||
strlen(raw_word),
|
||||
&mut wordutf8,
|
||||
);
|
||||
match r {
|
||||
2 => {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
1 | 3 => {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if mmap_string_append(gphrase, wordutf8).is_null() {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
free(raw_word as *mut libc::c_void);
|
||||
first = 0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 5005389895767293342;
|
||||
break;
|
||||
}
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
first = 0i32;
|
||||
current_block = 5005389895767293342;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
res = r;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
5005389895767293342 => {
|
||||
if 0 != first {
|
||||
if cur_token != length {
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
} else {
|
||||
current_block = 7072655752890836508;
|
||||
}
|
||||
} else {
|
||||
current_block = 7072655752890836508;
|
||||
}
|
||||
match current_block {
|
||||
13246848547199022064 => {}
|
||||
_ => {
|
||||
str = strdup((*gphrase).str_0);
|
||||
if str.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
mmap_string_free(gphrase);
|
||||
*result = str;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
mmap_string_free(gphrase);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_non_encoded_word_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
mut p_has_fwd: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut end: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut text: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut begin: size_t = 0;
|
||||
let mut state: libc::c_int = 0;
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
has_fwd = 0i32;
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
has_fwd = 1i32
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
begin = cur_token;
|
||||
state = 0i32;
|
||||
end = 0i32;
|
||||
while !(cur_token >= length) {
|
||||
let mut current_block_17: u64;
|
||||
match *message.offset(cur_token as isize) as libc::c_int {
|
||||
32 | 9 | 13 | 10 => {
|
||||
state = 0i32;
|
||||
end = 1i32;
|
||||
current_block_17 = 16924917904204750491;
|
||||
}
|
||||
61 => {
|
||||
state = 1i32;
|
||||
current_block_17 = 16924917904204750491;
|
||||
}
|
||||
63 => {
|
||||
if state == 1i32 {
|
||||
cur_token = cur_token.wrapping_sub(1);
|
||||
end = 1i32
|
||||
}
|
||||
current_block_17 = 10192508258555769664;
|
||||
}
|
||||
_ => {
|
||||
current_block_17 = 10192508258555769664;
|
||||
}
|
||||
}
|
||||
match current_block_17 {
|
||||
10192508258555769664 => state = 0i32,
|
||||
_ => {}
|
||||
}
|
||||
if 0 != end {
|
||||
break;
|
||||
}
|
||||
cur_token = cur_token.wrapping_add(1)
|
||||
}
|
||||
if cur_token.wrapping_sub(begin) == 0i32 as libc::size_t {
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int
|
||||
} else {
|
||||
text = malloc(
|
||||
cur_token
|
||||
.wrapping_sub(begin)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
) as *mut libc::c_char;
|
||||
if text.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
memcpy(
|
||||
text as *mut libc::c_void,
|
||||
message.offset(begin as isize) as *const libc::c_void,
|
||||
cur_token.wrapping_sub(begin),
|
||||
);
|
||||
*text.offset(cur_token.wrapping_sub(begin) as isize) =
|
||||
'\u{0}' as i32 as libc::c_char;
|
||||
*indx = cur_token;
|
||||
*result = text;
|
||||
*p_has_fwd = has_fwd;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_encoded_word,
|
||||
mut p_has_fwd: *mut libc::c_int,
|
||||
mut p_missing_closing_quote: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
/*
|
||||
Parse the following, when a unicode character encoding is split.
|
||||
=?UTF-8?B?4Lij4Liw4LmA4Lia4Li04LiU4LiE4Lin4Liy4Lih4Lih4Lix4LiZ4Liq4LmM?=
|
||||
=?UTF-8?B?4LmA4LiV4LmH4Lih4Lie4Li04LiB4Lix4LiUIFRSQU5TRk9STUVSUyA0IOC4?=
|
||||
=?UTF-8?B?oeC4seC4meC4quC5jOC4hOC4o+C4muC4l+C4uOC4geC4o+C4sOC4muC4miDg?=
|
||||
=?UTF-8?B?uJfguLXguYjguYDguJTguLXguKLguKfguYPguJnguYDguKHguLfguK3guIfg?=
|
||||
=?UTF-8?B?uYTguJfguKI=?=
|
||||
Expected result:
|
||||
ระเบิดความมันส์เต็มพิกัด TRANSFORMERS 4 มันส์ครบทุกระบบ ที่เดียวในเมืองไทย
|
||||
libetpan result:
|
||||
ระเบิดความมันส์เต็มพิกัด TRANSFORMERS 4 ?ันส์ครบทุกระบบ ??ี่เดียวในเมือง??ทย
|
||||
|
||||
See https://github.com/dinhviethoa/libetpan/pull/211
|
||||
*/
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut charset: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut encoding: libc::c_int = 0;
|
||||
let mut body: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut old_body_len: size_t = 0;
|
||||
let mut text: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut end_encoding: size_t = 0;
|
||||
let mut lookfwd_cur_token: size_t = 0;
|
||||
let mut lookfwd_charset: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut lookfwd_encoding: libc::c_int = 0;
|
||||
let mut copy_len: size_t = 0;
|
||||
let mut decoded_token: size_t = 0;
|
||||
let mut decoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut decoded_len: size_t = 0;
|
||||
let mut ew: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut opening_quote: libc::c_int = 0;
|
||||
let mut end: libc::c_int = 0;
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
let mut missing_closing_quote: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
text = 0 as *mut libc::c_char;
|
||||
lookfwd_charset = 0 as *mut libc::c_char;
|
||||
missing_closing_quote = 0i32;
|
||||
has_fwd = 0i32;
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
has_fwd = 1i32
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
opening_quote = 0i32;
|
||||
r = mailimf_char_parse(message, length, &mut cur_token, '\"' as i32 as libc::c_char);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
opening_quote = 1i32;
|
||||
current_block = 17788412896529399552;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 17788412896529399552;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 7995813543095296079;
|
||||
}
|
||||
match current_block {
|
||||
7995813543095296079 => {}
|
||||
_ => {
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"=?\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"=?\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailmime_charset_parse(message, length, &mut cur_token, &mut charset);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailmime_encoding_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut encoding,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
lookfwd_cur_token = cur_token;
|
||||
body = 0 as *mut libc::c_char;
|
||||
old_body_len = 0i32 as size_t;
|
||||
loop {
|
||||
let mut has_base64_padding: libc::c_int = 0;
|
||||
end = 0i32;
|
||||
has_base64_padding = 0i32;
|
||||
end_encoding = cur_token;
|
||||
while !(end_encoding >= length) {
|
||||
if end_encoding.wrapping_add(1i32 as libc::size_t)
|
||||
< length
|
||||
{
|
||||
if *message.offset(end_encoding as isize)
|
||||
as libc::c_int
|
||||
== '?' as i32
|
||||
&& *message.offset(
|
||||
end_encoding
|
||||
.wrapping_add(1i32 as libc::size_t)
|
||||
as isize,
|
||||
)
|
||||
as libc::c_int
|
||||
== '=' as i32
|
||||
{
|
||||
end = 1i32
|
||||
}
|
||||
}
|
||||
if 0 != end {
|
||||
break;
|
||||
}
|
||||
end_encoding = end_encoding.wrapping_add(1)
|
||||
}
|
||||
copy_len = end_encoding.wrapping_sub(lookfwd_cur_token);
|
||||
if copy_len > 0i32 as libc::size_t {
|
||||
if encoding == MAILMIME_ENCODING_B as libc::c_int {
|
||||
if end_encoding >= 1i32 as libc::size_t {
|
||||
if *message.offset(
|
||||
end_encoding
|
||||
.wrapping_sub(1i32 as libc::size_t)
|
||||
as isize,
|
||||
)
|
||||
as libc::c_int
|
||||
== '=' as i32
|
||||
{
|
||||
has_base64_padding = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
body = realloc(
|
||||
body as *mut libc::c_void,
|
||||
old_body_len
|
||||
.wrapping_add(copy_len)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
)
|
||||
as *mut libc::c_char;
|
||||
if body.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13900684162107791171;
|
||||
break;
|
||||
} else {
|
||||
memcpy(
|
||||
body.offset(old_body_len as isize)
|
||||
as *mut libc::c_void,
|
||||
&*message.offset(cur_token as isize)
|
||||
as *const libc::c_char
|
||||
as *const libc::c_void,
|
||||
copy_len,
|
||||
);
|
||||
*body
|
||||
.offset(old_body_len.wrapping_add(copy_len)
|
||||
as isize) = '\u{0}' as i32 as libc::c_char;
|
||||
old_body_len = (old_body_len as libc::size_t)
|
||||
.wrapping_add(copy_len)
|
||||
as size_t
|
||||
as size_t
|
||||
}
|
||||
}
|
||||
cur_token = end_encoding;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"?=\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
strlen(b"?=\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
if 0 != has_base64_padding {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
lookfwd_cur_token = cur_token;
|
||||
r = mailimf_fws_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
&& r != MAILIMF_ERROR_PARSE as libc::c_int
|
||||
{
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
b"=?\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
strlen(b"=?\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailmime_charset_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
&mut lookfwd_charset,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailmime_encoding_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
&mut lookfwd_encoding,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
if strcasecmp(charset, lookfwd_charset) == 0i32
|
||||
&& encoding == lookfwd_encoding
|
||||
{
|
||||
cur_token = lookfwd_cur_token;
|
||||
mailmime_charset_free(lookfwd_charset);
|
||||
lookfwd_charset = 0 as *mut libc::c_char
|
||||
} else {
|
||||
/* the next charset is not matched with the current one,
|
||||
therefore exit the loop to decode the body appended so far */
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
2652804691515851435 => {
|
||||
if !lookfwd_charset.is_null() {
|
||||
mailmime_charset_free(lookfwd_charset);
|
||||
lookfwd_charset = 0 as *mut libc::c_char
|
||||
}
|
||||
if body.is_null() {
|
||||
body = strdup(
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if body.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13900684162107791171;
|
||||
} else {
|
||||
current_block = 16778110326724371720;
|
||||
}
|
||||
} else {
|
||||
current_block = 16778110326724371720;
|
||||
}
|
||||
match current_block {
|
||||
13900684162107791171 => {}
|
||||
_ => {
|
||||
decoded_token = 0i32 as size_t;
|
||||
decoded_len = 0i32 as size_t;
|
||||
decoded = 0 as *mut libc::c_char;
|
||||
match encoding {
|
||||
0 => {
|
||||
r = mailmime_base64_body_parse(
|
||||
body,
|
||||
strlen(body),
|
||||
&mut decoded_token,
|
||||
&mut decoded,
|
||||
&mut decoded_len,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
{
|
||||
res = r;
|
||||
current_block =
|
||||
13900684162107791171;
|
||||
} else {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
r =
|
||||
mailmime_quoted_printable_body_parse(body,
|
||||
strlen(body),
|
||||
&mut decoded_token,
|
||||
&mut decoded,
|
||||
&mut decoded_len,
|
||||
1i32);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
{
|
||||
res = r;
|
||||
current_block =
|
||||
13900684162107791171;
|
||||
} else {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
13900684162107791171 => {}
|
||||
_ => {
|
||||
text =
|
||||
malloc(decoded_len.wrapping_add(
|
||||
1i32 as libc::size_t,
|
||||
))
|
||||
as *mut libc::c_char;
|
||||
if text.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY
|
||||
as libc::c_int
|
||||
} else {
|
||||
if decoded_len
|
||||
> 0i32 as libc::size_t
|
||||
{
|
||||
memcpy(
|
||||
text as *mut libc::c_void,
|
||||
decoded
|
||||
as *const libc::c_void,
|
||||
decoded_len,
|
||||
);
|
||||
}
|
||||
*text
|
||||
.offset(decoded_len as isize) =
|
||||
'\u{0}' as i32 as libc::c_char;
|
||||
if 0 != opening_quote {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'\"' as i32 as libc::c_char,
|
||||
);
|
||||
if r == MAILIMF_ERROR_PARSE
|
||||
as libc::c_int
|
||||
{
|
||||
missing_closing_quote = 1i32
|
||||
}
|
||||
}
|
||||
if strcasecmp(
|
||||
charset,
|
||||
b"utf8\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
free(
|
||||
charset
|
||||
as *mut libc::c_void,
|
||||
);
|
||||
charset = strdup(
|
||||
b"utf-8\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
}
|
||||
ew = mailmime_encoded_word_new(
|
||||
charset, text,
|
||||
);
|
||||
if ew.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY
|
||||
as libc::c_int
|
||||
} else {
|
||||
*result = ew;
|
||||
*indx = cur_token;
|
||||
*p_has_fwd = has_fwd;
|
||||
*p_missing_closing_quote =
|
||||
missing_closing_quote;
|
||||
mailmime_decoded_part_free(
|
||||
decoded,
|
||||
);
|
||||
free(body as *mut libc::c_void);
|
||||
return MAILIMF_NO_ERROR
|
||||
as libc::c_int;
|
||||
}
|
||||
}
|
||||
mailmime_decoded_part_free(decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(body as *mut libc::c_void);
|
||||
mailmime_encoded_text_free(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
mailmime_charset_free(charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_encoding_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut encoding: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
if cur_token >= length {
|
||||
return MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
}
|
||||
match toupper(*message.offset(cur_token as isize) as libc::c_uchar as libc::c_int)
|
||||
as libc::c_char as libc::c_int
|
||||
{
|
||||
81 => encoding = MAILMIME_ENCODING_Q as libc::c_int,
|
||||
66 => encoding = MAILMIME_ENCODING_B as libc::c_int,
|
||||
_ => return MAILIMF_ERROR_INVAL as libc::c_int,
|
||||
}
|
||||
cur_token = cur_token.wrapping_add(1);
|
||||
*result = encoding;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* $Id: mailmime_decode.c,v 1.37 2010/11/16 20:52:28 hoa Exp $
|
||||
*/
|
||||
/*
|
||||
RFC 2047 : MIME (Multipurpose Internet Mail Extensions) Part Three:
|
||||
Message Header Extensions for Non-ASCII Text
|
||||
*/
|
||||
unsafe fn mailmime_charset_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut charset: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailmime_etoken_parse(message, length, indx, charset);
|
||||
}
|
||||
unsafe fn mailmime_etoken_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailimf_custom_string_parse(message, length, indx, result, Some(is_etoken_char));
|
||||
}
|
||||
|
||||
unsafe fn is_etoken_char(mut ch: libc::c_char) -> libc::c_int {
|
||||
let mut uch: libc::c_uchar = ch as libc::c_uchar;
|
||||
if (uch as libc::c_int) < 31i32 {
|
||||
return 0i32;
|
||||
}
|
||||
match uch as libc::c_int {
|
||||
32 | 40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 34 | 47 | 91 | 93 | 63 | 61 => return 0i32,
|
||||
_ => {}
|
||||
}
|
||||
return 1i32;
|
||||
}
|
||||
583
mmime/src/mailmime/disposition.rs
Normal file
583
mmime/src/mailmime/disposition.rs
Normal file
@@ -0,0 +1,583 @@
|
||||
use libc::{self, toupper};
|
||||
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::*;
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mailmime::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const MAILMIME_DISPOSITION_TYPE_EXTENSION: libc::c_uint = 3;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_ATTACHMENT: libc::c_uint = 2;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_INLINE: libc::c_uint = 1;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn mailmime_disposition_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut final_token: size_t = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
let mut list: *mut clist = 0 as *mut clist;
|
||||
let mut dsp: *mut mailmime_disposition = 0 as *mut mailmime_disposition;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailmime_disposition_type_parse(message, length, &mut cur_token, &mut dsp_type);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
list = clist_new();
|
||||
if list.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
loop {
|
||||
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
final_token = cur_token;
|
||||
r = mailimf_unstrict_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
';' as i32 as libc::c_char,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
param = 0 as *mut mailmime_disposition_parm;
|
||||
r = mailmime_disposition_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut param,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
r = clist_insert_after(list, (*list).last, param as *mut libc::c_void);
|
||||
if !(r < 0i32) {
|
||||
continue;
|
||||
}
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
cur_token = final_token;
|
||||
current_block = 652864300344834934;
|
||||
break;
|
||||
} else {
|
||||
res = r;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do nothing */
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 652864300344834934;
|
||||
break;
|
||||
}
|
||||
res = r;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
652864300344834934 => {
|
||||
dsp = mailmime_disposition_new(dsp_type, list);
|
||||
if dsp.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
*result = dsp;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
clist_foreach(
|
||||
list,
|
||||
::std::mem::transmute::<
|
||||
Option<unsafe fn(_: *mut mailmime_disposition_parm) -> ()>,
|
||||
clist_func,
|
||||
>(Some(mailmime_disposition_parm_free)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free(list);
|
||||
}
|
||||
mailmime_disposition_type_free(dsp_type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* $Id: mailmime_disposition.c,v 1.17 2011/05/03 16:30:22 hoa Exp $
|
||||
*/
|
||||
unsafe fn mailmime_disposition_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition_parm,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut creation_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut modification_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut read_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut size: size_t = 0;
|
||||
let mut parameter: *mut mailmime_parameter = 0 as *mut mailmime_parameter;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut dsp_parm: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut guessed_type: libc::c_int = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
filename = 0 as *mut libc::c_char;
|
||||
creation_date = 0 as *mut libc::c_char;
|
||||
modification_date = 0 as *mut libc::c_char;
|
||||
read_date = 0 as *mut libc::c_char;
|
||||
size = 0i32 as size_t;
|
||||
parameter = 0 as *mut mailmime_parameter;
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
guessed_type = mailmime_disposition_guess_type(message, length, cur_token);
|
||||
type_0 = MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int;
|
||||
match guessed_type {
|
||||
0 => {
|
||||
r = mailmime_filename_parm_parse(message, length, &mut cur_token, &mut filename);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
r = mailmime_creation_date_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut creation_date,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
r = mailmime_modification_date_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut modification_date,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
r = mailmime_read_date_parm_parse(message, length, &mut cur_token, &mut read_date);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
r = mailmime_size_parm_parse(message, length, &mut cur_token, &mut size);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 13826291924415791078;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
9120900589700563584 => {}
|
||||
_ => {
|
||||
if type_0 == MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int {
|
||||
r = mailmime_parameter_parse(message, length, &mut cur_token, &mut parameter);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
} else {
|
||||
current_block = 6721012065216013753;
|
||||
}
|
||||
} else {
|
||||
current_block = 6721012065216013753;
|
||||
}
|
||||
match current_block {
|
||||
9120900589700563584 => {}
|
||||
_ => {
|
||||
dsp_parm = mailmime_disposition_parm_new(
|
||||
type_0,
|
||||
filename,
|
||||
creation_date,
|
||||
modification_date,
|
||||
read_date,
|
||||
size,
|
||||
parameter,
|
||||
);
|
||||
if dsp_parm.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
if !filename.is_null() {
|
||||
mailmime_filename_parm_free(filename);
|
||||
}
|
||||
if !creation_date.is_null() {
|
||||
mailmime_creation_date_parm_free(creation_date);
|
||||
}
|
||||
if !modification_date.is_null() {
|
||||
mailmime_modification_date_parm_free(modification_date);
|
||||
}
|
||||
if !read_date.is_null() {
|
||||
mailmime_read_date_parm_free(read_date);
|
||||
}
|
||||
if !parameter.is_null() {
|
||||
mailmime_parameter_free(parameter);
|
||||
}
|
||||
} else {
|
||||
*result = dsp_parm;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_size_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut value: uint32_t = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"size\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"size\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_number_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value as size_t;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_read_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"read-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"read-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_quoted_date_time_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailimf_quoted_string_parse(message, length, indx, result);
|
||||
}
|
||||
unsafe fn mailmime_modification_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"modification-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"modification-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_creation_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"creation-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"creation-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_filename_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"filename\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"filename\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_value_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_guess_type(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: size_t,
|
||||
) -> libc::c_int {
|
||||
if indx >= length {
|
||||
return MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int;
|
||||
}
|
||||
match toupper(*message.offset(indx as isize) as libc::c_uchar as libc::c_int) as libc::c_char
|
||||
as libc::c_int
|
||||
{
|
||||
70 => return MAILMIME_DISPOSITION_PARM_FILENAME as libc::c_int,
|
||||
67 => return MAILMIME_DISPOSITION_PARM_CREATION_DATE as libc::c_int,
|
||||
77 => return MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE as libc::c_int,
|
||||
82 => return MAILMIME_DISPOSITION_PARM_READ_DATE as libc::c_int,
|
||||
83 => return MAILMIME_DISPOSITION_PARM_SIZE as libc::c_int,
|
||||
_ => return MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int,
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition_type,
|
||||
) -> libc::c_int {
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut extension: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_ERROR as libc::c_int;
|
||||
extension = 0 as *mut libc::c_char;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"inline\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"inline\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_INLINE as libc::c_int
|
||||
}
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"attachment\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"attachment\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int
|
||||
}
|
||||
}
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailmime_extension_token_parse(message, length, &mut cur_token, &mut extension);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_EXTENSION as libc::c_int
|
||||
}
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
dsp_type = mailmime_disposition_type_new(type_0, extension);
|
||||
if dsp_type.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
if !extension.is_null() {
|
||||
free(extension as *mut libc::c_void);
|
||||
}
|
||||
} else {
|
||||
*result = dsp_type;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
1143
mmime/src/mailmime/mod.rs
Normal file
1143
mmime/src/mailmime/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
869
mmime/src/mailmime/types.rs
Normal file
869
mmime/src/mailmime/types.rs
Normal file
@@ -0,0 +1,869 @@
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::types::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const MAILMIME_MECHANISM_TOKEN: libc::c_uint = 6;
|
||||
pub const MAILMIME_MECHANISM_BASE64: libc::c_uint = 5;
|
||||
pub const MAILMIME_MECHANISM_QUOTED_PRINTABLE: libc::c_uint = 4;
|
||||
pub const MAILMIME_MECHANISM_BINARY: libc::c_uint = 3;
|
||||
pub const MAILMIME_MECHANISM_8BIT: libc::c_uint = 2;
|
||||
pub const MAILMIME_MECHANISM_7BIT: libc::c_uint = 1;
|
||||
pub const MAILMIME_MECHANISM_ERROR: libc::c_uint = 0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_composite_type {
|
||||
pub ct_type: libc::c_int,
|
||||
pub ct_token: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_content {
|
||||
pub ct_type: *mut mailmime_type,
|
||||
pub ct_subtype: *mut libc::c_char,
|
||||
pub ct_parameters: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_type {
|
||||
pub tp_type: libc::c_int,
|
||||
pub tp_data: unnamed,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed {
|
||||
pub tp_discrete_type: *mut mailmime_discrete_type,
|
||||
pub tp_composite_type: *mut mailmime_composite_type,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_discrete_type {
|
||||
pub dt_type: libc::c_int,
|
||||
pub dt_extension: *mut libc::c_char,
|
||||
}
|
||||
pub type unnamed_0 = libc::c_uint;
|
||||
pub const MAILMIME_FIELD_LOCATION: unnamed_0 = 8;
|
||||
pub const MAILMIME_FIELD_LANGUAGE: unnamed_0 = 7;
|
||||
pub const MAILMIME_FIELD_DISPOSITION: unnamed_0 = 6;
|
||||
pub const MAILMIME_FIELD_VERSION: unnamed_0 = 5;
|
||||
pub const MAILMIME_FIELD_DESCRIPTION: unnamed_0 = 4;
|
||||
pub const MAILMIME_FIELD_ID: unnamed_0 = 3;
|
||||
pub const MAILMIME_FIELD_TRANSFER_ENCODING: unnamed_0 = 2;
|
||||
pub const MAILMIME_FIELD_TYPE: unnamed_0 = 1;
|
||||
pub const MAILMIME_FIELD_NONE: unnamed_0 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_field {
|
||||
pub fld_type: libc::c_int,
|
||||
pub fld_data: unnamed_1,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_1 {
|
||||
pub fld_content: *mut mailmime_content,
|
||||
pub fld_encoding: *mut mailmime_mechanism,
|
||||
pub fld_id: *mut libc::c_char,
|
||||
pub fld_description: *mut libc::c_char,
|
||||
pub fld_version: uint32_t,
|
||||
pub fld_disposition: *mut mailmime_disposition,
|
||||
pub fld_language: *mut mailmime_language,
|
||||
pub fld_location: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_language {
|
||||
pub lg_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition {
|
||||
pub dsp_type: *mut mailmime_disposition_type,
|
||||
pub dsp_parms: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition_type {
|
||||
pub dsp_type: libc::c_int,
|
||||
pub dsp_extension: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_mechanism {
|
||||
pub enc_type: libc::c_int,
|
||||
pub enc_token: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_fields {
|
||||
pub fld_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_parameter {
|
||||
pub pa_name: *mut libc::c_char,
|
||||
pub pa_value: *mut libc::c_char,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition_parm {
|
||||
pub pa_type: libc::c_int,
|
||||
pub pa_data: unnamed_3,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_3 {
|
||||
pub pa_filename: *mut libc::c_char,
|
||||
pub pa_creation_date: *mut libc::c_char,
|
||||
pub pa_modification_date: *mut libc::c_char,
|
||||
pub pa_read_date: *mut libc::c_char,
|
||||
pub pa_size: size_t,
|
||||
pub pa_parameter: *mut mailmime_parameter,
|
||||
}
|
||||
pub const MAILMIME_DISPOSITION_PARM_PARAMETER: unnamed_11 = 5;
|
||||
pub const MAILMIME_DISPOSITION_PARM_READ_DATE: unnamed_11 = 3;
|
||||
pub const MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: unnamed_11 = 2;
|
||||
pub const MAILMIME_DISPOSITION_PARM_CREATION_DATE: unnamed_11 = 1;
|
||||
pub const MAILMIME_DISPOSITION_PARM_FILENAME: unnamed_11 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_multipart_body {
|
||||
pub bd_list: *mut clist,
|
||||
}
|
||||
pub type unnamed_4 = libc::c_uint;
|
||||
pub const MAILMIME_DATA_FILE: unnamed_4 = 1;
|
||||
pub const MAILMIME_DATA_TEXT: unnamed_4 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_data {
|
||||
pub dt_type: libc::c_int,
|
||||
pub dt_encoding: libc::c_int,
|
||||
pub dt_encoded: libc::c_int,
|
||||
pub dt_data: unnamed_5,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_5 {
|
||||
pub dt_text: unnamed_6,
|
||||
pub dt_filename: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_6 {
|
||||
pub dt_data: *const libc::c_char,
|
||||
pub dt_length: size_t,
|
||||
}
|
||||
pub type unnamed_7 = libc::c_uint;
|
||||
pub const MAILMIME_MESSAGE: unnamed_7 = 3;
|
||||
pub const MAILMIME_MULTIPLE: unnamed_7 = 2;
|
||||
pub const MAILMIME_SINGLE: unnamed_7 = 1;
|
||||
pub const MAILMIME_NONE: unnamed_7 = 0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Mailmime {
|
||||
pub mm_parent_type: libc::c_int,
|
||||
pub mm_parent: *mut Mailmime,
|
||||
pub mm_multipart_pos: *mut clistiter,
|
||||
pub mm_type: libc::c_int,
|
||||
pub mm_mime_start: *const libc::c_char,
|
||||
pub mm_length: size_t,
|
||||
pub mm_mime_fields: *mut mailmime_fields,
|
||||
pub mm_content_type: *mut mailmime_content,
|
||||
pub mm_body: *mut mailmime_data,
|
||||
pub mm_data: unnamed_8,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_8 {
|
||||
pub mm_single: *mut mailmime_data,
|
||||
pub mm_multipart: unnamed_10,
|
||||
pub mm_message: unnamed_9,
|
||||
}
|
||||
/* message */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_9 {
|
||||
pub mm_fields: *mut mailimf_fields,
|
||||
pub mm_msg_mime: *mut Mailmime,
|
||||
}
|
||||
/* multi-part */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_10 {
|
||||
pub mm_preamble: *mut mailmime_data,
|
||||
pub mm_epilogue: *mut mailmime_data,
|
||||
pub mm_mp_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_encoded_word {
|
||||
pub wd_charset: *mut libc::c_char,
|
||||
pub wd_text: *mut libc::c_char,
|
||||
}
|
||||
pub type unnamed_11 = libc::c_uint;
|
||||
pub const MAILMIME_DISPOSITION_PARM_SIZE: unnamed_11 = 4;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_section {
|
||||
pub sec_list: *mut clist,
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_attribute_free(mut attribute: *mut libc::c_char) {
|
||||
mailmime_token_free(attribute);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_token_free(mut token: *mut libc::c_char) {
|
||||
free(token as *mut libc::c_void);
|
||||
}
|
||||
pub unsafe fn mailmime_composite_type_new(
|
||||
mut ct_type: libc::c_int,
|
||||
mut ct_token: *mut libc::c_char,
|
||||
) -> *mut mailmime_composite_type {
|
||||
let mut ct: *mut mailmime_composite_type = 0 as *mut mailmime_composite_type;
|
||||
ct = malloc(::std::mem::size_of::<mailmime_composite_type>() as libc::size_t)
|
||||
as *mut mailmime_composite_type;
|
||||
if ct.is_null() {
|
||||
return 0 as *mut mailmime_composite_type;
|
||||
}
|
||||
(*ct).ct_type = ct_type;
|
||||
(*ct).ct_token = ct_token;
|
||||
return ct;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_composite_type_free(mut ct: *mut mailmime_composite_type) {
|
||||
if !(*ct).ct_token.is_null() {
|
||||
mailmime_extension_token_free((*ct).ct_token);
|
||||
}
|
||||
free(ct as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_extension_token_free(mut extension: *mut libc::c_char) {
|
||||
mailmime_token_free(extension);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_new(
|
||||
mut ct_type: *mut mailmime_type,
|
||||
mut ct_subtype: *mut libc::c_char,
|
||||
mut ct_parameters: *mut clist,
|
||||
) -> *mut mailmime_content {
|
||||
let mut content: *mut mailmime_content = 0 as *mut mailmime_content;
|
||||
content =
|
||||
malloc(::std::mem::size_of::<mailmime_content>() as libc::size_t) as *mut mailmime_content;
|
||||
if content.is_null() {
|
||||
return 0 as *mut mailmime_content;
|
||||
}
|
||||
(*content).ct_type = ct_type;
|
||||
(*content).ct_subtype = ct_subtype;
|
||||
(*content).ct_parameters = ct_parameters;
|
||||
return content;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_free(mut content: *mut mailmime_content) {
|
||||
mailmime_type_free((*content).ct_type);
|
||||
mailmime_subtype_free((*content).ct_subtype);
|
||||
if !(*content).ct_parameters.is_null() {
|
||||
clist_foreach(
|
||||
(*content).ct_parameters,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailmime_parameter) -> ()>, clist_func>(
|
||||
Some(mailmime_parameter_free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*content).ct_parameters);
|
||||
}
|
||||
free(content as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_parameter_free(mut parameter: *mut mailmime_parameter) {
|
||||
mailmime_attribute_free((*parameter).pa_name);
|
||||
mailmime_value_free((*parameter).pa_value);
|
||||
free(parameter as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_value_free(mut value: *mut libc::c_char) {
|
||||
free(value as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_subtype_free(mut subtype: *mut libc::c_char) {
|
||||
mailmime_extension_token_free(subtype);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_type_free(mut type_0: *mut mailmime_type) {
|
||||
match (*type_0).tp_type {
|
||||
1 => {
|
||||
mailmime_discrete_type_free((*type_0).tp_data.tp_discrete_type);
|
||||
}
|
||||
2 => {
|
||||
mailmime_composite_type_free((*type_0).tp_data.tp_composite_type);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(type_0 as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_discrete_type_free(mut discrete_type: *mut mailmime_discrete_type) {
|
||||
if !(*discrete_type).dt_extension.is_null() {
|
||||
mailmime_extension_token_free((*discrete_type).dt_extension);
|
||||
}
|
||||
free(discrete_type as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_description_free(mut description: *mut libc::c_char) {
|
||||
free(description as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_location_free(mut location: *mut libc::c_char) {
|
||||
free(location as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_discrete_type_new(
|
||||
mut dt_type: libc::c_int,
|
||||
mut dt_extension: *mut libc::c_char,
|
||||
) -> *mut mailmime_discrete_type {
|
||||
let mut discrete_type: *mut mailmime_discrete_type = 0 as *mut mailmime_discrete_type;
|
||||
discrete_type = malloc(::std::mem::size_of::<mailmime_discrete_type>() as libc::size_t)
|
||||
as *mut mailmime_discrete_type;
|
||||
if discrete_type.is_null() {
|
||||
return 0 as *mut mailmime_discrete_type;
|
||||
}
|
||||
(*discrete_type).dt_type = dt_type;
|
||||
(*discrete_type).dt_extension = dt_extension;
|
||||
return discrete_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoding_free(mut encoding: *mut mailmime_mechanism) {
|
||||
mailmime_mechanism_free(encoding);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_mechanism_free(mut mechanism: *mut mailmime_mechanism) {
|
||||
if !(*mechanism).enc_token.is_null() {
|
||||
mailmime_token_free((*mechanism).enc_token);
|
||||
}
|
||||
free(mechanism as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_id_free(mut id: *mut libc::c_char) {
|
||||
mailimf_msg_id_free(id);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_mechanism_new(
|
||||
mut enc_type: libc::c_int,
|
||||
mut enc_token: *mut libc::c_char,
|
||||
) -> *mut mailmime_mechanism {
|
||||
let mut mechanism: *mut mailmime_mechanism = 0 as *mut mailmime_mechanism;
|
||||
mechanism = malloc(::std::mem::size_of::<mailmime_mechanism>() as libc::size_t)
|
||||
as *mut mailmime_mechanism;
|
||||
if mechanism.is_null() {
|
||||
return 0 as *mut mailmime_mechanism;
|
||||
}
|
||||
(*mechanism).enc_type = enc_type;
|
||||
(*mechanism).enc_token = enc_token;
|
||||
return mechanism;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_parameter_new(
|
||||
mut pa_name: *mut libc::c_char,
|
||||
mut pa_value: *mut libc::c_char,
|
||||
) -> *mut mailmime_parameter {
|
||||
let mut parameter: *mut mailmime_parameter = 0 as *mut mailmime_parameter;
|
||||
parameter = malloc(::std::mem::size_of::<mailmime_parameter>() as libc::size_t)
|
||||
as *mut mailmime_parameter;
|
||||
if parameter.is_null() {
|
||||
return 0 as *mut mailmime_parameter;
|
||||
}
|
||||
(*parameter).pa_name = pa_name;
|
||||
(*parameter).pa_value = pa_value;
|
||||
return parameter;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_type_new(
|
||||
mut tp_type: libc::c_int,
|
||||
mut tp_discrete_type: *mut mailmime_discrete_type,
|
||||
mut tp_composite_type: *mut mailmime_composite_type,
|
||||
) -> *mut mailmime_type {
|
||||
let mut mime_type: *mut mailmime_type = 0 as *mut mailmime_type;
|
||||
mime_type =
|
||||
malloc(::std::mem::size_of::<mailmime_type>() as libc::size_t) as *mut mailmime_type;
|
||||
if mime_type.is_null() {
|
||||
return 0 as *mut mailmime_type;
|
||||
}
|
||||
(*mime_type).tp_type = tp_type;
|
||||
match tp_type {
|
||||
1 => (*mime_type).tp_data.tp_discrete_type = tp_discrete_type,
|
||||
2 => (*mime_type).tp_data.tp_composite_type = tp_composite_type,
|
||||
_ => {}
|
||||
}
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_language_new(mut lg_list: *mut clist) -> *mut mailmime_language {
|
||||
let mut lang: *mut mailmime_language = 0 as *mut mailmime_language;
|
||||
lang = malloc(::std::mem::size_of::<mailmime_language>() as libc::size_t)
|
||||
as *mut mailmime_language;
|
||||
if lang.is_null() {
|
||||
return 0 as *mut mailmime_language;
|
||||
}
|
||||
(*lang).lg_list = lg_list;
|
||||
return lang;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_language_free(mut lang: *mut mailmime_language) {
|
||||
clist_foreach(
|
||||
(*lang).lg_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut libc::c_char) -> ()>, clist_func>(Some(
|
||||
mailimf_atom_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*lang).lg_list);
|
||||
free(lang as *mut libc::c_void);
|
||||
}
|
||||
/*
|
||||
void mailmime_x_token_free(gchar * x_token);
|
||||
*/
|
||||
pub unsafe fn mailmime_field_new(
|
||||
mut fld_type: libc::c_int,
|
||||
mut fld_content: *mut mailmime_content,
|
||||
mut fld_encoding: *mut mailmime_mechanism,
|
||||
mut fld_id: *mut libc::c_char,
|
||||
mut fld_description: *mut libc::c_char,
|
||||
mut fld_version: uint32_t,
|
||||
mut fld_disposition: *mut mailmime_disposition,
|
||||
mut fld_language: *mut mailmime_language,
|
||||
mut fld_location: *mut libc::c_char,
|
||||
) -> *mut mailmime_field {
|
||||
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
|
||||
field = malloc(::std::mem::size_of::<mailmime_field>() as libc::size_t) as *mut mailmime_field;
|
||||
if field.is_null() {
|
||||
return 0 as *mut mailmime_field;
|
||||
}
|
||||
(*field).fld_type = fld_type;
|
||||
match fld_type {
|
||||
1 => (*field).fld_data.fld_content = fld_content,
|
||||
2 => (*field).fld_data.fld_encoding = fld_encoding,
|
||||
3 => (*field).fld_data.fld_id = fld_id,
|
||||
4 => (*field).fld_data.fld_description = fld_description,
|
||||
5 => (*field).fld_data.fld_version = fld_version,
|
||||
6 => (*field).fld_data.fld_disposition = fld_disposition,
|
||||
7 => (*field).fld_data.fld_language = fld_language,
|
||||
8 => (*field).fld_data.fld_location = fld_location,
|
||||
_ => {}
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_field_free(mut field: *mut mailmime_field) {
|
||||
match (*field).fld_type {
|
||||
1 => {
|
||||
if !(*field).fld_data.fld_content.is_null() {
|
||||
mailmime_content_free((*field).fld_data.fld_content);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if !(*field).fld_data.fld_encoding.is_null() {
|
||||
mailmime_encoding_free((*field).fld_data.fld_encoding);
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
if !(*field).fld_data.fld_id.is_null() {
|
||||
mailmime_id_free((*field).fld_data.fld_id);
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
if !(*field).fld_data.fld_description.is_null() {
|
||||
mailmime_description_free((*field).fld_data.fld_description);
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
if !(*field).fld_data.fld_disposition.is_null() {
|
||||
mailmime_disposition_free((*field).fld_data.fld_disposition);
|
||||
}
|
||||
}
|
||||
7 => {
|
||||
if !(*field).fld_data.fld_language.is_null() {
|
||||
mailmime_language_free((*field).fld_data.fld_language);
|
||||
}
|
||||
}
|
||||
8 => {
|
||||
if !(*field).fld_data.fld_location.is_null() {
|
||||
mailmime_location_free((*field).fld_data.fld_location);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(field as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_free(mut dsp: *mut mailmime_disposition) {
|
||||
mailmime_disposition_type_free((*dsp).dsp_type);
|
||||
clist_foreach(
|
||||
(*dsp).dsp_parms,
|
||||
::std::mem::transmute::<
|
||||
Option<unsafe fn(_: *mut mailmime_disposition_parm) -> ()>,
|
||||
clist_func,
|
||||
>(Some(mailmime_disposition_parm_free)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*dsp).dsp_parms);
|
||||
free(dsp as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_parm_free(mut dsp_parm: *mut mailmime_disposition_parm) {
|
||||
match (*dsp_parm).pa_type {
|
||||
0 => {
|
||||
mailmime_filename_parm_free((*dsp_parm).pa_data.pa_filename);
|
||||
}
|
||||
1 => {
|
||||
mailmime_creation_date_parm_free((*dsp_parm).pa_data.pa_creation_date);
|
||||
}
|
||||
2 => {
|
||||
mailmime_modification_date_parm_free((*dsp_parm).pa_data.pa_modification_date);
|
||||
}
|
||||
3 => {
|
||||
mailmime_read_date_parm_free((*dsp_parm).pa_data.pa_read_date);
|
||||
}
|
||||
5 => {
|
||||
mailmime_parameter_free((*dsp_parm).pa_data.pa_parameter);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(dsp_parm as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_read_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_quoted_date_time_free(mut date: *mut libc::c_char) {
|
||||
mailimf_quoted_string_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_modification_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_creation_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_filename_parm_free(mut filename: *mut libc::c_char) {
|
||||
mailmime_value_free(filename);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_free(mut dsp_type: *mut mailmime_disposition_type) {
|
||||
if !(*dsp_type).dsp_extension.is_null() {
|
||||
free((*dsp_type).dsp_extension as *mut libc::c_void);
|
||||
}
|
||||
free(dsp_type as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_fields_new(mut fld_list: *mut clist) -> *mut mailmime_fields {
|
||||
let mut fields: *mut mailmime_fields = 0 as *mut mailmime_fields;
|
||||
fields =
|
||||
malloc(::std::mem::size_of::<mailmime_fields>() as libc::size_t) as *mut mailmime_fields;
|
||||
if fields.is_null() {
|
||||
return 0 as *mut mailmime_fields;
|
||||
}
|
||||
(*fields).fld_list = fld_list;
|
||||
return fields;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_fields_free(mut fields: *mut mailmime_fields) {
|
||||
clist_foreach(
|
||||
(*fields).fld_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailmime_field) -> ()>, clist_func>(Some(
|
||||
mailmime_field_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*fields).fld_list);
|
||||
free(fields as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_multipart_body_new(mut bd_list: *mut clist) -> *mut mailmime_multipart_body {
|
||||
let mut mp_body: *mut mailmime_multipart_body = 0 as *mut mailmime_multipart_body;
|
||||
mp_body = malloc(::std::mem::size_of::<mailmime_multipart_body>() as libc::size_t)
|
||||
as *mut mailmime_multipart_body;
|
||||
if mp_body.is_null() {
|
||||
return 0 as *mut mailmime_multipart_body;
|
||||
}
|
||||
(*mp_body).bd_list = bd_list;
|
||||
return mp_body;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_multipart_body_free(mut mp_body: *mut mailmime_multipart_body) {
|
||||
clist_foreach(
|
||||
(*mp_body).bd_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailimf_body) -> ()>, clist_func>(Some(
|
||||
mailimf_body_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*mp_body).bd_list);
|
||||
free(mp_body as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_new(
|
||||
mut dt_type: libc::c_int,
|
||||
mut dt_encoding: libc::c_int,
|
||||
mut dt_encoded: libc::c_int,
|
||||
mut dt_data: *const libc::c_char,
|
||||
mut dt_length: size_t,
|
||||
mut dt_filename: *mut libc::c_char,
|
||||
) -> *mut mailmime_data {
|
||||
let mut mime_data: *mut mailmime_data = 0 as *mut mailmime_data;
|
||||
mime_data =
|
||||
malloc(::std::mem::size_of::<mailmime_data>() as libc::size_t) as *mut mailmime_data;
|
||||
if mime_data.is_null() {
|
||||
return 0 as *mut mailmime_data;
|
||||
}
|
||||
(*mime_data).dt_type = dt_type;
|
||||
(*mime_data).dt_encoding = dt_encoding;
|
||||
(*mime_data).dt_encoded = dt_encoded;
|
||||
match dt_type {
|
||||
0 => {
|
||||
(*mime_data).dt_data.dt_text.dt_data = dt_data;
|
||||
(*mime_data).dt_data.dt_text.dt_length = dt_length
|
||||
}
|
||||
1 => (*mime_data).dt_data.dt_filename = dt_filename,
|
||||
_ => {}
|
||||
}
|
||||
return mime_data;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_free(mut mime_data: *mut mailmime_data) {
|
||||
match (*mime_data).dt_type {
|
||||
1 => {
|
||||
free((*mime_data).dt_data.dt_filename as *mut libc::c_void);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(mime_data as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_new(
|
||||
mut mm_type: libc::c_int,
|
||||
mut mm_mime_start: *const libc::c_char,
|
||||
mut mm_length: size_t,
|
||||
mut mm_mime_fields: *mut mailmime_fields,
|
||||
mut mm_content_type: *mut mailmime_content,
|
||||
mut mm_body: *mut mailmime_data,
|
||||
mut mm_preamble: *mut mailmime_data,
|
||||
mut mm_epilogue: *mut mailmime_data,
|
||||
mut mm_mp_list: *mut clist,
|
||||
mut mm_fields: *mut mailimf_fields,
|
||||
mut mm_msg_mime: *mut Mailmime,
|
||||
) -> *mut Mailmime {
|
||||
let mut mime: *mut Mailmime = 0 as *mut Mailmime;
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
mime = malloc(::std::mem::size_of::<Mailmime>() as libc::size_t) as *mut Mailmime;
|
||||
if mime.is_null() {
|
||||
return 0 as *mut Mailmime;
|
||||
}
|
||||
(*mime).mm_parent = 0 as *mut Mailmime;
|
||||
(*mime).mm_parent_type = MAILMIME_NONE as libc::c_int;
|
||||
(*mime).mm_multipart_pos = 0 as *mut clistiter;
|
||||
(*mime).mm_type = mm_type;
|
||||
(*mime).mm_mime_start = mm_mime_start;
|
||||
(*mime).mm_length = mm_length;
|
||||
(*mime).mm_mime_fields = mm_mime_fields;
|
||||
(*mime).mm_content_type = mm_content_type;
|
||||
(*mime).mm_body = mm_body;
|
||||
match mm_type {
|
||||
1 => (*mime).mm_data.mm_single = mm_body,
|
||||
2 => {
|
||||
(*mime).mm_data.mm_multipart.mm_preamble = mm_preamble;
|
||||
(*mime).mm_data.mm_multipart.mm_epilogue = mm_epilogue;
|
||||
(*mime).mm_data.mm_multipart.mm_mp_list = mm_mp_list;
|
||||
cur = (*mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut submime: *mut Mailmime = 0 as *mut Mailmime;
|
||||
submime = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut Mailmime;
|
||||
(*submime).mm_parent = mime;
|
||||
(*submime).mm_parent_type = MAILMIME_MULTIPLE as libc::c_int;
|
||||
(*submime).mm_multipart_pos = cur;
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
(*mime).mm_data.mm_message.mm_fields = mm_fields;
|
||||
(*mime).mm_data.mm_message.mm_msg_mime = mm_msg_mime;
|
||||
if !mm_msg_mime.is_null() {
|
||||
(*mm_msg_mime).mm_parent = mime;
|
||||
(*mm_msg_mime).mm_parent_type = MAILMIME_MESSAGE as libc::c_int
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_free(mut mime: *mut Mailmime) {
|
||||
match (*mime).mm_type {
|
||||
1 => {
|
||||
if (*mime).mm_body.is_null() && !(*mime).mm_data.mm_single.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_single);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
/* do nothing */
|
||||
if !(*mime).mm_data.mm_multipart.mm_preamble.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_multipart.mm_preamble);
|
||||
}
|
||||
if !(*mime).mm_data.mm_multipart.mm_epilogue.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_multipart.mm_epilogue);
|
||||
}
|
||||
clist_foreach(
|
||||
(*mime).mm_data.mm_multipart.mm_mp_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut Mailmime) -> ()>, clist_func>(
|
||||
Some(mailmime_free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*mime).mm_data.mm_multipart.mm_mp_list);
|
||||
}
|
||||
3 => {
|
||||
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
|
||||
mailimf_fields_free((*mime).mm_data.mm_message.mm_fields);
|
||||
}
|
||||
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
|
||||
mailmime_free((*mime).mm_data.mm_message.mm_msg_mime);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !(*mime).mm_body.is_null() {
|
||||
mailmime_data_free((*mime).mm_body);
|
||||
}
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
mailmime_fields_free((*mime).mm_mime_fields);
|
||||
}
|
||||
if !(*mime).mm_content_type.is_null() {
|
||||
mailmime_content_free((*mime).mm_content_type);
|
||||
}
|
||||
free(mime as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_new(
|
||||
mut wd_charset: *mut libc::c_char,
|
||||
mut wd_text: *mut libc::c_char,
|
||||
) -> *mut mailmime_encoded_word {
|
||||
let mut ew: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
ew = malloc(::std::mem::size_of::<mailmime_encoded_word>() as libc::size_t)
|
||||
as *mut mailmime_encoded_word;
|
||||
if ew.is_null() {
|
||||
return 0 as *mut mailmime_encoded_word;
|
||||
}
|
||||
(*ew).wd_charset = wd_charset;
|
||||
(*ew).wd_text = wd_text;
|
||||
return ew;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_free(mut ew: *mut mailmime_encoded_word) {
|
||||
mailmime_charset_free((*ew).wd_charset);
|
||||
mailmime_encoded_text_free((*ew).wd_text);
|
||||
free(ew as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_text_free(mut text: *mut libc::c_char) {
|
||||
free(text as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_charset_free(mut charset: *mut libc::c_char) {
|
||||
free(charset as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_new(
|
||||
mut dsp_type: *mut mailmime_disposition_type,
|
||||
mut dsp_parms: *mut clist,
|
||||
) -> *mut mailmime_disposition {
|
||||
let mut dsp: *mut mailmime_disposition = 0 as *mut mailmime_disposition;
|
||||
dsp = malloc(::std::mem::size_of::<mailmime_disposition>() as libc::size_t)
|
||||
as *mut mailmime_disposition;
|
||||
if dsp.is_null() {
|
||||
return 0 as *mut mailmime_disposition;
|
||||
}
|
||||
(*dsp).dsp_type = dsp_type;
|
||||
(*dsp).dsp_parms = dsp_parms;
|
||||
return dsp;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_new(
|
||||
mut dsp_type: libc::c_int,
|
||||
mut dsp_extension: *mut libc::c_char,
|
||||
) -> *mut mailmime_disposition_type {
|
||||
let mut m_dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
m_dsp_type = malloc(::std::mem::size_of::<mailmime_disposition_type>() as libc::size_t)
|
||||
as *mut mailmime_disposition_type;
|
||||
if m_dsp_type.is_null() {
|
||||
return 0 as *mut mailmime_disposition_type;
|
||||
}
|
||||
(*m_dsp_type).dsp_type = dsp_type;
|
||||
(*m_dsp_type).dsp_extension = dsp_extension;
|
||||
return m_dsp_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_parm_new(
|
||||
mut pa_type: libc::c_int,
|
||||
mut pa_filename: *mut libc::c_char,
|
||||
mut pa_creation_date: *mut libc::c_char,
|
||||
mut pa_modification_date: *mut libc::c_char,
|
||||
mut pa_read_date: *mut libc::c_char,
|
||||
mut pa_size: size_t,
|
||||
mut pa_parameter: *mut mailmime_parameter,
|
||||
) -> *mut mailmime_disposition_parm {
|
||||
let mut dsp_parm: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
dsp_parm = malloc(::std::mem::size_of::<mailmime_disposition_parm>() as libc::size_t)
|
||||
as *mut mailmime_disposition_parm;
|
||||
if dsp_parm.is_null() {
|
||||
return 0 as *mut mailmime_disposition_parm;
|
||||
}
|
||||
(*dsp_parm).pa_type = pa_type;
|
||||
match pa_type {
|
||||
0 => (*dsp_parm).pa_data.pa_filename = pa_filename,
|
||||
1 => (*dsp_parm).pa_data.pa_creation_date = pa_creation_date,
|
||||
2 => (*dsp_parm).pa_data.pa_modification_date = pa_modification_date,
|
||||
3 => (*dsp_parm).pa_data.pa_read_date = pa_read_date,
|
||||
4 => (*dsp_parm).pa_data.pa_size = pa_size,
|
||||
5 => (*dsp_parm).pa_data.pa_parameter = pa_parameter,
|
||||
_ => {}
|
||||
}
|
||||
return dsp_parm;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_section_new(mut sec_list: *mut clist) -> *mut mailmime_section {
|
||||
let mut section: *mut mailmime_section = 0 as *mut mailmime_section;
|
||||
section =
|
||||
malloc(::std::mem::size_of::<mailmime_section>() as libc::size_t) as *mut mailmime_section;
|
||||
if section.is_null() {
|
||||
return 0 as *mut mailmime_section;
|
||||
}
|
||||
(*section).sec_list = sec_list;
|
||||
return section;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_section_free(mut section: *mut mailmime_section) {
|
||||
clist_foreach(
|
||||
(*section).sec_list,
|
||||
::std::mem::transmute::<Option<unsafe extern "C" fn(_: *mut libc::c_void) -> ()>, clist_func>(
|
||||
Some(free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*section).sec_list);
|
||||
free(section as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_decoded_part_free(mut part: *mut libc::c_char) {
|
||||
mmap_string_unref(part);
|
||||
}
|
||||
1445
mmime/src/mailmime/types_helper.rs
Normal file
1445
mmime/src/mailmime/types_helper.rs
Normal file
File diff suppressed because it is too large
Load Diff
1979
mmime/src/mailmime/write_generic.rs
Normal file
1979
mmime/src/mailmime/write_generic.rs
Normal file
File diff suppressed because it is too large
Load Diff
82
mmime/src/mailmime/write_mem.rs
Normal file
82
mmime/src/mailmime/write_mem.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mailmime::write_generic::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
unsafe fn do_write(
|
||||
mut data: *mut libc::c_void,
|
||||
mut str: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
) -> libc::c_int {
|
||||
let mut f: *mut MMAPString = 0 as *mut MMAPString;
|
||||
f = data as *mut MMAPString;
|
||||
if mmap_string_append_len(f, str, length).is_null() {
|
||||
return 0i32;
|
||||
} else {
|
||||
return length as libc::c_int;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut content: *mut mailmime_content,
|
||||
) -> libc::c_int {
|
||||
return mailmime_content_write_driver(Some(do_write), f as *mut libc::c_void, col, content);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_type_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut content: *mut mailmime_content,
|
||||
) -> libc::c_int {
|
||||
return mailmime_content_type_write_driver(
|
||||
Some(do_write),
|
||||
f as *mut libc::c_void,
|
||||
col,
|
||||
content,
|
||||
);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut build_info: *mut Mailmime,
|
||||
) -> libc::c_int {
|
||||
return mailmime_write_driver(Some(do_write), f as *mut libc::c_void, col, build_info);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_quoted_printable_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut istext: libc::c_int,
|
||||
mut text: *const libc::c_char,
|
||||
mut size: size_t,
|
||||
) -> libc::c_int {
|
||||
return mailmime_quoted_printable_write_driver(
|
||||
Some(do_write),
|
||||
f as *mut libc::c_void,
|
||||
col,
|
||||
istext,
|
||||
text,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_base64_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut text: *const libc::c_char,
|
||||
mut size: size_t,
|
||||
) -> libc::c_int {
|
||||
return mailmime_base64_write_driver(Some(do_write), f as *mut libc::c_void, col, text, size);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut data: *mut mailmime_data,
|
||||
mut istext: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
return mailmime_data_write_driver(Some(do_write), f as *mut libc::c_void, col, data, istext);
|
||||
}
|
||||
397
mmime/src/mmapstring.rs
Normal file
397
mmime/src/mmapstring.rs
Normal file
@@ -0,0 +1,397 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use libc;
|
||||
|
||||
use crate::chash::*;
|
||||
use crate::other::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref mmapstring_lock: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct MMAPString {
|
||||
pub str_0: *mut libc::c_char,
|
||||
pub len: size_t,
|
||||
pub allocated_len: size_t,
|
||||
pub fd: libc::c_int,
|
||||
pub mmapped_size: size_t,
|
||||
}
|
||||
|
||||
pub const TMPDIR: &'static str = "/tmp";
|
||||
|
||||
pub unsafe fn mmap_string_new(mut init: *const libc::c_char) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
string = mmap_string_sized_new(if !init.is_null() {
|
||||
strlen(init).wrapping_add(2i32 as libc::size_t)
|
||||
} else {
|
||||
2i32 as libc::size_t
|
||||
});
|
||||
if string.is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if !init.is_null() {
|
||||
mmap_string_append(string, init);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, (*string).len, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if mmap_string_maybe_expand(string, len).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if pos < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize).offset(len as isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos),
|
||||
);
|
||||
}
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize) as *mut libc::c_void,
|
||||
val as *const libc::c_void,
|
||||
len,
|
||||
);
|
||||
(*string).len = ((*string).len as libc::size_t).wrapping_add(len) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
unsafe fn mmap_string_maybe_expand(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if (*string).len.wrapping_add(len) >= (*string).allocated_len {
|
||||
let mut old_size: size_t = 0;
|
||||
let mut newstring: *mut MMAPString = 0 as *mut MMAPString;
|
||||
old_size = (*string).allocated_len;
|
||||
(*string).allocated_len = nearest_power(
|
||||
1i32 as size_t,
|
||||
(*string)
|
||||
.len
|
||||
.wrapping_add(len)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
);
|
||||
newstring = mmap_string_realloc_memory(string);
|
||||
if newstring.is_null() {
|
||||
(*string).allocated_len = old_size
|
||||
}
|
||||
return newstring;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
/* Strings.
|
||||
*/
|
||||
/* SEB */
|
||||
unsafe fn mmap_string_realloc_memory(mut string: *mut MMAPString) -> *mut MMAPString {
|
||||
let mut tmp: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
tmp = realloc(
|
||||
(*string).str_0 as *mut libc::c_void,
|
||||
(*string).allocated_len,
|
||||
) as *mut libc::c_char;
|
||||
if tmp.is_null() {
|
||||
string = 0 as *mut MMAPString
|
||||
} else {
|
||||
(*string).str_0 = tmp
|
||||
}
|
||||
return string;
|
||||
}
|
||||
/* MMAPString */
|
||||
#[inline]
|
||||
unsafe fn nearest_power(mut base: size_t, mut num: size_t) -> size_t {
|
||||
if num > (-1i32 as size_t).wrapping_div(2i32 as libc::size_t) {
|
||||
return -1i32 as size_t;
|
||||
} else {
|
||||
let mut n: size_t = base;
|
||||
while n < num {
|
||||
n <<= 1i32
|
||||
}
|
||||
return n;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_sized_new(mut dfl_size: size_t) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
string = malloc(::std::mem::size_of::<MMAPString>() as libc::size_t) as *mut MMAPString;
|
||||
if string.is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
(*string).allocated_len = 0i32 as size_t;
|
||||
(*string).len = 0i32 as size_t;
|
||||
(*string).str_0 = 0 as *mut libc::c_char;
|
||||
(*string).fd = -1i32;
|
||||
(*string).mmapped_size = 0i32 as size_t;
|
||||
if mmap_string_maybe_expand(
|
||||
string,
|
||||
if dfl_size > 2i32 as libc::size_t {
|
||||
dfl_size
|
||||
} else {
|
||||
2i32 as libc::size_t
|
||||
},
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
free(string as *mut libc::c_void);
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
*(*string).str_0.offset(0isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_new_len(
|
||||
mut init: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
if len <= 0i32 as libc::size_t {
|
||||
return mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
} else {
|
||||
string = mmap_string_sized_new(len);
|
||||
if string.is_null() {
|
||||
return string;
|
||||
}
|
||||
if !init.is_null() {
|
||||
mmap_string_append_len(string, init, len);
|
||||
}
|
||||
return string;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, (*string).len, val, len);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_free(mut string: *mut MMAPString) {
|
||||
if string.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*string).str_0 as *mut libc::c_void);
|
||||
free(string as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_assign(
|
||||
mut string: *mut MMAPString,
|
||||
mut rval: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
mmap_string_truncate(string, 0i32 as size_t);
|
||||
if mmap_string_append(string, rval).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_truncate(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
(*string).len = if len < (*string).len {
|
||||
len
|
||||
} else {
|
||||
(*string).len
|
||||
};
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_set_size(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if len >= (*string).allocated_len {
|
||||
if mmap_string_maybe_expand(string, len.wrapping_sub((*string).len)).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
}
|
||||
(*string).len = len;
|
||||
*(*string).str_0.offset(len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_c(string, (*string).len, c);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
if mmap_string_maybe_expand(string, 1i32 as size_t).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if pos < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize).offset(1isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos),
|
||||
);
|
||||
}
|
||||
*(*string).str_0.offset(pos as isize) = c;
|
||||
(*string).len =
|
||||
((*string).len as libc::size_t).wrapping_add(1i32 as libc::size_t) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, 0i32 as size_t, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_c(string, 0i32 as size_t, c);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, 0i32 as size_t, val, len);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, pos, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_erase(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if pos.wrapping_add(len) < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize).offset(len as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos.wrapping_add(len)),
|
||||
);
|
||||
}
|
||||
(*string).len = ((*string).len as libc::size_t).wrapping_sub(len) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_set_ceil(mut ceil: size_t) {
|
||||
mmap_string_ceil = ceil;
|
||||
}
|
||||
static mut mmap_string_ceil: size_t = (8i32 * 1024i32 * 1024i32) as size_t;
|
||||
|
||||
pub unsafe fn mmap_string_ref(mut string: *mut MMAPString) -> libc::c_int {
|
||||
let mut ht: *mut chash = 0 as *mut chash;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut key: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut data: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
mmapstring_lock.lock().unwrap();
|
||||
if mmapstring_hashtable.is_null() {
|
||||
mmapstring_hashtable_init();
|
||||
}
|
||||
ht = mmapstring_hashtable;
|
||||
if ht.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
key.data = &mut (*string).str_0 as *mut *mut libc::c_char as *mut libc::c_void;
|
||||
key.len = ::std::mem::size_of::<*mut libc::c_char>() as libc::size_t as libc::c_uint;
|
||||
data.data = string as *mut libc::c_void;
|
||||
data.len = 0i32 as libc::c_uint;
|
||||
r = chash_set(
|
||||
mmapstring_hashtable,
|
||||
&mut key,
|
||||
&mut data,
|
||||
0 as *mut chashdatum,
|
||||
);
|
||||
|
||||
if r < 0i32 {
|
||||
return r;
|
||||
}
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
static mut mmapstring_hashtable: *mut chash = 0 as *const chash as *mut chash;
|
||||
unsafe fn mmapstring_hashtable_init() {
|
||||
mmapstring_hashtable = chash_new(13i32 as libc::c_uint, 1i32);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_unref(mut str: *mut libc::c_char) -> libc::c_int {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
let mut ht: *mut chash = 0 as *mut chash;
|
||||
let mut key: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut data: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut r: libc::c_int = 0;
|
||||
if str.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
mmapstring_lock.lock().unwrap();
|
||||
ht = mmapstring_hashtable;
|
||||
if ht.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
key.data = &mut str as *mut *mut libc::c_char as *mut libc::c_void;
|
||||
key.len = ::std::mem::size_of::<*mut libc::c_char>() as libc::size_t as libc::c_uint;
|
||||
r = chash_get(ht, &mut key, &mut data);
|
||||
if r < 0i32 {
|
||||
string = 0 as *mut MMAPString
|
||||
} else {
|
||||
string = data.data as *mut MMAPString
|
||||
}
|
||||
if !string.is_null() {
|
||||
chash_delete(ht, &mut key, 0 as *mut chashdatum);
|
||||
if chash_count(ht) == 0i32 as libc::c_uint {
|
||||
chash_free(ht);
|
||||
mmapstring_hashtable = 0 as *mut chash
|
||||
}
|
||||
}
|
||||
if !string.is_null() {
|
||||
mmap_string_free(string);
|
||||
return 0i32;
|
||||
} else {
|
||||
return -1i32;
|
||||
};
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn chash_count(mut hash: *mut chash) -> libc::c_uint {
|
||||
return (*hash).count;
|
||||
}
|
||||
|
||||
pub unsafe fn mmapstring_init_lock() {}
|
||||
pub unsafe fn mmapstring_uninit_lock() {}
|
||||
1707
mmime/src/other.rs
Normal file
1707
mmime/src/other.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,3 +5,4 @@
|
||||
# It is recommended to check this file in to source control so that
|
||||
# everyone who runs the test benefits from these saved cases.
|
||||
cc 679506fe9ac59df773f8cfa800fdab5f0a32fe49d2ab370394000a1aa5bc2a72 # shrinks to buf = "%0A"
|
||||
cc e34960438edb2426904b44fb4215154e7e2880f2fd1c3183b98bfcc76fec4882 # shrinks to input = " 0"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ["DCC_RS_TARGET"] = target = "release"
|
||||
@@ -21,5 +21,5 @@ if __name__ == "__main__":
|
||||
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
|
||||
|
||||
subprocess.check_call([
|
||||
"pip", "install", "-e", "."
|
||||
sys.executable, "-m", "pip", "install", "-e", "."
|
||||
])
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import threading
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from array import array
|
||||
@@ -23,7 +22,7 @@ class Account(object):
|
||||
by the underlying deltachat c-library. All public Account methods are
|
||||
meant to be memory-safe and return memory-safe objects.
|
||||
"""
|
||||
def __init__(self, db_path, logid=None, eventlogging=True):
|
||||
def __init__(self, db_path, logid=None, eventlogging=True, debug=True):
|
||||
""" initialize account object.
|
||||
|
||||
:param db_path: a path to the account database. The database
|
||||
@@ -31,13 +30,14 @@ class Account(object):
|
||||
:param logid: an optional logging prefix that should be used with
|
||||
the default internal logging.
|
||||
:param eventlogging: if False no eventlogging and no context callback will be configured
|
||||
:param debug: turn on debug logging for events.
|
||||
"""
|
||||
self._dc_context = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
_destroy_dc_context,
|
||||
)
|
||||
if eventlogging:
|
||||
self._evlogger = EventLogger(self._dc_context, logid)
|
||||
self._evlogger = EventLogger(self._dc_context, logid, debug)
|
||||
deltachat.set_context_callback(self._dc_context, self._process_event)
|
||||
self._threads = IOThreads(self._dc_context, self._evlogger._log_event)
|
||||
else:
|
||||
@@ -48,7 +48,7 @@ class Account(object):
|
||||
if not lib.dc_open(self._dc_context, db_path, ffi.NULL):
|
||||
raise ValueError("Could not dc_open: {}".format(db_path))
|
||||
self._configkeys = self.get_config("sys.config_keys").split()
|
||||
self._imex_completed = threading.Event()
|
||||
self._imex_events = Queue()
|
||||
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
@@ -231,7 +231,7 @@ class Account(object):
|
||||
:returns: a :class:`deltachat.chatting.Chat` object.
|
||||
"""
|
||||
bytes_name = name.encode("utf8")
|
||||
chat_id = lib.dc_create_group_chat(self._dc_context, verified, bytes_name)
|
||||
chat_id = lib.dc_create_group_chat(self._dc_context, int(verified), bytes_name)
|
||||
return Chat(self, chat_id)
|
||||
|
||||
def get_chats(self):
|
||||
@@ -289,31 +289,64 @@ class Account(object):
|
||||
msg_ids = [msg.id for msg in messages]
|
||||
lib.dc_delete_msgs(self._dc_context, msg_ids, len(msg_ids))
|
||||
|
||||
def export_to_dir(self, backupdir):
|
||||
"""return after all delta chat state is exported to a new file in
|
||||
the specified directory.
|
||||
def export_self_keys(self, path):
|
||||
""" export public and private keys to the specified directory. """
|
||||
return self._export(path, imex_cmd=1)
|
||||
|
||||
def export_all(self, path):
|
||||
"""return new file containing a backup of all database state
|
||||
(chats, contacts, keys, media, ...). The file is created in the
|
||||
the `path` directory.
|
||||
"""
|
||||
snap_files = os.listdir(backupdir)
|
||||
self._imex_completed.clear()
|
||||
lib.dc_imex(self._dc_context, 11, as_dc_charpointer(backupdir), ffi.NULL)
|
||||
export_files = self._export(path, 11)
|
||||
if len(export_files) != 1:
|
||||
raise RuntimeError("found more than one new file")
|
||||
return export_files[0]
|
||||
|
||||
def _imex_events_clear(self):
|
||||
try:
|
||||
while True:
|
||||
self._imex_events.get_nowait()
|
||||
except Empty:
|
||||
pass
|
||||
|
||||
def _export(self, path, imex_cmd):
|
||||
self._imex_events_clear()
|
||||
lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL)
|
||||
if not self._threads.is_started():
|
||||
lib.dc_perform_imap_jobs(self._dc_context)
|
||||
self._imex_completed.wait()
|
||||
for x in os.listdir(backupdir):
|
||||
if x not in snap_files:
|
||||
return os.path.join(backupdir, x)
|
||||
files_written = []
|
||||
while True:
|
||||
ev = self._imex_events.get()
|
||||
if isinstance(ev, str):
|
||||
files_written.append(ev)
|
||||
elif isinstance(ev, bool):
|
||||
if not ev:
|
||||
raise ValueError("export failed, exp-files: {}".format(files_written))
|
||||
return files_written
|
||||
|
||||
def import_from_file(self, path):
|
||||
"""import delta chat state from the specified backup file.
|
||||
def import_self_keys(self, path):
|
||||
""" Import private keys found in the `path` directory.
|
||||
The last imported key is made the default keys unless its name
|
||||
contains the string legacy. Public keys are not imported.
|
||||
"""
|
||||
self._import(path, imex_cmd=2)
|
||||
|
||||
def import_all(self, path):
|
||||
"""import delta chat state from the specified backup `path` (a file).
|
||||
|
||||
The account must be in unconfigured state for import to attempted.
|
||||
"""
|
||||
assert not self.is_configured(), "cannot import into configured account"
|
||||
self._imex_completed.clear()
|
||||
lib.dc_imex(self._dc_context, 12, as_dc_charpointer(path), ffi.NULL)
|
||||
self._import(path, imex_cmd=12)
|
||||
|
||||
def _import(self, path, imex_cmd):
|
||||
self._imex_events_clear()
|
||||
lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL)
|
||||
if not self._threads.is_started():
|
||||
lib.dc_perform_imap_jobs(self._dc_context)
|
||||
self._imex_completed.wait()
|
||||
if not self._imex_events.get():
|
||||
raise ValueError("import from path '{}' failed".format(path))
|
||||
|
||||
def initiate_key_transfer(self):
|
||||
"""return setup code after a Autocrypt setup message
|
||||
@@ -378,7 +411,16 @@ class Account(object):
|
||||
raise ValueError("could not join group")
|
||||
return Chat(self, chat_id)
|
||||
|
||||
def start_threads(self):
|
||||
#
|
||||
# meta API for start/stop and event based processing
|
||||
#
|
||||
|
||||
def wait_next_incoming_message(self):
|
||||
""" wait for and return next incoming message. """
|
||||
ev = self._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||
return self.get_message_by_id(ev[2])
|
||||
|
||||
def start_threads(self, mvbox=False, sentbox=False):
|
||||
""" start IMAP/SMTP threads (and configure account if it hasn't happened).
|
||||
|
||||
:raises: ValueError if 'addr' or 'mail_pw' are not configured.
|
||||
@@ -386,7 +428,7 @@ class Account(object):
|
||||
"""
|
||||
if not self.is_configured():
|
||||
self.configure()
|
||||
self._threads.start()
|
||||
self._threads.start(mvbox=mvbox, sentbox=sentbox)
|
||||
|
||||
def stop_threads(self, wait=True):
|
||||
""" stop IMAP/SMTP threads. """
|
||||
@@ -414,7 +456,12 @@ class Account(object):
|
||||
|
||||
def on_dc_event_imex_progress(self, data1, data2):
|
||||
if data1 == 1000:
|
||||
self._imex_completed.set()
|
||||
self._imex_events.put(True)
|
||||
elif data1 == 0:
|
||||
self._imex_events.put(False)
|
||||
|
||||
def on_dc_event_imex_file_written(self, data1, data2):
|
||||
self._imex_events.put(data1)
|
||||
|
||||
|
||||
class IOThreads:
|
||||
@@ -427,10 +474,14 @@ class IOThreads:
|
||||
def is_started(self):
|
||||
return len(self._name2thread) > 0
|
||||
|
||||
def start(self, imap=True, smtp=True):
|
||||
def start(self, imap=True, smtp=True, mvbox=False, sentbox=False):
|
||||
assert not self.is_started()
|
||||
if imap:
|
||||
self._start_one_thread("imap", self.imap_thread_run)
|
||||
self._start_one_thread("inbox", self.imap_thread_run)
|
||||
if mvbox:
|
||||
self._start_one_thread("mvbox", self.mvbox_thread_run)
|
||||
if sentbox:
|
||||
self._start_one_thread("sentbox", self.sentbox_thread_run)
|
||||
if smtp:
|
||||
self._start_one_thread("smtp", self.smtp_thread_run)
|
||||
|
||||
@@ -443,17 +494,35 @@ class IOThreads:
|
||||
self._thread_quitflag = True
|
||||
lib.dc_interrupt_imap_idle(self._dc_context)
|
||||
lib.dc_interrupt_smtp_idle(self._dc_context)
|
||||
lib.dc_interrupt_mvbox_idle(self._dc_context)
|
||||
lib.dc_interrupt_sentbox_idle(self._dc_context)
|
||||
if wait:
|
||||
for name, thread in self._name2thread.items():
|
||||
thread.join()
|
||||
|
||||
def imap_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD START")
|
||||
self._log_event("py-bindings-info", 0, "INBOX THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_imap_jobs(self._dc_context)
|
||||
lib.dc_perform_imap_fetch(self._dc_context)
|
||||
lib.dc_perform_imap_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "IMAP THREAD FINISHED")
|
||||
self._log_event("py-bindings-info", 0, "INBOX THREAD FINISHED")
|
||||
|
||||
def mvbox_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "MVBOX THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_mvbox_jobs(self._dc_context)
|
||||
lib.dc_perform_mvbox_fetch(self._dc_context)
|
||||
lib.dc_perform_mvbox_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "MVBOX THREAD FINISHED")
|
||||
|
||||
def sentbox_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "SENTBOX THREAD START")
|
||||
while not self._thread_quitflag:
|
||||
lib.dc_perform_sentbox_jobs(self._dc_context)
|
||||
lib.dc_perform_sentbox_fetch(self._dc_context)
|
||||
lib.dc_perform_sentbox_idle(self._dc_context)
|
||||
self._log_event("py-bindings-info", 0, "SENTBOX THREAD FINISHED")
|
||||
|
||||
def smtp_thread_run(self):
|
||||
self._log_event("py-bindings-info", 0, "SMTP THREAD START")
|
||||
|
||||
@@ -109,6 +109,13 @@ class Chat(object):
|
||||
"""
|
||||
return not lib.dc_chat_is_unpromoted(self._dc_chat)
|
||||
|
||||
def is_verified(self):
|
||||
""" return True if this chat is a verified group.
|
||||
|
||||
:returns: True if chat is verified, False otherwise.
|
||||
"""
|
||||
return lib.dc_chat_is_verified(self._dc_chat)
|
||||
|
||||
def get_name(self):
|
||||
""" return name of this chat.
|
||||
|
||||
|
||||
@@ -101,6 +101,14 @@ class Message(object):
|
||||
""" return True if this message is a setup message. """
|
||||
return lib.dc_msg_is_setupmessage(self._dc_msg)
|
||||
|
||||
def get_setupcodebegin(self):
|
||||
""" return the first characters of a setup code in a setup message. """
|
||||
return from_dc_charpointer(lib.dc_msg_get_setupcodebegin(self._dc_msg))
|
||||
|
||||
def is_encrypted(self):
|
||||
""" return True if this message was encrypted. """
|
||||
return bool(lib.dc_msg_get_showpadlock(self._dc_msg))
|
||||
|
||||
def get_message_info(self):
|
||||
""" Return informational text for a single message.
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
lib.dc_set_config(ac._dc_context, b"configured", b"1")
|
||||
return ac
|
||||
|
||||
def get_online_configuring_account(self):
|
||||
def get_online_config(self):
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
configdict = session_liveconfig.get(self.live_count)
|
||||
@@ -161,8 +161,12 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
ac = self.make_account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
ac._evlogger.set_timeout(30)
|
||||
return ac, dict(configdict)
|
||||
|
||||
def get_online_configuring_account(self, mvbox=False, sentbox=False):
|
||||
ac, configdict = self.get_online_config()
|
||||
ac.configure(**configdict)
|
||||
ac.start_threads()
|
||||
ac.start_threads(mvbox=mvbox, sentbox=sentbox)
|
||||
return ac
|
||||
|
||||
def get_two_online_accounts(self):
|
||||
@@ -206,12 +210,13 @@ def lp():
|
||||
return Printer()
|
||||
|
||||
|
||||
def wait_configuration_progress(account, target):
|
||||
def wait_configuration_progress(account, min_target, max_target=1001):
|
||||
min_target = min(min_target, max_target)
|
||||
while 1:
|
||||
evt_name, data1, data2 = \
|
||||
account._evlogger.get_matching("DC_EVENT_CONFIGURE_PROGRESS")
|
||||
if data1 >= target:
|
||||
print("** CONFIG PROGRESS {}".format(target), account)
|
||||
if data1 >= min_target and data1 <= max_target:
|
||||
print("** CONFIG PROGRESS {}".format(min_target), account)
|
||||
break
|
||||
|
||||
|
||||
|
||||
@@ -93,8 +93,9 @@ class TestOfflineContact:
|
||||
ac1 = acfactory.get_configured_offline_account()
|
||||
contact1 = ac1.create_contact(email="some1@example.com", name="some1")
|
||||
chat = ac1.create_chat_by_contact(contact1)
|
||||
chat.send_text("one messae")
|
||||
msg = chat.send_text("one messae")
|
||||
assert not ac1.delete_contact(contact1)
|
||||
assert not msg.filemime
|
||||
|
||||
|
||||
class TestOfflineChat:
|
||||
@@ -106,7 +107,7 @@ class TestOfflineChat:
|
||||
def chat1(self, ac1):
|
||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||
chat = ac1.create_chat_by_contact(contact1)
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
||||
return chat
|
||||
|
||||
def test_display(self, chat1):
|
||||
@@ -293,10 +294,10 @@ class TestOfflineChat:
|
||||
assert contact == ac1.get_self_contact()
|
||||
assert not backupdir.listdir()
|
||||
|
||||
path = ac1.export_to_dir(backupdir.strpath)
|
||||
path = ac1.export_all(backupdir.strpath)
|
||||
assert os.path.exists(path)
|
||||
ac2 = acfactory.get_unconfigured_account()
|
||||
ac2.import_from_file(path)
|
||||
ac2.import_all(path)
|
||||
contacts = ac2.get_contacts(query="some1")
|
||||
assert len(contacts) == 1
|
||||
contact2 = contacts[0]
|
||||
@@ -337,14 +338,24 @@ class TestOnlineAccount:
|
||||
def get_chat(self, ac1, ac2):
|
||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
return chat
|
||||
|
||||
def test_export_import_self_keys(self, acfactory, tmpdir):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
dir = tmpdir.mkdir("exportdir")
|
||||
export_files = ac1.export_self_keys(dir.strpath)
|
||||
assert len(export_files) == 2
|
||||
for x in export_files:
|
||||
assert x.startswith(dir.strpath)
|
||||
ac1._evlogger.consume_events()
|
||||
ac1.import_self_keys(dir.strpath)
|
||||
|
||||
def test_one_account_send(self, acfactory):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
c2 = ac1.create_contact(email=ac1.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
wait_successful_IMAP_SMTP_connection(ac1)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
|
||||
@@ -353,17 +364,15 @@ class TestOnlineAccount:
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[1] == msg_out.id
|
||||
|
||||
def test_two_accounts_send_receive(self, acfactory):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
def test_mvbox_sentbox_threads(self, acfactory):
|
||||
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)
|
||||
chat = self.get_chat(ac1, ac2)
|
||||
|
||||
msg_out = chat.send_text("message1")
|
||||
|
||||
# wait for other account to receive
|
||||
chat.send_text("message1")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] == msg_out.id
|
||||
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||
assert msg_in.text == "message1"
|
||||
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
|
||||
def test_forward_messages(self, acfactory):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
@@ -390,7 +399,7 @@ class TestOnlineAccount:
|
||||
ac2.delete_messages(messages)
|
||||
assert not chat3.get_messages()
|
||||
|
||||
def test_send_and_receive_message(self, acfactory, lp):
|
||||
def test_send_and_receive_message_markseen(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
|
||||
lp.sec("ac1: create chat with ac2")
|
||||
@@ -430,8 +439,8 @@ class TestOnlineAccount:
|
||||
ac2.mark_seen_messages([msg_in])
|
||||
lp.step("1")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
||||
assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL
|
||||
assert ev[1] > const.DC_CHAT_ID_LAST_SPECIAL
|
||||
assert ev[2] > const.DC_MSG_ID_LAST_SPECIAL
|
||||
lp.step("2")
|
||||
assert msg_out.is_out_mdn_received()
|
||||
|
||||
@@ -443,6 +452,7 @@ class TestOnlineAccount:
|
||||
|
||||
lp.sec("sending text message from ac1 to ac2")
|
||||
msg_out = chat.send_text("message1")
|
||||
assert not msg_out.is_encrypted()
|
||||
|
||||
lp.sec("wait for ac2 to receive message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
@@ -460,6 +470,7 @@ class TestOnlineAccount:
|
||||
assert ev[2] > msg_out.id
|
||||
msg_back = ac1.get_message_by_id(ev[2])
|
||||
assert msg_back.text == "message-back"
|
||||
assert msg_back.is_encrypted()
|
||||
|
||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
@@ -501,7 +512,7 @@ class TestOnlineAccount:
|
||||
assert os.path.exists(msg_in.filename)
|
||||
assert os.stat(msg_in.filename).st_size == os.stat(path).st_size
|
||||
|
||||
def test_import_export_online(self, acfactory, tmpdir):
|
||||
def test_import_export_online_all(self, acfactory, tmpdir):
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
|
||||
@@ -509,11 +520,11 @@ class TestOnlineAccount:
|
||||
chat = ac1.create_chat_by_contact(contact1)
|
||||
chat.send_text("msg1")
|
||||
backupdir = tmpdir.mkdir("backup")
|
||||
path = ac1.export_to_dir(backupdir.strpath)
|
||||
path = ac1.export_all(backupdir.strpath)
|
||||
assert os.path.exists(path)
|
||||
|
||||
ac2 = acfactory.get_unconfigured_account()
|
||||
ac2.import_from_file(path)
|
||||
ac2.import_all(path)
|
||||
contacts = ac2.get_contacts(query="some1")
|
||||
assert len(contacts) == 1
|
||||
contact2 = contacts[0]
|
||||
@@ -523,7 +534,7 @@ class TestOnlineAccount:
|
||||
assert len(messages) == 1
|
||||
assert messages[0].text == "msg1"
|
||||
|
||||
def test_ac_setup_message(self, acfactory):
|
||||
def test_ac_setup_message(self, acfactory, lp):
|
||||
# note that the receiving account needs to be configured and running
|
||||
# before ther setup message is send. DC does not read old messages
|
||||
# as of Jul2019
|
||||
@@ -531,15 +542,18 @@ class TestOnlineAccount:
|
||||
ac2 = acfactory.clone_online_account(ac1)
|
||||
wait_configuration_progress(ac2, 1000)
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
lp.sec("trigger ac setup message and return setupcode")
|
||||
assert ac1.get_info()["fingerprint"] != ac2.get_info()["fingerprint"]
|
||||
setup_code = ac1.initiate_key_transfer()
|
||||
ac2._evlogger.set_timeout(30)
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||
msg = ac2.get_message_by_id(ev[2])
|
||||
assert msg.is_setup_message()
|
||||
# first try a bad setup code
|
||||
assert msg.get_setupcodebegin() == setup_code[:2]
|
||||
lp.sec("try a bad setup code")
|
||||
with pytest.raises(ValueError):
|
||||
msg.continue_key_transfer(str(reversed(setup_code)))
|
||||
lp.sec("try a good setup code")
|
||||
print("*************** Incoming ASM File at: ", msg.filename)
|
||||
print("*************** Setup Code: ", setup_code)
|
||||
msg.continue_key_transfer(setup_code)
|
||||
@@ -564,6 +578,38 @@ class TestOnlineAccount:
|
||||
assert ch.id >= 10
|
||||
wait_securejoin_inviter_progress(ac1, 1000)
|
||||
|
||||
def test_qr_verified_group_and_chatting(self, acfactory, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
lp.sec("ac1: create verified-group QR, ac2 scans and joins")
|
||||
chat1 = ac1.create_group_chat("hello", verified=True)
|
||||
assert chat1.is_verified()
|
||||
qr = chat1.get_join_qr()
|
||||
lp.sec("ac2: start QR-code based join-group protocol")
|
||||
chat2 = ac2.qr_join_chat(qr)
|
||||
assert chat2.id >= 10
|
||||
wait_securejoin_inviter_progress(ac1, 1000)
|
||||
|
||||
lp.sec("ac2: read member added message")
|
||||
msg = ac2.wait_next_incoming_message()
|
||||
assert msg.is_encrypted()
|
||||
assert "added" in msg.text.lower()
|
||||
|
||||
lp.sec("ac1: send message")
|
||||
msg_out = chat1.send_text("hello")
|
||||
assert msg_out.is_encrypted()
|
||||
|
||||
lp.sec("ac2: read message and check it's verified chat")
|
||||
msg = ac2.wait_next_incoming_message()
|
||||
assert msg.text == "hello"
|
||||
assert msg.chat.is_verified()
|
||||
assert msg.is_encrypted()
|
||||
|
||||
lp.sec("ac2: send message and let ac1 read it")
|
||||
chat2.send_text("world")
|
||||
msg = ac1.wait_next_incoming_message()
|
||||
assert msg.text == "world"
|
||||
assert msg.is_encrypted()
|
||||
|
||||
def test_set_get_profile_image(self, acfactory, data, lp):
|
||||
ac1, ac2 = acfactory.get_two_online_accounts()
|
||||
|
||||
@@ -616,3 +662,32 @@ class TestOnlineAccount:
|
||||
chat1b = ac1.create_chat_by_message(ev[2])
|
||||
assert chat1b.get_profile_image() is None
|
||||
assert chat.get_profile_image() is None
|
||||
|
||||
|
||||
class TestOnlineConfigureFails:
|
||||
def test_invalid_password(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"], mail_pw="123")
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_user(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr="x" + configdict["addr"], mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_domain(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"] + "x", mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "could not connect" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
@@ -59,6 +59,16 @@ def test_wrong_db(tmpdir):
|
||||
assert not lib.dc_open(dc_context, p.strpath.encode("ascii"), ffi.NULL)
|
||||
|
||||
|
||||
def test_empty_blobdir(tmpdir):
|
||||
# Apparently some client code expects this to be the same as passing NULL.
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
db_fname = tmpdir.join("hello.db")
|
||||
assert lib.dc_open(ctx, db_fname.strpath.encode("ascii"), b"")
|
||||
|
||||
|
||||
def test_event_defines():
|
||||
assert const.DC_EVENT_INFO == 100
|
||||
assert const.DC_CONTACT_ID_SELF
|
||||
@@ -98,3 +108,43 @@ def test_provider_info():
|
||||
|
||||
def test_provider_info_none():
|
||||
assert lib.dc_provider_new_from_email(cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL
|
||||
|
||||
|
||||
def test_get_info_closed():
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
info = cutil.from_dc_charpointer(lib.dc_get_info(ctx))
|
||||
assert 'deltachat_core_version' in info
|
||||
assert 'database_dir' not in info
|
||||
|
||||
|
||||
def test_get_info_open(tmpdir):
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
db_fname = tmpdir.join("test.db")
|
||||
lib.dc_open(ctx, db_fname.strpath.encode("ascii"), ffi.NULL)
|
||||
info = cutil.from_dc_charpointer(lib.dc_get_info(ctx))
|
||||
assert 'deltachat_core_version' in info
|
||||
assert 'database_dir' in info
|
||||
|
||||
|
||||
def test_is_open_closed():
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
assert lib.dc_is_open(ctx) == 0
|
||||
|
||||
|
||||
def test_is_open_actually_open(tmpdir):
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
db_fname = tmpdir.join("test.db")
|
||||
lib.dc_open(ctx, db_fname.strpath.encode("ascii"), ffi.NULL)
|
||||
assert lib.dc_is_open(ctx) == 1
|
||||
|
||||
23
spec.md
23
spec.md
@@ -117,7 +117,8 @@ The sender plus the recipients are the group members.
|
||||
To allow different groups with the same members,
|
||||
groups are identified by a group-id.
|
||||
The group-id MUST be created only from the characters
|
||||
`0`-`9`, `A`-`Z`, `a`-`z` `_` and `-`.
|
||||
`0`-`9`, `A`-`Z`, `a`-`z` `_` and `-`
|
||||
and MUST have a length of at least 11 characters.
|
||||
|
||||
Groups MUST have a group-name.
|
||||
The group-name is any non-zero-length UTF-8 string.
|
||||
@@ -144,9 +145,9 @@ The message-id MUST have the format `Gr.<group-id>.<unique data>`.
|
||||
From: member1@domain
|
||||
To: member2@domain, member3@domain
|
||||
Chat-Version: 1.0
|
||||
Chat-Group-ID: 1234xyZ
|
||||
Chat-Group-ID: 12345uvwxyZ
|
||||
Chat-Group-Name: My Group
|
||||
Message-ID: Gr.1234xyZ.0001@domain
|
||||
Message-ID: Gr.12345uvwxyZ.0001@domain
|
||||
Subject: Chat: My Group: Hello group ...
|
||||
|
||||
Hello group - this group contains three members
|
||||
@@ -196,10 +197,10 @@ and the message SHOULD appear as a message or action from the sender.
|
||||
From: member1@domain
|
||||
To: member2@domain, member3@domain, member4@domain
|
||||
Chat-Version: 1.0
|
||||
Chat-Group-ID: 1234xyZ
|
||||
Chat-Group-ID: 12345uvwxyZ
|
||||
Chat-Group-Name: My Group
|
||||
Chat-Group-Member-Added: member4@domain
|
||||
Message-ID: Gr.1234xyZ.0002@domain
|
||||
Message-ID: Gr.12345uvwxyZ.0002@domain
|
||||
Subject: Chat: My Group: Hello, ...
|
||||
|
||||
Hello, I've added member4@domain to our group. Now we have 4 members.
|
||||
@@ -209,10 +210,10 @@ To remove a member:
|
||||
From: member1@domain
|
||||
To: member2@domain, member3@domain
|
||||
Chat-Version: 1.0
|
||||
Chat-Group-ID: 1234xyZ
|
||||
Chat-Group-ID: 12345uvwxyZ
|
||||
Chat-Group-Name: My Group
|
||||
Chat-Group-Member-Removed: member4@domain
|
||||
Message-ID: Gr.1234xyZ.0003@domain
|
||||
Message-ID: Gr.12345uvwxyZ.0003@domain
|
||||
Subject: Chat: My Group: Hello, ...
|
||||
|
||||
Hello, I've removed member4@domain from our group. Now we have 3 members.
|
||||
@@ -233,10 +234,10 @@ and the message SHOULD appear as a message or action from the sender.
|
||||
From: member1@domain
|
||||
To: member2@domain, member3@domain
|
||||
Chat-Version: 1.0
|
||||
Chat-Group-ID: 1234xyZ
|
||||
Chat-Group-ID: 12345uvwxyZ
|
||||
Chat-Group-Name: Our Group
|
||||
Chat-Group-Name-Changed: My Group
|
||||
Message-ID: Gr.1234xyZ.0004@domain
|
||||
Message-ID: Gr.12345uvwxyZ.0004@domain
|
||||
Subject: Chat: Our Group: Hello, ...
|
||||
|
||||
Hello, I've changed the group name from "My Group" to "Our Group".
|
||||
@@ -262,10 +263,10 @@ and the message SHOULD appear as a message or action from the sender.
|
||||
From: member1@domain
|
||||
To: member2@domain, member3@domain
|
||||
Chat-Version: 1.0
|
||||
Chat-Group-ID: 1234xyZ
|
||||
Chat-Group-ID: 12345uvwxyZ
|
||||
Chat-Group-Name: Our Group
|
||||
Chat-Group-Image: image.jpg
|
||||
Message-ID: Gr.1234xyZ.0005@domain
|
||||
Message-ID: Gr.12345uvwxyZ.0005@domain
|
||||
Subject: Chat: Our Group: Hello, ...
|
||||
Content-Type: multipart/mixed; boundary="==break=="
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use mmime::mailimf_types::*;
|
||||
use mmime::mailimf::types::*;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
|
||||
500
src/chat.rs
500
src/chat.rs
@@ -1,6 +1,4 @@
|
||||
use std::ffi::CString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use crate::chatlist::*;
|
||||
use crate::config::*;
|
||||
@@ -12,11 +10,10 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::*;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::param::*;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
/// An object representing a single chat in memory.
|
||||
/// Chat objects are created using eg. `Chat::load_from_db`
|
||||
@@ -156,7 +153,7 @@ impl Chat {
|
||||
}
|
||||
let cnt = get_chat_contact_cnt(context, self.id);
|
||||
return context
|
||||
.stock_string_repl_int(StockMessage::Member, cnt)
|
||||
.stock_string_repl_int(StockMessage::Member, cnt as i32)
|
||||
.into();
|
||||
}
|
||||
|
||||
@@ -233,15 +230,14 @@ impl Chat {
|
||||
self.is_sending_locations
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn prepare_msg_raw(
|
||||
fn prepare_msg_raw(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
msg: &mut Message,
|
||||
timestamp: i64,
|
||||
) -> Result<u32, Error> {
|
||||
let mut do_guarantee_e2ee: libc::c_int;
|
||||
let e2ee_enabled: libc::c_int;
|
||||
let mut do_guarantee_e2ee: bool;
|
||||
let e2ee_enabled: bool;
|
||||
let mut new_references = "".into();
|
||||
let mut new_in_reply_to = "".into();
|
||||
let mut msg_id = 0;
|
||||
@@ -257,7 +253,7 @@ impl Chat {
|
||||
}
|
||||
|
||||
if (self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup)
|
||||
&& 0 == is_contact_in_chat(context, self.id, 1 as u32)
|
||||
&& !is_contact_in_chat(context, self.id, 1 as u32)
|
||||
{
|
||||
emit_event!(
|
||||
context,
|
||||
@@ -272,7 +268,7 @@ impl Chat {
|
||||
Chattype::Group | Chattype::VerifiedGroup => Some(self.grpid.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
dc_create_outgoing_rfc724_mid_safe(grpid, &from)
|
||||
dc_create_outgoing_rfc724_mid(grpid, &from)
|
||||
};
|
||||
|
||||
if self.typ == Chattype::Single {
|
||||
@@ -302,14 +298,13 @@ impl Chat {
|
||||
if we guarantee E2EE, and circumstances change
|
||||
so that E2EE is no longer available at a later point (reset, changed settings),
|
||||
we do not send the message out at all */
|
||||
do_guarantee_e2ee = 0;
|
||||
do_guarantee_e2ee = false;
|
||||
e2ee_enabled = context
|
||||
.sql
|
||||
.get_config_int(context, "e2ee_enabled")
|
||||
.unwrap_or_else(|| 1);
|
||||
if 0 != e2ee_enabled
|
||||
&& msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0
|
||||
{
|
||||
.unwrap_or_else(|| 1)
|
||||
== 1;
|
||||
if e2ee_enabled && msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0 {
|
||||
let mut can_encrypt = 1;
|
||||
let mut all_mutual = 1;
|
||||
|
||||
@@ -354,13 +349,13 @@ impl Chat {
|
||||
|
||||
if 0 != can_encrypt {
|
||||
if 0 != all_mutual {
|
||||
do_guarantee_e2ee = 1;
|
||||
do_guarantee_e2ee = true;
|
||||
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
|
||||
do_guarantee_e2ee = 1;
|
||||
do_guarantee_e2ee = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 != do_guarantee_e2ee {
|
||||
if do_guarantee_e2ee {
|
||||
msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
}
|
||||
msg.param.remove(Param::ErroneousE2ee);
|
||||
@@ -486,7 +481,7 @@ pub fn create_by_msg_id(context: &Context, msg_id: u32) -> Result<u32, Error> {
|
||||
let mut chat_id = 0;
|
||||
let mut send_event = false;
|
||||
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, msg_id) {
|
||||
if let Ok(msg) = Message::load_from_db(context, msg_id) {
|
||||
if let Ok(chat) = Chat::load_from_db(context, msg.chat_id) {
|
||||
if chat.id > DC_CHAT_ID_LAST_SPECIAL {
|
||||
chat_id = chat.id;
|
||||
@@ -693,13 +688,13 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res
|
||||
// - from FILE to AUDIO/VIDEO/IMAGE
|
||||
// - from FILE/IMAGE to GIF */
|
||||
if let Some((better_type, better_mime)) =
|
||||
dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename))
|
||||
message::guess_msgtype_from_suffix(Path::new(&path_filename))
|
||||
{
|
||||
msg.type_0 = better_type;
|
||||
msg.param.set(Param::MimeType, better_mime);
|
||||
}
|
||||
} else if !msg.param.exists(Param::MimeType) {
|
||||
if let Some((_, mime)) = dc_msg_guess_msgtype_from_suffix(Path::new(&path_filename)) {
|
||||
if let Some((_, mime)) = message::guess_msgtype_from_suffix(Path::new(&path_filename)) {
|
||||
msg.param.set(Param::MimeType, mime);
|
||||
}
|
||||
}
|
||||
@@ -718,7 +713,7 @@ fn prepare_msg_common(context: &Context, chat_id: u32, msg: &mut Message) -> Res
|
||||
msg.state = MessageState::OutPending;
|
||||
}
|
||||
|
||||
msg.id = unsafe { chat.prepare_msg_raw(context, msg, dc_create_smeared_timestamp(context))? };
|
||||
msg.id = chat.prepare_msg_raw(context, msg, dc_create_smeared_timestamp(context))?;
|
||||
msg.chat_id = chat_id;
|
||||
|
||||
Ok(msg.id)
|
||||
@@ -746,7 +741,7 @@ fn last_msg_in_chat_encrypted(context: &Context, sql: &Sql, chat_id: u32) -> boo
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> libc::c_int {
|
||||
pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
/* this function works for group and for normal chats, however, it is more useful for group chats.
|
||||
DC_CONTACT_ID_SELF may be used to check, if the user itself is in a group chat (DC_CONTACT_ID_SELF is not added to normal chats) */
|
||||
|
||||
@@ -756,7 +751,7 @@ pub fn is_contact_in_chat(context: &Context, chat_id: u32, contact_id: u32) -> l
|
||||
"SELECT contact_id FROM chats_contacts WHERE chat_id=? AND contact_id=?;",
|
||||
params![chat_id as i32, contact_id as i32],
|
||||
)
|
||||
.unwrap_or_default() as libc::c_int
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// Should return Result
|
||||
@@ -785,11 +780,11 @@ pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u3
|
||||
chat_id == 0 || chat_id == msg.chat_id,
|
||||
"Inconsistent chat ID"
|
||||
);
|
||||
dc_update_msg_state(context, msg.id, MessageState::OutPending);
|
||||
message::update_msg_state(context, msg.id, MessageState::OutPending);
|
||||
}
|
||||
|
||||
ensure!(
|
||||
unsafe { job_send_msg(context, msg.id) } != 0,
|
||||
job_send_msg(context, msg.id) != 0,
|
||||
"Failed to initiate send job"
|
||||
);
|
||||
|
||||
@@ -811,101 +806,111 @@ pub fn send_msg(context: &Context, chat_id: u32, msg: &mut Message) -> Result<u3
|
||||
// avoid hanging if user tampers with db
|
||||
break;
|
||||
} else {
|
||||
if let Ok(mut copy) = dc_get_msg(context, id as u32) {
|
||||
if let Ok(mut copy) = Message::load_from_db(context, id as u32) {
|
||||
// TODO: handle cleanup and return early instead
|
||||
send_msg(context, 0, &mut copy).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
msg.param.remove(Param::PrepForwards);
|
||||
dc_msg_save_param_to_disk(context, msg);
|
||||
msg.save_param_to_disk(context);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(msg.id)
|
||||
}
|
||||
|
||||
pub unsafe fn send_text_msg(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
text_to_send: String,
|
||||
) -> Result<u32, Error> {
|
||||
pub fn send_text_msg(context: &Context, chat_id: u32, text_to_send: String) -> Result<u32, Error> {
|
||||
ensure!(
|
||||
chat_id > DC_CHAT_ID_LAST_SPECIAL,
|
||||
"bad chat_id = {} <= 9",
|
||||
chat_id
|
||||
);
|
||||
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.text = Some(text_to_send);
|
||||
send_msg(context, chat_id, &mut msg)
|
||||
}
|
||||
|
||||
// passing `None` as message jsut deletes the draft
|
||||
pub unsafe fn set_draft(context: &Context, chat_id: u32, msg: Option<&mut Message>) {
|
||||
pub fn set_draft(context: &Context, chat_id: u32, msg: Option<&mut Message>) {
|
||||
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return;
|
||||
}
|
||||
if set_draft_raw(context, chat_id, msg) {
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id: 0 });
|
||||
|
||||
let changed = match msg {
|
||||
None => maybe_delete_draft(context, chat_id),
|
||||
Some(msg) => set_draft_raw(context, chat_id, msg),
|
||||
};
|
||||
|
||||
if changed {
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete draft message in specified chat, if there is one.
|
||||
///
|
||||
/// Return {true}, if message was deleted, {false} otherwise.
|
||||
fn maybe_delete_draft(context: &Context, chat_id: u32) -> bool {
|
||||
let draft = get_draft_msg_id(context, chat_id);
|
||||
if draft != 0 {
|
||||
Message::delete_from_db(context, draft);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Set provided message as draft message for specified chat.
|
||||
///
|
||||
/// Return true on success, false on database error.
|
||||
fn do_set_draft(context: &Context, chat_id: u32, msg: &mut Message) -> bool {
|
||||
match msg.type_0 {
|
||||
Viewtype::Unknown => return false,
|
||||
Viewtype::Text => {
|
||||
if msg.text.as_ref().map_or(false, |s| s.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(path_filename) = msg.param.get(Param::File) {
|
||||
let mut path_filename = path_filename.to_string();
|
||||
if msg.is_increation() && !dc_is_blobdir_path(context, &path_filename) {
|
||||
return false;
|
||||
}
|
||||
if !dc_make_rel_and_copy(context, &mut path_filename) {
|
||||
return false;
|
||||
}
|
||||
msg.param.set(Param::File, path_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"INSERT INTO msgs (chat_id, from_id, timestamp, type, state, txt, param, hidden) \
|
||||
VALUES (?,?,?, ?,?,?,?,?);",
|
||||
params![
|
||||
chat_id as i32,
|
||||
1,
|
||||
time(),
|
||||
msg.type_0,
|
||||
MessageState::OutDraft,
|
||||
msg.text.as_ref().map(String::as_str).unwrap_or(""),
|
||||
msg.param.to_string(),
|
||||
1,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
// similar to as dc_set_draft() but does not emit an event
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn set_draft_raw(context: &Context, chat_id: u32, mut msg: Option<&mut Message>) -> bool {
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
fn set_draft_raw(context: &Context, chat_id: u32, msg: &mut Message) -> bool {
|
||||
let deleted = maybe_delete_draft(context, chat_id);
|
||||
let set = do_set_draft(context, chat_id, msg);
|
||||
|
||||
let mut sth_changed = false;
|
||||
|
||||
let prev_draft_msg_id = get_draft_msg_id(context, chat_id);
|
||||
if 0 != prev_draft_msg_id {
|
||||
dc_delete_msg_from_db(context, prev_draft_msg_id);
|
||||
sth_changed = true;
|
||||
}
|
||||
|
||||
if let Some(ref mut msg) = msg {
|
||||
// save new draft
|
||||
if msg.type_0 == Viewtype::Text {
|
||||
OK_TO_CONTINUE = msg.text.as_ref().map_or(false, |s| !s.is_empty());
|
||||
} else if msgtype_has_file(msg.type_0) {
|
||||
if let Some(path_filename) = msg.param.get(Param::File) {
|
||||
let mut path_filename = path_filename.to_string();
|
||||
if dc_msg_is_increation(msg) && !dc_is_blobdir_path(context, &path_filename) {
|
||||
OK_TO_CONTINUE = false;
|
||||
} else if !dc_make_rel_and_copy(context, &mut path_filename) {
|
||||
OK_TO_CONTINUE = false;
|
||||
} else {
|
||||
msg.param.set(Param::File, path_filename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
if OK_TO_CONTINUE {
|
||||
if sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"INSERT INTO msgs (chat_id, from_id, timestamp, type, state, txt, param, hidden) \
|
||||
VALUES (?,?,?, ?,?,?,?,?);",
|
||||
params![
|
||||
chat_id as i32,
|
||||
1,
|
||||
time(),
|
||||
msg.type_0,
|
||||
MessageState::OutDraft,
|
||||
msg.text.as_ref().map(String::as_str).unwrap_or(""),
|
||||
msg.param.to_string(),
|
||||
1,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
sth_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
sth_changed
|
||||
// Can't inline. Both functions above must be called, no shortcut!
|
||||
deleted || set
|
||||
}
|
||||
|
||||
fn get_draft_msg_id(context: &Context, chat_id: u32) -> u32 {
|
||||
@@ -920,12 +925,14 @@ fn get_draft_msg_id(context: &Context, chat_id: u32) -> u32 {
|
||||
}
|
||||
|
||||
pub fn get_draft(context: &Context, chat_id: u32) -> Result<Option<Message>, Error> {
|
||||
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
|
||||
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return Ok(None);
|
||||
}
|
||||
let draft_msg_id = get_draft_msg_id(context, chat_id);
|
||||
if draft_msg_id == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(dc_msg_load_from_db(context, draft_msg_id)?))
|
||||
Ok(Some(Message::load_from_db(context, draft_msg_id)?))
|
||||
}
|
||||
|
||||
pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before: u32) -> Vec<u32> {
|
||||
@@ -943,7 +950,7 @@ pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before:
|
||||
}
|
||||
if 0 != flags & 0x1 {
|
||||
let curr_local_timestamp = ts + cnv_to_local;
|
||||
let curr_day = (curr_local_timestamp / 86400) as libc::c_int;
|
||||
let curr_day = curr_local_timestamp / 86400;
|
||||
if curr_day != last_day {
|
||||
ret.push(DC_MSG_ID_LAST_SPECIAL);
|
||||
last_day = curr_day;
|
||||
@@ -1110,17 +1117,25 @@ pub fn get_chat_media(
|
||||
).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub unsafe fn get_next_media(
|
||||
/// Indicates the direction over which to iterate.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum Direction {
|
||||
Forward = 1,
|
||||
Backward = -1,
|
||||
}
|
||||
|
||||
pub fn get_next_media(
|
||||
context: &Context,
|
||||
curr_msg_id: u32,
|
||||
dir: libc::c_int,
|
||||
direction: Direction,
|
||||
msg_type: Viewtype,
|
||||
msg_type2: Viewtype,
|
||||
msg_type3: Viewtype,
|
||||
) -> u32 {
|
||||
let mut ret = 0;
|
||||
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, curr_msg_id) {
|
||||
if let Ok(msg) = Message::load_from_db(context, curr_msg_id) {
|
||||
let list = get_chat_media(
|
||||
context,
|
||||
msg.chat_id,
|
||||
@@ -1134,13 +1149,16 @@ pub unsafe fn get_next_media(
|
||||
);
|
||||
for i in 0..list.len() {
|
||||
if curr_msg_id == list[i] {
|
||||
if dir > 0 {
|
||||
if i + 1 < list.len() {
|
||||
ret = list[i + 1]
|
||||
match direction {
|
||||
Direction::Forward => {
|
||||
if i + 1 < list.len() {
|
||||
ret = list[i + 1]
|
||||
}
|
||||
}
|
||||
} else if dir < 0 {
|
||||
if i >= 1 {
|
||||
ret = list[i - 1];
|
||||
Direction::Backward => {
|
||||
if i >= 1 {
|
||||
ret = list[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1257,16 +1275,14 @@ pub fn get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub unsafe fn create_group_chat(
|
||||
pub fn create_group_chat(
|
||||
context: &Context,
|
||||
verified: VerifiedStatus,
|
||||
chat_name: impl AsRef<str>,
|
||||
) -> Result<u32, Error> {
|
||||
ensure!(!chat_name.as_ref().is_empty(), "Invalid chat name");
|
||||
|
||||
let draft_txt =
|
||||
CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, &chat_name))
|
||||
.unwrap();
|
||||
let draft_txt = context.stock_string_repl_str(StockMessage::NewGroupDraft, &chat_name);
|
||||
let grpid = dc_create_id();
|
||||
|
||||
sql::execute(
|
||||
@@ -1288,9 +1304,9 @@ pub unsafe fn create_group_chat(
|
||||
|
||||
if chat_id != 0 {
|
||||
if add_to_chat_contacts_table(context, chat_id, 1) {
|
||||
let mut draft_msg = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut draft_msg, draft_txt.as_ptr());
|
||||
set_draft_raw(context, chat_id, Some(&mut draft_msg));
|
||||
let mut draft_msg = Message::new(Viewtype::Text);
|
||||
draft_msg.set_text(Some(draft_txt));
|
||||
set_draft_raw(context, chat_id, &mut draft_msg);
|
||||
}
|
||||
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
@@ -1316,106 +1332,105 @@ pub fn add_to_chat_contacts_table(context: &Context, chat_id: u32, contact_id: u
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
pub unsafe fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
add_contact_to_chat_ex(context, chat_id, contact_id, 0)
|
||||
pub fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u32) -> bool {
|
||||
match add_contact_to_chat_ex(context, chat_id, contact_id, false) {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
error!(context, "failed to add contact: {}", err);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn add_contact_to_chat_ex(
|
||||
pub(crate) fn add_contact_to_chat_ex(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
contact_id: u32,
|
||||
flags: libc::c_int,
|
||||
) -> bool {
|
||||
let mut OK_TO_CONTINUE = true;
|
||||
let mut success = false;
|
||||
let contact = Contact::get_by_id(context, contact_id);
|
||||
|
||||
if contact.is_err() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return false;
|
||||
}
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
from_handshake: bool,
|
||||
) -> Result<bool, Error> {
|
||||
ensure!(
|
||||
chat_id > DC_CHAT_ID_LAST_SPECIAL,
|
||||
"can not add member to special chats"
|
||||
);
|
||||
let contact = Contact::get_by_id(context, contact_id)?;
|
||||
let mut msg = Message::default();
|
||||
|
||||
reset_gossiped_timestamp(context, chat_id);
|
||||
let contact = contact.unwrap();
|
||||
|
||||
/*this also makes sure, not contacts are added to special or normal chats*/
|
||||
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
|
||||
if !(!real_group_exists(context, chat_id)
|
||||
|| !Contact::real_exists_by_id(context, contact_id) && contact_id != DC_CONTACT_ID_SELF)
|
||||
{
|
||||
if !(is_contact_in_chat(context, chat_id, 1 as u32) == 1) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
"Cannot add contact to group; self not in group.".into()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if 0 != flags & 0x1
|
||||
&& chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1
|
||||
{
|
||||
chat.param.remove(Param::Unpromoted);
|
||||
chat.update_param(context).unwrap();
|
||||
}
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.unwrap_or_default();
|
||||
if contact.get_addr() != &self_addr {
|
||||
// ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly.
|
||||
// if SELF is not in the group, members cannot be added at all.
|
||||
let mut chat = Chat::load_from_db(context, chat_id)?;
|
||||
ensure!(
|
||||
real_group_exists(context, chat_id),
|
||||
"chat_id {} is not a group where one can add members",
|
||||
chat_id
|
||||
);
|
||||
ensure!(
|
||||
Contact::real_exists_by_id(context, contact_id) && contact_id != DC_CONTACT_ID_SELF,
|
||||
"invalid contact_id {} for removal in group",
|
||||
contact_id
|
||||
);
|
||||
|
||||
if 0 != is_contact_in_chat(context, chat_id, contact_id) {
|
||||
if 0 == flags & 0x1 {
|
||||
success = true;
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
} else {
|
||||
// else continue and send status mail
|
||||
if chat.typ == Chattype::VerifiedGroup {
|
||||
if contact.is_verified(context) != VerifiedStatus::BidirectVerified {
|
||||
error!(
|
||||
context,
|
||||
"Only bidirectional verified contacts can be added to verified groups."
|
||||
);
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
}
|
||||
if OK_TO_CONTINUE {
|
||||
if !add_to_chat_contacts_table(context, chat_id, contact_id) {
|
||||
OK_TO_CONTINUE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if OK_TO_CONTINUE {
|
||||
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
|
||||
msg.type_0 = Viewtype::Text;
|
||||
msg.text = Some(context.stock_system_msg(
|
||||
StockMessage::MsgAddMember,
|
||||
contact.get_addr(),
|
||||
"",
|
||||
DC_CONTACT_ID_SELF as u32,
|
||||
));
|
||||
msg.param.set_int(Param::Cmd, 4);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.param.set_int(Param::Arg2, flags);
|
||||
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: msg.id,
|
||||
});
|
||||
}
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id: 0 });
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
if !is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF as u32) {
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup("Cannot add contact to group; self not in group.".into())
|
||||
);
|
||||
bail!("can not add contact because our account is not part of it");
|
||||
}
|
||||
if from_handshake && chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
|
||||
chat.param.remove(Param::Unpromoted);
|
||||
chat.update_param(context).unwrap();
|
||||
}
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.unwrap_or_default();
|
||||
if contact.get_addr() == &self_addr {
|
||||
bail!("invalid attempt to add self e-mail address to group");
|
||||
}
|
||||
// ourself is added using DC_CONTACT_ID_SELF, do not add it explicitly.
|
||||
// if SELF is not in the group, members cannot be added at all.
|
||||
|
||||
if is_contact_in_chat(context, chat_id, contact_id) {
|
||||
if !from_handshake {
|
||||
return Ok(true);
|
||||
}
|
||||
} else {
|
||||
// else continue and send status mail
|
||||
if chat.typ == Chattype::VerifiedGroup {
|
||||
if contact.is_verified(context) != VerifiedStatus::BidirectVerified {
|
||||
error!(
|
||||
context,
|
||||
"Only bidirectional verified contacts can be added to verified groups."
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
success
|
||||
if !add_to_chat_contacts_table(context, chat_id, contact_id) {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
|
||||
msg.type_0 = Viewtype::Text;
|
||||
msg.text = Some(context.stock_system_msg(
|
||||
StockMessage::MsgAddMember,
|
||||
contact.get_addr(),
|
||||
"",
|
||||
DC_CONTACT_ID_SELF as u32,
|
||||
));
|
||||
msg.param.set_int(Param::Cmd, 4);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.param.set_int(Param::Arg2, from_handshake.into());
|
||||
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: msg.id,
|
||||
});
|
||||
}
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id: 0 });
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
fn real_group_exists(context: &Context, chat_id: u32) -> bool {
|
||||
@@ -1467,7 +1482,7 @@ pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn remove_contact_from_chat(
|
||||
pub fn remove_contact_from_chat(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
contact_id: u32,
|
||||
@@ -1482,14 +1497,14 @@ pub unsafe fn remove_contact_from_chat(
|
||||
"Cannot remove special contact"
|
||||
);
|
||||
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
let mut msg = Message::default();
|
||||
let mut success = false;
|
||||
|
||||
/* we do not check if "contact_id" exists but just delete all records with the id from chats_contacts */
|
||||
/* this allows to delete pending references to deleted contacts. Of course, this should _not_ happen. */
|
||||
if let Ok(chat) = Chat::load_from_db(context, chat_id) {
|
||||
if real_group_exists(context, chat_id) {
|
||||
if !(is_contact_in_chat(context, chat_id, 1 as u32) == 1) {
|
||||
if !is_contact_in_chat(context, chat_id, 1 as u32) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
@@ -1568,7 +1583,7 @@ pub fn is_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Re
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn set_chat_name(
|
||||
pub fn set_chat_name(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
new_name: impl AsRef<str>,
|
||||
@@ -1580,12 +1595,12 @@ pub unsafe fn set_chat_name(
|
||||
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
|
||||
|
||||
let chat = Chat::load_from_db(context, chat_id)?;
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
let mut msg = Message::default();
|
||||
|
||||
if real_group_exists(context, chat_id) {
|
||||
if &chat.name == new_name.as_ref() {
|
||||
success = true;
|
||||
} else if !(is_contact_in_chat(context, chat_id, 1) == 1) {
|
||||
} else if !is_contact_in_chat(context, chat_id, 1) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup("Cannot set chat name; self not in group".into())
|
||||
@@ -1647,7 +1662,7 @@ pub fn set_chat_profile_image(
|
||||
|
||||
if real_group_exists(context, chat_id) {
|
||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||
if !(is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF) == 1i32) {
|
||||
if !is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF) {
|
||||
emit_event!(
|
||||
context,
|
||||
Event::ErrorSelfNotInGroup(
|
||||
@@ -1669,7 +1684,7 @@ pub fn set_chat_profile_image(
|
||||
chat.param.set(Param::ProfileImage, &new_image_rel);
|
||||
if chat.update_param(context).is_ok() {
|
||||
if chat.is_promoted() {
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
let mut msg = Message::default();
|
||||
msg.param
|
||||
.set_int(Param::Cmd, SystemMessage::GroupImageChanged as i32);
|
||||
msg.type_0 = Viewtype::Text;
|
||||
@@ -1701,13 +1716,8 @@ pub fn set_chat_profile_image(
|
||||
bail!("Failed to set profile image");
|
||||
}
|
||||
|
||||
pub unsafe fn forward_msgs(
|
||||
context: &Context,
|
||||
msg_ids: *const u32,
|
||||
msg_cnt: libc::c_int,
|
||||
chat_id: u32,
|
||||
) {
|
||||
if msg_ids.is_null() || msg_cnt <= 0 || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) {
|
||||
if msg_ids.is_empty() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1716,14 +1726,13 @@ pub unsafe fn forward_msgs(
|
||||
|
||||
unarchive(context, chat_id).unwrap();
|
||||
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
|
||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
|
||||
let idsstr = std::slice::from_raw_parts(msg_ids, msg_cnt as usize)
|
||||
.iter()
|
||||
curr_timestamp = dc_create_smeared_timestamps(context, msg_ids.len());
|
||||
let idsstr = msg_ids
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.fold(
|
||||
String::with_capacity(2 * msg_cnt as usize),
|
||||
|acc, (i, n)| (if i == 0 { acc } else { acc + "," }) + &n.to_string(),
|
||||
);
|
||||
.fold(String::with_capacity(2 * msg_ids.len()), |acc, (i, n)| {
|
||||
(if i == 0 { acc } else { acc + "," }) + &n.to_string()
|
||||
});
|
||||
|
||||
let ids = context
|
||||
.sql
|
||||
@@ -1740,7 +1749,7 @@ pub unsafe fn forward_msgs(
|
||||
|
||||
for id in ids {
|
||||
let src_msg_id = id;
|
||||
let msg = dc_msg_load_from_db(context, src_msg_id as u32);
|
||||
let msg = Message::load_from_db(context, src_msg_id as u32);
|
||||
if msg.is_err() {
|
||||
break;
|
||||
}
|
||||
@@ -1771,7 +1780,7 @@ pub unsafe fn forward_msgs(
|
||||
msg.param.set(Param::PrepForwards, new_msg_id.to_string());
|
||||
}
|
||||
|
||||
dc_msg_save_param_to_disk(context, &mut msg);
|
||||
msg.save_param_to_disk(context);
|
||||
msg.param = save_param;
|
||||
} else {
|
||||
msg.state = MessageState::OutPending;
|
||||
@@ -1795,15 +1804,15 @@ pub unsafe fn forward_msgs(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_chat_contact_cnt(context: &Context, chat_id: u32) -> libc::c_int {
|
||||
pub fn get_chat_contact_cnt(context: &Context, chat_id: u32) -> usize {
|
||||
context
|
||||
.sql
|
||||
.query_get_value(
|
||||
.query_get_value::<_, isize>(
|
||||
context,
|
||||
"SELECT COUNT(*) FROM chats_contacts WHERE chat_id=?;",
|
||||
params![chat_id as i32],
|
||||
)
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default() as usize
|
||||
}
|
||||
|
||||
pub fn get_chat_cnt(context: &Context) -> usize {
|
||||
@@ -1840,12 +1849,7 @@ pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32,
|
||||
}
|
||||
|
||||
pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
let rfc724_mid = unsafe {
|
||||
dc_create_outgoing_rfc724_mid(
|
||||
ptr::null(),
|
||||
b"@device\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
|
||||
|
||||
if context.sql.execute(
|
||||
"INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);",
|
||||
@@ -1857,21 +1861,13 @@ pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
Viewtype::Text,
|
||||
MessageState::InNoticed,
|
||||
text.as_ref(),
|
||||
as_str(rfc724_mid),
|
||||
rfc724_mid,
|
||||
]
|
||||
).is_err() {
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
return;
|
||||
}
|
||||
|
||||
let msg_id = sql::get_rowid(
|
||||
context,
|
||||
&context.sql,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
let msg_id = sql::get_rowid(context, &context.sql, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id });
|
||||
}
|
||||
|
||||
@@ -1892,8 +1888,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_get_draft_special_chat_id() {
|
||||
let t = dummy_context();
|
||||
let draft = get_draft(&t.ctx, DC_CHAT_ID_LAST_SPECIAL);
|
||||
assert!(draft.is_err());
|
||||
let draft = get_draft(&t.ctx, DC_CHAT_ID_LAST_SPECIAL).unwrap();
|
||||
assert!(draft.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1907,16 +1903,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_draft() {
|
||||
unsafe {
|
||||
let t = dummy_context();
|
||||
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF).unwrap();
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
dc_msg_set_text(&mut msg, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
set_draft(&t.ctx, chat_id, Some(&mut msg));
|
||||
let draft = get_draft(&t.ctx, chat_id).unwrap().unwrap();
|
||||
let msg_text = dc_msg_get_text(&msg);
|
||||
let draft_text = dc_msg_get_text(&draft);
|
||||
assert_eq!(as_str(msg_text), as_str(draft_text));
|
||||
}
|
||||
let t = dummy_context();
|
||||
let chat_id = create_by_contact_id(&t.ctx, DC_CONTACT_ID_SELF).unwrap();
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.set_text(Some("hello".to_string()));
|
||||
set_draft(&t.ctx, chat_id, Some(&mut msg));
|
||||
let draft = get_draft(&t.ctx, chat_id).unwrap().unwrap();
|
||||
let msg_text = msg.get_text();
|
||||
let draft_text = draft.get_text();
|
||||
assert_eq!(msg_text, draft_text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::contact::*;
|
||||
use crate::context::*;
|
||||
use crate::error::Result;
|
||||
use crate::lot::Lot;
|
||||
use crate::message::*;
|
||||
use crate::message::Message;
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
/// An object representing a single chatlist in memory.
|
||||
@@ -271,7 +271,7 @@ impl Chatlist {
|
||||
let mut lastcontact = None;
|
||||
|
||||
let lastmsg = if 0 != lastmsg_id {
|
||||
if let Ok(lastmsg) = dc_msg_load_from_db(context, lastmsg_id) {
|
||||
if let Ok(lastmsg) = Message::load_from_db(context, lastmsg_id) {
|
||||
if lastmsg.from_id != 1 as libc::c_uint
|
||||
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
@@ -5,7 +6,6 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::x::*;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
/* ******************************************************************************
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use std::ptr;
|
||||
|
||||
use libc::free;
|
||||
use quick_xml;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
@@ -5,8 +8,6 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::x::*;
|
||||
use std::ptr;
|
||||
|
||||
use super::read_autoconf_file;
|
||||
/* ******************************************************************************
|
||||
@@ -46,7 +47,7 @@ pub unsafe fn outlk_autodiscover(
|
||||
ok_to_continue = true;
|
||||
break;
|
||||
}
|
||||
memset(
|
||||
libc::memset(
|
||||
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
|
||||
0,
|
||||
::std::mem::size_of::<outlk_autodiscover_t>(),
|
||||
|
||||
@@ -18,7 +18,7 @@ use auto_mozilla::moz_autoconfigure;
|
||||
macro_rules! progress {
|
||||
($context:tt, $progress:expr) => {
|
||||
assert!(
|
||||
$progress > 0 && $progress <= 1000,
|
||||
$progress <= 1000,
|
||||
"value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success"
|
||||
);
|
||||
$context.call_cb($crate::events::Event::ConfigureProgress($progress));
|
||||
@@ -45,7 +45,7 @@ pub fn dc_is_configured(context: &Context) -> bool {
|
||||
******************************************************************************/
|
||||
// the other dc_job_do_DC_JOB_*() functions are declared static in the c-file
|
||||
#[allow(non_snake_case, unused_must_use)]
|
||||
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) {
|
||||
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
|
||||
let mut success = false;
|
||||
let mut imap_connected_here = false;
|
||||
let mut smtp_connected_here = false;
|
||||
@@ -660,3 +660,23 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::config::*;
|
||||
use crate::configure::dc_job_do_DC_JOB_CONFIGURE_IMAP;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_no_panic_on_bad_credentials() {
|
||||
let t = dummy_context();
|
||||
t.ctx
|
||||
.set_config(Config::Addr, Some("probably@unexistant.addr"))
|
||||
.unwrap();
|
||||
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
|
||||
unsafe {
|
||||
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,9 @@ const DC_GCM_ADDDAYMARKER: usize = 0x01;
|
||||
pub const DC_GCL_VERIFIED_ONLY: usize = 0x01;
|
||||
pub const DC_GCL_ADD_SELF: usize = 0x02;
|
||||
|
||||
/// param1 is a directory where the keys are written to
|
||||
const DC_IMEX_EXPORT_SELF_KEYS: usize = 1;
|
||||
/// param1 is a directory where the keys are searched in and read from
|
||||
const DC_IMEX_IMPORT_SELF_KEYS: usize = 2;
|
||||
/// param1 is a directory where the backup is written to
|
||||
const DC_IMEX_EXPORT_BACKUP: usize = 11;
|
||||
/// param1 is the file with the backup to import
|
||||
const DC_IMEX_IMPORT_BACKUP: usize = 12;
|
||||
// values for DC_PARAM_FORCE_PLAINTEXT
|
||||
pub(crate) const DC_FP_NO_AUTOCRYPT_HEADER: i32 = 2;
|
||||
pub(crate) const DC_FP_ADD_AUTOCRYPT_HEADER: i32 = 1;
|
||||
|
||||
/// virtual chat showing all messages belonging to chats flagged with chats.blocked=2
|
||||
pub(crate) const DC_CHAT_ID_DEADDROP: u32 = 1;
|
||||
@@ -122,7 +117,7 @@ const DC_MAX_GET_INFO_LEN: usize = 100000;
|
||||
|
||||
pub const DC_CONTACT_ID_UNDEFINED: u32 = 0;
|
||||
pub const DC_CONTACT_ID_SELF: u32 = 1;
|
||||
const DC_CONTACT_ID_DEVICE: u32 = 2;
|
||||
pub const DC_CONTACT_ID_DEVICE: u32 = 2;
|
||||
pub const DC_CONTACT_ID_LAST_SPECIAL: u32 = 9;
|
||||
|
||||
pub const DC_CREATE_MVBOX: usize = 1;
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::job_thread::JobThread;
|
||||
use crate::key::*;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::lot::Lot;
|
||||
use crate::message::*;
|
||||
use crate::message::{self, Message};
|
||||
use crate::param::Params;
|
||||
use crate::smtp::*;
|
||||
use crate::sql::Sql;
|
||||
@@ -66,6 +66,30 @@ pub struct RunningState {
|
||||
pub shall_stop_ongoing: bool,
|
||||
}
|
||||
|
||||
/// Return some info about deltachat-core
|
||||
///
|
||||
/// This contains information mostly about the library itself, the
|
||||
/// actual keys and their values which will be present are not
|
||||
/// guaranteed. Calling [Context::get_info] also includes information
|
||||
/// about the context on top of the information here.
|
||||
pub fn get_info() -> HashMap<&'static str, String> {
|
||||
let mut res = HashMap::new();
|
||||
res.insert("deltachat_core_version", format!("v{}", &*DC_VERSION_STR));
|
||||
res.insert("sqlite_version", rusqlite::version().to_string());
|
||||
res.insert(
|
||||
"sqlite_thread_safe",
|
||||
unsafe { rusqlite::ffi::sqlite3_threadsafe() }.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"arch",
|
||||
(::std::mem::size_of::<*mut libc::c_void>())
|
||||
.wrapping_mul(8)
|
||||
.to_string(),
|
||||
);
|
||||
res.insert("level", "awesome".into());
|
||||
res
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(cb: Box<ContextCallback>, os_name: String, dbfile: PathBuf) -> Result<Context> {
|
||||
let mut blob_fname = OsString::new();
|
||||
@@ -144,8 +168,8 @@ impl Context {
|
||||
let l2 = LoginParam::from_database(self, "configured_");
|
||||
let displayname = self.sql.get_config(self, "displayname");
|
||||
let chats = get_chat_cnt(self) as usize;
|
||||
let real_msgs = dc_get_real_msg_cnt(self) as usize;
|
||||
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(self) as usize;
|
||||
let real_msgs = message::get_real_msg_cnt(self) as usize;
|
||||
let deaddrop_msgs = message::get_deaddrop_msg_cnt(self) as usize;
|
||||
let contacts = Contact::get_real_cnt(self) as usize;
|
||||
let is_configured = self
|
||||
.sql
|
||||
@@ -209,19 +233,7 @@ impl Context {
|
||||
.get_config(self, "configured_mvbox_folder")
|
||||
.unwrap_or_else(|| "<unset>".to_string());
|
||||
|
||||
let mut res = HashMap::new();
|
||||
res.insert("deltachat_core_version", format!("v{}", &*DC_VERSION_STR));
|
||||
res.insert("sqlite_version", rusqlite::version().to_string());
|
||||
res.insert(
|
||||
"sqlite_thread_safe",
|
||||
unsafe { rusqlite::ffi::sqlite3_threadsafe() }.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"arch",
|
||||
(::std::mem::size_of::<*mut libc::c_void>())
|
||||
.wrapping_mul(8)
|
||||
.to_string(),
|
||||
);
|
||||
let mut res = get_info();
|
||||
res.insert("number_of_chats", chats.to_string());
|
||||
res.insert("number_of_chat_messages", real_msgs.to_string());
|
||||
res.insert("messages_in_contact_requests", deaddrop_msgs.to_string());
|
||||
@@ -251,7 +263,6 @@ impl Context {
|
||||
pub_key_cnt.unwrap_or_default().to_string(),
|
||||
);
|
||||
res.insert("fingerprint", fingerprint_str);
|
||||
res.insert("level", "awesome".into());
|
||||
|
||||
res
|
||||
}
|
||||
@@ -354,15 +365,15 @@ impl Context {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(msg) = dc_msg_new_load(self, msg_id) {
|
||||
if dc_msg_is_setupmessage(&msg) {
|
||||
if let Ok(msg) = Message::load_from_db(self, msg_id) {
|
||||
if msg.is_setupmessage() {
|
||||
// do not move setup messages;
|
||||
// there may be a non-delta device that wants to handle it
|
||||
return;
|
||||
}
|
||||
|
||||
if self.is_mvbox(folder) {
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Stay);
|
||||
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
@@ -374,7 +385,7 @@ impl Context {
|
||||
Params::new(),
|
||||
0,
|
||||
);
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Moving);
|
||||
message::update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,6 +515,14 @@ mod tests {
|
||||
let t = dummy_context();
|
||||
|
||||
let info = t.ctx.get_info();
|
||||
assert!(info.get("database_dir").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_info_no_context() {
|
||||
let info = get_info();
|
||||
assert!(info.get("deltachat_core_version").is_some());
|
||||
assert!(info.get("database_dir").is_none());
|
||||
assert_eq!(info.get("level").unwrap(), "awesome");
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1251
src/dc_mimeparser.rs
1251
src/dc_mimeparser.rs
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,13 @@ use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use itertools::join;
|
||||
use libc::{free, strcmp, strlen};
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::*;
|
||||
use mmime::mailimf_types::*;
|
||||
use mmime::mailmime::content::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mailmime_types::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
@@ -23,13 +23,12 @@ use crate::error::Result;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::location;
|
||||
use crate::message::*;
|
||||
use crate::message::{self, MessageState};
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::securejoin::handle_securejoin_handshake;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum CreateEvent {
|
||||
@@ -40,8 +39,7 @@ enum CreateEvent {
|
||||
/// Receive a message and add it to the database.
|
||||
pub unsafe fn dc_receive_imf(
|
||||
context: &Context,
|
||||
imf_raw_not_terminated: *const libc::c_char,
|
||||
imf_raw_bytes: libc::size_t,
|
||||
imf_raw: &[u8],
|
||||
server_folder: impl AsRef<str>,
|
||||
server_uid: u32,
|
||||
flags: u32,
|
||||
@@ -62,9 +60,10 @@ pub unsafe fn dc_receive_imf(
|
||||
// we use mailmime_parse() through dc_mimeparser (both call mailimf_struct_multiple_parse()
|
||||
// somewhen, I did not found out anything that speaks against this approach yet)
|
||||
|
||||
let body = std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes);
|
||||
let mut mime_parser = MimeParser::new(context);
|
||||
mime_parser.parse(body);
|
||||
if let Err(err) = mime_parser.parse(imf_raw) {
|
||||
error!(context, "dc_receive_imf parse error: {}", err);
|
||||
};
|
||||
|
||||
if mime_parser.header.is_empty() {
|
||||
// Error - even adding an empty record won't help as we do not know the message ID
|
||||
@@ -85,8 +84,6 @@ pub unsafe fn dc_receive_imf(
|
||||
let mut add_delete_job: libc::c_int = 0;
|
||||
let mut insert_msg_id = 0;
|
||||
|
||||
// Message-ID from the header
|
||||
let rfc724_mid = std::ptr::null_mut();
|
||||
let mut sent_timestamp = 0;
|
||||
let mut created_db_entries = Vec::new();
|
||||
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
|
||||
@@ -96,12 +93,9 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
// helper method to handle early exit and memory cleanup
|
||||
let cleanup = |context: &Context,
|
||||
rfc724_mid: *mut libc::c_char,
|
||||
create_event_to_send: &Option<CreateEvent>,
|
||||
created_db_entries: &Vec<(usize, usize)>,
|
||||
rr_event_to_send: &Vec<(u32, u32)>| {
|
||||
free(rfc724_mid.cast());
|
||||
|
||||
if let Some(create_event_to_send) = create_event_to_send {
|
||||
for (chat_id, msg_id) in created_db_entries {
|
||||
let event = match create_event_to_send {
|
||||
@@ -184,18 +178,39 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
|
||||
// Add parts
|
||||
|
||||
let rfc724_mid = match mime_parser.get_rfc724_mid() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
// missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS
|
||||
match dc_create_incoming_rfc724_mid(sent_timestamp, from_id, &to_ids) {
|
||||
Some(x) => x.to_string(),
|
||||
None => {
|
||||
error!(context, "can not create incoming rfc724_mid");
|
||||
cleanup(
|
||||
context,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if mime_parser.get_last_nonmeta().is_some() {
|
||||
if let Err(err) = add_parts(
|
||||
context,
|
||||
&mut mime_parser,
|
||||
imf_raw_not_terminated,
|
||||
imf_raw_bytes,
|
||||
imf_raw,
|
||||
incoming,
|
||||
&mut incoming_origin,
|
||||
server_folder.as_ref(),
|
||||
server_uid,
|
||||
&mut to_ids,
|
||||
rfc724_mid,
|
||||
&rfc724_mid,
|
||||
&mut sent_timestamp,
|
||||
&mut from_id,
|
||||
from_id_blocked,
|
||||
@@ -213,7 +228,6 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -263,14 +277,11 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
info!(
|
||||
context,
|
||||
"received message {} has Message-Id: {}",
|
||||
server_uid,
|
||||
to_string(rfc724_mid)
|
||||
"received message {} has Message-Id: {}", server_uid, rfc724_mid
|
||||
);
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -280,14 +291,13 @@ pub unsafe fn dc_receive_imf(
|
||||
unsafe fn add_parts(
|
||||
context: &Context,
|
||||
mut mime_parser: &mut MimeParser,
|
||||
imf_raw_not_terminated: *const libc::c_char,
|
||||
imf_raw_bytes: libc::size_t,
|
||||
imf_raw: &[u8],
|
||||
incoming: i32,
|
||||
incoming_origin: &mut Origin,
|
||||
server_folder: impl AsRef<str>,
|
||||
server_uid: u32,
|
||||
to_ids: &mut Vec<u32>,
|
||||
mut rfc724_mid: *mut libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
sent_timestamp: &mut i64,
|
||||
from_id: &mut u32,
|
||||
from_id_blocked: i32,
|
||||
@@ -336,42 +346,16 @@ unsafe fn add_parts(
|
||||
}
|
||||
}
|
||||
|
||||
// get Message-ID; if the header is lacking one, generate one based on fields that do never
|
||||
// change. (missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS)
|
||||
if let Some(field) = mime_parser.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
|
||||
let fld_message_id = (*field).fld_data.fld_message_id;
|
||||
if !fld_message_id.is_null() {
|
||||
rfc724_mid = dc_strdup((*fld_message_id).mid_value)
|
||||
}
|
||||
}
|
||||
|
||||
if rfc724_mid.is_null() {
|
||||
rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids);
|
||||
if rfc724_mid.is_null() {
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Cannot create Message-ID");
|
||||
}
|
||||
}
|
||||
|
||||
// check, if the mail is already in our database - if so, just update the folder/uid
|
||||
// (if the mail was moved around) and finish. (we may get a mail twice eg. if it is
|
||||
// moved between folders. make sure, this check is done eg. before securejoin-processing) */
|
||||
let mut old_server_folder = std::ptr::null_mut();
|
||||
let mut old_server_uid = 0;
|
||||
|
||||
if 0 != dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
) {
|
||||
if as_str(old_server_folder) != server_folder.as_ref() || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
if let Ok((old_server_folder, old_server_uid, _)) =
|
||||
message::rfc724_mid_exists(context, &rfc724_mid)
|
||||
{
|
||||
if old_server_folder != server_folder.as_ref() || old_server_uid != server_uid {
|
||||
message::update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
}
|
||||
|
||||
free(old_server_folder.cast());
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Message already in DB");
|
||||
}
|
||||
@@ -666,8 +650,19 @@ unsafe fn add_parts(
|
||||
.set_int(Param::Cmd, mime_parser.is_system_message as i32);
|
||||
}
|
||||
|
||||
/*
|
||||
info!(
|
||||
context,
|
||||
"received mime message {:?}",
|
||||
String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
imf_raw_not_terminated as *const u8,
|
||||
imf_raw_bytes,
|
||||
))
|
||||
);
|
||||
*/
|
||||
|
||||
stmt.execute(params![
|
||||
as_str(rfc724_mid),
|
||||
rfc724_mid,
|
||||
server_folder.as_ref(),
|
||||
server_uid as libc::c_int,
|
||||
*chat_id as libc::c_int,
|
||||
@@ -686,10 +681,7 @@ unsafe fn add_parts(
|
||||
part.bytes,
|
||||
*hidden,
|
||||
if save_mime_headers {
|
||||
Some(String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
imf_raw_not_terminated as *const u8,
|
||||
imf_raw_bytes,
|
||||
)))
|
||||
Some(String::from_utf8_lossy(imf_raw))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@@ -698,13 +690,8 @@ unsafe fn add_parts(
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
*insert_msg_id = sql::get_rowid_with_conn(
|
||||
context,
|
||||
conn,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
*insert_msg_id =
|
||||
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
created_db_entries.push((*chat_id as usize, *insert_msg_id as usize));
|
||||
}
|
||||
Ok(())
|
||||
@@ -760,10 +747,7 @@ unsafe fn handle_reports(
|
||||
for report_root in &mime_parser.reports {
|
||||
let report_root = *report_root;
|
||||
let mut mdn_consumed = 0;
|
||||
let report_type = mailmime_find_ct_parameter(
|
||||
report_root,
|
||||
b"report-type\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let report_type = mailmime_find_ct_parameter(report_root, "report-type");
|
||||
|
||||
if report_root.is_null() || report_type.is_null() || (*report_type).pa_value.is_null() {
|
||||
continue;
|
||||
@@ -799,7 +783,7 @@ unsafe fn handle_reports(
|
||||
.data
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *mut mailmime;
|
||||
}) as *mut Mailmime;
|
||||
|
||||
if !report_data.is_null()
|
||||
&& (*(*(*report_data).mm_content_type).ct_type).tp_type
|
||||
@@ -814,22 +798,13 @@ unsafe fn handle_reports(
|
||||
b"disposition-notification\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
let mut report_body = std::ptr::null();
|
||||
let mut report_body_bytes = 0;
|
||||
let mut to_mmap_string_unref = std::ptr::null_mut();
|
||||
|
||||
if mailmime_transfer_decode(
|
||||
report_data,
|
||||
&mut report_body,
|
||||
&mut report_body_bytes,
|
||||
&mut to_mmap_string_unref,
|
||||
) {
|
||||
if let Ok(report_body) = mailmime_transfer_decode(report_data) {
|
||||
let mut report_parsed = std::ptr::null_mut();
|
||||
let mut dummy = 0;
|
||||
|
||||
if mailmime_parse(
|
||||
report_body,
|
||||
report_body_bytes,
|
||||
report_body.as_ptr() as *const _,
|
||||
report_body.len(),
|
||||
&mut dummy,
|
||||
&mut report_parsed,
|
||||
) == MAIL_NO_ERROR as libc::c_int
|
||||
@@ -864,10 +839,10 @@ unsafe fn handle_reports(
|
||||
let mut chat_id_0 = 0;
|
||||
let mut msg_id = 0;
|
||||
|
||||
if 0 != dc_mdn_from_ext(
|
||||
if message::mdn_from_ext(
|
||||
context,
|
||||
from_id,
|
||||
rfc724_mid_0,
|
||||
as_str(rfc724_mid_0),
|
||||
sent_timestamp,
|
||||
&mut chat_id_0,
|
||||
&mut msg_id,
|
||||
@@ -881,9 +856,6 @@ unsafe fn handle_reports(
|
||||
}
|
||||
mailmime_free(report_parsed);
|
||||
}
|
||||
if !to_mmap_string_unref.is_null() {
|
||||
mmap_string_unref(to_mmap_string_unref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1178,26 +1150,20 @@ unsafe fn create_or_lookup_group(
|
||||
// check, if we have a chat with this group ID
|
||||
let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid);
|
||||
if chat_id != 0 {
|
||||
let mut failure_reason = std::ptr::null_mut();
|
||||
|
||||
if chat_id_verified
|
||||
&& 0 == check_verified_properties(
|
||||
context,
|
||||
mime_parser,
|
||||
from_id as u32,
|
||||
to_ids,
|
||||
&mut failure_reason,
|
||||
)
|
||||
{
|
||||
mime_parser.repl_msg_by_error(to_string(failure_reason));
|
||||
if chat_id_verified {
|
||||
if let Err(err) =
|
||||
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
||||
{
|
||||
warn!(context, "verification problem: {}", err);
|
||||
let s = format!("{}. See 'Info' for more details", err);
|
||||
mime_parser.repl_msg_by_error(s);
|
||||
}
|
||||
}
|
||||
|
||||
free(failure_reason.cast());
|
||||
}
|
||||
|
||||
// check if the sender is a member of the existing group -
|
||||
// if not, we'll recreate the group list
|
||||
if chat_id != 0 && 0 == chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
if chat_id != 0 && !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
||||
recreate_member_list = 1;
|
||||
}
|
||||
|
||||
@@ -1221,18 +1187,14 @@ unsafe fn create_or_lookup_group(
|
||||
let mut create_verified = VerifiedStatus::Unverified;
|
||||
if mime_parser.lookup_field("Chat-Verified").is_some() {
|
||||
create_verified = VerifiedStatus::Verified;
|
||||
let mut failure_reason = std::ptr::null_mut();
|
||||
|
||||
if 0 == check_verified_properties(
|
||||
context,
|
||||
mime_parser,
|
||||
from_id as u32,
|
||||
to_ids,
|
||||
&mut failure_reason,
|
||||
) {
|
||||
mime_parser.repl_msg_by_error(to_string(failure_reason));
|
||||
if let Err(err) =
|
||||
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
||||
{
|
||||
warn!(context, "verification problem: {}", err);
|
||||
let s = format!("{}. See 'Info' for more details", err);
|
||||
mime_parser.repl_msg_by_error(&s);
|
||||
}
|
||||
free(failure_reason.cast());
|
||||
}
|
||||
if 0 == allow_creation {
|
||||
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
||||
@@ -1639,51 +1601,41 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
|
||||
chat_ids
|
||||
}
|
||||
|
||||
unsafe fn check_verified_properties(
|
||||
fn check_verified_properties(
|
||||
context: &Context,
|
||||
mimeparser: &MimeParser,
|
||||
from_id: u32,
|
||||
to_ids: &Vec<u32>,
|
||||
failure_reason: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let verify_fail = |reason: String| {
|
||||
*failure_reason = format!("{}. See \"Info\" for details.", reason).strdup();
|
||||
warn!(context, "{}", reason);
|
||||
};
|
||||
) -> Result<()> {
|
||||
let contact = Contact::load_from_db(context, from_id)?;
|
||||
|
||||
let contact = match Contact::load_from_db(context, from_id) {
|
||||
Ok(contact) => contact,
|
||||
Err(_err) => {
|
||||
verify_fail("Internal Error; cannot load contact".into());
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
if !mimeparser.e2ee_helper.encrypted {
|
||||
verify_fail("This message is not encrypted".into());
|
||||
return 0;
|
||||
}
|
||||
ensure!(
|
||||
mimeparser.e2ee_helper.encrypted,
|
||||
"This message is not encrypted."
|
||||
);
|
||||
|
||||
// ensure, the contact is verified
|
||||
// and the message is signed with a verified key of the sender.
|
||||
// this check is skipped for SELF as there is no proper SELF-peerstate
|
||||
// and results in group-splits otherwise.
|
||||
if from_id != 1 {
|
||||
if from_id != DC_CONTACT_ID_SELF {
|
||||
let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr());
|
||||
|
||||
if peerstate.is_none()
|
||||
|| contact.is_verified_ex(context, peerstate.as_ref())
|
||||
!= VerifiedStatus::BidirectVerified
|
||||
{
|
||||
verify_fail("The sender of this message is not verified.".into());
|
||||
return 0;
|
||||
bail!(
|
||||
"Sender of this message is not verified: {}",
|
||||
contact.get_addr()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(peerstate) = peerstate {
|
||||
if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) {
|
||||
verify_fail("The message was sent with non-verified encryption.".into());
|
||||
return 0;
|
||||
}
|
||||
ensure!(
|
||||
peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures),
|
||||
"The message was sent with non-verified encryption."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1696,18 +1648,18 @@ unsafe fn check_verified_properties(
|
||||
to_ids_str,
|
||||
),
|
||||
params![],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1).unwrap_or(0))),
|
||||
|rows| {
|
||||
rows.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.map_err(Into::into)
|
||||
},
|
||||
);
|
||||
)?;
|
||||
|
||||
if rows.is_err() {
|
||||
return 0;
|
||||
}
|
||||
for (to_addr, mut is_verified) in rows.unwrap().into_iter() {
|
||||
for (to_addr, _is_verified) in rows.into_iter() {
|
||||
let mut is_verified = _is_verified != 0;
|
||||
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
|
||||
|
||||
// mark gossiped keys (if any) as verified
|
||||
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
|
||||
let peerstate = peerstate.as_mut().unwrap();
|
||||
|
||||
@@ -1716,29 +1668,27 @@ unsafe fn check_verified_properties(
|
||||
// - OR if the verified-key does not match public-key or gossip-key
|
||||
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
|
||||
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
|
||||
if 0 == is_verified
|
||||
if !is_verified
|
||||
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint
|
||||
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint
|
||||
{
|
||||
info!(context, "{} has verfied {}.", contact.get_addr(), to_addr,);
|
||||
info!(context, "{} has verified {}.", contact.get_addr(), to_addr,);
|
||||
let fp = peerstate.gossip_key_fingerprint.clone();
|
||||
if let Some(fp) = fp {
|
||||
peerstate.set_verified(0, &fp, 2);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
is_verified = 1;
|
||||
peerstate.save_to_db(&context.sql, false).unwrap();
|
||||
is_verified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 == is_verified {
|
||||
verify_fail(format!(
|
||||
if !is_verified {
|
||||
bail!(
|
||||
"{} is not a member of this verified group",
|
||||
to_addr
|
||||
));
|
||||
return 0;
|
||||
to_addr.to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
1
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_better_msg(mime_parser: &mut MimeParser, better_msg: impl AsRef<str>) {
|
||||
@@ -1870,11 +1820,11 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
while !cur.is_null() {
|
||||
if 0 != is_msgrmsg_rfc724_mid(
|
||||
context,
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
if !cur.is_null() {
|
||||
as_str((*cur).data as *const libc::c_char)
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *const libc::c_char,
|
||||
""
|
||||
},
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1889,15 +1839,15 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
}
|
||||
|
||||
/// Check if a message is a reply to any messenger message.
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int {
|
||||
if rfc724_mid.is_null() {
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: &str) -> libc::c_int {
|
||||
if rfc724_mid.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.exists(
|
||||
"SELECT id FROM msgs WHERE rfc724_mid=? AND msgrmsg!=0 AND chat_id>9;",
|
||||
params![as_str(rfc724_mid)],
|
||||
params![rfc724_mid],
|
||||
)
|
||||
.unwrap_or_default() as libc::c_int
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use itertools::Itertools;
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use charset::Charset;
|
||||
use mmime::mailmime_decode::*;
|
||||
use mmime::mmapstring::*;
|
||||
use libc::{free, strlen};
|
||||
use mmime::mailmime::decode::mailmime_encoded_phrase_parse;
|
||||
use mmime::other::*;
|
||||
use percent_encoding::{percent_decode, utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
|
||||
use crate::dc_tools::*;
|
||||
use crate::x::*;
|
||||
|
||||
/**
|
||||
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
||||
@@ -25,200 +25,49 @@ use crate::x::*;
|
||||
* @return Returns the encoded string which must be free()'d when no longed needed.
|
||||
* On errors, NULL is returned.
|
||||
*/
|
||||
pub unsafe fn dc_encode_header_words(to_encode_r: impl AsRef<str>) -> *mut libc::c_char {
|
||||
let to_encode =
|
||||
CString::new(to_encode_r.as_ref().as_bytes()).expect("invalid cstring to_encode");
|
||||
|
||||
let mut ok_to_continue = true;
|
||||
let mut ret_str: *mut libc::c_char = ptr::null_mut();
|
||||
let mut cur: *const libc::c_char = to_encode.as_ptr();
|
||||
let mmapstr: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
if mmapstr.is_null() {
|
||||
ok_to_continue = false;
|
||||
}
|
||||
loop {
|
||||
if !ok_to_continue {
|
||||
if !mmapstr.is_null() {
|
||||
mmap_string_free(mmapstr);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if *cur as libc::c_int != '\u{0}' as i32 {
|
||||
let begin: *const libc::c_char;
|
||||
let mut end: *const libc::c_char;
|
||||
let mut do_quote: bool;
|
||||
let mut quote_words: libc::c_int;
|
||||
begin = cur;
|
||||
end = begin;
|
||||
quote_words = 0i32;
|
||||
do_quote = true;
|
||||
while *cur as libc::c_int != '\u{0}' as i32 {
|
||||
get_word(cur, &mut cur, &mut do_quote);
|
||||
if !do_quote {
|
||||
break;
|
||||
}
|
||||
quote_words = 1i32;
|
||||
end = cur;
|
||||
if *cur as libc::c_int != '\u{0}' as i32 {
|
||||
cur = cur.offset(1isize)
|
||||
}
|
||||
}
|
||||
if 0 != quote_words {
|
||||
if !quote_word(
|
||||
b"utf-8\x00" as *const u8 as *const libc::c_char,
|
||||
mmapstr,
|
||||
begin,
|
||||
end.wrapping_offset_from(begin) as libc::size_t,
|
||||
) {
|
||||
ok_to_continue = false;
|
||||
continue;
|
||||
}
|
||||
if *end as libc::c_int == ' ' as i32 || *end as libc::c_int == '\t' as i32 {
|
||||
if mmap_string_append_c(mmapstr, *end).is_null() {
|
||||
ok_to_continue = false;
|
||||
continue;
|
||||
}
|
||||
end = end.offset(1isize)
|
||||
}
|
||||
if *end as libc::c_int != '\u{0}' as i32 {
|
||||
if mmap_string_append_len(
|
||||
mmapstr,
|
||||
end,
|
||||
cur.wrapping_offset_from(end) as libc::size_t,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
ok_to_continue = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if mmap_string_append_len(
|
||||
mmapstr,
|
||||
begin,
|
||||
cur.wrapping_offset_from(begin) as libc::size_t,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
ok_to_continue = false;
|
||||
continue;
|
||||
}
|
||||
if !(*cur as libc::c_int == ' ' as i32 || *cur as libc::c_int == '\t' as i32) {
|
||||
continue;
|
||||
}
|
||||
if mmap_string_append_c(mmapstr, *cur).is_null() {
|
||||
ok_to_continue = false;
|
||||
continue;
|
||||
}
|
||||
cur = cur.offset(1isize);
|
||||
} else {
|
||||
ret_str = strdup((*mmapstr).str_0);
|
||||
ok_to_continue = false;
|
||||
}
|
||||
}
|
||||
pub fn dc_encode_header_words(input: impl AsRef<str>) -> String {
|
||||
let mut result = String::default();
|
||||
for (_, group) in &input.as_ref().chars().group_by(|c| c.is_whitespace()) {
|
||||
let word: String = group.collect();
|
||||
result.push_str("e_word(&word.as_bytes()));
|
||||
}
|
||||
|
||||
ret_str
|
||||
result
|
||||
}
|
||||
|
||||
unsafe fn quote_word(
|
||||
display_charset: *const libc::c_char,
|
||||
mmapstr: *mut MMAPString,
|
||||
word: *const libc::c_char,
|
||||
size: libc::size_t,
|
||||
) -> bool {
|
||||
let mut cur: *const libc::c_char;
|
||||
let mut i = 0;
|
||||
let mut hex: [libc::c_char; 4] = [0; 4];
|
||||
// let mut col: libc::c_int = 0i32;
|
||||
if mmap_string_append(mmapstr, b"=?\x00" as *const u8 as *const libc::c_char).is_null() {
|
||||
return false;
|
||||
}
|
||||
if mmap_string_append(mmapstr, display_charset).is_null() {
|
||||
return false;
|
||||
}
|
||||
if mmap_string_append(mmapstr, b"?Q?\x00" as *const u8 as *const libc::c_char).is_null() {
|
||||
return false;
|
||||
}
|
||||
// col = (*mmapstr).len as libc::c_int;
|
||||
cur = word;
|
||||
while i < size {
|
||||
let mut do_quote_char = false;
|
||||
match *cur as u8 as char {
|
||||
',' | ':' | '!' | '"' | '#' | '$' | '@' | '[' | '\\' | ']' | '^' | '`' | '{' | '|'
|
||||
| '}' | '~' | '=' | '?' | '_' => do_quote_char = true,
|
||||
_ => {
|
||||
if *cur as u8 >= 128 {
|
||||
do_quote_char = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if do_quote_char {
|
||||
print_hex(hex.as_mut_ptr(), cur);
|
||||
if mmap_string_append(mmapstr, hex.as_mut_ptr()).is_null() {
|
||||
return false;
|
||||
}
|
||||
// col += 3i32
|
||||
} else {
|
||||
if *cur as libc::c_int == ' ' as i32 {
|
||||
if mmap_string_append_c(mmapstr, '_' as i32 as libc::c_char).is_null() {
|
||||
return false;
|
||||
}
|
||||
} else if mmap_string_append_c(mmapstr, *cur).is_null() {
|
||||
return false;
|
||||
}
|
||||
// col += 3i32
|
||||
}
|
||||
cur = cur.offset(1isize);
|
||||
i = i.wrapping_add(1)
|
||||
}
|
||||
if mmap_string_append(mmapstr, b"?=\x00" as *const u8 as *const libc::c_char).is_null() {
|
||||
return false;
|
||||
}
|
||||
fn must_encode(byte: u8) -> bool {
|
||||
static SPECIALS: &[u8] = b",:!\"#$@[\\]^`{|}~=?_";
|
||||
|
||||
true
|
||||
SPECIALS.into_iter().any(|b| *b == byte)
|
||||
}
|
||||
|
||||
unsafe fn get_word(
|
||||
begin: *const libc::c_char,
|
||||
pend: *mut *const libc::c_char,
|
||||
pto_be_quoted: *mut bool,
|
||||
) {
|
||||
let mut cur: *const libc::c_char = begin;
|
||||
while *cur as libc::c_int != ' ' as i32
|
||||
&& *cur as libc::c_int != '\t' as i32
|
||||
&& *cur as libc::c_int != '\u{0}' as i32
|
||||
{
|
||||
cur = cur.offset(1isize)
|
||||
fn quote_word(word: &[u8]) -> String {
|
||||
let mut result = String::default();
|
||||
let mut encoded = false;
|
||||
|
||||
for byte in word {
|
||||
let byte = *byte;
|
||||
if byte >= 128 || must_encode(byte) {
|
||||
result.push_str(&format!("={:2X}", byte));
|
||||
encoded = true;
|
||||
} else if byte == b' ' {
|
||||
result.push('_');
|
||||
encoded = true;
|
||||
} else {
|
||||
result.push(byte as _);
|
||||
}
|
||||
}
|
||||
*pto_be_quoted = to_be_quoted(begin, cur.wrapping_offset_from(begin) as libc::size_t);
|
||||
*pend = cur;
|
||||
|
||||
if encoded {
|
||||
result = format!("=?utf-8?Q?{}?=", &result);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/* ******************************************************************************
|
||||
* Encode/decode header words, RFC 2047
|
||||
******************************************************************************/
|
||||
|
||||
/* see comment below */
|
||||
unsafe fn to_be_quoted(word: *const libc::c_char, size: libc::size_t) -> bool {
|
||||
let mut cur: *const libc::c_char = word;
|
||||
let mut i = 0;
|
||||
while i < size {
|
||||
match *cur as libc::c_int {
|
||||
44 | 58 | 33 | 34 | 35 | 36 | 64 | 91 | 92 | 93 | 94 | 96 | 123 | 124 | 125 | 126
|
||||
| 61 | 63 | 95 => return true,
|
||||
_ => {
|
||||
if *cur as libc::c_uchar as libc::c_int >= 128i32 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = cur.offset(1isize);
|
||||
i = i.wrapping_add(1)
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub unsafe fn dc_decode_header_words(in_0: *const libc::c_char) -> *mut libc::c_char {
|
||||
if in_0.is_null() {
|
||||
return ptr::null_mut();
|
||||
@@ -324,18 +173,11 @@ pub fn dc_decode_ext_header(to_decode: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(to_decode)
|
||||
}
|
||||
|
||||
unsafe fn print_hex(target: *mut libc::c_char, cur: *const libc::c_char) {
|
||||
assert!(!target.is_null());
|
||||
assert!(!cur.is_null());
|
||||
|
||||
let bytes = std::slice::from_raw_parts(cur as *const _, strlen(cur));
|
||||
let raw = CString::yolo(format!("={}", &hex::encode_upper(bytes)[..2]));
|
||||
libc::memcpy(target as *mut _, raw.as_ptr() as *const _, 4);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use libc::strcmp;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[test]
|
||||
@@ -358,19 +200,15 @@ mod tests {
|
||||
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "just ascii test");
|
||||
free(buf1 as *mut libc::c_void);
|
||||
|
||||
buf1 = dc_encode_header_words("abcdef");
|
||||
assert_eq!(CStr::from_ptr(buf1).to_str().unwrap(), "abcdef");
|
||||
free(buf1 as *mut libc::c_void);
|
||||
assert_eq!(dc_encode_header_words("abcdef"), "abcdef");
|
||||
|
||||
buf1 = dc_encode_header_words(
|
||||
let r = dc_encode_header_words(
|
||||
std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec())
|
||||
.unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
strncmp(buf1, b"=?utf-8\x00" as *const u8 as *const libc::c_char, 7),
|
||||
0
|
||||
);
|
||||
assert!(r.starts_with("=?utf-8"));
|
||||
|
||||
buf1 = r.strdup();
|
||||
let buf2: *mut libc::c_char = dc_decode_header_words(buf1);
|
||||
assert_eq!(
|
||||
strcmp(
|
||||
@@ -379,7 +217,6 @@ mod tests {
|
||||
),
|
||||
0
|
||||
);
|
||||
free(buf1 as *mut libc::c_void);
|
||||
free(buf2 as *mut libc::c_void);
|
||||
|
||||
buf1 = dc_decode_header_words(
|
||||
@@ -393,7 +230,6 @@ mod tests {
|
||||
),
|
||||
0
|
||||
);
|
||||
free(buf1 as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,18 +274,6 @@ mod tests {
|
||||
assert_eq!(dc_needs_ext_header("a b"), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_print_hex() {
|
||||
let mut hex: [libc::c_char; 4] = [0; 4];
|
||||
let cur = b"helloworld" as *const u8 as *const libc::c_char;
|
||||
unsafe { print_hex(hex.as_mut_ptr(), cur) };
|
||||
assert_eq!(to_string(hex.as_ptr() as *const _), "=68");
|
||||
|
||||
let cur = b":" as *const u8 as *const libc::c_char;
|
||||
unsafe { print_hex(hex.as_mut_ptr(), cur) };
|
||||
assert_eq!(to_string(hex.as_ptr() as *const _), "=3A");
|
||||
}
|
||||
|
||||
use proptest::prelude::*;
|
||||
|
||||
proptest! {
|
||||
@@ -465,5 +289,13 @@ mod tests {
|
||||
// make sure this never panics
|
||||
let _decoded = dc_decode_ext_header(&buf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_header_roundtrip(input: String) {
|
||||
let encoded = dc_encode_header_words(&input);
|
||||
let decoded = dc_decode_header_words_safe(&encoded);
|
||||
|
||||
assert_eq!(input, decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
766
src/dc_tools.rs
766
src/dc_tools.rs
File diff suppressed because it is too large
Load Diff
1159
src/e2ee.rs
1159
src/e2ee.rs
File diff suppressed because it is too large
Load Diff
16
src/error.rs
16
src/error.rs
@@ -26,6 +26,10 @@ pub enum Error {
|
||||
CStringError(crate::dc_tools::CStringError),
|
||||
#[fail(display = "PGP: {:?}", _0)]
|
||||
Pgp(pgp::errors::Error),
|
||||
#[fail(display = "Base64Decode: {:?}", _0)]
|
||||
Base64Decode(base64::DecodeError),
|
||||
#[fail(display = "{:?}", _0)]
|
||||
FromUtf8(std::string::FromUtf8Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -36,6 +40,12 @@ impl From<rusqlite::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<base64::DecodeError> for Error {
|
||||
fn from(err: base64::DecodeError) -> Error {
|
||||
Error::Base64Decode(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<failure::Error> for Error {
|
||||
fn from(err: failure::Error) -> Error {
|
||||
Error::Failure(err)
|
||||
@@ -60,6 +70,12 @@ impl From<std::str::Utf8Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::FromUtf8Error> for Error {
|
||||
fn from(err: std::string::FromUtf8Error) -> Error {
|
||||
Error::FromUtf8(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<image_meta::ImageError> for Error {
|
||||
fn from(err: image_meta::ImageError) -> Error {
|
||||
Error::Image(err)
|
||||
|
||||
@@ -167,7 +167,7 @@ pub enum Event {
|
||||
#[strum(props(id = "2041"))]
|
||||
ConfigureProgress(usize),
|
||||
|
||||
/// Inform about the import/export progress started by dc_imex().
|
||||
/// Inform about the import/export progress started by imex().
|
||||
///
|
||||
/// @param data1 (usize) 0=error, 1-999=progress in permille, 1000=success and done
|
||||
/// @param data2 0
|
||||
@@ -175,8 +175,8 @@ pub enum Event {
|
||||
#[strum(props(id = "2051"))]
|
||||
ImexProgress(usize),
|
||||
|
||||
/// A file has been exported. A file has been written by dc_imex().
|
||||
/// This event may be sent multiple times by a single call to dc_imex().
|
||||
/// A file has been exported. A file has been written by imex().
|
||||
/// This event may be sent multiple times by a single call to imex().
|
||||
///
|
||||
/// A typical purpose for a handler of this event may be to make the file public to some system
|
||||
/// services.
|
||||
|
||||
142
src/imap.rs
142
src/imap.rs
@@ -1,6 +1,4 @@
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::ptr;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Condvar, Mutex, RwLock,
|
||||
@@ -10,21 +8,22 @@ use std::time::{Duration, SystemTime};
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_receive_imf::dc_receive_imf;
|
||||
use crate::dc_tools::CStringExt;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use crate::job::{job_add, Action};
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::{dc_rfc724_mid_exists, dc_update_msg_move_state, dc_update_server_uid};
|
||||
use crate::message::{self, update_msg_move_state, update_server_uid};
|
||||
use crate::oauth2::dc_get_oauth2_access_token;
|
||||
use crate::param::Params;
|
||||
|
||||
const DC_IMAP_SEEN: usize = 0x0001;
|
||||
|
||||
const DC_SUCCESS: usize = 3;
|
||||
const DC_ALREADY_DONE: usize = 2;
|
||||
const DC_RETRY_LATER: usize = 1;
|
||||
const DC_FAILED: usize = 0;
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ImapResult {
|
||||
Failed,
|
||||
RetryLater,
|
||||
AlreadyDone,
|
||||
Success,
|
||||
}
|
||||
|
||||
const PREFETCH_FLAGS: &str = "(UID ENVELOPE)";
|
||||
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
||||
@@ -111,6 +110,8 @@ impl Client {
|
||||
) -> imap::error::Result<Self> {
|
||||
let stream = net::TcpStream::connect(addr)?;
|
||||
let tls = native_tls::TlsConnector::builder()
|
||||
// see also: https://github.com/deltachat/deltachat-core-rust/issues/203
|
||||
.danger_accept_invalid_certs(true)
|
||||
.danger_accept_invalid_hostnames(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
@@ -821,10 +822,7 @@ impl Imap {
|
||||
.message_id
|
||||
.expect("missing message id");
|
||||
|
||||
if 0 == unsafe {
|
||||
let message_id_c = CString::yolo(message_id);
|
||||
precheck_imf(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
|
||||
} {
|
||||
if !precheck_imf(context, &message_id, folder.as_ref(), cur_uid) {
|
||||
// check passed, go fetch the rest
|
||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||
info!(
|
||||
@@ -957,14 +955,7 @@ impl Imap {
|
||||
if !is_deleted && msg.body().is_some() {
|
||||
let body = msg.body().unwrap();
|
||||
unsafe {
|
||||
dc_receive_imf(
|
||||
context,
|
||||
body.as_ptr() as *const libc::c_char,
|
||||
body.len(),
|
||||
folder.as_ref(),
|
||||
server_uid,
|
||||
flags as u32,
|
||||
);
|
||||
dc_receive_imf(context, &body, folder.as_ref(), server_uid, flags as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1135,12 +1126,12 @@ impl Imap {
|
||||
uid: u32,
|
||||
dest_folder: S2,
|
||||
dest_uid: &mut u32,
|
||||
) -> usize {
|
||||
let mut res = DC_RETRY_LATER;
|
||||
) -> ImapResult {
|
||||
let mut res = ImapResult::RetryLater;
|
||||
let set = format!("{}", uid);
|
||||
|
||||
if uid == 0 {
|
||||
res = DC_FAILED;
|
||||
res = ImapResult::Failed;
|
||||
} else if folder.as_ref() == dest_folder.as_ref() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1150,7 +1141,7 @@ impl Imap {
|
||||
dest_folder.as_ref()
|
||||
);
|
||||
|
||||
res = DC_ALREADY_DONE;
|
||||
res = ImapResult::AlreadyDone;
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
@@ -1170,7 +1161,7 @@ impl Imap {
|
||||
let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||
match session.uid_mv(&set, &dest_folder) {
|
||||
Ok(_) => {
|
||||
res = DC_SUCCESS;
|
||||
res = ImapResult::Success;
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -1210,22 +1201,22 @@ impl Imap {
|
||||
warn!(context, "Cannot mark message as \"Deleted\".",);
|
||||
}
|
||||
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
||||
res = DC_SUCCESS;
|
||||
res = ImapResult::Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if res == DC_SUCCESS {
|
||||
if res == ImapResult::Success {
|
||||
// TODO: is this correct?
|
||||
*dest_uid = uid;
|
||||
}
|
||||
|
||||
if res == DC_RETRY_LATER {
|
||||
if res == ImapResult::RetryLater {
|
||||
if self.should_reconnect() {
|
||||
DC_RETRY_LATER
|
||||
ImapResult::RetryLater
|
||||
} else {
|
||||
DC_FAILED
|
||||
ImapResult::Failed
|
||||
}
|
||||
} else {
|
||||
res
|
||||
@@ -1259,11 +1250,11 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
||||
let mut res = DC_RETRY_LATER;
|
||||
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||
let mut res = ImapResult::RetryLater;
|
||||
|
||||
if uid == 0 {
|
||||
res = DC_FAILED
|
||||
res = ImapResult::Failed
|
||||
} else if self.is_connected() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1281,28 +1272,28 @@ impl Imap {
|
||||
} else if self.add_flag(context, uid, "\\Seen") == 0 {
|
||||
warn!(context, "Cannot mark message as seen.",);
|
||||
} else {
|
||||
res = DC_SUCCESS
|
||||
res = ImapResult::Success
|
||||
}
|
||||
}
|
||||
|
||||
if res == DC_RETRY_LATER {
|
||||
if res == ImapResult::RetryLater {
|
||||
if self.should_reconnect() {
|
||||
DC_RETRY_LATER
|
||||
ImapResult::RetryLater
|
||||
} else {
|
||||
DC_FAILED
|
||||
ImapResult::Failed
|
||||
}
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
||||
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||
// returns 0=job should be retried later, 1=job done, 2=job done and flag just set
|
||||
let mut res = DC_RETRY_LATER;
|
||||
let mut res = ImapResult::RetryLater;
|
||||
let set = format!("{}", uid);
|
||||
|
||||
if uid == 0 {
|
||||
res = DC_FAILED;
|
||||
res = ImapResult::Failed;
|
||||
} else if self.is_connected() {
|
||||
info!(
|
||||
context,
|
||||
@@ -1372,21 +1363,21 @@ impl Imap {
|
||||
.unwrap_or_else(|| false);
|
||||
|
||||
res = if flag_set {
|
||||
DC_ALREADY_DONE
|
||||
ImapResult::AlreadyDone
|
||||
} else if self.add_flag(context, uid, "$MDNSent") != 0 {
|
||||
DC_SUCCESS
|
||||
ImapResult::Success
|
||||
} else {
|
||||
res
|
||||
};
|
||||
|
||||
if res == DC_SUCCESS {
|
||||
if res == ImapResult::Success {
|
||||
info!(context, "$MDNSent just set and MDN will be sent.");
|
||||
} else {
|
||||
info!(context, "$MDNSent already set and MDN already sent.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = DC_SUCCESS;
|
||||
res = ImapResult::Success;
|
||||
info!(
|
||||
context,
|
||||
"Cannot store $MDNSent flags, risk sending duplicate MDN.",
|
||||
@@ -1395,11 +1386,11 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
if res == DC_RETRY_LATER {
|
||||
if res == ImapResult::RetryLater {
|
||||
if self.should_reconnect() {
|
||||
DC_RETRY_LATER
|
||||
ImapResult::RetryLater
|
||||
} else {
|
||||
DC_FAILED
|
||||
ImapResult::Failed
|
||||
}
|
||||
} else {
|
||||
res
|
||||
@@ -1643,43 +1634,28 @@ fn get_folder_meaning(folder_name: &imap::types::Name) -> FolderMeaning {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn precheck_imf(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
server_folder: &str,
|
||||
server_uid: u32,
|
||||
) -> libc::c_int {
|
||||
let mut rfc724_mid_exists: libc::c_int = 0i32;
|
||||
let msg_id: u32;
|
||||
let mut old_server_folder: *mut libc::c_char = ptr::null_mut();
|
||||
let mut old_server_uid: u32 = 0i32 as u32;
|
||||
let mut mark_seen: libc::c_int = 0i32;
|
||||
msg_id = dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
);
|
||||
if msg_id != 0i32 as libc::c_uint {
|
||||
rfc724_mid_exists = 1i32;
|
||||
if *old_server_folder.offset(0isize) as libc::c_int == 0i32
|
||||
&& old_server_uid == 0i32 as libc::c_uint
|
||||
{
|
||||
info!(context, "[move] detected bbc-self {}", as_str(rfc724_mid),);
|
||||
mark_seen = 1i32
|
||||
} else if as_str(old_server_folder) != server_folder {
|
||||
info!(
|
||||
context,
|
||||
"[move] detected moved message {}",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
|
||||
fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server_uid: u32) -> bool {
|
||||
let mut rfc724_mid_exists = false;
|
||||
let mut mark_seen = false;
|
||||
|
||||
if let Ok((old_server_folder, old_server_uid, msg_id)) =
|
||||
message::rfc724_mid_exists(context, &rfc724_mid)
|
||||
{
|
||||
rfc724_mid_exists = true;
|
||||
|
||||
if old_server_folder.is_empty() && old_server_uid == 0 {
|
||||
info!(context, "[move] detected bbc-self {}", rfc724_mid,);
|
||||
mark_seen = true;
|
||||
} else if old_server_folder != server_folder {
|
||||
info!(context, "[move] detected moved message {}", rfc724_mid,);
|
||||
update_msg_move_state(context, &rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
if old_server_folder != server_folder || old_server_uid != server_uid {
|
||||
update_server_uid(context, &rfc724_mid, server_folder, server_uid);
|
||||
}
|
||||
context.do_heuristics_moves(server_folder, msg_id);
|
||||
if 0 != mark_seen {
|
||||
|
||||
if mark_seen {
|
||||
job_add(
|
||||
context,
|
||||
Action::MarkseenMsgOnImap,
|
||||
@@ -1689,6 +1665,6 @@ unsafe fn precheck_imf(
|
||||
);
|
||||
}
|
||||
}
|
||||
libc::free(old_server_folder as *mut libc::c_void);
|
||||
|
||||
rfc724_mid_exists
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
316
src/job.rs
316
src/job.rs
@@ -1,26 +1,22 @@
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use mmime::clist::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::chat;
|
||||
use crate::configure::*;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_imex::*;
|
||||
use crate::dc_mimefactory::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use crate::imap::*;
|
||||
use crate::imex::*;
|
||||
use crate::location;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::*;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::mimefactory::{vec_contains_lowercase, Loaded, MimeFactory};
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
use crate::x::*;
|
||||
|
||||
/// Thread IDs
|
||||
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
||||
@@ -141,7 +137,7 @@ impl Job {
|
||||
}
|
||||
|
||||
if let Some(filename) = self.param.get(Param::File) {
|
||||
if let Some(body) = dc_read_file_safe(context, filename) {
|
||||
if let Ok(body) = dc_read_file(context, filename) {
|
||||
if let Some(recipients) = self.param.get(Param::Recipients) {
|
||||
let recipients_list = recipients
|
||||
.split("\x1e")
|
||||
@@ -157,7 +153,7 @@ impl Job {
|
||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||
this happends if dc_delete_msgs() was called
|
||||
before the generated mime was sent out */
|
||||
if 0 != self.foreign_id && !dc_msg_exists(context, self.foreign_id) {
|
||||
if 0 != self.foreign_id && !message::exists(context, self.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
"Message {} for job {} does not exist", self.foreign_id, self.job_id,
|
||||
@@ -176,7 +172,7 @@ impl Job {
|
||||
} else {
|
||||
dc_delete_file(context, filename);
|
||||
if 0 != self.foreign_id {
|
||||
dc_update_msg_state(
|
||||
message::update_msg_state(
|
||||
context,
|
||||
self.foreign_id,
|
||||
MessageState::OutDelivered,
|
||||
@@ -210,53 +206,49 @@ impl Job {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn do_DC_JOB_MOVE_MSG(&mut self, context: &Context) {
|
||||
let ok_to_continue;
|
||||
let mut dest_uid = 0;
|
||||
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
self.try_again_later(3, None);
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
let mut dest_uid = 0;
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
msg.server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
3 => {
|
||||
dc_update_server_uid(context, msg.rfc724_mid, &dest_folder, dest_uid);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
msg.server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) {
|
||||
ImapResult::RetryLater => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
ImapResult::Success => {
|
||||
message::update_server_uid(
|
||||
context,
|
||||
&msg.rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
ImapResult::Failed | ImapResult::AlreadyDone => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,101 +256,75 @@ impl Job {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn do_DC_JOB_DELETE_MSG_ON_IMAP(&mut self, context: &Context) {
|
||||
let mut delete_from_server = 1;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
if !(msg.rfc724_mid.is_null()
|
||||
|| unsafe { *msg.rfc724_mid.offset(0isize) as libc::c_int == 0 })
|
||||
{
|
||||
let ok_to_continue1;
|
||||
if let Ok(mut msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
if !msg.rfc724_mid.is_empty() {
|
||||
/* eg. device messages have no Message-ID */
|
||||
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
|
||||
let mut delete_from_server = true;
|
||||
if message::rfc724_mid_cnt(context, &msg.rfc724_mid) != 1 {
|
||||
info!(
|
||||
context,
|
||||
"The message is deleted from the server when all parts are deleted.",
|
||||
);
|
||||
delete_from_server = 0i32
|
||||
delete_from_server = false;
|
||||
}
|
||||
/* if this is the last existing part of the message, we delete the message from the server */
|
||||
if 0 != delete_from_server {
|
||||
let ok_to_continue;
|
||||
if delete_from_server {
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
self.try_again_later(3i32, None);
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mid = unsafe { CStr::from_ptr(msg.rfc724_mid).to_str().unwrap() };
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut msg.server_uid) {
|
||||
self.try_again_later(-1i32, None);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = false;
|
||||
let mid = msg.rfc724_mid;
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
if 0 == inbox.delete_msg(context, &mid, server_folder, &mut msg.server_uid) {
|
||||
self.try_again_later(-1i32, None);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
dc_delete_msg_from_db(context, msg.id);
|
||||
}
|
||||
Message::delete_from_db(context, msg.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn do_DC_JOB_MARKSEEN_MSG_ON_IMAP(&mut self, context: &Context) {
|
||||
let ok_to_continue;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
self.try_again_later(3i32, None);
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
match inbox.set_seen(context, server_folder, msg.server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
_ => {
|
||||
if 0 != msg.param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder = msg.server_folder.as_ref().unwrap();
|
||||
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
match inbox.set_seen(context, server_folder, msg.server_uid) {
|
||||
ImapResult::Failed => {}
|
||||
ImapResult::RetryLater => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
_ => {
|
||||
if 0 != msg.param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder = msg.server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.set_mdnsent(context, folder, msg.server_uid) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
3 => {
|
||||
send_mdn(context, msg.id);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
match inbox.set_mdnsent(context, folder, msg.server_uid) {
|
||||
ImapResult::RetryLater => {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
ImapResult::Success => {
|
||||
send_mdn(context, msg.id);
|
||||
}
|
||||
ImapResult::Failed | ImapResult::AlreadyDone => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,47 +334,40 @@ impl Job {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn do_DC_JOB_MARKSEEN_MDN_ON_IMAP(&mut self, context: &Context) {
|
||||
let ok_to_continue;
|
||||
let folder = self
|
||||
.param
|
||||
.get(Param::ServerFolder)
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
let uid = self.param.get_int(Param::ServerUid).unwrap_or_default() as u32;
|
||||
let mut dest_uid = 0;
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
self.try_again_later(3, None);
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
self.try_again_later(3i32, None);
|
||||
if inbox.set_seen(context, &folder, uid) == ImapResult::Failed {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let mut dest_uid = 0;
|
||||
if ImapResult::RetryLater
|
||||
== inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
self.try_again_later(3, None);
|
||||
}
|
||||
self.try_again_later(3, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -642,12 +601,12 @@ pub fn job_action_exists(context: &Context, action: Action) -> bool {
|
||||
|
||||
/* special case for DC_JOB_SEND_MSG_TO_SMTP */
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
pub fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
let mut success = 0;
|
||||
|
||||
/* load message data */
|
||||
let mimefactory = dc_mimefactory_load_msg(context, msg_id);
|
||||
if mimefactory.is_err() || mimefactory.as_ref().unwrap().from_addr.is_null() {
|
||||
let mimefactory = MimeFactory::load_msg(context, msg_id);
|
||||
if mimefactory.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot load data to send, maybe the message is deleted in between.",
|
||||
@@ -669,53 +628,48 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
mimefactory.msg.param.set_int(Param::Width, 0);
|
||||
mimefactory.msg.param.set_int(Param::Height, 0);
|
||||
|
||||
if let Some(buf) = dc_read_file_safe(context, pathNfilename) {
|
||||
if let Ok(buf) = dc_read_file(context, pathNfilename) {
|
||||
if let Ok((width, height)) = dc_get_filemeta(&buf) {
|
||||
mimefactory.msg.param.set_int(Param::Width, width as i32);
|
||||
mimefactory.msg.param.set_int(Param::Height, height as i32);
|
||||
}
|
||||
}
|
||||
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* create message */
|
||||
if !dc_mimefactory_render(context, &mut mimefactory) {
|
||||
dc_set_msg_failed(context, msg_id, as_opt_str(mimefactory.error));
|
||||
if let Err(msg) = unsafe { mimefactory.render() } {
|
||||
let e = msg.to_string();
|
||||
message::set_msg_failed(context, msg_id, Some(e));
|
||||
} else if 0
|
||||
!= mimefactory
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
&& 0 == mimefactory.out_encrypted
|
||||
&& !mimefactory.out_encrypted
|
||||
{
|
||||
/* unrecoverable */
|
||||
warn!(
|
||||
context,
|
||||
"e2e encryption unavailable {} - {:?}",
|
||||
msg_id,
|
||||
mimefactory.msg.param.get_int(Param::GuranteeE2ee),
|
||||
);
|
||||
dc_set_msg_failed(
|
||||
message::set_msg_failed(
|
||||
context,
|
||||
msg_id,
|
||||
Some("End-to-end-encryption unavailable unexpectedly."),
|
||||
);
|
||||
} else {
|
||||
/* unrecoverable */
|
||||
if !clist_search_string_nocase(mimefactory.recipients_addr, mimefactory.from_addr) {
|
||||
clist_insert_after(
|
||||
mimefactory.recipients_names,
|
||||
(*mimefactory.recipients_names).last,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
clist_insert_after(
|
||||
mimefactory.recipients_addr,
|
||||
(*mimefactory.recipients_addr).last,
|
||||
dc_strdup(mimefactory.from_addr) as *mut libc::c_void,
|
||||
);
|
||||
if !vec_contains_lowercase(&mimefactory.recipients_addr, &mimefactory.from_addr) {
|
||||
mimefactory.recipients_names.push("".to_string());
|
||||
mimefactory
|
||||
.recipients_addr
|
||||
.push(mimefactory.from_addr.to_string());
|
||||
}
|
||||
if 0 != mimefactory.out_gossiped {
|
||||
if mimefactory.out_gossiped {
|
||||
chat::set_gossiped_timestamp(context, mimefactory.msg.chat_id, time());
|
||||
}
|
||||
if 0 != mimefactory.out_last_added_location_id {
|
||||
@@ -734,7 +688,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 != mimefactory.out_encrypted
|
||||
if mimefactory.out_encrypted
|
||||
&& mimefactory
|
||||
.msg
|
||||
.param
|
||||
@@ -743,7 +697,7 @@ pub unsafe fn job_send_msg(context: &Context, msg_id: u32) -> libc::c_int {
|
||||
== 0
|
||||
{
|
||||
mimefactory.msg.param.set_int(Param::GuranteeE2ee, 1);
|
||||
dc_msg_save_param_to_disk(context, &mut mimefactory.msg);
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
}
|
||||
success = add_smtp_job(context, Action::SendMsgToSmtp, &mut mimefactory);
|
||||
}
|
||||
@@ -763,6 +717,14 @@ pub fn perform_imap_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_imap_jobs ended.",);
|
||||
}
|
||||
|
||||
pub fn perform_mvbox_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_mbox_jobs EMPTY (for now).",);
|
||||
}
|
||||
|
||||
pub fn perform_sentbox_jobs(context: &Context) {
|
||||
info!(context, "dc_perform_sentbox_jobs EMPTY (for now).",);
|
||||
}
|
||||
|
||||
fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
let query = if !probe_network {
|
||||
// processing for first-try and after backoff-timeouts:
|
||||
@@ -861,8 +823,13 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
Action::MarkseenMdnOnImap => job.do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context),
|
||||
Action::MoveMsg => job.do_DC_JOB_MOVE_MSG(context),
|
||||
Action::SendMdn => job.do_DC_JOB_SEND(context),
|
||||
Action::ConfigureImap => unsafe { dc_job_do_DC_JOB_CONFIGURE_IMAP(context, &job) },
|
||||
Action::ImexImap => unsafe { dc_job_do_DC_JOB_IMEX_IMAP(context, &job) },
|
||||
Action::ConfigureImap => unsafe { dc_job_do_DC_JOB_CONFIGURE_IMAP(context) },
|
||||
Action::ImexImap => match job_do_DC_JOB_IMEX_IMAP(context, &job) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
error!(context, "{}", err);
|
||||
}
|
||||
},
|
||||
Action::MaybeSendLocations => {
|
||||
location::job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context, &job)
|
||||
}
|
||||
@@ -936,7 +903,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
||||
}
|
||||
} else {
|
||||
if job.action == Action::SendMsgToSmtp {
|
||||
dc_set_msg_failed(context, job.foreign_id, job.pending_error.as_ref());
|
||||
message::set_msg_failed(context, job.foreign_id, job.pending_error.as_ref());
|
||||
}
|
||||
job.delete(context);
|
||||
}
|
||||
@@ -989,20 +956,18 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
}
|
||||
|
||||
fn send_mdn(context: &Context, msg_id: u32) {
|
||||
if let Ok(mut mimefactory) = unsafe { dc_mimefactory_load_mdn(context, msg_id) } {
|
||||
if unsafe { dc_mimefactory_render(context, &mut mimefactory) } {
|
||||
if let Ok(mut mimefactory) = MimeFactory::load_mdn(context, msg_id) {
|
||||
if unsafe { mimefactory.render() }.is_ok() {
|
||||
add_smtp_job(context, Action::SendMdn, &mut mimefactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_t) -> libc::c_int {
|
||||
fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut recipients: *mut libc::c_char = ptr::null_mut();
|
||||
let mut param = Params::new();
|
||||
let path_filename =
|
||||
dc_get_fine_path_filename(context, "$BLOBDIR", as_str(mimefactory.rfc724_mid));
|
||||
let path_filename = dc_get_fine_path_filename(context, "$BLOBDIR", &mimefactory.rfc724_mid);
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(*mimefactory.out).str_0 as *const u8,
|
||||
@@ -1013,24 +978,18 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
|
||||
error!(
|
||||
context,
|
||||
"Could not write message <{}> to \"{}\".",
|
||||
to_string(mimefactory.rfc724_mid),
|
||||
mimefactory.rfc724_mid,
|
||||
path_filename.display(),
|
||||
);
|
||||
} else {
|
||||
recipients = unsafe {
|
||||
dc_str_from_clist(
|
||||
mimefactory.recipients_addr,
|
||||
b"\x1e\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
info!(context, "add_smtp_job file written: {:?}", path_filename);
|
||||
let recipients = mimefactory.recipients_addr.join("\x1e");
|
||||
param.set(Param::File, path_filename.to_string_lossy());
|
||||
param.set(Param::Recipients, as_str(recipients));
|
||||
param.set(Param::Recipients, &recipients);
|
||||
job_add(
|
||||
context,
|
||||
action,
|
||||
(if mimefactory.loaded as libc::c_uint
|
||||
== DC_MF_MSG_LOADED as libc::c_int as libc::c_uint
|
||||
{
|
||||
(if mimefactory.loaded == Loaded::Message {
|
||||
mimefactory.msg.id
|
||||
} else {
|
||||
0
|
||||
@@ -1040,9 +999,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
|
||||
);
|
||||
success = 1;
|
||||
}
|
||||
unsafe {
|
||||
free(recipients.cast());
|
||||
}
|
||||
success
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::collections::BTreeMap;
|
||||
use std::io::Cursor;
|
||||
use std::path::Path;
|
||||
|
||||
use libc;
|
||||
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
|
||||
use pgp::ser::Serialize;
|
||||
use pgp::types::{KeyTrait, SecretKeyTrait};
|
||||
@@ -254,14 +253,14 @@ pub fn dc_key_save_self_keypair(
|
||||
public_key: &Key,
|
||||
private_key: &Key,
|
||||
addr: impl AsRef<str>,
|
||||
is_default: libc::c_int,
|
||||
is_default: bool,
|
||||
sql: &Sql,
|
||||
) -> bool {
|
||||
sql::execute(
|
||||
context,
|
||||
sql,
|
||||
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
|
||||
params![addr.as_ref(), is_default, public_key.to_bytes(), private_key.to_bytes(), time()],
|
||||
params![addr.as_ref(), is_default as i32, public_key.to_bytes(), private_key.to_bytes(), time()],
|
||||
).is_ok()
|
||||
}
|
||||
|
||||
|
||||
13
src/lib.rs
13
src/lib.rs
@@ -39,35 +39,36 @@ pub mod contact;
|
||||
pub mod context;
|
||||
mod e2ee;
|
||||
mod imap;
|
||||
pub mod imex;
|
||||
pub mod job;
|
||||
mod job_thread;
|
||||
pub mod key;
|
||||
pub mod keyring;
|
||||
pub mod location;
|
||||
mod login_param;
|
||||
pub mod lot;
|
||||
pub mod message;
|
||||
mod mimefactory;
|
||||
pub mod oauth2;
|
||||
mod param;
|
||||
pub mod peerstate;
|
||||
pub mod pgp;
|
||||
pub mod qr;
|
||||
pub mod securejoin;
|
||||
mod smtp;
|
||||
pub mod sql;
|
||||
mod stock;
|
||||
pub mod x;
|
||||
mod token;
|
||||
#[macro_use]
|
||||
mod wrapmime;
|
||||
|
||||
pub mod dc_array;
|
||||
mod dc_dehtml;
|
||||
pub mod dc_imex;
|
||||
mod dc_mimefactory;
|
||||
pub mod dc_mimeparser;
|
||||
pub mod dc_receive_imf;
|
||||
mod dc_simplify;
|
||||
mod dc_strencode;
|
||||
pub mod dc_tools;
|
||||
mod login_param;
|
||||
pub mod securejoin;
|
||||
mod token;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::*;
|
||||
use crate::message::Message;
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
@@ -214,7 +214,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
|
||||
.is_ok()
|
||||
{
|
||||
if 0 != seconds && !is_sending_locations_before {
|
||||
msg = dc_msg_new(Viewtype::Text);
|
||||
msg = Message::new(Viewtype::Text);
|
||||
msg.text =
|
||||
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
|
||||
msg.param.set_int(Param::Cmd, 8);
|
||||
@@ -601,7 +601,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
|
||||
// the easiest way to determine this, is to check for an empty message queue.
|
||||
// (might not be 100%, however, as positions are sent combined later
|
||||
// and dc_set_location() is typically called periodically, this is ok)
|
||||
let mut msg = dc_msg_new(Viewtype::Text);
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.hidden = true;
|
||||
msg.param.set_int(Param::Cmd, 9);
|
||||
Some((chat_id, msg))
|
||||
|
||||
1147
src/message.rs
1147
src/message.rs
File diff suppressed because it is too large
Load Diff
954
src/mimefactory.rs
Normal file
954
src/mimefactory.rs
Normal file
@@ -0,0 +1,954 @@
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
|
||||
use chrono::TimeZone;
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::types_helper::*;
|
||||
use mmime::mailmime::disposition::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::types_helper::*;
|
||||
use mmime::mailmime::write_mem::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
use crate::chat::{self, Chat};
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::{get_version_str, Context};
|
||||
use crate::dc_mimeparser::{mailmime_find_mailimf_fields, SystemMessage};
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::e2ee::*;
|
||||
use crate::error::Error;
|
||||
use crate::location;
|
||||
use crate::message::{self, Message};
|
||||
use crate::param::*;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::wrapmime;
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum Loaded {
|
||||
Nothing,
|
||||
Message,
|
||||
MDN, // TODO: invent more descriptive name
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MimeFactory<'a> {
|
||||
pub from_addr: String,
|
||||
pub from_displayname: String,
|
||||
pub selfstatus: String,
|
||||
pub recipients_names: Vec<String>,
|
||||
pub recipients_addr: Vec<String>,
|
||||
pub timestamp: i64,
|
||||
pub rfc724_mid: String,
|
||||
pub loaded: Loaded,
|
||||
pub msg: Message,
|
||||
pub chat: Option<Chat>,
|
||||
pub increation: bool,
|
||||
pub in_reply_to: String,
|
||||
pub references: String,
|
||||
pub req_mdn: bool,
|
||||
pub out: *mut MMAPString,
|
||||
pub out_encrypted: bool,
|
||||
pub out_gossiped: bool,
|
||||
pub out_last_added_location_id: u32,
|
||||
pub context: &'a Context,
|
||||
}
|
||||
|
||||
impl<'a> MimeFactory<'a> {
|
||||
fn new(context: &'a Context, msg: Message) -> Self {
|
||||
let cget = |context: &Context, name: &str| context.sql.get_config(context, name);
|
||||
MimeFactory {
|
||||
from_addr: cget(&context, "configured_addr").unwrap_or_default(),
|
||||
from_displayname: cget(&context, "displayname").unwrap_or_default(),
|
||||
selfstatus: cget(&context, "selfstatus")
|
||||
.unwrap_or_else(|| context.stock_str(StockMessage::StatusLine).to_string()),
|
||||
recipients_names: Vec::with_capacity(5),
|
||||
recipients_addr: Vec::with_capacity(5),
|
||||
timestamp: 0,
|
||||
rfc724_mid: String::default(),
|
||||
loaded: Loaded::Nothing,
|
||||
msg,
|
||||
chat: None,
|
||||
increation: false,
|
||||
in_reply_to: String::default(),
|
||||
references: String::default(),
|
||||
req_mdn: false,
|
||||
out: ptr::null_mut(),
|
||||
out_encrypted: false,
|
||||
out_gossiped: false,
|
||||
out_last_added_location_id: 0,
|
||||
context,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize_mime_message(
|
||||
&mut self,
|
||||
message: *mut Mailmime,
|
||||
encrypted: bool,
|
||||
gossiped: bool,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
assert!(self.out.is_null()); // guard against double-calls
|
||||
self.out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
let mut col: libc::c_int = 0;
|
||||
ensure_eq!(
|
||||
mailmime_write_mem(self.out, &mut col, message),
|
||||
0,
|
||||
"mem-error"
|
||||
);
|
||||
}
|
||||
self.out_encrypted = encrypted;
|
||||
self.out_gossiped = encrypted && gossiped;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_mdn(context: &'a Context, msg_id: u32) -> Result<MimeFactory, Error> {
|
||||
if 0 == context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
// MDNs not enabled - check this is late, in the job. the use may have changed its
|
||||
// choice while offline ...
|
||||
|
||||
bail!("MDNs disabled ")
|
||||
}
|
||||
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
let mut factory = MimeFactory::new(context, msg);
|
||||
let contact = Contact::load_from_db(factory.context, factory.msg.from_id)?;
|
||||
|
||||
// Do not send MDNs trash etc.; chats.blocked is already checked by the caller
|
||||
// in dc_markseen_msgs()
|
||||
ensure!(!contact.is_blocked(), "Contact blocked");
|
||||
ensure!(
|
||||
factory.msg.chat_id > DC_CHAT_ID_LAST_SPECIAL,
|
||||
"Invalid chat id"
|
||||
);
|
||||
|
||||
factory
|
||||
.recipients_names
|
||||
.push(contact.get_authname().to_string());
|
||||
factory.recipients_addr.push(contact.get_addr().to_string());
|
||||
factory.timestamp = dc_create_smeared_timestamp(factory.context);
|
||||
factory.rfc724_mid = dc_create_outgoing_rfc724_mid(None, &factory.from_addr);
|
||||
factory.loaded = Loaded::MDN;
|
||||
|
||||
Ok(factory)
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Render
|
||||
******************************************************************************/
|
||||
// restrict unsafe to parts, introduce wrapmime helpers where appropriate
|
||||
pub unsafe fn render(&mut self) -> Result<(), Error> {
|
||||
if self.loaded == Loaded::Nothing || !self.out.is_null() {
|
||||
bail!("Invalid use of mimefactory-object.");
|
||||
}
|
||||
let context = &self.context;
|
||||
|
||||
/* create basic mail
|
||||
*************************************************************************/
|
||||
|
||||
let from: *mut mailimf_mailbox_list = mailimf_mailbox_list_new_empty();
|
||||
mailimf_mailbox_list_add(
|
||||
from,
|
||||
mailimf_mailbox_new(
|
||||
if !self.from_displayname.is_empty() {
|
||||
dc_encode_header_words(&self.from_displayname).strdup()
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
},
|
||||
self.from_addr.strdup(),
|
||||
),
|
||||
);
|
||||
let mut to: *mut mailimf_address_list = ptr::null_mut();
|
||||
if !self.recipients_names.is_empty() && !self.recipients_addr.is_empty() {
|
||||
to = mailimf_address_list_new_empty();
|
||||
let name_iter = self.recipients_names.iter();
|
||||
let addr_iter = self.recipients_addr.iter();
|
||||
for (name, addr) in name_iter.zip(addr_iter) {
|
||||
mailimf_address_list_add(
|
||||
to,
|
||||
mailimf_address_new(
|
||||
MAILIMF_ADDRESS_MAILBOX as libc::c_int,
|
||||
mailimf_mailbox_new(
|
||||
if !name.is_empty() {
|
||||
dc_encode_header_words(&name).strdup()
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
},
|
||||
addr.strdup(),
|
||||
),
|
||||
ptr::null_mut(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
let references_list = if !self.references.is_empty() {
|
||||
dc_str_to_clist(&self.references, " ")
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
};
|
||||
let in_reply_to_list = if !self.in_reply_to.is_empty() {
|
||||
dc_str_to_clist(&self.in_reply_to, " ")
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
};
|
||||
let imf_fields = mailimf_fields_new_with_data_all(
|
||||
mailimf_get_date(self.timestamp as i64),
|
||||
from,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
to,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
self.rfc724_mid.strdup(),
|
||||
in_reply_to_list,
|
||||
references_list,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
let os_name = &self.context.os_name;
|
||||
let os_part = os_name
|
||||
.as_ref()
|
||||
.map(|s| format!("/{}", s))
|
||||
.unwrap_or_default();
|
||||
let version = get_version_str();
|
||||
let headerval = format!("Delta Chat Core {}{}", version, os_part);
|
||||
|
||||
/* Add a X-Mailer header.
|
||||
This is only informational for debugging and may be removed in the release.
|
||||
We do not rely on this header as it may be removed by MTAs. */
|
||||
wrapmime::new_custom_field(imf_fields, "X-Mailer", &headerval);
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Version", "1.0");
|
||||
if self.req_mdn {
|
||||
/* we use "Chat-Disposition-Notification-To"
|
||||
because replies to "Disposition-Notification-To" are weird in many cases
|
||||
eg. are just freetext and/or do not follow any standard. */
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Disposition-Notification-To",
|
||||
&self.from_addr,
|
||||
);
|
||||
}
|
||||
|
||||
let cleanup = |message: *mut Mailmime| {
|
||||
if !message.is_null() {
|
||||
mailmime_free(message);
|
||||
}
|
||||
};
|
||||
let message = mailmime_new_message_data(0 as *mut Mailmime);
|
||||
ensure!(!message.is_null(), "could not create mime message data");
|
||||
|
||||
mailmime_set_imf_fields(message, imf_fields);
|
||||
|
||||
// 1=add Autocrypt-header (needed eg. for handshaking), 2=no Autocrypte-header (used for MDN)
|
||||
let mut e2ee_guaranteed = false;
|
||||
let mut min_verified: libc::c_int = 0;
|
||||
let mut do_gossip = false;
|
||||
let mut grpimage = None;
|
||||
let force_plaintext: libc::c_int;
|
||||
let subject_str = match self.loaded {
|
||||
Loaded::Message => {
|
||||
/* Render a normal message
|
||||
*********************************************************************/
|
||||
let chat = self.chat.as_ref().unwrap();
|
||||
let mut meta_part: *mut Mailmime = ptr::null_mut();
|
||||
let mut placeholdertext = None;
|
||||
|
||||
if chat.typ == Chattype::VerifiedGroup {
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Verified", "1");
|
||||
force_plaintext = 0;
|
||||
e2ee_guaranteed = true;
|
||||
min_verified = 2
|
||||
} else {
|
||||
force_plaintext = self
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::ForcePlaintext)
|
||||
.unwrap_or_default();
|
||||
if force_plaintext == 0 {
|
||||
e2ee_guaranteed = self
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
!= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* beside key- and member-changes, force re-gossip every 48 hours */
|
||||
if chat.gossiped_timestamp == 0
|
||||
|| (chat.gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
|
||||
{
|
||||
do_gossip = true
|
||||
}
|
||||
|
||||
/* build header etc. */
|
||||
let command = self.msg.param.get_cmd();
|
||||
if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Group-ID", &chat.grpid);
|
||||
|
||||
let encoded = dc_encode_header_words(&chat.name);
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Group-Name", &encoded);
|
||||
|
||||
match command {
|
||||
SystemMessage::MemberRemovedFromGroup => {
|
||||
let email_to_remove =
|
||||
self.msg.param.get(Param::Arg).unwrap_or_default();
|
||||
if !email_to_remove.is_empty() {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Group-Member-Removed",
|
||||
&email_to_remove,
|
||||
);
|
||||
}
|
||||
}
|
||||
SystemMessage::MemberAddedToGroup => {
|
||||
let msg = &self.msg;
|
||||
do_gossip = true;
|
||||
let email_to_add = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
if !email_to_add.is_empty() {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Group-Member-Added",
|
||||
&email_to_add,
|
||||
);
|
||||
grpimage = chat.param.get(Param::ProfileImage);
|
||||
}
|
||||
if 0 != msg.param.get_int(Param::Arg2).unwrap_or_default() & 0x1 {
|
||||
info!(
|
||||
context,
|
||||
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
|
||||
"vg-member-added",
|
||||
);
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Secure-Join",
|
||||
"vg-member-added",
|
||||
);
|
||||
}
|
||||
}
|
||||
SystemMessage::GroupNameChanged => {
|
||||
let msg = &self.msg;
|
||||
let value_to_add = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Group-Name-Changed",
|
||||
&value_to_add,
|
||||
);
|
||||
}
|
||||
SystemMessage::GroupImageChanged => {
|
||||
let msg = &self.msg;
|
||||
grpimage = msg.param.get(Param::Arg);
|
||||
if grpimage.is_none() {
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Group-Image", "0");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match command {
|
||||
SystemMessage::LocationStreamingEnabled => {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Content",
|
||||
"location-streaming-enabled",
|
||||
);
|
||||
}
|
||||
SystemMessage::AutocryptSetupMessage => {
|
||||
wrapmime::new_custom_field(imf_fields, "Autocrypt-Setup-Message", "v1");
|
||||
placeholdertext = Some(
|
||||
self.context
|
||||
.stock_str(StockMessage::AcSetupMsgBody)
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
SystemMessage::SecurejoinMessage => {
|
||||
let msg = &self.msg;
|
||||
let step = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
if !step.is_empty() {
|
||||
info!(
|
||||
context,
|
||||
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
|
||||
step,
|
||||
);
|
||||
wrapmime::new_custom_field(imf_fields, "Secure-Join", &step);
|
||||
let param2 = msg.param.get(Param::Arg2).unwrap_or_default();
|
||||
if !param2.is_empty() {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
if step == "vg-request-with-auth"
|
||||
|| step == "vc-request-with-auth"
|
||||
{
|
||||
"Secure-Join-Auth"
|
||||
} else {
|
||||
"Secure-Join-Invitenumber"
|
||||
},
|
||||
param2,
|
||||
)
|
||||
}
|
||||
let fingerprint = msg.param.get(Param::Arg3).unwrap_or_default();
|
||||
if !fingerprint.is_empty() {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Secure-Join-Fingerprint",
|
||||
&fingerprint,
|
||||
);
|
||||
}
|
||||
match msg.param.get(Param::Arg4) {
|
||||
Some(id) => {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Secure-Join-Group",
|
||||
&id,
|
||||
);
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(grpimage) = grpimage {
|
||||
info!(self.context, "setting group image '{}'", grpimage);
|
||||
let mut meta = Message::default();
|
||||
meta.type_0 = Viewtype::Image;
|
||||
meta.param.set(Param::File, grpimage);
|
||||
|
||||
let res = build_body_file(context, &meta, "group-image")?;
|
||||
meta_part = res.0;
|
||||
let filename_as_sent = res.1;
|
||||
if !meta_part.is_null() {
|
||||
wrapmime::new_custom_field(
|
||||
imf_fields,
|
||||
"Chat-Group-Image",
|
||||
&filename_as_sent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if self.msg.type_0 == Viewtype::Voice
|
||||
|| self.msg.type_0 == Viewtype::Audio
|
||||
|| self.msg.type_0 == Viewtype::Video
|
||||
{
|
||||
if self.msg.type_0 == Viewtype::Voice {
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Voice-Message", "1");
|
||||
}
|
||||
let duration_ms = self.msg.param.get_int(Param::Duration).unwrap_or_default();
|
||||
if duration_ms > 0 {
|
||||
let dur = duration_ms.to_string();
|
||||
wrapmime::new_custom_field(imf_fields, "Chat-Duration", &dur);
|
||||
}
|
||||
}
|
||||
|
||||
/* add text part - we even add empty text and force a MIME-multipart-message as:
|
||||
- some Apps have problems with Non-text in the main part (eg. "Mail" from stock Android)
|
||||
- we can add "forward hints" this way
|
||||
- it looks better */
|
||||
let afwd_email = self.msg.param.exists(Param::Forwarded);
|
||||
let fwdhint = if afwd_email {
|
||||
Some(
|
||||
"---------- Forwarded message ----------\r\nFrom: Delta Chat\r\n\r\n"
|
||||
.to_string(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let final_text = {
|
||||
if let Some(ref text) = placeholdertext {
|
||||
text
|
||||
} else if let Some(ref text) = self.msg.text {
|
||||
text
|
||||
} else {
|
||||
""
|
||||
}
|
||||
};
|
||||
|
||||
let footer = &self.selfstatus;
|
||||
let message_text = format!(
|
||||
"{}{}{}{}{}",
|
||||
fwdhint.unwrap_or_default(),
|
||||
&final_text,
|
||||
if !final_text.is_empty() && !footer.is_empty() {
|
||||
"\r\n\r\n"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if !footer.is_empty() { "-- \r\n" } else { "" },
|
||||
footer
|
||||
);
|
||||
let text_part = wrapmime::build_body_text(&message_text)?;
|
||||
mailmime_smart_add_part(message, text_part);
|
||||
|
||||
/* add attachment part */
|
||||
if chat::msgtype_has_file(self.msg.type_0) {
|
||||
if !is_file_size_okay(context, &self.msg) {
|
||||
cleanup(message);
|
||||
bail!(
|
||||
"Message exceeds the recommended {} MB.",
|
||||
24 * 1024 * 1024 / 4 * 3 / 1000 / 1000,
|
||||
);
|
||||
} else {
|
||||
let (file_part, _) = build_body_file(context, &self.msg, "")?;
|
||||
mailmime_smart_add_part(message, file_part);
|
||||
}
|
||||
}
|
||||
if !meta_part.is_null() {
|
||||
mailmime_smart_add_part(message, meta_part);
|
||||
}
|
||||
if self.msg.param.exists(Param::SetLatitude) {
|
||||
let param = &self.msg.param;
|
||||
let kml_file = location::get_message_kml(
|
||||
self.msg.timestamp_sort,
|
||||
param.get_float(Param::SetLatitude).unwrap_or_default(),
|
||||
param.get_float(Param::SetLongitude).unwrap_or_default(),
|
||||
);
|
||||
wrapmime::add_filename_part(
|
||||
message,
|
||||
"message.kml",
|
||||
"application/vnd.google-earth.kml+xml",
|
||||
&kml_file,
|
||||
)?;
|
||||
}
|
||||
|
||||
if location::is_sending_locations_to_chat(context, self.msg.chat_id) {
|
||||
if let Ok((kml_file, last_added_location_id)) =
|
||||
location::get_kml(context, self.msg.chat_id)
|
||||
{
|
||||
wrapmime::add_filename_part(
|
||||
message,
|
||||
"location.kml",
|
||||
"application/vnd.google-earth.kml+xml",
|
||||
&kml_file,
|
||||
)?;
|
||||
if !self.msg.param.exists(Param::SetLatitude) {
|
||||
// otherwise, the independent location is already filed
|
||||
self.out_last_added_location_id = last_added_location_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
get_subject(context, self.chat.as_ref(), &mut self.msg, afwd_email)
|
||||
}
|
||||
Loaded::MDN => {
|
||||
/* Render a MDN
|
||||
*********************************************************************/
|
||||
/* RFC 6522, this also requires the `report-type` parameter which is equal
|
||||
to the MIME subtype of the second body part of the multipart/report */
|
||||
let multipart = mailmime_multiple_new(
|
||||
b"multipart/report\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
wrapmime::append_ct_param(
|
||||
(*multipart).mm_content_type,
|
||||
"report-type",
|
||||
"disposition-notification",
|
||||
)?;
|
||||
|
||||
mailmime_add_part(message, multipart);
|
||||
|
||||
/* first body part: always human-readable, always REQUIRED by RFC 6522 */
|
||||
let p1 = if 0
|
||||
!= self
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
self.context
|
||||
.stock_str(StockMessage::EncryptedMsg)
|
||||
.into_owned()
|
||||
} else {
|
||||
self.msg.get_summarytext(context, 32)
|
||||
};
|
||||
let p2 = self
|
||||
.context
|
||||
.stock_string_repl_str(StockMessage::ReadRcptMailBody, p1);
|
||||
let message_text = format!("{}\r\n", p2);
|
||||
let human_mime_part = wrapmime::build_body_text(&message_text)?;
|
||||
mailmime_add_part(multipart, human_mime_part);
|
||||
|
||||
/* second body part: machine-readable, always REQUIRED by RFC 6522 */
|
||||
let version = get_version_str();
|
||||
let message_text2 = format!(
|
||||
"Reporting-UA: Delta Chat {}\r\nOriginal-Recipient: rfc822;{}\r\nFinal-Recipient: rfc822;{}\r\nOriginal-Message-ID: <{}>\r\nDisposition: manual-action/MDN-sent-automatically; displayed\r\n",
|
||||
version,
|
||||
self.from_addr,
|
||||
self.from_addr,
|
||||
self.msg.rfc724_mid
|
||||
);
|
||||
|
||||
let content_type_0 =
|
||||
wrapmime::new_content_type("message/disposition-notification")?;
|
||||
let mime_fields_0: *mut mailmime_fields =
|
||||
mailmime_fields_new_encoding(MAILMIME_MECHANISM_8BIT as libc::c_int);
|
||||
let mach_mime_part: *mut Mailmime =
|
||||
mailmime_new_empty(content_type_0, mime_fields_0);
|
||||
wrapmime::set_body_text(mach_mime_part, &message_text2)?;
|
||||
mailmime_add_part(multipart, mach_mime_part);
|
||||
force_plaintext = DC_FP_NO_AUTOCRYPT_HEADER;
|
||||
info!(context, "sending MDM {:?}", message_text2);
|
||||
/* currently, we do not send MDNs encrypted:
|
||||
- in a multi-device-setup that is not set up properly, MDNs would disturb the communication as they
|
||||
are send automatically which may lead to spreading outdated Autocrypt headers.
|
||||
- they do not carry any information but the Message-ID
|
||||
- this save some KB
|
||||
- in older versions, we did not encrypt messages to ourself when they to to SMTP - however, if these messages
|
||||
are forwarded for any reasons (eg. gmail always forwards to IMAP), we have no chance to decrypt them;
|
||||
this issue is fixed with 0.9.4 */
|
||||
let e = self.context.stock_str(StockMessage::ReadRcpt);
|
||||
format!("Chat: {}", e).to_string()
|
||||
}
|
||||
_ => {
|
||||
cleanup(message);
|
||||
bail!("No message loaded.");
|
||||
}
|
||||
};
|
||||
|
||||
/* Create the mime message
|
||||
*************************************************************************/
|
||||
|
||||
mailimf_fields_add(
|
||||
imf_fields,
|
||||
mailimf_field_new(
|
||||
MAILIMF_FIELD_SUBJECT as libc::c_int,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
mailimf_subject_new(dc_encode_header_words(subject_str).strdup()),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
),
|
||||
);
|
||||
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields_unprotected = mailmime_find_mailimf_fields(message);
|
||||
ensure!(
|
||||
!imffields_unprotected.is_null(),
|
||||
"could not find mime fields"
|
||||
);
|
||||
|
||||
let mut encrypt_helper = EncryptHelper::new(&context)?;
|
||||
if force_plaintext != DC_FP_NO_AUTOCRYPT_HEADER {
|
||||
// unless determined otherwise we add Autocrypt header
|
||||
let aheader = encrypt_helper.get_aheader().to_string();
|
||||
wrapmime::new_custom_field(imffields_unprotected, "Autocrypt", &aheader);
|
||||
}
|
||||
let mut finalized = false;
|
||||
if force_plaintext == 0 {
|
||||
finalized = encrypt_helper.try_encrypt(
|
||||
self,
|
||||
e2ee_guaranteed,
|
||||
min_verified,
|
||||
do_gossip,
|
||||
message,
|
||||
imffields_unprotected,
|
||||
)?;
|
||||
}
|
||||
if !finalized {
|
||||
self.finalize_mime_message(message, false, false)?;
|
||||
}
|
||||
cleanup(message);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_msg(context: &Context, msg_id: u32) -> Result<MimeFactory, Error> {
|
||||
ensure!(msg_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat id");
|
||||
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
let chat = Chat::load_from_db(context, msg.chat_id)?;
|
||||
let mut factory = MimeFactory::new(context, msg);
|
||||
factory.chat = Some(chat);
|
||||
|
||||
// just set the chat above
|
||||
let chat = factory.chat.as_ref().unwrap();
|
||||
|
||||
if chat.is_self_talk() {
|
||||
factory
|
||||
.recipients_names
|
||||
.push(factory.from_displayname.to_string());
|
||||
factory.recipients_addr.push(factory.from_addr.to_string());
|
||||
} else {
|
||||
context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT c.authname, c.addr \
|
||||
FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON cc.contact_id=c.id \
|
||||
WHERE cc.chat_id=? AND cc.contact_id>9;",
|
||||
params![factory.msg.chat_id as i32],
|
||||
|row| {
|
||||
let authname: String = row.get(0)?;
|
||||
let addr: String = row.get(1)?;
|
||||
Ok((authname, addr))
|
||||
},
|
||||
|rows| {
|
||||
for row in rows {
|
||||
let (authname, addr) = row?;
|
||||
if !vec_contains_lowercase(&factory.recipients_addr, &addr) {
|
||||
factory.recipients_addr.push(addr);
|
||||
factory.recipients_names.push(authname);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let command = factory.msg.param.get_cmd();
|
||||
let msg = &factory.msg;
|
||||
|
||||
/* for added members, the list is just fine */
|
||||
if command == SystemMessage::MemberRemovedFromGroup {
|
||||
let email_to_remove = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
|
||||
let self_addr = context
|
||||
.sql
|
||||
.get_config(context, "configured_addr")
|
||||
.unwrap_or_default();
|
||||
|
||||
if !email_to_remove.is_empty() && email_to_remove != self_addr {
|
||||
if !vec_contains_lowercase(&factory.recipients_addr, &email_to_remove) {
|
||||
factory.recipients_names.push("".to_string());
|
||||
factory.recipients_addr.push(email_to_remove.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
if command != SystemMessage::AutocryptSetupMessage
|
||||
&& command != SystemMessage::SecurejoinMessage
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
factory.req_mdn = true;
|
||||
}
|
||||
}
|
||||
let row = context.sql.query_row(
|
||||
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
|
||||
params![factory.msg.id as i32],
|
||||
|row| {
|
||||
let in_reply_to: String = row.get(0)?;
|
||||
let references: String = row.get(1)?;
|
||||
|
||||
Ok((in_reply_to, references))
|
||||
},
|
||||
);
|
||||
match row {
|
||||
Ok((in_reply_to, references)) => {
|
||||
factory.in_reply_to = in_reply_to;
|
||||
factory.references = references;
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
context,
|
||||
"mimefactory: failed to load mime_in_reply_to: {:?}", err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
factory.loaded = Loaded::Message;
|
||||
factory.timestamp = factory.msg.timestamp_sort;
|
||||
factory.rfc724_mid = factory.msg.rfc724_mid.clone();
|
||||
factory.increation = factory.msg.is_increation();
|
||||
|
||||
Ok(factory)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for MimeFactory<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.out.is_null() {
|
||||
mmap_string_free(self.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_subject(
|
||||
context: &Context,
|
||||
chat: Option<&Chat>,
|
||||
msg: &mut Message,
|
||||
afwd_email: bool,
|
||||
) -> String {
|
||||
if chat.is_none() {
|
||||
return String::default();
|
||||
}
|
||||
|
||||
let chat = chat.unwrap();
|
||||
let raw_subject =
|
||||
message::get_summarytext_by_raw(msg.type_0, msg.text.as_ref(), &mut msg.param, 32, context);
|
||||
let fwd = if afwd_email { "Fwd: " } else { "" };
|
||||
|
||||
if msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage {
|
||||
/* do not add the "Chat:" prefix for setup messages */
|
||||
context
|
||||
.stock_str(StockMessage::AcSetupMsgSubject)
|
||||
.into_owned()
|
||||
} else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
|
||||
format!("Chat: {}: {}{}", chat.name, fwd, raw_subject,)
|
||||
} else {
|
||||
format!("Chat: {}{}", fwd, raw_subject)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn build_body_file(
|
||||
context: &Context,
|
||||
msg: &Message,
|
||||
base_name: &str,
|
||||
) -> Result<(*mut Mailmime, String), Error> {
|
||||
let path_filename = match msg.param.get(Param::File) {
|
||||
None => {
|
||||
bail!("msg has no filename");
|
||||
}
|
||||
Some(path) => path,
|
||||
};
|
||||
let suffix = dc_get_filesuffix_lc(path_filename).unwrap_or_else(|| "dat".into());
|
||||
|
||||
/* get file name to use for sending
|
||||
(for privacy purposes, we do not transfer the original filenames eg. for images;
|
||||
these names are normally not needed and contain timestamps, running numbers etc.) */
|
||||
let filename_to_send = match msg.type_0 {
|
||||
Viewtype::Voice => chrono::Utc
|
||||
.timestamp(msg.timestamp_sort as i64, 0)
|
||||
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
|
||||
.to_string(),
|
||||
Viewtype::Audio => Path::new(path_filename)
|
||||
.file_name()
|
||||
.map(|c| c.to_string_lossy().to_string())
|
||||
.unwrap_or_default(),
|
||||
Viewtype::Image | Viewtype::Gif => format!(
|
||||
"{}.{}",
|
||||
if base_name.is_empty() {
|
||||
"image"
|
||||
} else {
|
||||
base_name
|
||||
},
|
||||
&suffix,
|
||||
),
|
||||
Viewtype::Video => format!("video.{}", &suffix),
|
||||
_ => Path::new(path_filename)
|
||||
.file_name()
|
||||
.map(|c| c.to_string_lossy().to_string())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
/* check mimetype */
|
||||
let mimetype = match msg.param.get(Param::MimeType) {
|
||||
Some(mtype) => mtype,
|
||||
None => {
|
||||
let path = Path::new(path_filename);
|
||||
if let Some(res) = message::guess_msgtype_from_suffix(&path) {
|
||||
res.1
|
||||
} else {
|
||||
"application/octet-stream"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let needs_ext = dc_needs_ext_header(&filename_to_send);
|
||||
|
||||
unsafe {
|
||||
/* create mime part, for Content-Disposition, see RFC 2183.
|
||||
`Content-Disposition: attachment` seems not to make a difference to `Content-Disposition: inline` at least on tested Thunderbird and Gma'l in 2017.
|
||||
But I've heard about problems with inline and outl'k, so we just use the attachment-type until we run into other problems ... */
|
||||
let mime_fields = mailmime_fields_new_filename(
|
||||
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
|
||||
if needs_ext {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
filename_to_send.strdup()
|
||||
},
|
||||
MAILMIME_MECHANISM_BASE64 as libc::c_int,
|
||||
);
|
||||
if needs_ext {
|
||||
for cur_data in (*(*mime_fields).fld_list).into_iter() {
|
||||
let field: *mut mailmime_field = cur_data as *mut _;
|
||||
if (*field).fld_type == MAILMIME_FIELD_DISPOSITION as libc::c_int
|
||||
&& !(*field).fld_data.fld_disposition.is_null()
|
||||
{
|
||||
let file_disposition = (*field).fld_data.fld_disposition;
|
||||
if !file_disposition.is_null() {
|
||||
let parm = mailmime_disposition_parm_new(
|
||||
MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0 as libc::size_t,
|
||||
mailmime_parameter_new(
|
||||
strdup(b"filename*\x00" as *const u8 as *const libc::c_char),
|
||||
dc_encode_ext_header(&filename_to_send).strdup(),
|
||||
),
|
||||
);
|
||||
if !parm.is_null() {
|
||||
clist_insert_after(
|
||||
(*file_disposition).dsp_parms,
|
||||
(*(*file_disposition).dsp_parms).last,
|
||||
parm as *mut libc::c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let content = wrapmime::new_content_type(&mimetype)?;
|
||||
let filename_encoded = dc_encode_header_words(&filename_to_send);
|
||||
wrapmime::append_ct_param(content, "name", &filename_encoded)?;
|
||||
|
||||
let mime_sub = mailmime_new_empty(content, mime_fields);
|
||||
let abs_path = dc_get_abs_path(context, path_filename)
|
||||
.to_c_string()
|
||||
.unwrap();
|
||||
mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr()));
|
||||
Ok((mime_sub, filename_to_send))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn vec_contains_lowercase(vec: &Vec<String>, part: &str) -> bool {
|
||||
let partlc = part.to_lowercase();
|
||||
for cur in vec.iter() {
|
||||
if cur.to_lowercase() == partlc {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_file_size_okay(context: &Context, msg: &Message) -> bool {
|
||||
let mut file_size_okay = true;
|
||||
let path = msg.param.get(Param::File).unwrap_or_default();
|
||||
let bytes = dc_get_filebytes(context, &path);
|
||||
|
||||
if bytes > (49 * 1024 * 1024 / 4 * 3) {
|
||||
file_size_okay = false;
|
||||
}
|
||||
|
||||
file_size_okay
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use crate::aheader::*;
|
||||
use crate::chat::*;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::error::*;
|
||||
use crate::key::*;
|
||||
use crate::sql::{self, Sql};
|
||||
|
||||
@@ -408,28 +409,19 @@ impl<'a> Peerstate<'a> {
|
||||
success
|
||||
}
|
||||
|
||||
pub fn save_to_db(&self, sql: &Sql, create: bool) -> bool {
|
||||
let mut success = false;
|
||||
|
||||
if self.addr.is_none() {
|
||||
return success;
|
||||
}
|
||||
|
||||
pub fn save_to_db(&self, sql: &Sql, create: bool) -> Result<()> {
|
||||
ensure!(!self.addr.is_none(), "self.addr is not configured");
|
||||
if create {
|
||||
if sql::execute(
|
||||
sql::execute(
|
||||
self.context,
|
||||
sql,
|
||||
"INSERT INTO acpeerstates (addr) VALUES(?);",
|
||||
params![self.addr.as_ref().unwrap()],
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
success = sql::execute(
|
||||
sql::execute(
|
||||
self.context,
|
||||
sql,
|
||||
"UPDATE acpeerstates \
|
||||
@@ -450,10 +442,9 @@ impl<'a> Peerstate<'a> {
|
||||
&self.verified_key_fingerprint,
|
||||
&self.addr,
|
||||
],
|
||||
).is_ok();
|
||||
assert_eq!(success, true);
|
||||
)?
|
||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||
success = sql::execute(
|
||||
sql::execute(
|
||||
self.context,
|
||||
sql,
|
||||
"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
|
||||
@@ -464,15 +455,14 @@ impl<'a> Peerstate<'a> {
|
||||
self.gossip_timestamp,
|
||||
&self.addr
|
||||
],
|
||||
)
|
||||
.is_ok();
|
||||
)?;
|
||||
}
|
||||
|
||||
if self.to_save == Some(ToSave::All) || create {
|
||||
reset_gossiped_timestamp(self.context, 0);
|
||||
}
|
||||
|
||||
success
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn has_verified_key(&self, fingerprints: &HashSet<String>) -> bool {
|
||||
@@ -522,7 +512,10 @@ mod tests {
|
||||
degrade_event: None,
|
||||
};
|
||||
|
||||
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
||||
assert!(
|
||||
peerstate.save_to_db(&ctx.ctx.sql, true).is_ok(),
|
||||
"failed to save to db"
|
||||
);
|
||||
|
||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
||||
.expect("failed to load peerstate from db");
|
||||
@@ -564,7 +557,10 @@ mod tests {
|
||||
degrade_event: None,
|
||||
};
|
||||
|
||||
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
||||
assert!(
|
||||
peerstate.save_to_db(&ctx.ctx.sql, true).is_ok(),
|
||||
"failed to save"
|
||||
);
|
||||
|
||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
||||
.expect("failed to load peerstate from db");
|
||||
|
||||
13
src/pgp.rs
13
src/pgp.rs
@@ -3,6 +3,7 @@ use std::convert::TryInto;
|
||||
use std::io::Cursor;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{strchr, strlen, strncmp, strspn, strstr};
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||
SignedSecretKey, SubkeyParamsBuilder,
|
||||
@@ -15,11 +16,10 @@ use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::x::*;
|
||||
|
||||
pub unsafe fn dc_split_armored_data(
|
||||
buf: *mut libc::c_char,
|
||||
ret_headerline: *mut *const libc::c_char,
|
||||
ret_headerline: *mut String,
|
||||
ret_setupcodebegin: *mut *const libc::c_char,
|
||||
ret_preferencrypt: *mut *const libc::c_char,
|
||||
ret_base64: *mut *const libc::c_char,
|
||||
@@ -31,9 +31,6 @@ pub unsafe fn dc_split_armored_data(
|
||||
let mut p2: *mut libc::c_char;
|
||||
let mut headerline: *mut libc::c_char = ptr::null_mut();
|
||||
let mut base64: *mut libc::c_char = ptr::null_mut();
|
||||
if !ret_headerline.is_null() {
|
||||
*ret_headerline = ptr::null()
|
||||
}
|
||||
if !ret_setupcodebegin.is_null() {
|
||||
*ret_setupcodebegin = ptr::null_mut();
|
||||
}
|
||||
@@ -43,7 +40,7 @@ pub unsafe fn dc_split_armored_data(
|
||||
if !ret_base64.is_null() {
|
||||
*ret_base64 = ptr::null();
|
||||
}
|
||||
if !(buf.is_null() || ret_headerline.is_null()) {
|
||||
if !buf.is_null() {
|
||||
dc_remove_cr_chars(buf);
|
||||
while 0 != *p1 {
|
||||
if *p1 as libc::c_int == '\n' as i32 {
|
||||
@@ -62,9 +59,7 @@ pub unsafe fn dc_split_armored_data(
|
||||
) == 0i32
|
||||
{
|
||||
headerline = line;
|
||||
if !ret_headerline.is_null() {
|
||||
*ret_headerline = headerline
|
||||
}
|
||||
*ret_headerline = as_str(headerline).to_string();
|
||||
}
|
||||
} else if strspn(line, b"\t\r\n \x00" as *const u8 as *const libc::c_char)
|
||||
== strlen(line)
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::key::*;
|
||||
use crate::lot::LotState;
|
||||
use crate::message::*;
|
||||
use crate::message::Message;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::qr::check_qr;
|
||||
@@ -266,7 +266,7 @@ fn send_handshake_msg(
|
||||
fingerprint: Option<String>,
|
||||
grpid: impl AsRef<str>,
|
||||
) {
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
let mut msg = Message::default();
|
||||
msg.type_0 = Viewtype::Text;
|
||||
msg.text = Some(format!("Secure-Join: {}", step));
|
||||
msg.hidden = true;
|
||||
@@ -522,7 +522,11 @@ pub fn handle_securejoin_handshake(
|
||||
error!(context, "Chat {} not found.", &field_grpid);
|
||||
return ret;
|
||||
} else {
|
||||
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, 0x1i32);
|
||||
if let Err(err) =
|
||||
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, true)
|
||||
{
|
||||
error!(context, "failed to add contact: {}", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
send_handshake_msg(context, contact_chat_id, "vc-contact-confirm", "", None, "");
|
||||
@@ -674,7 +678,7 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
|
||||
if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
|
||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||
peerstate.to_save = Some(ToSave::All);
|
||||
peerstate.save_to_db(&context.sql, false);
|
||||
peerstate.save_to_db(&context.sql, false).unwrap();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,9 @@ impl Smtp {
|
||||
let port = lp.send_port as u16;
|
||||
|
||||
let tls = native_tls::TlsConnector::builder()
|
||||
// FIXME: unfortunately this is needed to make things work on macos + testrun.org
|
||||
// see also: https://github.com/deltachat/deltachat-core-rust/issues/203
|
||||
.danger_accept_invalid_hostnames(true)
|
||||
.danger_accept_invalid_certs(true)
|
||||
.min_protocol_version(Some(DEFAULT_TLS_PROTOCOLS[0]))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
@@ -777,7 +777,7 @@ fn open(
|
||||
if let Some(ref mut peerstate) = Peerstate::from_addr(context, sql, &addr?)
|
||||
{
|
||||
peerstate.recalc_fingerprint();
|
||||
peerstate.save_to_db(sql, false);
|
||||
peerstate.save_to_db(sql, false).unwrap();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use libc::free;
|
||||
|
||||
/// Stock strings
|
||||
///
|
||||
@@ -133,7 +132,7 @@ impl Context {
|
||||
Cow::Borrowed(id.fallback())
|
||||
} else {
|
||||
let ret = to_string(ptr);
|
||||
unsafe { free(ptr as *mut libc::c_void) };
|
||||
unsafe { libc::free(ptr as *mut libc::c_void) };
|
||||
Cow::Owned(ret)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,98 +68,15 @@ pub fn configure_alice_keypair(ctx: &Context) -> String {
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let public =
|
||||
key::Key::from_base64(include_str!("../test-data/key/public.asc"), KeyType::Public)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtq",
|
||||
"m1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353",
|
||||
"r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68",
|
||||
"JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6F",
|
||||
"FrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHb",
|
||||
"Iu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3V",
|
||||
"WushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0S",
|
||||
"ut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQ",
|
||||
"sWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEm",
|
||||
"dr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8k",
|
||||
"QrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJW",
|
||||
"yyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj",
|
||||
"5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3",
|
||||
"jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeG",
|
||||
"Kyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl08",
|
||||
"6fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQ",
|
||||
"k6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Ee",
|
||||
"h+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BM",
|
||||
"zcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwb",
|
||||
"YklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP",
|
||||
"12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmh",
|
||||
"o0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugz",
|
||||
"OmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnF",
|
||||
"n7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6",
|
||||
"uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEe",
|
||||
"LrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCIC",
|
||||
"N1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86K",
|
||||
"C2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIdd",
|
||||
"KsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T",
|
||||
"/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZL",
|
||||
"j3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtp",
|
||||
"Do5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9u",
|
||||
"RMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe",
|
||||
"/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH",
|
||||
"95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9",
|
||||
"QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ",
|
||||
"8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//",
|
||||
"wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg",
|
||||
"9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwK",
|
||||
"Gjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPB",
|
||||
"f4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAg",
|
||||
"BQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/",
|
||||
"dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJ",
|
||||
"ywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJ",
|
||||
"uiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6",
|
||||
"RDXIeYJfqrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMl",
|
||||
"ammDliPwsK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKOb",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
include_str!("../test-data/key/private.asc"),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql);
|
||||
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, true, &ctx.sql);
|
||||
assert_eq!(saved, true, "Failed to save Alice's key");
|
||||
addr
|
||||
}
|
||||
|
||||
@@ -15,19 +15,21 @@ if __name__ == "__main__":
|
||||
unsafe = s.count("unsafe")
|
||||
free = s.count("free(")
|
||||
gotoblocks = s.count("ok_to_continue") + s.count('OK_TO_CONTINUE')
|
||||
filestats.append((fn, unsafe, free, gotoblocks))
|
||||
chars = s.count("c_char") + s.count("CStr")
|
||||
filestats.append((fn, unsafe, free, gotoblocks, chars))
|
||||
|
||||
sum_unsafe, sum_free, sum_gotoblocks = 0, 0, 0
|
||||
sum_unsafe, sum_free, sum_gotoblocks, sum_chars = 0, 0, 0, 0
|
||||
|
||||
for fn, unsafe, free, gotoblocks in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
print("{0: <30} unsafe: {1: >3} free: {2: >3} ok_to_continue: {3: >3}".format(str(fn), unsafe, free, gotoblocks))
|
||||
for fn, unsafe, free, gotoblocks, chars in reversed(sorted(filestats, key=lambda x: sum(x[1:]))):
|
||||
print("{0: <25} unsafe: {1: >3} free: {2: >3} ok_to_cont: {3: >3} chars: {4: >3}".format(str(fn), unsafe, free, gotoblocks, chars))
|
||||
sum_unsafe += unsafe
|
||||
sum_free += free
|
||||
sum_gotoblocks += gotoblocks
|
||||
sum_chars += chars
|
||||
|
||||
|
||||
print()
|
||||
print("total unsafe:", sum_unsafe)
|
||||
print("total free:", sum_free)
|
||||
print("total ok_to_continue:", sum_gotoblocks)
|
||||
|
||||
print("total c_chars:", sum_chars)
|
||||
|
||||
282
src/wrapmime.rs
Normal file
282
src/wrapmime.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::types_helper::*;
|
||||
use mmime::mailmime::content::*;
|
||||
use mmime::mailmime::disposition::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::types_helper::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::other::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! clist_append {
|
||||
($clist:expr, $item:expr) => {
|
||||
if clist_insert_after(
|
||||
$clist as *mut clist,
|
||||
(*$clist).last,
|
||||
$item as *mut libc::c_void,
|
||||
) != 0
|
||||
{
|
||||
bail!("could not allocate or append list item");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* mime parsing API
|
||||
**************************************/
|
||||
|
||||
pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
|
||||
unsafe {
|
||||
let ct: *mut mailmime_content = (*mime).mm_content_type;
|
||||
|
||||
if !ct.is_null() && !(*ct).ct_subtype.is_null() {
|
||||
println!("ct_subtype: {}", to_string((*ct).ct_subtype));
|
||||
Some(to_string((*ct).ct_subtype))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_autocrypt_mime(
|
||||
mime_undetermined: *mut Mailmime,
|
||||
) -> Result<(*mut Mailmime, *mut Mailmime), Error> {
|
||||
/* return Result with two mime pointers:
|
||||
First mime pointer is to the multipart-mime message
|
||||
(which is replaced with a decrypted version later)
|
||||
Second one is to the encrypted payload.
|
||||
For non-autocrypt message an Error is returned.
|
||||
*/
|
||||
unsafe {
|
||||
ensure!(
|
||||
(*mime_undetermined).mm_type == MAILMIME_MESSAGE as libc::c_int,
|
||||
"Not a root mime message"
|
||||
);
|
||||
let mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime;
|
||||
|
||||
ensure!(
|
||||
(*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int
|
||||
&& "encrypted" == get_ct_subtype(mime).unwrap_or_default(),
|
||||
"Not a multipart/encrypted message"
|
||||
);
|
||||
let parts: Vec<_> = (*(*mime).mm_data.mm_multipart.mm_mp_list)
|
||||
.into_iter()
|
||||
.map(|c| c as *mut Mailmime)
|
||||
.collect();
|
||||
ensure!(parts.len() == 2, "Invalid Autocrypt Level 1 Mime Parts");
|
||||
// XXX ensure protocol-parameter "application/pgp-encrypted")
|
||||
// XXX ensure wrapmime::get_content_type(parts[1])) == "application/octetstream"
|
||||
// a proper OpenPGP multipart/encrypted Autocrypt Level 1 message
|
||||
// https://tools.ietf.org/html/rfc3156.html#section-4
|
||||
Ok((mime, parts[1]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_decryptable_data(mime_data: *mut mailmime_data) -> bool {
|
||||
/* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */
|
||||
unsafe {
|
||||
(*mime_data).dt_type == MAILMIME_DATA_TEXT as libc::c_int
|
||||
&& !(*mime_data).dt_data.dt_text.dt_data.is_null()
|
||||
&& (*mime_data).dt_data.dt_text.dt_length > 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
|
||||
unsafe {
|
||||
let mm_mime_fields = (*mime).mm_mime_fields;
|
||||
if !mm_mime_fields.is_null() {
|
||||
for cur_data in (*(*mm_mime_fields).fld_list).into_iter() {
|
||||
let field: *mut mailmime_field = cur_data as *mut _;
|
||||
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
&& !(*field).fld_data.fld_encoding.is_null()
|
||||
{
|
||||
return Some((*(*field).fld_data.fld_encoding).enc_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn decode_dt_data(
|
||||
mime_data: *mut mailmime_data,
|
||||
mime_transfer_encoding: libc::c_int,
|
||||
) -> Result<(*mut libc::c_char, libc::size_t), Error> {
|
||||
// Decode data according to mime_transfer_encoding
|
||||
// returns Ok with a (decoded_data,decoded_data_bytes) pointer
|
||||
// where the caller must make sure to free it.
|
||||
// It may return Ok(ptr::null_mut(), 0)
|
||||
|
||||
let mut transfer_decoding_buffer: *mut libc::c_char = ptr::null_mut();
|
||||
let decoded_data: *mut libc::c_char;
|
||||
let mut decoded_data_bytes: libc::size_t = 0;
|
||||
if mime_transfer_encoding == MAILMIME_MECHANISM_7BIT as libc::c_int
|
||||
|| mime_transfer_encoding == MAILMIME_MECHANISM_8BIT as libc::c_int
|
||||
|| mime_transfer_encoding == MAILMIME_MECHANISM_BINARY as libc::c_int
|
||||
{
|
||||
unsafe {
|
||||
decoded_data = (*mime_data).dt_data.dt_text.dt_data as *mut _;
|
||||
decoded_data_bytes = (*mime_data).dt_data.dt_text.dt_length;
|
||||
}
|
||||
ensure!(
|
||||
!decoded_data.is_null() && decoded_data_bytes > 0,
|
||||
"could not decode mime message"
|
||||
);
|
||||
} else {
|
||||
let mut current_index: libc::size_t = 0;
|
||||
unsafe {
|
||||
let r = mailmime_part_parse(
|
||||
(*mime_data).dt_data.dt_text.dt_data,
|
||||
(*mime_data).dt_data.dt_text.dt_length,
|
||||
&mut current_index,
|
||||
mime_transfer_encoding,
|
||||
&mut transfer_decoding_buffer,
|
||||
&mut decoded_data_bytes,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
|| transfer_decoding_buffer.is_null()
|
||||
|| decoded_data_bytes <= 0
|
||||
{
|
||||
bail!("mailmime_part_parse returned error or invalid data");
|
||||
}
|
||||
decoded_data = transfer_decoding_buffer;
|
||||
}
|
||||
}
|
||||
Ok((decoded_data, decoded_data_bytes))
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* mime creation API
|
||||
**************************************/
|
||||
|
||||
pub fn add_filename_part(
|
||||
message: *mut Mailmime,
|
||||
basename: &str,
|
||||
mime_type: &str,
|
||||
file_content: &str,
|
||||
) -> Result<(), Error> {
|
||||
let mime_type_c = CString::new(mime_type.to_string()).expect("failed to create CString");
|
||||
unsafe {
|
||||
let content_type = mailmime_content_new_with_str(mime_type_c.as_ptr());
|
||||
let mime_fields = mailmime_fields_new_filename(
|
||||
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
|
||||
basename.strdup(),
|
||||
MAILMIME_MECHANISM_8BIT as libc::c_int,
|
||||
);
|
||||
let file_mime_part = mailmime_new_empty(content_type, mime_fields);
|
||||
set_body_text(file_mime_part, file_content)?;
|
||||
mailmime_smart_add_part(message, file_mime_part);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_custom_field(fields: *mut mailimf_fields, name: &str, value: &str) {
|
||||
unsafe {
|
||||
let field = mailimf_field_new_custom(name.strdup(), value.strdup());
|
||||
let res = mailimf_fields_add(fields, field);
|
||||
assert!(
|
||||
res as u32 == MAILIMF_NO_ERROR,
|
||||
"could not create mailimf field"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_body_text(text: &str) -> Result<*mut Mailmime, Error> {
|
||||
let mime_fields: *mut mailmime_fields;
|
||||
let message_part: *mut Mailmime;
|
||||
|
||||
let content = new_content_type("text/plain")?;
|
||||
append_ct_param(content, "charset", "utf-8")?;
|
||||
|
||||
unsafe {
|
||||
mime_fields = mailmime_fields_new_encoding(MAILMIME_MECHANISM_8BIT as libc::c_int);
|
||||
message_part = mailmime_new_empty(content, mime_fields);
|
||||
}
|
||||
set_body_text(message_part, text)?;
|
||||
|
||||
Ok(message_part)
|
||||
}
|
||||
|
||||
pub fn append_ct_param(
|
||||
content: *mut mailmime_content,
|
||||
name: &str,
|
||||
value: &str,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let name_c = CString::new(name).unwrap();
|
||||
let value_c = CString::new(value).unwrap();
|
||||
|
||||
clist_append!(
|
||||
(*content).ct_parameters,
|
||||
mailmime_param_new_with_data(
|
||||
name_c.as_ptr() as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
value_c.as_ptr() as *const u8 as *const libc::c_char as *mut libc::c_char
|
||||
)
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_content_type(content_type: &str) -> Result<*mut mailmime_content, Error> {
|
||||
let ct = CString::new(content_type).unwrap();
|
||||
let content: *mut mailmime_content;
|
||||
// mailmime_content_new_with_str only parses but does not retain/own ct
|
||||
unsafe {
|
||||
content = mailmime_content_new_with_str(ct.as_ptr());
|
||||
}
|
||||
ensure!(!content.is_null(), "mailimf failed to allocate");
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub fn set_body_text(part: *mut Mailmime, text: &str) -> Result<(), Error> {
|
||||
use libc::strlen;
|
||||
unsafe {
|
||||
let text_c = text.strdup();
|
||||
if 0 != mailmime_set_body_text(part, text_c, strlen(text_c)) {
|
||||
bail!("could not set body text on mime-structure");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn content_type_needs_encoding(content: *const mailmime_content) -> bool {
|
||||
unsafe {
|
||||
if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int {
|
||||
let composite = (*(*content).ct_type).tp_data.tp_composite_type;
|
||||
match (*composite).ct_type as u32 {
|
||||
MAILMIME_COMPOSITE_TYPE_MESSAGE => as_str((*content).ct_subtype) != "rfc822",
|
||||
MAILMIME_COMPOSITE_TYPE_MULTIPART => false,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_needs_encoding() {
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("text/plain").unwrap()
|
||||
));
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("application/octect-stream").unwrap()
|
||||
));
|
||||
assert!(!content_type_needs_encoding(
|
||||
new_content_type("multipart/encrypted").unwrap()
|
||||
));
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("application/pgp-encrypted").unwrap()
|
||||
));
|
||||
}
|
||||
}
|
||||
67
src/x.rs
67
src/x.rs
@@ -1,67 +0,0 @@
|
||||
pub use libc::{
|
||||
calloc, exit, free, malloc, memcmp, memcpy, memmove, memset, realloc, strcat, strchr, strcmp,
|
||||
strcpy, strcspn, strlen, strncmp, strncpy, strrchr, strspn, strstr, strtol, system,
|
||||
};
|
||||
|
||||
pub unsafe fn strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let slen = strlen(s);
|
||||
let result = malloc(slen + 1);
|
||||
if result.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
memcpy(result, s as *const _, slen + 1);
|
||||
result as *mut _
|
||||
}
|
||||
|
||||
pub fn strndup(s: *const libc::c_char, n: libc::c_ulong) -> *mut libc::c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let end = std::cmp::min(n as usize, unsafe { strlen(s) });
|
||||
unsafe {
|
||||
let result = malloc(end + 1);
|
||||
memcpy(result, s as *const _, end);
|
||||
std::ptr::write_bytes(result.offset(end as isize), b'\x00', 1);
|
||||
|
||||
result as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
||||
let s1 = std::ffi::CStr::from_ptr(s1)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
let s2 = std::ffi::CStr::from_ptr(s2)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
if s1 == s2 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dc_tools::to_string;
|
||||
|
||||
#[test]
|
||||
fn test_strndup() {
|
||||
unsafe {
|
||||
let res = strndup(b"helloworld\x00" as *const u8 as *const libc::c_char, 4);
|
||||
assert_eq!(
|
||||
to_string(res),
|
||||
to_string(b"hell\x00" as *const u8 as *const libc::c_char)
|
||||
);
|
||||
assert_eq!(strlen(res), 4);
|
||||
free(res as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
test-data/key/private.asc
Normal file
1
test-data/key/private.asc
Normal file
@@ -0,0 +1 @@
|
||||
xcLYBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1lFrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSXAMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchwoFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAEACAChqzVOuErmVRqvcYtqm1xt1H+ZjX20z5Sn1fhTLYAcq236AWMqJvwxCXoKlc8bt2UfB+Ls9cQb1YcVq353r0QiExiDeK3YlCxqd/peXJwFYTNKFC3QcnUhtpG9oS/jWjN+BRotGbjtu6Vj3M68JJAq+mHJ0/9OyrqrREvGfo7uLZt7iMGemDlrDakvrbIyZrPLgay+nZ3dEFKeOQ6FFrU05jyUVdoHBy0Tqx/6VpFUX9+IHcMHL2lTJB0nynBj+XZ/G4aX3WYoo3YlixHbIu35fGFA0TChoGaGPzqcI/kg2Z+b/BryG9NM3LA2cO8iGrGXAE1nPFp91jmCrQ3VWushBADERP+uojjjfdO5J+RkmcFe9mFYDdtkhN+kV+LdePjiNNtcXMBhasstio0Sut0GKnE7DFRhX7mkN9w2apJ2ooeFeVVWot18eSdp6Rzh6/1Z7TmhYFJ3oUxxLbnQsWIXIec1SzqWBFJUCn3IP0mCnJktFg/uGW6yLs01r5ds52uSBQQA2LSWiTwk9tEmdr9mz3tHnmrkyGiyKhKGM1Z7Rch63D5yQc1s4kUMBlyuLL2QtM/e4dtaz2JAkO8kQrYCnNgJ+2roTAK3kDZgYtymjdvK3HpQNtjVo7dds5RJVb6U618phZwU5WNFAEJWyyImmycGfjLv+18cW/3mq0QVZejkM78D/2kHaIeJAowtBOFY2zDrKyDRoBHaUSgj5BjGoviRC5rYihWDEyYDQ6mBJQstAD0Ty3MYzyUxl6ruB/BMWnMDFq5+TqtdBzu3jCtZ8OEyH8A5Kdo68Wzo/PGxzMtusOdNj9+3PBmSq4yibJxbLSrn59aVUYpGLjeGKyvm9OTKkrOGN27NEzxhbGljZUBleGFtcGxlLmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkKA8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUKu5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxDFcfC2ARdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/RnoW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAmjxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABAAgAhSvFEYZoj1sSrXrHDjZOrryViGjCCH9t3pmkxLDrGIddKsFyN8ORUo6KUZS745yx3yFnI9EZ1IZvm9aF+jxk2lGJFtgLvfoxFOvGckwCSy8T/MCiJZkz01hWo5s2VCLJheWL/GqTKjS5wXDcm+y8Wtilh+UawycdlDsSNr/D4MZLj3Chq9K03l5UIR8DcC7SavNi55R2oGOfboXsdvwOlrNZdCkZOlXDI4ZKFwbDHCtpDo5FS30hnJi2TecUPZWB1CaGFWnevINd4ikugVjcAoZj/QAIvfrOCgqisF/Ylg9uRMUPBapmcJUueILwd0iQqvGG0aCqtchvSmlg15/lQQQA9G1NNjNAH+NQrXvDJFJe/V1U3F3pz7jCjQa69c0dxSBUeNX1pG8XXD6tSkkd4Ni1mzZGcZXOmVUM6cA9I7RH95RqV+QIfnXVneCRrlCjV8m6OBlkivkESXc3nW5wtCIfw7oKg9w1xuVNUaAlbCt9QVLaxXJiY7ad0f5U9XJ1+w8EAPFs+M/+GZK1wOZYBL1vo7x0gL9ZggmjC4B+viBJ8Q60mqTrphYFsbXHuwKV0g9aIoZMucKyEE0QLR7imttiLEz1nD8bfEScbGy9ZG//wRfyJmCVAjA0pQ6LtB93d70PSVzzJrMHgbLKrDuSd6RChl7n9BIEdVyk7LEph0Yg9UsRBADm6DvpKL+P3lQ0eLTfAgcQTOqLZDYmI3PvqqSkHb1kHChqOXXs8hGOSSwKGjcd4CZeNOGWR42rZyRhVgtkt6iYviIaVAWUfme6K+sLQBCeyMlmEGtykAA+LmPBf4zdyUNADfoxgZF3EKHf6I3nlVn5cdT+o/9vjdY2XAOwcls1RzaFwsB2BBgBCAAgBQJdPOn4AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoWqEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwXFNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9mMjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6
|
||||
13
test-data/message/mail_with_message_id.txt
Normal file
13
test-data/message/mail_with_message_id.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Return-Path: <x@testrun.org>
|
||||
Received: from hq5.merlinux.eu
|
||||
by hq5.merlinux.eu (Dovecot) with LMTP id yRKOBakcfV1AewAAPzvFDg
|
||||
; Sat, 14 Sep 2019 19:00:25 +0200
|
||||
Received: from localhost (unknown 7.165.105.24])
|
||||
by hq5.merlinux.eu (Postfix) with ESMTPSA id 8D9844E023;
|
||||
Sat, 14 Sep 2019 19:00:22 +0200 (CEST)
|
||||
message-id: <2dfdbde7@example.org>
|
||||
Date: Sat, 14 Sep 2019 19:00:13 +0200
|
||||
From: lmn <x@tux.org>
|
||||
To: abc <abc@bcd.com>, def <def@def.de>,
|
||||
jik
|
||||
|
||||
125
test-data/message/stress.txt
Normal file
125
test-data/message/stress.txt
Normal file
@@ -0,0 +1,125 @@
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Passphrase-Format: numeric9x4
|
||||
Passphrase-Begin: 17
|
||||
|
||||
wy4ECQMI0jNRBQfVKHVg1+a2Yihd6JAjR9H0kk3oDVeX7nc4Oi+IjEtonUJt
|
||||
PQpO0tPWASWYuYvjZSuTz9r1yZYV+y4mu9bu9NEQoRlWg2wnbjoUoKk4emFF
|
||||
FweUj84iI6VWTCSRyMu5d5JS1RfOdX4CG/muLAegyIHezqYOEC0Z3b9Ci9rd
|
||||
DiSgqqN+/LDkUR/vr7L2CSLN5suBP9Hsz75AtaV8DJ2DYDywYX89yH1CfL1O
|
||||
WohyrJPdmGJZfdvQX0LI9mzN7MH0W6vUJeCaUpujc+UkLiOM6TDB74rmYF+V
|
||||
Z7K9BXbaN4V6dyxVZfgpXUoZlaNpvqPJXuLHJ68umkuIgIyQvzmMj3mFgZ8s
|
||||
akCt6Cf3o5O9n2PJvX89vuNnDGJrO5booEqGaBJfwUk0Rwb0gWsm5U0gceUz
|
||||
dce8KZK15CzX+bNv5OC+8jjjBw7mBHVt+2q8LI+G9fEy9NIREkp5/v2ZRN0G
|
||||
R6lpZwW+8TkMvJnriQeABqDpxsJVT6ENYAhkPG3AZCr/whGBU3EbDzPexXkz
|
||||
qt8Pdu5DrazLSFtjpjkekrjCh43vHjGl8IOiWxKQx0VfBkHJ7O9CsHmb0r1o
|
||||
F++fMh0bH1/aewmlg5wd0ixwZoP1o79he8Q4kfATZAjvB1xSLyMma+jxW5uu
|
||||
U3wYUOsUmYmzo46/QzizFCUpaTJ4ZQZY1/4sflidsl/XgZ0fD1NCrdkWBNA1
|
||||
0tQF949pEAeA4hSfHfQDNKAY8A7fk8lZblqWPkyu/0x8eV537QOhs89ZvhSB
|
||||
V87KEAwxWt60+Eolf8PvvkvB/AKlfWq4MYShgyldwwCfkED3rv2mvTsdqfvW
|
||||
WvqZNo4eRkJrnv9Be3LaXoFyY6a3z+ObBIkKI+u5azGJYge97O4E2DrUEKdQ
|
||||
cScq5upzXity0E+Yhm964jzBzxnA52S4RoXzkjTxH+AHjQ5+MHQxmRfMd2ly
|
||||
7skM106weVOR0JgOdkvfiOFDTHZLIVCzVyYVlOUJYYwPhmM1426zbegHNkaM
|
||||
M2WgvjMp5G+X9qfDWKecntQJTziyDFZKfd1UrUCPHrvl1Ac9cuqgcCXLtdUS
|
||||
jI+e1Y9fXvgyvHiMX0ztSz1yfvnRt34508G9j68fEQFQR/VIepULB5/SqKbq
|
||||
p2flgJL48kY32hEw2GRPri64Tv3vMPIWa//zvQDhQPmcd3S4TqnTIIKUoTAO
|
||||
NUo6GS9UAX12fdSFPZINcAkNIaB69+iwGyuJE4FLHKVkqNnNmDwF3fl0Oczo
|
||||
hbboWzA3GlpR2Ri6kfe0SocfGR0CHT5ZmqI6es8hWx+RN8hpXcsRxGS0BMi2
|
||||
mcJ7fPY+bKastnEeatP+b0XN/eaJAPZPZSF8PuPeQ0Uc735fylPrrgtWK9Gp
|
||||
Wq0DPaWV/+O94OB/JvWT5wq7d/EEVbTck5FPl4gdv3HHpaaQ6/8G89wVMEXA
|
||||
GUxB8WuvNeHAtQ7qXF7TkaZvUpF0rb1aV88uABOOPpsfAyWJo/PExCZacg8R
|
||||
GOQYI6inV5HcGUw06yDSqArHZmONveqjbDBApenearcskv6Uz7q+Bp60GGSA
|
||||
lvU3C3RyP/OUc1azOp72MIe0+JvP8S5DN9/Ltc/5ZyZHOjLoG+npIXnThYwV
|
||||
0kkrlsi/7loCzvhcWOac1vrSaGVCfifkYf+LUFQFrFVbxKLOQ6vTsYZWM0yM
|
||||
QsMMywW5A6CdROT5UB0UKRh/S1cwCwrN5UFTRt2UpDF3wSBAcChsHyy90RAL
|
||||
Xd4+ZIyf29GIFuwwQyzGBWnXQ2ytU4kg/D5XSqJbJJTya386UuyQpnFjI19R
|
||||
uuD0mvEfFvojCKDJDWguUNtWsHSg01NXDSrY26BhlOkMpUrzPfX5r0FQpgDS
|
||||
zOdY9SIG+y9MKG+4nwmYnFM6V5NxVL+6XZ7BQTvlLIcIIu+BujVNWteDnWNZ
|
||||
T1UukCGmFd8sNZpCc3wu4o/gLDQxih/545tWMf0dmeUfYhKcjSX9uucMRZHT
|
||||
1N0FINw04fDdp2LccL+WCGatFGnkZVPw3asid4d1od9RG9DbNRBJEp/QeNhc
|
||||
/peJCPLGYlA1NjTEq+MVB+DHdGNOuy//be3KhedBr6x4VVaDzL6jyHu/a7PR
|
||||
BWRVtI1CIVDxyrEXucHdGQoEm7p+0G2zouOe/oxbPFoEYrjaI+0e/FN3u/Y3
|
||||
aG0dlYWbxeHMqTh2F3lB/CFALReeGqqN6PwRyePWKaVctZYb6ydf9JVl6q1/
|
||||
aV9C5rf9eFGqqA+OIx/+XuAG1w0rwlznvtajHzCoUeA4QfbmuOV/t5drWN2N
|
||||
PCk2mJlcSmd7lx53rnOIgme1hggchjezc4TisL4PvSLxjJ7DxzktD2jv2I/Q
|
||||
OlSxTUaXnGfIVedsI0WjFomz5w9tZjC0B5O5TpSRRz6gfpe/OC3kV7qs1YCS
|
||||
lJTTxj1mTs6wqt0WjKkN/Ke0Cm5r7NQ79szDNlcC0AViEOQb3U1R88nNdiVx
|
||||
ymKT5Dl+yM6acv53lNX6O5BH+mpP2/pCpi3x+kYFyr4cUsNgVVGlhmkPWctZ
|
||||
trHvO7wcLrAsrLNqRxt1G3DLjQt9VY+w5qOPJv6s9qd5JBL/qtH5zqIXiXlM
|
||||
IWI9LLwHFFXqjk/f6G4LyOeHB9AqccGQ4IztgzTKmYEmFWVIpTO4UN6+E7yQ
|
||||
gtcYSIUEJo824ht5rL+ODqmCSAWsWIomEoTPvgn9QqO0YRwAEMpsFtE17klS
|
||||
qjbYyV7Y5A0jpCvqbnGmZPqCgzjjN/p5VKSNjSdM0vdwBRgpXlyooXg/EGoJ
|
||||
ZTZH8nLSuYMMu7AK8c7DKJ1AocTNYHRe9xFV8RzEiIm3zaezxa0r+Fo3nuTX
|
||||
UR9DOH0EHaDLrFQcfS5y1iRxY9CHg0N2ECaUzr/H7jck9mLZ7v9xisj3QDuv
|
||||
i0xQbC4BTxMEBGTK8fOcjHHOABOyhqotOreERqwOV2c1OOGUQE8QK18zJCUd
|
||||
BTmQZ709ttASD7VWK4TraOGczZXkZsKdZko5T6+6EkFy9H+gwENLUG9zk0x9
|
||||
2G5zicDr6PDoAGDuoB3B3VA8ertXTX7zEz30N6m+tcAtPWka0owokLy3f0o7
|
||||
ZdytBPkly8foTMWKF2vsJ8K4Xdn/57jJ2qFku32xmtiPIoa6s8wINO06AVB0
|
||||
0/AuttvxcPr+ycE+9wRZHx6JBujAqOZztU3zu8WZMaqVKb7gnmkWPiL+1XFp
|
||||
2+mr0AghScIvjzTDEjigDtLydURJrW01wXjaR0ByBT4z8ZjaNmQAxIPOIRFC
|
||||
bD0mviaoX61qgQLmSc6mzVlzzNZRCKtSvvGEK5NJ6CB6g2EeFau8+w0Zd+vv
|
||||
/iv6Img3pUBgvpMaIsxRXvGZwmo2R0tztJt+CqHRvyTWjQL+CjIAWyoHEdVH
|
||||
k7ne/q9zo3iIMsQUO7tVYtgURpRYc2OM1IVQtrgbmbYGEdOrhMjaWULg9C7o
|
||||
6oDM0EFlCAId3P8ykXQNMluFKlf9il5nr19B/qf/wh6C7DFLOmnjTWDXrEiP
|
||||
6wFEWTeUWLchGlbpiJFEu05MWPIRoRd3BHQvVpzLLgeBdxMVW7D6WCK+KJxI
|
||||
W1rOKhhLVvKU3BrFgr12A4uQm+6w1j33Feh68Y0JB7GLDBBGe11QtLCD6kz5
|
||||
RzFl+GbgiwpHi3nlCc5yiNwyPq/JRxU3GRb62YJcsSQBg+CD3Mk5FGiDcuvp
|
||||
kZXOcTE2FAnUDigjEs+oH2qkhD4/5CiHkrfFJTzv+wqw+jwxPor2jkZH2akN
|
||||
6PssXQYupXJE3NmcyaYT+b5E6qbkIyQj7CknkiqmrqrmxkOQxA+Ab2Vy9zrW
|
||||
u0+Wvf+C+SebWTo3qfJZQ3KcASZHa5AGoSHetWzH2fNLIHfULXac/T++1DWE
|
||||
nbeNvhXiFmAJ+BRsZj9p6RcnSamk4bjAbX1lg2G3Sq6MiA1fIRSMlSjuDLrQ
|
||||
8xfVFrg7gfBIIQPErJWv2GdAsz76sLxuSXQLKYpFnozvMT7xRs84+iRNWWh9
|
||||
SNibbEjlh0DcJlKw49Eis/bN22sDQWy4awHuRvvQetk/QCgp54epuqWnbxoE
|
||||
XZDgGBBkMc3or+6Cxr3q9x7J/oHLvPb+Q5yVP9fyz6ZiSVWluMefA9smjJ/A
|
||||
KMD84s7uO/8/4yug+swXGrcBjHSddTcy05vm+7X6o9IEZKZb5tz7VqAfEcuk
|
||||
QNPUWCMudhzxSNr4+yVXRVpcjsjKtplJcXC5aIuJwq3C5OdysCGqXWjLuUu1
|
||||
OFSoPvTsYC2VxYdFUcczeHEFTxXoXz3I0TyLPyxUNsJiKpUGt/SXmV/IyAx+
|
||||
h6pZ2OUXspC9d78DdiHZtItPjEGiIb678ZyMxWPE59XQd/ad92mlPHU8InXD
|
||||
yTq6otZ7LwAOLGbDR9bqN7oX8PCHRwuu30hk2b4+WkZn/WLd2KCPddQswZJg
|
||||
Qgi5ajUaFhZvxF5YNTqIzzYVh7Y8fFMfzH9AO+SJqy+0ECX0GwtHHeVsXYNb
|
||||
P/NO/ma4MI8301JyipPmdtzvvt9NOD/PJcnZH2KmDquARXMO/vKbn3rNUXog
|
||||
pTFqqyNTr4L5FK86QPEoE4hDy9ItHGlEuiNVD+5suGVGUgYfV7AvZU46EeqO
|
||||
rfFj8wNSX1aK/pIwWmh1EkygPSxomWRUANLX1jO6zX9wk2X80Xn9q/8jot1k
|
||||
Vl54OOd7cvGls2wKkEZi5h3p6KKZHJ+WIDBQupeJbuma1GK8wAiwjDH59Y0X
|
||||
wXHAk7XA+t4u0dgRpZbUUMqQmvEvfJaCr4qMlpuGdEYbbpIMUB1qCfYU9taL
|
||||
zbepMIT+XYD5mTyytZhR+zrsfpt1EzbrhuabqPioySoIS/1+bWfxvndq16r0
|
||||
AdNxR5LiVSVh8QJr3B/HJhVghgSVrrynniG3E94abNWL/GNxPS/dTHSf8ass
|
||||
vbv7+uznADzHsMiG/ZlLAEkQJ9j0ENJvHmnayeVFIXDV6jPCcQJ+rURDgl7z
|
||||
/qTLfe3o3zBMG78LcB+xDNXTQrK5Z0LX7h17hLSElpiUghFa9nviCsT0nkcr
|
||||
nz302P4IOFwJuYMMCEfW+ywTn+CHpKjLHWkZSZ4q6LzNTbbgXZn/vh7njNf0
|
||||
QHaHmaMNxnDhUw/Bl13uM52qtsfEYK07SEhLFlJbAk0G7q+OabK8dJxCRwS3
|
||||
X9k4juzLUYhX8XBovg9G3YEVckb6iM8/LF/yvNXbUsPrdhYU9lPA63xD0Pgb
|
||||
zthZCLIlnF+lS6e41WJv3n1dc4dFWD7F5tmt/7uwLC6oUGYsccSzY+bUkYhL
|
||||
dp7tlQRd5AG/Xz8XilORk8cUjvi6uZss5LyQpKvGSU+77C8ZV/oS62BdS5TE
|
||||
osBTrO2/9FGzQtHT+8DJSTPPgR6rcQUWLPemiG09ACKfRQ/g3b9Qj0upOcKL
|
||||
6dti0lq7Aorc39vV18DPMFBOwzchUEBlBFyuSa4AoD30tsoilAC3qbzBwu3z
|
||||
QLjmst76HEcWDkxgDAhlBz6/XgiVZsCivn7ygigmc2+hNEzIdDsKKfM9bkoe
|
||||
3uJzmmsv8Bh5ZEtfGoGNmu/zA7tgvTOCBeotYeHr2O6pLmYb3hK+E/qCBl14
|
||||
8pK4qYrjAlF+ZMq9BzXcaz5mRfKVfAQtghHOaNqopBczSE1bjFF6HaNhIaGa
|
||||
N8YdabNQG7mLI/fgBxJfkPl6HdIhEpctp4RURbSFhW+wn0o85VyHM6a+6Vgj
|
||||
NrYmhxPZ6N1KN0Qy76aNiw7nAToRRcOv87uZnkDIeVH8mP/0hldyiy/Y97cG
|
||||
QgOeQHOG27QW57nHhqLRqvf0zzQZekuXWFbqajpaabEcdGXyiUpJ8/ZopBPM
|
||||
AJwfkyA2LkV946IA4JV6sPnu9pYzpXQ4vdQKJ6DoDUyRTQmgmfSFGtfHAozY
|
||||
V9k0iQeetSkYYtOagTrg3t92v7M00o/NJW/rKX4jj2djD8wtBovOcv4kxg4Z
|
||||
o58Iv94ROim48XfyesvSYKN1xqqbXH4sfE6b4b9pLUxQVOmWANLK9MK8D+Ci
|
||||
IvrGbz5U5bZP6vlNbe9bYzjvWTPjaMrjXknRTBcikavqOfDTSIVFtT4qvhvK
|
||||
42PpOrm0qdiLwExGKQ9FfEfYZRgEcYRGg7rH3oNz6ZNOEXppF3tCl9yVOlFb
|
||||
ygdIeT3Z3HeOQbAsi8jK7o16DSXL7ZOpFq9Bv9yzusrF7Eht/fSEpAVUO3D1
|
||||
IuqjZcsQRhMtIvnF0oFujFtooJx9x3dj/RarvEGX/NzwATZkgJ+yWs2etruA
|
||||
EzMQqED4j7Lb790zEWnt+nuHdCdlPnNy8RG5u5X62p3h5KqUbg9HfmIuuESi
|
||||
hwr6dKsVQGc5XUB5KTt0dtjWlK5iaetDsZFuF5+aE0Xa6PmiQ2e7ZPFyxXmO
|
||||
T/PSHzobx0qClKCu+tSWA1HDSL08IeoGZEyyhoaxyn5D9r1Mqg101v/iu59r
|
||||
lRRs+plAhbuq5aQA3WKtF1N6Zb5+AVRpNUyrxyHoH36ddR4/n7lnIld3STGD
|
||||
RqZLrOuKHS3dCNW2Pt15lU+loYsWFZwC6T/tAbvwhax+XaBMiKQSDFmG9sBw
|
||||
TiM1JWXhq2IsjXBvCl6k2AKWLQOvc/Hin+oYs4d7M9mi0vdoEOAMadU/+Pqn
|
||||
uZzP941mOUV5UeTCCbjpyfI7qtIi3TH1cQmC2kG2HrvQYuM6Momp//JusH1+
|
||||
9eHgFo25HbitcKJ1sAqxsnYIW5/jIVyIJC7tatxmNfFQQ/LUb2cT+Jowwsf4
|
||||
bbPinA9S6aQFy9k3vk07V2ouYl+cpMMXmNAUrboFRLxw7QDapWYMKdmnbU5O
|
||||
HZuDz3iyrm0lMPsRtt/f5WUhZYY4vXT5/dj+8P6Pr5fdc4S84i5qEzf7bX/I
|
||||
Sc6fpISdYBscfHdv6uXsEVtVPKEuQVYwhyc4kkwVKjZBaqsgjAA7VEhQXzO3
|
||||
rC7di4UhabWQCQTG1GYZyrj4bm6dg/32uVxMoLS5kuSpi3nMz5JmQahLqRxh
|
||||
argg13K2/MJ7w2AI23gCvO5bEmD1ZXIi1aGYdZfu7+KqrTumYxj0KgIesgU0
|
||||
6ekmPh4Zu5lIyKopa89nfQVj3uKbwr9LLHegfzeMhvI5WQWghKcNcXEvJwSA
|
||||
vEik5aXm2qSKXT+ijXBy5MuNeICoGaQ5WA0OJ30Oh5dN0XpLtFUWHZKThJvR
|
||||
mngm1QCMMw2v/j8=
|
||||
=9sJE
|
||||
-----END PGP MESSAGE-----
|
||||
210
tests/stress.rs
210
tests/stress.rs
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user