diff --git a/Cargo.lock b/Cargo.lock index 1cc74b5c..42da72a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "anyhow" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arc-swap" version = "0.4.2" @@ -48,6 +53,11 @@ dependencies = [ "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bincode" version = "1.2.0" @@ -77,11 +87,25 @@ name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bumpalo" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "c2-chacha" version = "0.2.2" @@ -232,6 +256,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dtoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "encoding" version = "0.2.33" @@ -289,6 +318,14 @@ name = "encoding_index_tests" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "encoding_rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.5" @@ -392,6 +429,43 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures-channel-preview" +version = "0.3.0-alpha.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core-preview" +version = "0.3.0-alpha.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-io-preview" +version = "0.3.0-alpha.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-sink-preview" +version = "0.3.0-alpha.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util-preview" +version = "0.3.0-alpha.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "getrandom" version = "0.1.6" @@ -401,6 +475,121 @@ dependencies = [ "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "h2" +version = "0.2.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http-body" +version = "0.2.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.13.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)", + "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-tls" +version = "0.4.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indexmap" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "inotify" version = "0.6.1" @@ -433,6 +622,14 @@ name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "js-sys" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -490,6 +687,14 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.6" @@ -525,13 +730,23 @@ dependencies = [ "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "meli" version = "0.4.1" dependencies = [ "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "melib 0.4.1", - "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "ui 0.4.1", "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -554,8 +769,10 @@ dependencies = [ "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "notify-rust 3.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.10.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "text_processing 0.4.1", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -594,11 +811,25 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mime_apps" version = "0.2.0" source = "git+https://git.meli.delivery/meli/mime_apps#fdd4f43a843eb729ef0d1f58a52b0e74bab7b9d6" +[[package]] +name = "mime_guess" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.6.19" @@ -627,6 +858,16 @@ dependencies = [ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.2.1" @@ -665,18 +906,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nix" -version = "0.14.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)", - "cc 1.0.37 (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.64 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nix" version = "0.15.0" @@ -702,6 +931,15 @@ dependencies = [ "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "notify" version = "4.0.12" @@ -746,6 +984,15 @@ dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num_cpus" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "numtoa" version = "0.1.0" @@ -807,6 +1054,58 @@ dependencies = [ "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pin-project" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pin-project-internal 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.14" @@ -825,6 +1124,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "1.0.6" +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)", +] + [[package]] name = "quote" version = "0.6.12" @@ -833,6 +1140,14 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.6.5" @@ -1006,6 +1321,42 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "reqwest" +version = "0.10.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.4.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rusqlite" version = "0.20.0" @@ -1122,6 +1473,17 @@ dependencies = [ "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_urlencoded" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "signal-hook" version = "0.1.10" @@ -1145,11 +1507,37 @@ name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smallvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.15.35" @@ -1160,6 +1548,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (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)", +] + [[package]] name = "synstructure" version = "0.10.2" @@ -1220,6 +1618,133 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-macros" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-net" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.3.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tls" +version = "0.3.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.5.3" @@ -1228,6 +1753,55 @@ dependencies = [ "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tower-make" +version = "0.3.0-alpha.2a" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tower-service" +version = "0.3.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tracing" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tracing-core" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ui" version = "0.4.1" @@ -1255,6 +1829,30 @@ dependencies = [ "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-segmentation" version = "1.3.0" @@ -1265,6 +1863,21 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "uuid" version = "0.7.4" @@ -1279,6 +1892,16 @@ name = "vcpkg" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -1294,6 +1917,112 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "web-sys" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "weedle" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -1331,6 +2060,14 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1346,17 +2083,21 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" "checksum arc-swap 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "854ede29f7a0ce90519fb2439d030320c6201119b87dab0ee96044603e1130b9" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "ada4c783bb7e7443c14e0480f429ae2cc99da95065aeab7ee1b81ada0419404f" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" @@ -1374,6 +2115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "checksum dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e1b39f3f6aa3d4a1522c4f0f9f1e9e9167bd93740a8690874caa7cf8ce47d7" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" "checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" "checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" "checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" @@ -1381,6 +2123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" "checksum encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" +"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" @@ -1395,11 +2138,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a" +"checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a" +"checksum futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda" +"checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec" +"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" "checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" +"checksum h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f107db1419ef8271686187b1a5d47c6431af4a7f4d98b495e7b7fc249bb0a78" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +"checksum http 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "2790658cddc82e82b08e25176c431d7015a0adeb1718498715cbd20138a0bf68" +"checksum http-body 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f3aef6f3de2bd8585f5b366f3f550b5774500b4764d00cf00f903c95749eec3" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d05aa523087ac0b9d8b93dd80d5d482a697308ed3b0dca7b0667511a7fa7cdc" +"checksum hyper-tls 0.4.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "47cb3975f80cc809efe5dfcc52b73c9b281fde33f2df35a2e5f79f35e384ae7f" +"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "1c840fdb2167497b0bd0db43d6dfe61e91637fa72f9d061f8bd17ddc44ba6414" "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 lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" @@ -1408,28 +2167,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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" "checksum linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ce9439c6f4a1092dc1861272bef01034891da39f13aa1cdcf40ca3e4081de5f" +"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" "checksum mac-notification-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46f3c7359028b31999287dae4e5047ddfe90a23b7dca2282ce759b491080c99b" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" "checksum mime_apps 0.2.0 (git+https://git.meli.delivery/meli/mime_apps)" = "" +"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "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.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943" "checksum notify-rust 3.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2956515e032b56214c2712b79f41ad39519af8bf3584d064b307f578b7f88c5e" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" @@ -1437,10 +2203,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +"checksum pin-project 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "94b90146c7216e4cb534069fb91366de4ea0ea353105ee45ed297e2d1619e469" +"checksum pin-project-internal 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "44ca92f893f0656d3cba8158dd0f2b99b94de256a4a54e870bd6922fcc6c8355" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1460,6 +2234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum reqwest 0.10.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e83b47defcad97ddbe592fd5fe49e16661f754b0ba5847cf41bcd870a2d338d7" "checksum rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a194373ef527035645a1bc21b10dc2125f73497e6e155771233eb187aedd051" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1475,27 +2250,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" "checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" +"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" "checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68" "checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" +"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum syn 0.15.35 (registry+https://github.com/rust-lang/crates.io-index)" = "641e117d55514d6d918490e47102f7e08d096fdde360247e4a10f7a91a8478d3" +"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f17f5d6ab0f35c1506678b28fb1798bdf74fcb737e9843c7b17b73e426eba38" +"checksum tokio-codec 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9f5d22fd1e84bd4045d28813491cb7d7caae34d45c80517c2213f09a85e8787a" +"checksum tokio-executor 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee9ceecf69145923834ea73f32ba40c790fd877b74a7817dd0b089f1eb9c7c8" +"checksum tokio-io 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "112784d5543df30660b04a72ca423bfbd90e8bb32f94dcf610f15401218b22c5" +"checksum tokio-macros 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "86b616374bcdadd95974e1f0dfca07dc913f1163c53840c0d664aca35114964e" +"checksum tokio-net 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a441682cd32f3559383112c4a7f372f5c9fa1950c5cf8c8dd05274a2ce8c2654" +"checksum tokio-sync 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f1aaeb685540f7407ea0e27f1c9757d258c7c6bf4e3eb19da6fc59b747239d2" +"checksum tokio-timer 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b97c1587fe71018eb245a4a9daa13a5a3b681bbc1f7fdadfe24720e141472c13" +"checksum tokio-tls 0.3.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "566b4086589c7eebb86aa625d302ab80720ef2aa088649dcae18ec4d754cbd16" "checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum tower-make 0.3.0-alpha.2a (registry+https://github.com/rust-lang/crates.io-index)" = "316d47dd40cde4ac5d88110eaf9a10a4e2a68612d9c056cd2aa24e37dcb484cd" +"checksum tower-service 0.3.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "63ff37396cd966ce43bea418bfa339f802857495f797dafa00bea5b7221ebdfa" +"checksum tracing 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c21ff9457accc293386c20e8f754d0b059e67e325edf2284f04230d125d7e5ff" +"checksum tracing-attributes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a4263b12c3d3c403274493eb805966093b53214124796552d674ca1dd5d27c2b" +"checksum tracing-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bc913647c520c959b6d21e35ed8fa6984971deca9f0a2fcb8c51207e0c56af1d" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" +"checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +"checksum wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "29ae32af33bacd663a9a28241abecf01f2be64e6a185c6139b04f18b6385c5f2" +"checksum wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "1845584bd3593442dc0de6e6d9f84454a59a057722f36f005e44665d6ab19d85" +"checksum wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1458706aa1b8fe6898d19433c9f110d93a05d1f22ae6adf55810409a94df34b4" +"checksum wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "87fcc747e6b73c93d22c947a6334644d22cfec5abd8b66238484dc2b0aeb9fe4" +"checksum wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc4b3f2c4078c8c4a5f363b92fcf62604c5913cbd16c6ff5aaf0f74ec03f570" +"checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d" +"checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5" +"checksum web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "98405c0a2e722ed3db341b4c5b70eb9fe0021621f7350bab76df93b09b649bbf" +"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" diff --git a/melib/Cargo.toml b/melib/Cargo.toml index 35d4526a..1a8e8b2a 100644 --- a/melib/Cargo.toml +++ b/melib/Cargo.toml @@ -26,9 +26,11 @@ bincode = "1.2.0" uuid = { version = "0.7.4", features = ["serde", "v4"] } text_processing = { path = "../text_processing", version = "*", optional= true } libc = {version = "0.2.59", features = ["extra_traits",]} +reqwest = { version ="0.10.0-alpha.2", optional=true, features = ["json", "blocking" ]} +serde_json = { version = "1.0", optional = true, features = ["raw_value",] } [features] -default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard"] +default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "jmap_backend", "vcard"] debug-tracing = [] unicode_algorithms = ["text_processing"] @@ -36,4 +38,5 @@ imap_backend = ["native-tls"] maildir_backend = ["notify", "notify-rust", "memmap"] mbox_backend = ["notify", "notify-rust", "memmap"] notmuch_backend = [] +jmap_backend = ["reqwest", "serde_json" ] vcard = [] diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 656cc465..a6d0b1ba 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -38,6 +38,10 @@ pub mod mbox; pub mod notmuch; #[cfg(feature = "notmuch_backend")] pub use self::notmuch::NotmuchDb; +#[cfg(feature = "jmap_backend")] +pub mod jmap; +#[cfg(feature = "jmap_backend")] +pub use self::jmap::JmapType; #[cfg(feature = "imap_backend")] pub use self::imap::ImapType; @@ -129,6 +133,16 @@ impl Backends { }, ); } + #[cfg(feature = "jmap_backend")] + { + b.register( + "jmap".to_string(), + Backend { + create_fn: Box::new(|| Box::new(|f, i| JmapType::new(f, i))), + validate_conf_fn: Box::new(JmapType::validate_config), + }, + ); + } b } @@ -356,6 +370,28 @@ impl Default for SpecialUsageMailbox { } } +impl SpecialUsageMailbox { + pub fn detect_usage(name: &str) -> Option { + if name.eq_ignore_ascii_case("inbox") { + Some(SpecialUsageMailbox::Inbox) + } else if name.eq_ignore_ascii_case("archive") { + Some(SpecialUsageMailbox::Archive) + } else if name.eq_ignore_ascii_case("drafts") { + Some(SpecialUsageMailbox::Drafts) + } else if name.eq_ignore_ascii_case("junk") { + Some(SpecialUsageMailbox::Junk) + } else if name.eq_ignore_ascii_case("spam") { + Some(SpecialUsageMailbox::Junk) + } else if name.eq_ignore_ascii_case("sent") { + Some(SpecialUsageMailbox::Sent) + } else if name.eq_ignore_ascii_case("trash") { + Some(SpecialUsageMailbox::Trash) + } else { + Some(SpecialUsageMailbox::Normal) + } + } +} + pub trait BackendFolder: Debug { fn hash(&self) -> FolderHash; fn name(&self) -> &str; diff --git a/melib/src/backends/jmap.rs b/melib/src/backends/jmap.rs new file mode 100644 index 00000000..1537b338 --- /dev/null +++ b/melib/src/backends/jmap.rs @@ -0,0 +1,303 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; +use crate::backends::BackendOp; +use crate::backends::FolderHash; +use crate::backends::{BackendFolder, Folder, FolderOperation, MailBackend, RefreshEventConsumer}; +use crate::conf::AccountSettings; +use crate::email::*; +use crate::error::{MeliError, Result}; +use fnv::FnvHashMap; +use reqwest::blocking::Client; +use std::collections::BTreeMap; +use std::str::FromStr; +use std::sync::{Arc, Mutex, RwLock}; + +#[macro_export] +macro_rules! _impl { + ($(#[$outer:meta])*$field:ident : $t:ty) => { + $(#[$outer])* + pub fn $field(mut self, new_val: $t) -> Self { + self.$field = new_val; + self + } + }; + (get_mut $(#[$outer:meta])*$method:ident, $field:ident : $t:ty) => { + $(#[$outer])* + pub fn $method(&mut self) -> &mut $t { + &mut self.$field + } + }; + (get $(#[$outer:meta])*$method:ident, $field:ident : $t:ty) => { + $(#[$outer])* + pub fn $method(&self) -> &$t { + &self.$field + } + } + } + +pub mod operations; +use operations::*; + +pub mod connection; +use connection::*; + +pub mod protocol; +use protocol::*; + +pub mod rfc8620; +use rfc8620::*; + +pub mod objects; +use objects::*; + +pub mod folder; +use folder::*; + +#[derive(Debug, Default)] +pub struct EnvelopeCache { + bytes: Option, + headers: Option, + body: Option, + flags: Option, +} + +#[derive(Debug, Clone)] +pub struct JmapServerConf { + pub server_hostname: String, + pub server_username: String, + pub server_password: String, + pub server_port: u16, + pub danger_accept_invalid_certs: bool, +} + +macro_rules! get_conf_val { + ($s:ident[$var:literal]) => { + $s.extra.get($var).ok_or_else(|| { + MeliError::new(format!( + "Configuration error ({}): JMAP connection requires the field `{}` set", + $s.name.as_str(), + $var + )) + }) + }; + ($s:ident[$var:literal], $default:expr) => { + $s.extra + .get($var) + .map(|v| { + <_>::from_str(v).map_err(|e| { + MeliError::new(format!( + "Configuration error ({}): Invalid value for field `{}`: {}\n{}", + $s.name.as_str(), + $var, + v, + e + )) + }) + }) + .unwrap_or_else(|| Ok($default)) + }; +} + +impl JmapServerConf { + pub fn new(s: &AccountSettings) -> Result { + Ok(JmapServerConf { + server_hostname: get_conf_val!(s["server_hostname"])?.to_string(), + server_username: get_conf_val!(s["server_username"])?.to_string(), + server_password: get_conf_val!(s["server_password"])?.to_string(), + server_port: get_conf_val!(s["server_port"], 443)?, + danger_accept_invalid_certs: get_conf_val!(s["danger_accept_invalid_certs"], false)?, + }) + } +} + +struct IsSubscribedFn(Box bool + Send + Sync>); + +impl std::fmt::Debug for IsSubscribedFn { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "IsSubscribedFn Box") + } +} + +impl std::ops::Deref for IsSubscribedFn { + type Target = Box bool + Send + Sync>; + fn deref(&self) -> &Box bool + Send + Sync> { + &self.0 + } +} +macro_rules! get_conf_val { + ($s:ident[$var:literal]) => { + $s.extra.get($var).ok_or_else(|| { + MeliError::new(format!( + "Configuration error ({}): JMAP connection requires the field `{}` set", + $s.name.as_str(), + $var + )) + }) + }; + ($s:ident[$var:literal], $default:expr) => { + $s.extra + .get($var) + .map(|v| { + <_>::from_str(v).map_err(|e| { + MeliError::new(format!( + "Configuration error ({}): Invalid value for field `{}`: {}\n{}", + $s.name.as_str(), + $var, + v, + e + )) + }) + }) + .unwrap_or_else(|| Ok($default)) + }; +} + +#[derive(Debug, Default)] +pub struct Store { + byte_cache: FnvHashMap, + id_store: FnvHashMap, + blob_id_store: FnvHashMap, +} + +#[derive(Debug)] +pub struct JmapType { + account_name: String, + online: Arc>, + is_subscribed: Arc, + server_conf: JmapServerConf, + connection: Arc, + store: Arc>, + tag_index: Arc>>, + folders: Arc>>, +} + +impl MailBackend for JmapType { + fn is_online(&self) -> bool { + *self.online.lock().unwrap() + } + fn get(&mut self, folder: &Folder) -> Async>> { + let mut w = AsyncBuilder::new(); + let folders = self.folders.clone(); + let store = self.store.clone(); + let tag_index = self.tag_index.clone(); + let connection = self.connection.clone(); + let folder_hash = folder.hash(); + let handle = { + let tx = w.tx(); + let closure = move |_work_context| { + tx.send(AsyncStatus::Payload(protocol::get( + &connection, + &store, + &tag_index, + &folders.read().unwrap()[&folder_hash], + ))) + .unwrap(); + tx.send(AsyncStatus::Finished).unwrap(); + }; + Box::new(closure) + }; + w.build(handle) + } + + fn watch( + &self, + _sender: RefreshEventConsumer, + _work_context: WorkContext, + ) -> Result { + Err(MeliError::from("sadfsa")) + } + + fn folders(&self) -> Result> { + if self.folders.read().unwrap().is_empty() { + let folders = std::dbg!(protocol::get_mailboxes(&self.connection))?; + let ret = Ok(folders + .iter() + .map(|(&h, f)| (h, BackendFolder::clone(f) as Folder)) + .collect()); + *self.folders.write().unwrap() = folders; + ret + } else { + Ok(self + .folders + .read() + .unwrap() + .iter() + .map(|(&h, f)| (h, BackendFolder::clone(f) as Folder)) + .collect()) + } + } + + fn operation(&self, hash: EnvelopeHash) -> Box { + Box::new(JmapOp::new( + hash, + self.connection.clone(), + self.store.clone(), + )) + } + + fn save(&self, _bytes: &[u8], _folder: &str, _flags: Option) -> Result<()> { + Ok(()) + } + + fn folder_operation(&mut self, _path: &str, _op: FolderOperation) -> Result<()> { + Ok(()) + } + + fn as_any(&self) -> &dyn::std::any::Any { + self + } + + fn tags(&self) -> Option>>> { + Some(self.tag_index.clone()) + } +} + +impl JmapType { + pub fn new( + s: &AccountSettings, + is_subscribed: Box bool + Send + Sync>, + ) -> Result> { + let online = Arc::new(Mutex::new(false)); + let server_conf = JmapServerConf::new(s)?; + + Ok(Box::new(JmapType { + connection: Arc::new(JmapConnection::new(&server_conf, online.clone())?), + store: Arc::new(RwLock::new(Store::default())), + tag_index: Arc::new(RwLock::new(Default::default())), + folders: Arc::new(RwLock::new(FnvHashMap::default())), + account_name: s.name.clone(), + online, + is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)), + server_conf, + })) + } + + pub fn validate_config(s: &AccountSettings) -> Result<()> { + get_conf_val!(s["server_hostname"])?; + get_conf_val!(s["server_username"])?; + get_conf_val!(s["server_password"])?; + get_conf_val!(s["server_port"], 443)?; + get_conf_val!(s["danger_accept_invalid_certs"], false)?; + Ok(()) + } +} diff --git a/melib/src/backends/jmap/connection.rs b/melib/src/backends/jmap/connection.rs new file mode 100644 index 00000000..321aeb26 --- /dev/null +++ b/melib/src/backends/jmap/connection.rs @@ -0,0 +1,91 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +#[derive(Debug)] +pub struct JmapConnection { + pub session: JmapSession, + pub request_no: Arc>, + pub client: Arc>, + pub online_status: Arc>, + pub server_conf: JmapServerConf, + pub account_id: Arc>, + pub method_call_states: Arc>>, +} + +impl JmapConnection { + pub fn new(server_conf: &JmapServerConf, online_status: Arc>) -> Result { + use reqwest::header; + let mut headers = header::HeaderMap::new(); + headers.insert( + header::ACCEPT, + header::HeaderValue::from_static("application/json"), + ); + headers.insert( + header::CONTENT_TYPE, + header::HeaderValue::from_static("application/json"), + ); + let client = reqwest::blocking::ClientBuilder::new() + .danger_accept_invalid_certs(server_conf.danger_accept_invalid_certs) + .default_headers(headers) + .build()?; + let req = client + .get(&server_conf.server_hostname) + .basic_auth( + &server_conf.server_username, + Some(&server_conf.server_password), + ) + .send()?; + let res_text = req.text()?; + debug!(&res_text); + + let session: JmapSession = serde_json::from_str(&res_text)?; + + if !session + .capabilities + .contains_key("urn:ietf:params:jmap:core") + { + return Err(MeliError::new(format!("Server {} did not return JMAP Core capability (urn:ietf:params:jmap:core). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::>().join(", ")))); + } + if !session + .capabilities + .contains_key("urn:ietf:params:jmap:mail") + { + return Err(MeliError::new(format!("Server {} does not support JMAP Mail capability (urn:ietf:params:jmap:mail). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::>().join(", ")))); + } + + let server_conf = server_conf.clone(); + Ok(JmapConnection { + session, + request_no: Arc::new(Mutex::new(0)), + client: Arc::new(Mutex::new(client)), + online_status, + server_conf, + account_id: Arc::new(Mutex::new(String::new())), + method_call_states: Arc::new(Mutex::new(Default::default())), + }) + } + + pub fn mail_account_id(&self) -> &Id { + &self.session.primary_accounts["urn:ietf:params:jmap:mail"] + } +} diff --git a/melib/src/backends/jmap/folder.rs b/melib/src/backends/jmap/folder.rs new file mode 100644 index 00000000..87e34c91 --- /dev/null +++ b/melib/src/backends/jmap/folder.rs @@ -0,0 +1,94 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; +use crate::backends::{FolderPermissions, SpecialUsageMailbox}; + +#[derive(Debug, Clone)] +pub struct JmapFolder { + pub name: String, + pub path: String, + pub hash: FolderHash, + pub v: Vec, + pub id: String, + pub is_subscribed: bool, + pub my_rights: JmapRights, + pub parent_id: Option, + pub role: Option, + pub sort_order: u64, + pub total_emails: u64, + pub total_threads: u64, + pub unread_emails: u64, + pub unread_threads: u64, + pub usage: SpecialUsageMailbox, +} + +impl BackendFolder for JmapFolder { + fn hash(&self) -> FolderHash { + self.hash + } + + fn name(&self) -> &str { + &self.name + } + + fn path(&self) -> &str { + &self.path + } + + fn change_name(&mut self, _s: &str) {} + + fn clone(&self) -> Folder { + Box::new(std::clone::Clone::clone(self)) + } + + fn children(&self) -> &[FolderHash] { + &self.v + } + + fn parent(&self) -> Option { + None + } + + fn permissions(&self) -> FolderPermissions { + FolderPermissions::default() + } + + fn special_usage(&self) -> SpecialUsageMailbox { + match self.role.as_ref().map(String::as_str) { + Some("inbox") => SpecialUsageMailbox::Inbox, + Some("archive") => SpecialUsageMailbox::Archive, + Some("junk") => SpecialUsageMailbox::Junk, + Some("trash") => SpecialUsageMailbox::Trash, + Some("drafts") => SpecialUsageMailbox::Drafts, + Some("sent") => SpecialUsageMailbox::Sent, + Some(other) => { + debug!( + "unknown JMAP mailbox role for folder {}: {}", + self.path(), + other + ); + SpecialUsageMailbox::Normal + } + None => SpecialUsageMailbox::Normal, + } + } +} diff --git a/melib/src/backends/jmap/objects.rs b/melib/src/backends/jmap/objects.rs new file mode 100644 index 00000000..b4ec2ea6 --- /dev/null +++ b/melib/src/backends/jmap/objects.rs @@ -0,0 +1,28 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +mod email; +pub use email::*; + +mod mailbox; +pub use mailbox::*; diff --git a/melib/src/backends/jmap/objects/email.rs b/melib/src/backends/jmap/objects/email.rs new file mode 100644 index 00000000..49a1ef60 --- /dev/null +++ b/melib/src/backends/jmap/objects/email.rs @@ -0,0 +1,566 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; +use crate::backends::jmap::rfc8620::bool_false; +use core::marker::PhantomData; +use serde::de::{Deserialize, Deserializer}; +use serde_json::Value; +use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; +use std::hash::Hasher; + +// 4.1.1. +// Metadata +// These properties represent metadata about the message in the mail +// store and are not derived from parsing the message itself. +// +// o id: "Id" (immutable; server-set) +// +// The id of the Email object. Note that this is the JMAP object id, +// NOT the Message-ID header field value of the message [RFC5322]. +// +// o blobId: "Id" (immutable; server-set) +// +// The id representing the raw octets of the message [RFC5322] for +// this Email. This may be used to download the raw original message +// or to attach it directly to another Email, etc. +// +// o threadId: "Id" (immutable; server-set) +// +// The id of the Thread to which this Email belongs. +// +// o mailboxIds: "Id[Boolean]" +// +// The set of Mailbox ids this Email belongs to. An Email in the +// mail store MUST belong to one or more Mailboxes at all times +// (until it is destroyed). The set is represented as an object, +// with each key being a Mailbox id. The value for each key in the +// object MUST be true. +// +// o keywords: "String[Boolean]" (default: {}) +// +// A set of keywords that apply to the Email. The set is represented +// as an object, with the keys being the keywords. The value for +// each key in the object MUST be true. +// +// Keywords are shared with IMAP. The six system keywords from IMAP +// get special treatment. The following four keywords have their +// first character changed from "\" in IMAP to "$" in JMAP and have +// particular semantic meaning: +// +// * "$draft": The Email is a draft the user is composing. +// +// * "$seen": The Email has been read. +// +// * "$flagged": The Email has been flagged for urgent/special +// attention. +// +// * "$answered": The Email has been replied to. +// +// The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP +// "\Deleted" keyword is also not present: IMAP uses a delete+expunge +// model, which JMAP does not. Any message with the "\Deleted" +// keyword MUST NOT be visible via JMAP (and so are not counted in +// the "totalEmails", "unreadEmails", "totalThreads", and +// "unreadThreads" Mailbox properties). +// +// Users may add arbitrary keywords to an Email. For compatibility +// with IMAP, a keyword is a case-insensitive string of 1-255 +// characters in the ASCII subset %x21-%x7e (excludes control chars +// and space), and it MUST NOT include any of these characters: +// +// ( ) { ] % * " \ +// +// Because JSON is case sensitive, servers MUST return keywords in +// lowercase. +// +// The IANA "IMAP and JMAP Keywords" registry at +// as +// established in [RFC5788] assigns semantic meaning to some other +// keywords in common use. New keywords may be established here in +// the future. In particular, note: +// +// * "$forwarded": The Email has been forwarded. +// +// * "$phishing": The Email is highly likely to be phishing. +// Clients SHOULD warn users to take care when viewing this Email +// and disable links and attachments. +// +// * "$junk": The Email is definitely spam. Clients SHOULD set this +// flag when users report spam to help train automated spam- +// detection systems. +// +// * "$notjunk": The Email is definitely not spam. Clients SHOULD +// set this flag when users indicate an Email is legitimate, to +// help train automated spam-detection systems. +// +// o size: "UnsignedInt" (immutable; server-set) +// +// The size, in octets, of the raw data for the message [RFC5322] (as +// referenced by the "blobId", i.e., the number of octets in the file +// the user would download). +// +// o receivedAt: "UTCDate" (immutable; default: time of creation on +// server) +// +// The date the Email was received by the message store. This is the +// "internal date" in IMAP [RFC3501]./ + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailObject { + #[serde(default)] + pub id: Id, + #[serde(default)] + pub blob_id: String, + #[serde(default)] + mailbox_ids: HashMap, + #[serde(default)] + size: u64, + #[serde(default)] + received_at: String, + #[serde(default)] + message_id: Vec, + #[serde(default)] + to: Vec, + #[serde(default)] + bcc: Option>, + #[serde(default)] + reply_to: Option>, + #[serde(default)] + cc: Option>, + #[serde(default)] + sender: Option>, + #[serde(default)] + from: Vec, + #[serde(default)] + in_reply_to: Option>, + #[serde(default)] + references: Option>, + #[serde(default)] + keywords: HashMap, + #[serde(default)] + attached_emails: Option, + #[serde(default)] + attachments: Vec, + #[serde(default)] + has_attachment: bool, + #[serde(default)] + #[serde(deserialize_with = "deserialize_header")] + headers: HashMap, + #[serde(default)] + html_body: Vec, + #[serde(default)] + preview: Option, + #[serde(default)] + sent_at: Option, + #[serde(default)] + subject: Option, + #[serde(default)] + text_body: Vec, + #[serde(default)] + thread_id: Id, + #[serde(flatten)] + extra: HashMap, +} + +impl EmailObject { + _impl!(get keywords, keywords: HashMap); +} + +#[derive(Deserialize, Serialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +struct Header { + name: String, + value: String, +} + +fn deserialize_header<'de, D>( + deserializer: D, +) -> std::result::Result, D::Error> +where + D: Deserializer<'de>, +{ + let v = >::deserialize(deserializer)?; + Ok(v.into_iter().map(|t| (t.name, t.value)).collect()) +} + +#[derive(Deserialize, Serialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +struct EmailAddress { + email: String, + name: Option, +} + +impl Into for EmailAddress { + fn into(self) -> crate::email::Address { + let Self { email, mut name } = self; + crate::make_address!((name.take().unwrap_or_default()), email) + } +} + +impl std::fmt::Display for EmailAddress { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.name.is_some() { + write!(f, "{} <{}>", self.name.as_ref().unwrap(), &self.email) + } else { + write!(f, "{}", &self.email) + } + } +} + +impl std::convert::From for crate::Envelope { + fn from(mut t: EmailObject) -> crate::Envelope { + let mut env = crate::Envelope::new(0); + if let Some(ref mut sent_at) = t.sent_at { + env.set_date(std::mem::replace(sent_at, String::new()).as_bytes()); + } + if let Ok(d) = crate::email::parser::date(env.date_as_str().as_bytes()) { + env.set_datetime(d); + } + + if let Some(v) = t.message_id.get(0) { + env.set_message_id(v.as_bytes()); + } + if let Some(ref in_reply_to) = t.in_reply_to { + env.set_in_reply_to(in_reply_to[0].as_bytes()); + env.push_references(in_reply_to[0].as_bytes()); + } + if let Some(v) = t.headers.get("References") { + let parse_result = crate::email::parser::references(v.as_bytes()); + if parse_result.is_done() { + for v in parse_result.to_full_result().unwrap() { + env.push_references(v); + } + } + env.set_references(v.as_bytes()); + } + if let Some(v) = t.headers.get("Date") { + env.set_date(v.as_bytes()); + if let Ok(d) = crate::email::parser::date(v.as_bytes()) { + env.set_datetime(d); + } + } + env.set_has_attachments(t.has_attachment); + if let Some(ref mut subject) = t.subject { + env.set_subject(std::mem::replace(subject, String::new()).into_bytes()); + } + + env.set_from( + std::mem::replace(&mut t.from, Vec::new()) + .into_iter() + .map(|addr| addr.into()) + .collect::>(), + ); + env.set_to( + std::mem::replace(&mut t.to, Vec::new()) + .into_iter() + .map(|addr| addr.into()) + .collect::>(), + ); + + if let Some(ref mut cc) = t.cc { + env.set_cc( + std::mem::replace(cc, Vec::new()) + .into_iter() + .map(|addr| addr.into()) + .collect::>(), + ); + } + + if let Some(ref mut bcc) = t.bcc { + env.set_bcc( + std::mem::replace(bcc, Vec::new()) + .into_iter() + .map(|addr| addr.into()) + .collect::>(), + ); + } + + if env.references.is_some() { + if let Some(pos) = env + .references + .as_ref() + .map(|r| &r.refs) + .unwrap() + .iter() + .position(|r| r == env.message_id()) + { + env.references.as_mut().unwrap().refs.remove(pos); + } + } + + let mut h = DefaultHasher::new(); + h.write(t.id.as_bytes()); + env.set_hash(h.finish()); + env + } +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +struct HtmlBody { + blob_id: Id, + #[serde(default)] + charset: String, + #[serde(default)] + cid: Option, + #[serde(default)] + disposition: Option, + #[serde(default)] + headers: Value, + #[serde(default)] + language: Option>, + #[serde(default)] + location: Option, + #[serde(default)] + name: Option, + #[serde(default)] + part_id: Option, + size: u64, + #[serde(alias = "type")] + content_type: String, + #[serde(default)] + sub_parts: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +struct TextBody { + blob_id: Id, + #[serde(default)] + charset: String, + #[serde(default)] + cid: Option, + #[serde(default)] + disposition: Option, + #[serde(default)] + headers: Value, + #[serde(default)] + language: Option>, + #[serde(default)] + location: Option, + #[serde(default)] + name: Option, + #[serde(default)] + part_id: Option, + size: u64, + #[serde(alias = "type")] + content_type: String, + #[serde(default)] + sub_parts: Vec, +} + +impl Object for EmailObject { + const NAME: &'static str = "Email"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailQueryResponse { + pub account_id: Id, + pub can_calculate_changes: bool, + pub collapse_threads: bool, + // FIXME + pub filter: String, + pub ids: Vec, + pub position: u64, + pub query_state: String, + pub sort: Option, + pub total: usize, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailQuery { + #[serde(flatten)] + pub query_call: Query, + //pub filter: EmailFilterCondition, /* "inMailboxes": [ folder.id ] },*/ + pub collapse_threads: bool, +} + +impl Method for EmailQuery { + const NAME: &'static str = "Email/query"; +} + +impl EmailQuery { + pub const RESULT_FIELD_IDS: ResultField = + ResultField:: { + field: "/ids", + _ph: PhantomData, + }; + + pub fn new(query_call: Query) -> Self { + EmailQuery { + query_call, + collapse_threads: false, + } + } + + _impl!(collapse_threads: bool); +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailGet { + #[serde(flatten)] + pub get_call: Get, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub body_properties: Vec, + #[serde(default = "bool_false")] + pub fetch_text_body_values: bool, + #[serde(default = "bool_false")] + #[serde(rename = "fetchHTMLBodyValues")] + pub fetch_html_body_values: bool, + #[serde(default = "bool_false")] + pub fetch_all_body_values: bool, + #[serde(default)] + #[serde(skip_serializing_if = "u64_zero")] + pub max_body_value_bytes: u64, +} + +impl Method for EmailGet { + const NAME: &'static str = "Email/get"; +} + +impl EmailGet { + pub fn new(get_call: Get) -> Self { + EmailGet { + get_call, + body_properties: Vec::new(), + fetch_text_body_values: false, + fetch_html_body_values: false, + fetch_all_body_values: false, + max_body_value_bytes: 0, + } + } + + _impl!(body_properties: Vec); + _impl!(fetch_text_body_values: bool); + _impl!(fetch_html_body_values: bool); + _impl!(fetch_all_body_values: bool); + _impl!(max_body_value_bytes: u64); +} + +#[derive(Serialize, Deserialize, Default, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EmailFilterCondition { + #[serde(skip_serializing_if = "Option::is_none")] + pub in_mailbox: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub in_mailbox_other_than: Vec, + #[serde(skip_serializing_if = "String::is_empty")] + pub before: UtcDate, + #[serde(skip_serializing_if = "String::is_empty")] + pub after: UtcDate, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub min_size: Option, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub max_size: Option, + #[serde(skip_serializing_if = "String::is_empty")] + pub all_in_thread_have_keyword: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub some_in_thread_have_keyword: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub none_in_thread_have_keyword: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub has_keyword: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub not_keyword: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub has_attachment: Option, + #[serde(skip_serializing_if = "String::is_empty")] + pub text: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub from: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub to: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub cc: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub bcc: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub subject: String, + #[serde(skip_serializing_if = "String::is_empty")] + pub body: String, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub header: Vec, +} + +impl EmailFilterCondition { + pub fn new() -> Self { + Self::default() + } + + _impl!(in_mailbox: Option); + _impl!(in_mailbox_other_than: Vec); + _impl!(before: UtcDate); + _impl!(after: UtcDate); + _impl!(min_size: Option); + _impl!(max_size: Option); + _impl!(all_in_thread_have_keyword: String); + _impl!(some_in_thread_have_keyword: String); + _impl!(none_in_thread_have_keyword: String); + _impl!(has_keyword: String); + _impl!(not_keyword: String); + _impl!(has_attachment: Option); + _impl!(text: String); + _impl!(from: String); + _impl!(to: String); + _impl!(cc: String); + _impl!(bcc: String); + _impl!(subject: String); + _impl!(body: String); + _impl!(header: Vec); +} + +impl FilterTrait for EmailFilterCondition {} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub enum MessageProperty { + ThreadId, + MailboxIds, + Keywords, + Size, + ReceivedAt, + IsUnread, + IsFlagged, + IsAnswered, + IsDraft, + HasAttachment, + From, + To, + Cc, + Bcc, + ReplyTo, + Subject, + SentAt, + Preview, + Id, + BlobId, + MessageId, + InReplyTo, + Sender, +} diff --git a/melib/src/backends/jmap/objects/mailbox.rs b/melib/src/backends/jmap/objects/mailbox.rs new file mode 100644 index 00000000..1c41e392 --- /dev/null +++ b/melib/src/backends/jmap/objects/mailbox.rs @@ -0,0 +1,71 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MailboxObject { + pub id: String, + pub is_subscribed: bool, + pub my_rights: JmapRights, + pub name: String, + pub parent_id: Option, + pub role: Option, + pub sort_order: u64, + pub total_emails: u64, + pub total_threads: u64, + pub unread_emails: u64, + pub unread_threads: u64, +} + +impl Object for MailboxObject { + const NAME: &'static str = "Mailbox"; +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct JmapRights { + pub may_add_items: bool, + pub may_create_child: bool, + pub may_delete: bool, + pub may_read_items: bool, + pub may_remove_items: bool, + pub may_rename: bool, + pub may_set_keywords: bool, + pub may_set_seen: bool, + pub may_submit: bool, +} +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MailboxGet { + #[serde(flatten)] + pub get_call: Get, +} +impl MailboxGet { + pub fn new(get_call: Get) -> Self { + MailboxGet { get_call } + } +} + +impl Method for MailboxGet { + const NAME: &'static str = "Mailbox/get"; +} diff --git a/melib/src/backends/jmap/operations.rs b/melib/src/backends/jmap/operations.rs new file mode 100644 index 00000000..8ec3712f --- /dev/null +++ b/melib/src/backends/jmap/operations.rs @@ -0,0 +1,111 @@ +/* + * meli - jmap module. + * + * Copyright 2017 - 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +use crate::backends::BackendOp; +use crate::error::Result; +use std::cell::Cell; +use std::sync::{Arc, RwLock}; + +/// `BackendOp` implementor for Imap +#[derive(Debug, Clone)] +pub struct JmapOp { + hash: EnvelopeHash, + connection: Arc, + store: Arc>, + bytes: Option, + flags: Cell>, + headers: Option, + body: Option, +} + +impl JmapOp { + pub fn new( + hash: EnvelopeHash, + connection: Arc, + store: Arc>, + ) -> Self { + JmapOp { + hash, + connection, + store, + bytes: None, + headers: None, + body: None, + flags: Cell::new(None), + } + } +} + +impl BackendOp for JmapOp { + fn description(&self) -> String { + self.store + .try_read() + .and_then(|store_lck| Ok(store_lck.id_store[&self.hash].clone())) + .unwrap_or(String::new()) + } + + fn as_bytes(&mut self) -> Result<&[u8]> { + if self.bytes.is_none() { + let mut store_lck = self.store.write().unwrap(); + if !(store_lck.byte_cache.contains_key(&self.hash) + && store_lck.byte_cache[&self.hash].bytes.is_some()) + { + let blob_id = &store_lck.blob_id_store[&self.hash]; + let res = self + .connection + .client + .lock() + .unwrap() + .get(&downloadRequestFormat( + &self.connection.session, + self.connection.mail_account_id(), + blob_id, + None, + )) + .basic_auth( + &self.connection.server_conf.server_username, + Some(&self.connection.server_conf.server_password), + ) + .send(); + + let res_text = res?.text()?; + + store_lck.byte_cache.entry(self.hash).or_default().bytes = Some(res_text); + } + self.bytes = store_lck.byte_cache[&self.hash].bytes.clone(); + } + Ok(&self.bytes.as_ref().unwrap().as_bytes()) + } + + fn fetch_flags(&self) -> Flag { + Flag::default() + } + + fn set_flag(&mut self, _envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> { + Ok(()) + } + + fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, value: bool) -> Result<()> { + Ok(()) + } +} diff --git a/melib/src/backends/jmap/protocol.rs b/melib/src/backends/jmap/protocol.rs new file mode 100644 index 00000000..4029e48c --- /dev/null +++ b/melib/src/backends/jmap/protocol.rs @@ -0,0 +1,370 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::folder::JmapFolder; +use super::*; +use crate::structs::StackVec; +use serde::Serialize; +use serde_json::{json, Value}; +use std::collections::hash_map::DefaultHasher; +use std::convert::TryFrom; +use std::hash::{Hash, Hasher}; + +pub type Id = String; +pub type UtcDate = String; + +use super::rfc8620::Object; + +macro_rules! get_request_no { + ($lock:expr) => {{ + let mut lck = $lock.lock().unwrap(); + let ret = *lck; + *lck += 1; + ret + }}; +} + +macro_rules! tag_hash { + ($t:ident) => {{ + let mut hasher = DefaultHasher::default(); + $t.hash(&mut hasher); + hasher.finish() + }}; + ($t:literal) => {{ + let mut hasher = DefaultHasher::default(); + $t.hash(&mut hasher); + hasher.finish() + }}; +} + +pub trait Response { + const NAME: &'static str; +} + +pub trait Method: Serialize { + const NAME: &'static str; +} + +macro_rules! get_path_hash { + ($path:expr) => {{ + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + let mut hasher = DefaultHasher::new(); + $path.hash(&mut hasher); + hasher.finish() + }}; +} + +static USING: &'static [&'static str] = &["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"]; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Request { + using: &'static [&'static str], + /* Why is this Value instead of Box>? The Method trait cannot be made into a + * Trait object because its serialize() will be generic. */ + method_calls: Vec, + + #[serde(skip)] + request_no: Arc>, +} + +impl Request { + pub fn new(request_no: Arc>) -> Self { + Request { + using: USING, + method_calls: Vec::new(), + request_no, + } + } + + pub fn add_call, O: Object>(&mut self, call: &M) -> usize { + let seq = get_request_no!(self.request_no); + self.method_calls + .push(serde_json::to_value((M::NAME, call, &format!("m{}", seq))).unwrap()); + seq + } +} + +pub fn get_mailboxes(conn: &JmapConnection) -> Result> { + let seq = get_request_no!(conn.request_no); + let res = conn + .client + .lock() + .unwrap() + .post(&conn.session.api_url) + .basic_auth( + &conn.server_conf.server_username, + Some(&conn.server_conf.server_password), + ) + .json(&json!({ + "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], + "methodCalls": [["Mailbox/get", { + "accountId": conn.mail_account_id() + }, + format!("#m{}",seq).as_str()]], + })) + .send(); + + let res_text = res?.text()?; + let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap(); + *conn.online_status.lock().unwrap() = true; + let m = GetResponse::::try_from(v.method_responses.remove(0))?; + let GetResponse:: { + list, account_id, .. + } = m; + *conn.account_id.lock().unwrap() = account_id; + Ok(list + .into_iter() + .map(|r| { + let MailboxObject { + id, + is_subscribed, + my_rights, + name, + parent_id, + role, + sort_order, + total_emails, + total_threads, + unread_emails, + unread_threads, + } = r; + let hash = get_path_hash!(&name); + ( + hash, + JmapFolder { + name: name.clone(), + hash, + path: name, + v: Vec::new(), + id, + is_subscribed, + my_rights, + parent_id, + role, + usage: Default::default(), + sort_order, + total_emails, + total_threads, + unread_emails, + unread_threads, + }, + ) + }) + .collect()) +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct JsonResponse<'a> { + #[serde(borrow)] + method_responses: Vec>, +} + +pub fn get_message_list(conn: &JmapConnection, folder: &JmapFolder) -> Result> { + let email_call: EmailQuery = EmailQuery::new( + Query::new() + .account_id(conn.mail_account_id().to_string()) + .filter(Some( + EmailFilterCondition::new().in_mailbox(Some(folder.id.clone())), + )) + .position(0), + ) + .collapse_threads(false); + + let mut req = Request::new(conn.request_no.clone()); + req.add_call(&email_call); + + let res = conn + .client + .lock() + .unwrap() + .post(&conn.session.api_url) + .basic_auth( + &conn.server_conf.server_username, + Some(&conn.server_conf.server_password), + ) + .json(&req) + .send(); + + let res_text = res?.text()?; + let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap(); + *conn.online_status.lock().unwrap() = true; + let m = QueryResponse::::try_from(v.method_responses.remove(0))?; + let QueryResponse:: { ids, .. } = m; + Ok(ids) +} + +pub fn get_message(conn: &JmapConnection, ids: &[String]) -> Result> { + let email_call: EmailGet = EmailGet::new( + Get::new() + .ids(Some(JmapArgument::value( + ids.iter().cloned().collect::>(), + ))) + .account_id(conn.mail_account_id().to_string()), + ); + + let mut req = Request::new(conn.request_no.clone()); + req.add_call(&email_call); + let res = conn + .client + .lock() + .unwrap() + .post(&conn.session.api_url) + .basic_auth( + &conn.server_conf.server_username, + Some(&conn.server_conf.server_password), + ) + .json(&req) + .send(); + + let res_text = res?.text()?; + let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap(); + let e = GetResponse::::try_from(v.method_responses.remove(0))?; + let GetResponse:: { list, .. } = e; + Ok(list + .into_iter() + .map(std::convert::Into::into) + .collect::>()) +} + +pub fn get( + conn: &JmapConnection, + store: &Arc>, + tag_index: &Arc>>, + folder: &JmapFolder, +) -> Result> { + let email_query_call: EmailQuery = EmailQuery::new( + Query::new() + .account_id(conn.mail_account_id().to_string()) + .filter(Some( + EmailFilterCondition::new().in_mailbox(Some(folder.id.clone())), + )) + .position(0), + ) + .collapse_threads(false); + + let mut req = Request::new(conn.request_no.clone()); + let prev_seq = req.add_call(&email_query_call); + + let email_call: EmailGet = EmailGet::new( + Get::new() + .ids(Some(JmapArgument::reference( + prev_seq, + EmailQuery::RESULT_FIELD_IDS, + ))) + .account_id(conn.mail_account_id().to_string()), + ); + + req.add_call(&email_call); + + let res = conn + .client + .lock() + .unwrap() + .post(&conn.session.api_url) + .basic_auth( + &conn.server_conf.server_username, + Some(&conn.server_conf.server_password), + ) + .json(&req) + .send(); + + let res_text = res?.text()?; + + let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap(); + let e = GetResponse::::try_from(v.method_responses.pop().unwrap())?; + let GetResponse:: { list, state, .. } = e; + { + let mut states_lck = conn.method_call_states.lock().unwrap(); + + if let Some(prev_state) = states_lck.get_mut(&EmailGet::NAME) { + debug!("{:?}: prev_state was {}", EmailGet::NAME, prev_state); + + if *prev_state != state { /* FIXME Query Changes. */ } + + *prev_state = state; + debug!("{:?}: curr state is {}", EmailGet::NAME, prev_state); + } else { + debug!("{:?}: inserting state {}", EmailGet::NAME, &state); + states_lck.insert(EmailGet::NAME, state); + } + } + let mut tag_lck = tag_index.write().unwrap(); + let ids = list + .iter() + .map(|obj| { + let tags = obj + .keywords() + .keys() + .map(|tag| { + let tag_hash = { + let mut hasher = DefaultHasher::default(); + tag.hash(&mut hasher); + hasher.finish() + }; + if !tag_lck.contains_key(&tag_hash) { + tag_lck.insert(tag_hash, tag.to_string()); + } + tag_hash + }) + .collect::>(); + (tags, obj.id.clone(), obj.blob_id.clone()) + }) + .collect::, Id, Id)>>(); + drop(tag_lck); + let mut ret = list + .into_iter() + .map(std::convert::Into::into) + .collect::>(); + + let mut store_lck = store.write().unwrap(); + debug_assert_eq!(tag_hash!("$draft"), 6613915297903591176); + debug_assert_eq!(tag_hash!("$seen"), 1683863812294339685); + debug_assert_eq!(tag_hash!("$flagged"), 2714010747478170100); + debug_assert_eq!(tag_hash!("$answered"), 8940855303929342213); + debug_assert_eq!(tag_hash!("$junk"), 2656839745430720464); + debug_assert_eq!(tag_hash!("$notjunk"), 4091323799684325059); + for (env, (tags, id, blob_id)) in ret.iter_mut().zip(ids.into_iter()) { + store_lck.id_store.insert(env.hash(), id); + store_lck.blob_id_store.insert(env.hash(), blob_id); + for t in tags { + match t { + 6613915297903591176 => { + env.set_flags(env.flags() | Flag::DRAFT); + } + 1683863812294339685 => { + env.set_flags(env.flags() | Flag::SEEN); + } + 2714010747478170100 => { + env.set_flags(env.flags() | Flag::FLAGGED); + } + 8940855303929342213 => { + env.set_flags(env.flags() | Flag::REPLIED); + } + 2656839745430720464 | 4091323799684325059 => { /* ignore */ } + _ => env.labels_mut().push(t), + } + } + } + Ok(ret) +} diff --git a/melib/src/backends/jmap/rfc8620.rs b/melib/src/backends/jmap/rfc8620.rs new file mode 100644 index 00000000..7f668418 --- /dev/null +++ b/melib/src/backends/jmap/rfc8620.rs @@ -0,0 +1,544 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::Id; +use crate::email::parser::BytesExt; +use core::marker::PhantomData; +use serde::de::DeserializeOwned; +use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde_json::{value::RawValue, Value}; + +mod filters; +pub use filters::*; +mod comparator; +pub use comparator::*; +mod argument; +pub use argument::*; + +use super::protocol::Method; +use std::collections::HashMap; +pub trait Object { + const NAME: &'static str; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct JmapSession { + pub capabilities: HashMap, + pub accounts: HashMap, + pub primary_accounts: HashMap, + pub username: String, + pub api_url: String, + pub download_url: String, + + pub upload_url: String, + pub event_source_url: String, + pub state: String, + #[serde(flatten)] + pub extra_properties: HashMap, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CapabilitiesObject { + #[serde(default)] + max_size_upload: u64, + #[serde(default)] + max_concurrent_upload: u64, + #[serde(default)] + max_size_request: u64, + #[serde(default)] + max_concurrent_requests: u64, + #[serde(default)] + max_calls_in_request: u64, + #[serde(default)] + max_objects_in_get: u64, + #[serde(default)] + max_objects_in_set: u64, + #[serde(default)] + collation_algorithms: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Account { + name: String, + is_personal: bool, + is_read_only: bool, + account_capabilities: HashMap, + #[serde(flatten)] + extra_properties: HashMap, +} + +/// #`get` +/// +/// Objects of type `Foo` are fetched via a call to `Foo/get`. +/// +/// It takes the following arguments: +/// +/// - `account_id`: "Id" +/// +/// The id of the account to use. +/// +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Get +where + OBJ: std::fmt::Debug + Serialize, +{ + #[serde(skip_serializing_if = "String::is_empty")] + pub account_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(flatten)] + pub ids: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub properties: Option>, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +impl Get +where + OBJ: std::fmt::Debug + Serialize, +{ + pub fn new() -> Self { + Self { + account_id: String::new(), + ids: None, + properties: None, + _ph: PhantomData, + } + } + _impl!( + /// - accountId: "Id" + /// + /// The id of the account to use. + /// + account_id: String + ); + _impl!( + /// - ids: `Option>>` + /// + /// The ids of the Foo objects to return. If `None`, then *all* records + /// of the data type are returned, if this is supported for that data + /// type and the number of records does not exceed the + /// "max_objects_in_get" limit. + /// + ids: Option>> + ); + _impl!( + /// - properties: Option> + /// + /// If supplied, only the properties listed in the array are returned + /// for each `Foo` object. If `None`, all properties of the object are + /// returned. The `id` property of the object is *always* returned, + /// even if not explicitly requested. If an invalid property is + /// requested, the call WILL be rejected with an "invalid_arguments" + /// error. + properties: Option> + ); +} + +impl Serialize for Get { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut fields_no = 0; + if !self.account_id.is_empty() { + fields_no += 1; + } + if !self.ids.is_none() { + fields_no += 1; + } + if !self.properties.is_none() { + fields_no += 1; + } + + let mut state = serializer.serialize_struct("Get", fields_no)?; + if !self.account_id.is_empty() { + state.serialize_field("accountId", &self.account_id)?; + } + match self.ids.as_ref() { + None => {} + Some(JmapArgument::Value(ref v)) => state.serialize_field("ids", v)?, + Some(JmapArgument::ResultReference { + ref result_of, + ref name, + ref path, + }) => { + #[derive(Serialize)] + #[serde(rename_all = "camelCase")] + struct A<'a> { + result_of: &'a str, + name: &'a str, + path: &'a str, + } + + state.serialize_field( + "#ids", + &A { + result_of, + name, + path, + }, + )?; + } + } + + if !self.properties.is_none() { + state.serialize_field("properties", self.properties.as_ref().unwrap())?; + } + + state.end() + } +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MethodResponse<'a> { + #[serde(borrow)] + pub method_responses: Vec<&'a RawValue>, + #[serde(default)] + pub created_ids: HashMap, + #[serde(default)] + pub session_state: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct GetResponse { + #[serde(skip_serializing_if = "String::is_empty")] + pub account_id: String, + #[serde(default)] + pub state: String, + pub list: Vec, + pub not_found: Vec, +} + +impl std::convert::TryFrom<&RawValue> for GetResponse { + type Error = crate::error::MeliError; + fn try_from(t: &RawValue) -> Result, crate::error::MeliError> { + let res: (String, GetResponse, String) = serde_json::from_str(t.get())?; + assert_eq!(&res.0, &format!("{}/get", OBJ::NAME)); + Ok(res.1) + } +} + +impl GetResponse { + _impl!(get_mut account_id_mut, account_id: String); + _impl!(get_mut state_mut, state: String); + _impl!(get_mut list_mut, list: Vec); + _impl!(get_mut not_found_mut, not_found: Vec); +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +enum JmapError { + RequestTooLarge, + InvalidArguments, + InvalidResultReference, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Query, OBJ: Object> +where + OBJ: std::fmt::Debug + Serialize, +{ + account_id: String, + filter: Option, + sort: Option>, + #[serde(default)] + position: u64, + #[serde(skip_serializing_if = "Option::is_none")] + anchor: Option, + #[serde(default)] + #[serde(skip_serializing_if = "u64_zero")] + anchor_offset: u64, + #[serde(skip_serializing_if = "Option::is_none")] + limit: Option, + #[serde(default = "bool_false")] + calculate_total: bool, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +impl, OBJ: Object> Query +where + OBJ: std::fmt::Debug + Serialize, +{ + pub fn new() -> Self { + Self { + account_id: String::new(), + filter: None, + sort: None, + position: 0, + anchor: None, + anchor_offset: 0, + limit: None, + calculate_total: false, + _ph: PhantomData, + } + } + + _impl!(account_id: String); + _impl!(filter: Option); + _impl!(sort: Option>); + _impl!(position: u64); + _impl!(anchor: Option); + _impl!(anchor_offset: u64); + _impl!(limit: Option); + _impl!(calculate_total: bool); +} + +pub fn u64_zero(num: &u64) -> bool { + *num == 0 +} + +pub fn bool_false() -> bool { + false +} + +pub fn bool_true() -> bool { + true +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct QueryResponse { + #[serde(skip_serializing_if = "String::is_empty", default)] + pub account_id: String, + pub query_state: String, + pub can_calculate_changes: bool, + pub position: u64, + pub ids: Vec, + #[serde(default)] + pub total: u64, + #[serde(default)] + pub limit: u64, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +impl std::convert::TryFrom<&RawValue> for QueryResponse { + type Error = crate::error::MeliError; + fn try_from(t: &RawValue) -> Result, crate::error::MeliError> { + let res: (String, QueryResponse, String) = serde_json::from_str(t.get())?; + assert_eq!(&res.0, &format!("{}/query", OBJ::NAME)); + Ok(res.1) + } +} + +impl QueryResponse { + _impl!(get_mut ids_mut, ids: Vec); +} + +pub struct ResultField, OBJ: Object> { + pub field: &'static str, + pub _ph: PhantomData<*const (OBJ, M)>, +} + +// error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable +// --> melib/src/backends/jmap/rfc8620.rs:626:6 +// | +// 626 | impl, OBJ: Object> ResultField { +// | ^ +// | +// = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 +// = help: add `#![feature(const_fn)]` to the crate attributes to enable +// impl, OBJ: Object> ResultField { +// pub const fn new(field: &'static str) -> Self { +// Self { +// field, +// _ph: PhantomData, +// } +// } +// } + +/// #`changes` +/// +/// The "Foo/changes" method allows a client to efficiently update the state of its Foo cache +/// to match the new state on the server. It takes the following arguments: +/// +/// - accountId: "Id" The id of the account to use. +/// - sinceState: "String" +/// The current state of the client. This is the string that was +/// returned as the "state" argument in the "Foo/get" response. The +/// server will return the changes that have occurred since this +/// state. +/// +/// - maxChanges: "UnsignedInt|null" +/// The maximum number of ids to return in the response. The server +/// MAY choose to return fewer than this value but MUST NOT return +/// more. If not given by the client, the server may choose how many +/// to return. If supplied by the client, the value MUST be a +/// positive integer greater than 0. If a value outside of this range +/// is given, the server MUST re +/// +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +/* ch-ch-ch-ch-ch-Changes */ +pub struct Changes +where + OBJ: std::fmt::Debug + Serialize, +{ + #[serde(skip_serializing_if = "String::is_empty")] + pub account_id: String, + pub since_state: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_changes: Option, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +impl Changes +where + OBJ: std::fmt::Debug + Serialize, +{ + pub fn new() -> Self { + Self { + account_id: String::new(), + since_state: String::new(), + max_changes: None, + _ph: PhantomData, + } + } + _impl!( + /// - accountId: "Id" + /// + /// The id of the account to use. + /// + account_id: String + ); + _impl!( + /// - since_state: "String" + /// The current state of the client. This is the string that was + /// returned as the "state" argument in the "Foo/get" response. The + /// server will return the changes that have occurred since this + /// state. + /// + /// + since_state: String + ); + _impl!( + /// - max_changes: "UnsignedInt|null" + /// The maximum number of ids to return in the response. The server + /// MAY choose to return fewer than this value but MUST NOT return + /// more. If not given by the client, the server may choose how many + /// to return. If supplied by the client, the value MUST be a + /// positive integer greater than 0. If a value outside of this range + /// is given, the server MUST re + max_changes: Option + ); +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ChangesResponse { + #[serde(skip_serializing_if = "String::is_empty")] + pub account_id: String, + pub old_state: String, + pub new_state: String, + pub has_more_changes: bool, + pub created: Vec, + pub updated: Vec, + pub destroyed: Vec, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +impl std::convert::TryFrom<&RawValue> for ChangesResponse { + type Error = crate::error::MeliError; + fn try_from(t: &RawValue) -> Result, crate::error::MeliError> { + let res: (String, ChangesResponse, String) = serde_json::from_str(t.get())?; + assert_eq!(&res.0, &format!("{}/changes", OBJ::NAME)); + Ok(res.1) + } +} + +impl ChangesResponse { + _impl!(get_mut account_id_mut, account_id: String); + _impl!(get_mut old_state_mut, old_state: String); + _impl!(get_mut new_state_mut, new_state: String); + _impl!(get has_more_changes, has_more_changes: bool); + _impl!(get_mut created_mut, created: Vec); + _impl!(get_mut updated_mut, updated: Vec); + _impl!(get_mut destroyed_mut, destroyed: Vec); +} + +pub fn downloadRequestFormat( + session: &JmapSession, + account_id: &Id, + blob_id: &Id, + name: Option, +) -> String { + // https://jmap.fastmail.com/download/{accountId}/{blobId}/{name} + let mut ret = String::with_capacity( + session.download_url.len() + + blob_id.len() + + name.as_ref().map(|n| n.len()).unwrap_or(0) + + account_id.len(), + ); + let mut prev_pos = 0; + + while let Some(pos) = session.download_url.as_bytes()[prev_pos..].find(b"{") { + ret.push_str(&session.download_url[prev_pos..prev_pos + pos]); + prev_pos += pos; + if session.download_url[prev_pos..].starts_with("{accountId}") { + ret.push_str(account_id); + prev_pos += "{accountId}".len(); + } else if session.download_url[prev_pos..].starts_with("{blobId}") { + ret.push_str(blob_id); + prev_pos += "{blobId}".len(); + } else if session.download_url[prev_pos..].starts_with("{name}") { + ret.push_str(name.as_ref().map(String::as_str).unwrap_or("")); + prev_pos += "{name}".len(); + } + } + if prev_pos != session.download_url.len() { + ret.push_str(&session.download_url[prev_pos..]); + } + ret +} + +pub fn uploadRequestFormat(session: &JmapSession, account_id: &Id) -> String { + //"uploadUrl": "https://jmap.fastmail.com/upload/{accountId}/", + let mut ret = String::with_capacity(session.upload_url.len() + account_id.len()); + let mut prev_pos = 0; + + while let Some(pos) = session.upload_url.as_bytes()[prev_pos..].find(b"{") { + ret.push_str(&session.upload_url[prev_pos..prev_pos + pos]); + prev_pos += pos; + if session.upload_url[prev_pos..].starts_with("{accountId}") { + ret.push_str(account_id); + prev_pos += "{accountId}".len(); + break; + } else { + ret.push('{'); + prev_pos += 1; + } + } + if prev_pos != session.upload_url.len() { + ret.push_str(&session.upload_url[prev_pos..]); + } + ret +} diff --git a/melib/src/backends/jmap/rfc8620/argument.rs b/melib/src/backends/jmap/rfc8620/argument.rs new file mode 100644 index 00000000..1410d0b8 --- /dev/null +++ b/melib/src/backends/jmap/rfc8620/argument.rs @@ -0,0 +1,53 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use crate::backends::jmap::protocol::Method; +use crate::backends::jmap::rfc8620::Object; +use crate::backends::jmap::rfc8620::ResultField; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub enum JmapArgument { + Value(T), + ResultReference { + result_of: String, + name: String, + path: String, + }, +} + +impl JmapArgument { + pub fn value(v: T) -> Self { + JmapArgument::Value(v) + } + + pub fn reference(result_of: usize, path: ResultField) -> Self + where + M: Method, + OBJ: Object, + { + JmapArgument::ResultReference { + result_of: format!("m{}", result_of), + name: M::NAME.to_string(), + path: path.field.to_string(), + } + } +} diff --git a/melib/src/backends/jmap/rfc8620/comparator.rs b/melib/src/backends/jmap/rfc8620/comparator.rs new file mode 100644 index 00000000..e1bad283 --- /dev/null +++ b/melib/src/backends/jmap/rfc8620/comparator.rs @@ -0,0 +1,61 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Comparator { + property: String, + #[serde(default = "bool_true")] + is_ascending: bool, + //FIXME + collation: Option, + //#[serde(flatten)] + additional_properties: Vec, + + _ph: PhantomData<*const OBJ>, +} + +impl Comparator { + pub fn new() -> Self { + Self { + property: String::new(), + is_ascending: true, + collation: None, + additional_properties: Vec::new(), + _ph: PhantomData, + } + } + + _impl!(property: String); + _impl!(is_ascending: bool); + _impl!(collation: Option); + _impl!(additional_properties: Vec); +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "UPPERCASE")] +pub enum FilterOperator { + And, + Or, + Not, +} diff --git a/melib/src/backends/jmap/rfc8620/filters.rs b/melib/src/backends/jmap/rfc8620/filters.rs new file mode 100644 index 00000000..61697d0d --- /dev/null +++ b/melib/src/backends/jmap/rfc8620/filters.rs @@ -0,0 +1,50 @@ +/* + * meli - jmap module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::*; + +pub trait FilterTrait {} +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum Filter, OBJ: Object> { + Operator { + operator: FilterOperator, + conditions: Vec>, + }, + Condition(FilterCondition), +} + +#[derive(Serialize, Debug)] +pub struct FilterCondition, OBJ: Object> { + #[serde(flatten)] + cond: F, + #[serde(skip)] + _ph: PhantomData<*const OBJ>, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "UPPERCASE")] +pub enum FilterOperator { + And, + Or, + Not, +} diff --git a/melib/src/email.rs b/melib/src/email.rs index 0dff6cb7..48f7c76b 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -125,7 +125,7 @@ pub struct Envelope { subject: Option, message_id: MessageID, in_reply_to: Option, - references: Option, + pub references: Option, other_headers: FnvHashMap, timestamp: UnixTimestamp, @@ -490,14 +490,14 @@ impl Envelope { self.subject = Some(new_val); } pub fn set_message_id(&mut self, new_val: &[u8]) { - let slice = match parser::message_id(new_val).to_full_result() { - Ok(v) => v, - Err(e) => { - debug!(e); - return; + match parser::message_id(new_val).to_full_result() { + Ok(slice) => { + self.message_id = MessageID::new(new_val, slice); } - }; - self.message_id = MessageID::new(new_val, slice); + Err(_) => { + self.message_id = MessageID::new(new_val, new_val); + } + } } pub fn push_references(&mut self, new_val: &[u8]) { let slice = match parser::message_id(new_val).to_full_result() { @@ -557,6 +557,7 @@ impl Envelope { None => Vec::new(), } } + pub fn other_headers(&self) -> &FnvHashMap { &self.other_headers } diff --git a/melib/src/email/address.rs b/melib/src/email/address.rs index 85231418..400738a2 100644 --- a/melib/src/email/address.rs +++ b/melib/src/email/address.rs @@ -257,3 +257,34 @@ impl fmt::Debug for References { write!(f, "{:#?}", self.refs) } } + +#[macro_export] +macro_rules! make_address { + ($d:expr, $a:expr) => { + Address::Mailbox(if $d.is_empty() { + MailboxAddress { + raw: format!("{}", $a).into_bytes(), + display_name: StrBuilder { + offset: 0, + length: 0, + }, + address_spec: StrBuilder { + offset: 0, + length: $a.len(), + }, + } + } else { + MailboxAddress { + raw: format!("{} <{}>", $d, $a).into_bytes(), + display_name: StrBuilder { + offset: 0, + length: $d.len(), + }, + address_spec: StrBuilder { + offset: $d.len() + 2, + length: $a.len(), + }, + } + }) + }; +} diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 4176dce9..cad0dd32 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -1102,36 +1102,6 @@ mod tests { ); } - macro_rules! make_address { - ($d:literal, $a:literal) => { - Address::Mailbox(if $d.is_empty() { - MailboxAddress { - raw: format!("<{}>", $a).into_bytes(), - display_name: StrBuilder { - offset: 0, - length: 0, - }, - address_spec: StrBuilder { - offset: 1, - length: $a.len(), - }, - } - } else { - MailboxAddress { - raw: format!("{} <{}>", $d, $a).into_bytes(), - display_name: StrBuilder { - offset: 0, - length: $d.len(), - }, - address_spec: StrBuilder { - offset: $d.len() + 2, - length: $a.len(), - }, - } - }) - }; - } - #[test] fn test_address_list() { let s = b"Obit Oppidum , diff --git a/melib/src/error.rs b/melib/src/error.rs index 25182a65..47fd2203 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -151,6 +151,22 @@ impl From for MeliError { } } +#[cfg(feature = "jmap_backend")] +impl From for MeliError { + #[inline] + fn from(kind: reqwest::Error) -> MeliError { + MeliError::new(format!("{}", kind)) + } +} + +#[cfg(feature = "jmap_backend")] +impl From for MeliError { + #[inline] + fn from(kind: serde_json::error::Error) -> MeliError { + MeliError::new(format!("{}", kind)) + } +} + impl From<&str> for MeliError { #[inline] fn from(kind: &str) -> MeliError { diff --git a/ui/src/conf.rs b/ui/src/conf.rs index 65af869c..aa255da3 100644 --- a/ui/src/conf.rs +++ b/ui/src/conf.rs @@ -182,7 +182,8 @@ impl From for AccountConf { .split(if s.contains('/') { '/' } else { '.' }) .last() .unwrap_or(""); - folder_confs.get_mut(s).unwrap().folder_conf.usage = usage(name); + folder_confs.get_mut(s).unwrap().folder_conf.usage = + SpecialUsageMailbox::detect_usage(name); } if folder_confs[s].folder_conf().ignore.is_unset() { @@ -564,26 +565,6 @@ impl Serialize for CacheType { } } -pub fn usage(name: &str) -> Option { - if name.eq_ignore_ascii_case("inbox") { - Some(SpecialUsageMailbox::Inbox) - } else if name.eq_ignore_ascii_case("archive") { - Some(SpecialUsageMailbox::Archive) - } else if name.eq_ignore_ascii_case("drafts") { - Some(SpecialUsageMailbox::Drafts) - } else if name.eq_ignore_ascii_case("junk") { - Some(SpecialUsageMailbox::Junk) - } else if name.eq_ignore_ascii_case("spam") { - Some(SpecialUsageMailbox::Junk) - } else if name.eq_ignore_ascii_case("sent") { - Some(SpecialUsageMailbox::Sent) - } else if name.eq_ignore_ascii_case("trash") { - Some(SpecialUsageMailbox::Trash) - } else { - Some(SpecialUsageMailbox::Normal) - } -} - pub fn create_config_file(p: &Path) -> Result<()> { let mut file = OpenOptions::new() .write(true) diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index f20166cb..bbe6cdef 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -353,7 +353,7 @@ impl Account { } else { let mut new = FileFolderConf::default(); new.folder_conf.subscribe = super::ToggleFlag::InternalVal(true); - new.folder_conf.usage = super::usage(f.name()); + new.folder_conf.usage = SpecialUsageMailbox::detect_usage(f.name()); folder_confs.insert(f.hash(), new); } folder_names.insert(f.hash(), f.path().to_string());