add the daemon back
This commit is contained in:
parent
e4bc3e4b98
commit
f32dd58aac
10 changed files with 422 additions and 81 deletions
317
Cargo.lock
generated
317
Cargo.lock
generated
|
@ -114,6 +114,38 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "3.0.0-beta.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"os_str_bytes",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "3.0.0-beta.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
|
@ -308,6 +340,40 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"indexmap",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
@ -317,12 +383,101 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b031475cb1b103ee221afb806a23d35e0570bf7271d7588762ceba8127ed43b3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"futures-core",
|
||||||
|
"inotify-sys",
|
||||||
|
"libc",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify-sys"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -332,6 +487,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.52"
|
version = "0.3.52"
|
||||||
|
@ -469,9 +630,35 @@ version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panorama-daemon"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"clap",
|
||||||
|
"futures",
|
||||||
|
"hyper",
|
||||||
|
"inotify",
|
||||||
|
"log",
|
||||||
|
"panorama-imap",
|
||||||
|
"serde",
|
||||||
|
"stderrlog",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"toml",
|
||||||
|
"xdg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "panorama-imap"
|
name = "panorama-imap"
|
||||||
version = "0.0.3"
|
version = "0.0.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -528,6 +715,30 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.19"
|
version = "0.5.19"
|
||||||
|
@ -629,6 +840,26 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -707,6 +938,15 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -783,6 +1023,59 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-service"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -795,12 +1088,28 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.0+wasi-snapshot-preview1"
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
@ -926,3 +1235,9 @@ name = "wyz"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
# "daemon",
|
"daemon",
|
||||||
"imap",
|
"imap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ async-trait = "0.1.50"
|
||||||
clap = "3.0.0-beta.2"
|
clap = "3.0.0-beta.2"
|
||||||
futures = "0.3.16"
|
futures = "0.3.16"
|
||||||
hyper = { version = "0.14.11", features = ["server", "http2", "stream"] }
|
hyper = { version = "0.14.11", features = ["server", "http2", "stream"] }
|
||||||
imap = { path = "../imap" }
|
|
||||||
inotify = { version = "0.9.3", features = ["stream"] }
|
inotify = { version = "0.9.3", features = ["stream"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
panorama-imap = { path = "../imap" }
|
||||||
serde = { version = "1.0.126", features = ["derive"] }
|
serde = { version = "1.0.126", features = ["derive"] }
|
||||||
stderrlog = "0.5.1"
|
stderrlog = "0.5.1"
|
||||||
tokio = { version = "1.9.0", features = ["full"] }
|
tokio = { version = "1.9.0", features = ["full"] }
|
||||||
|
|
|
@ -11,8 +11,9 @@ use super::Config;
|
||||||
|
|
||||||
pub type ConfigWatcher = watch::Receiver<Config>;
|
pub type ConfigWatcher = watch::Receiver<Config>;
|
||||||
|
|
||||||
/// Start the entire config watcher system, and return a [ConfigWatcher][self::ConfigWatcher],
|
/// Start the entire config watcher system, and return a
|
||||||
/// which is a cloneable receiver of config update events.
|
/// [ConfigWatcher][self::ConfigWatcher], which is a cloneable receiver of
|
||||||
|
/// config update events.
|
||||||
pub fn spawn_config_watcher_system() -> Result<(JoinHandle<()>, ConfigWatcher)> {
|
pub fn spawn_config_watcher_system() -> Result<(JoinHandle<()>, ConfigWatcher)> {
|
||||||
let mut inotify = Inotify::init()?;
|
let mut inotify = Inotify::init()?;
|
||||||
let xdg = BaseDirectories::new()?;
|
let xdg = BaseDirectories::new()?;
|
||||||
|
|
|
@ -1,101 +1,126 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
mod store;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use futures::stream::{ StreamExt, };
|
||||||
|
use panorama_imap::{
|
||||||
|
client::{auth::Login, ConfigBuilder},
|
||||||
|
proto::{
|
||||||
|
command::FetchItems,
|
||||||
|
response::{MailboxData, Response},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use crate::config::{ImapAuth, MailAccountConfig, TlsMethod};
|
||||||
|
|
||||||
|
use self::store::MailStore;
|
||||||
|
|
||||||
|
pub enum MailEvent {}
|
||||||
|
|
||||||
/// The main function for the IMAP syncing thread
|
/// The main function for the IMAP syncing thread
|
||||||
pub async fn sync_main(
|
pub async fn sync_main(
|
||||||
acct_name: impl AsRef<str>,
|
acct_name: impl AsRef<str>,
|
||||||
acct: MailAccountConfig,
|
acct: MailAccountConfig,
|
||||||
mail2ui_tx: UnboundedSender<MailEvent>,
|
_mail2ui_tx: UnboundedSender<MailEvent>,
|
||||||
mail_store: MailStore,
|
_mail_store: MailStore,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let acct_name = acct_name.as_ref().to_owned();
|
let _acct_name = acct_name.as_ref().to_owned();
|
||||||
// loop ensures that the connection is retried after it dies
|
// loop ensures that the connection is retried after it dies
|
||||||
loop {
|
loop {
|
||||||
let builder: ClientConfig = ClientBuilder::default()
|
let client = ConfigBuilder::default()
|
||||||
.hostname(acct.imap.server.clone())
|
.hostname(acct.imap.server.clone())
|
||||||
.port(acct.imap.port)
|
.port(acct.imap.port)
|
||||||
.tls(matches!(acct.imap.tls, TlsMethod::On))
|
.tls(matches!(acct.imap.tls, TlsMethod::On))
|
||||||
.build()
|
.open()
|
||||||
|
.await
|
||||||
.map_err(|err| anyhow!("err: {}", err))?;
|
.map_err(|err| anyhow!("err: {}", err))?;
|
||||||
debug!("connecting to {}:{}", &acct.imap.server, acct.imap.port);
|
|
||||||
let unauth = builder.open().await?;
|
debug!("connected to {}:{}", &acct.imap.server, acct.imap.port);
|
||||||
let unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
|
let unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
|
||||||
debug!("attempting to upgrade");
|
debug!("attempting to upgrade");
|
||||||
let client = unauth.upgrade().await?;
|
let client = client.upgrade().await?;
|
||||||
debug!("upgrade successful");
|
debug!("upgrade successful");
|
||||||
client
|
client
|
||||||
} else {
|
} else {
|
||||||
unauth
|
client
|
||||||
};
|
};
|
||||||
debug!("preparing to auth");
|
debug!("preparing to auth");
|
||||||
// check if the authentication method is supported
|
// check if the authentication method is supported
|
||||||
let mut authed = match &acct.imap.auth {
|
let mut authed = match &acct.imap.auth {
|
||||||
ImapAuth::Plain { username, password } => {
|
ImapAuth::Plain { username, password } => {
|
||||||
let auth = auth::Plain {
|
let login = Login {
|
||||||
username: username.clone(),
|
username: username.clone(),
|
||||||
password: password.clone(),
|
password: password.clone(),
|
||||||
};
|
};
|
||||||
auth.perform_auth(unauth).await?
|
unauth.auth(login).await?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("authentication successful!");
|
debug!("authentication successful!");
|
||||||
let folder_list = authed.list().await?;
|
let folder_list = authed.list().await?;
|
||||||
let _ = mail2ui_tx.send(MailEvent::FolderList(
|
// let _ = mail2ui_tx.send(MailEvent::FolderList(
|
||||||
acct_name.clone(),
|
// acct_name.clone(),
|
||||||
folder_list.clone(),
|
// folder_list.clone(),
|
||||||
));
|
// ));
|
||||||
debug!("mailbox list: {:?}", folder_list);
|
debug!("mailbox list: {:?}", folder_list);
|
||||||
for folder in folder_list.iter() {
|
for folder in folder_list.iter() {
|
||||||
debug!("folder: {}", folder);
|
debug!("folder: {:?}", folder);
|
||||||
let select = authed.select(folder).await?;
|
let select = authed.select("INBOX").await?;
|
||||||
debug!("select response: {:?}", select);
|
debug!("select response: {:?}", select);
|
||||||
if let (Some(exists), Some(uidvalidity)) = (select.exists, select.uid_validity) {
|
if let (Some(_exists), Some(_uidvalidity)) = (select.exists, select.uid_validity) {
|
||||||
// figure out which uids don't exist locally yet
|
// figure out which uids don't exist locally yet
|
||||||
let new_uids = stream::iter(1..exists).map(Ok).try_filter_map(|uid| {
|
let new_uids = vec![];
|
||||||
mail_store.try_identify_email(&acct_name, &folder, uid, uidvalidity, None)
|
// let new_uids = stream::iter(1..exists).map(Ok).try_filter_map(|uid| {
|
||||||
// invert the option to only select uids that haven't been downloaded
|
// todo!()
|
||||||
.map_ok(move |o| o.map_or_else(move || Some(uid), |v| None))
|
// // mail_store.try_identify_email(&acct_name, &folder, uid, uidvalidity, None)
|
||||||
.map_err(|err| err.context("error checking if the email is already downloaded [try_identify_email]"))
|
// // // invert the option to only select uids that haven't been downloaded
|
||||||
}).try_collect::<Vec<_>>().await?;
|
// // .map_ok(move |o| o.map_or_else(move || Some(uid), |v| None))
|
||||||
|
// // .map_err(|err| err.context("error checking if the email is already downloaded [try_identify_email]"))
|
||||||
|
// }).try_collect::<Vec<_>>().await?;
|
||||||
if !new_uids.is_empty() {
|
if !new_uids.is_empty() {
|
||||||
debug!("fetching uids {:?}", new_uids);
|
debug!("fetching uids {:?}", new_uids);
|
||||||
let fetched = authed
|
let _fetched = authed
|
||||||
.uid_fetch(&new_uids, FetchItems::PanoramaAll)
|
.uid_fetch(&new_uids, FetchItems::PanoramaAll)
|
||||||
.await
|
.await
|
||||||
.context("error fetching uids")?;
|
.context("error fetching uids")?;
|
||||||
fetched
|
// fetched
|
||||||
.map(Ok)
|
// .map(Ok)
|
||||||
.try_for_each_concurrent(None, |(uid, attrs)| {
|
// .try_for_each_concurrent(None, |(uid, attrs)| {
|
||||||
mail_store.store_email(&acct_name, &folder, uid, uidvalidity, attrs)
|
// mail_store.store_email(&acct_name, &folder, uid, uidvalidity, attrs)
|
||||||
})
|
// })
|
||||||
.await
|
// .await
|
||||||
.context("error during fetch-store")?;
|
// .context("error during fetch-store")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(50)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(50)).await;
|
||||||
// TODO: remove this later
|
// TODO: remove this later
|
||||||
continue;
|
// continue;
|
||||||
// let's just select INBOX for now, maybe have a config for default mailbox later?
|
// let's just select INBOX for now, maybe have a config for default mailbox
|
||||||
|
// later?
|
||||||
debug!("selecting the INBOX mailbox");
|
debug!("selecting the INBOX mailbox");
|
||||||
let select = authed.select("INBOX").await?;
|
let select = authed.select("INBOX").await?;
|
||||||
debug!("select result: {:?}", select);
|
debug!("select result: {:?}", select);
|
||||||
loop {
|
loop {
|
||||||
let message_uids = authed.uid_search().await?;
|
let message_uids = authed.uid_search().await?;
|
||||||
let message_uids = message_uids.into_iter().take(30).collect::<Vec<_>>();
|
let message_uids = message_uids.into_iter().take(30).collect::<Vec<_>>();
|
||||||
let _ = mail2ui_tx.send(MailEvent::MessageUids(
|
// let _ = mail2ui_tx.send(MailEvent::MessageUids(
|
||||||
acct_name.clone(),
|
// acct_name.clone(),
|
||||||
message_uids.clone(),
|
// message_uids.clone(),
|
||||||
));
|
// ));
|
||||||
// TODO: make this happen concurrently with the main loop?
|
// TODO: make this happen concurrently with the main loop?
|
||||||
let mut message_list = authed
|
let mut message_list = authed
|
||||||
.uid_fetch(&message_uids, FetchItems::All)
|
.uid_fetch(&message_uids, FetchItems::All)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
while let Some((uid, attrs)) = message_list.next().await {
|
while let Some((_uid, _attrs)) = message_list.next().await {
|
||||||
let evt = MailEvent::UpdateUid(acct_name.clone(), uid, attrs);
|
// let evt = MailEvent::UpdateUid(acct_name.clone(), uid,
|
||||||
// TODO: probably odn't care about this?
|
// attrs); TODO: probably odn't care about this?
|
||||||
let _ = mail2ui_tx.send(evt);
|
// let _ = mail2ui_tx.send(evt);
|
||||||
}
|
}
|
||||||
// check if IDLE is supported
|
// check if IDLE is supported
|
||||||
let supports_idle = authed.has_capability("IDLE").await?;
|
let supports_idle = true; // authed.has_capability("IDLE").await?;
|
||||||
if supports_idle {
|
if supports_idle {
|
||||||
let mut idle_stream = authed.idle().await?;
|
let mut idle_stream = authed.idle().await?;
|
||||||
loop {
|
loop {
|
||||||
|
@ -109,29 +134,31 @@ pub async fn sync_main(
|
||||||
debug!("NEW MESSAGE WITH UID {:?}, droping everything", uid);
|
debug!("NEW MESSAGE WITH UID {:?}, droping everything", uid);
|
||||||
// send DONE to stop the idle
|
// send DONE to stop the idle
|
||||||
std::mem::drop(idle_stream);
|
std::mem::drop(idle_stream);
|
||||||
let handle = Notification::new()
|
// let handle = Notification::new()
|
||||||
.summary("New Email")
|
// .summary("New Email")
|
||||||
.body("holy Shit,")
|
// .body("TODO")
|
||||||
.icon("firefox")
|
// .icon("firefox")
|
||||||
.timeout(Timeout::Milliseconds(6000))
|
// .timeout(Timeout::Milliseconds(6000))
|
||||||
.show()?;
|
// .show()?;
|
||||||
let message_uids = authed.uid_search().await?;
|
let message_uids = authed.uid_search().await?;
|
||||||
let message_uids =
|
let message_uids =
|
||||||
message_uids.into_iter().take(20).collect::<Vec<_>>();
|
message_uids.into_iter().take(20).collect::<Vec<_>>();
|
||||||
let _ = mail2ui_tx.send(MailEvent::MessageUids(
|
// let _ = mail2ui_tx.send(MailEvent::MessageUids(
|
||||||
acct_name.clone(),
|
// acct_name.clone(),
|
||||||
message_uids.clone(),
|
// message_uids.clone(),
|
||||||
));
|
// ));
|
||||||
// TODO: make this happen concurrently with the main loop?
|
// TODO: make this happen concurrently with the main loop?
|
||||||
let mut message_list = authed
|
let mut message_list = authed
|
||||||
.uid_fetch(&message_uids, FetchItems::All)
|
.uid_fetch(&message_uids, FetchItems::All)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
while let Some((uid, attrs)) = message_list.next().await {
|
while let Some((_uid, _attrs)) = message_list.next().await {
|
||||||
let evt = MailEvent::UpdateUid(acct_name.clone(), uid, attrs);
|
// let evt = MailEvent::UpdateUid(acct_name.
|
||||||
|
// clone(), uid, attrs);
|
||||||
// debug!("sent {:?}", evt);
|
// debug!("sent {:?}", evt);
|
||||||
mail2ui_tx.send(evt);
|
// mail2ui_tx.send(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
idle_stream = authed.idle().await?;
|
idle_stream = authed.idle().await?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
1
daemon/src/mail/store.rs
Normal file
1
daemon/src/mail/store.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub struct MailStore;
|
|
@ -1,6 +1,8 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate anyhow;
|
||||||
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
@ -15,13 +17,15 @@ use futures::future::{
|
||||||
Either::{Left, Right},
|
Either::{Left, Right},
|
||||||
FutureExt,
|
FutureExt,
|
||||||
};
|
};
|
||||||
|
use panorama_imap::client::ConfigBuilder;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
use crate::config::{Config, MailAccountConfig, TlsMethod};
|
use crate::config::{Config, MailAccountConfig, TlsMethod};
|
||||||
|
|
||||||
type ExitListener = oneshot::Receiver<()>;
|
type ExitListener = oneshot::Receiver<()>;
|
||||||
|
|
||||||
/// The panorama daemon runs in the background and communicates with other panorama components over Unix sockets.
|
/// The panorama daemon runs in the background and communicates with other
|
||||||
|
/// panorama components over Unix sockets.
|
||||||
#[derive(Debug, Clap)]
|
#[derive(Debug, Clap)]
|
||||||
struct Options {
|
struct Options {
|
||||||
// /// Config file path (defaults to XDG)
|
// /// Config file path (defaults to XDG)
|
||||||
|
@ -80,11 +84,12 @@ async fn run_single_mail_account(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
debug!("connecting to account {}", account_name);
|
debug!("connecting to account {}", account_name);
|
||||||
|
|
||||||
let imap_cookie = ImapClient::open(
|
// set up the connection
|
||||||
&account.imap.server,
|
let mut builder = ConfigBuilder::default();
|
||||||
account.imap.port,
|
let imap_cookie = builder
|
||||||
matches!(account.imap.tls, TlsMethod::On),
|
.hostname(account.imap.server.clone())
|
||||||
);
|
.port(account.imap.port)
|
||||||
|
.tls(matches!(account.imap.tls, TlsMethod::On)).open();
|
||||||
|
|
||||||
pin_mut!(imap_cookie);
|
pin_mut!(imap_cookie);
|
||||||
pin_mut!(exit);
|
pin_mut!(exit);
|
||||||
|
@ -95,7 +100,7 @@ async fn run_single_mail_account(
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("connected to {}", account.imap.server);
|
debug!("connected to {}", account.imap.server);
|
||||||
let imap = imap?;
|
let _imap = imap?;
|
||||||
let mut exit = exit.fuse();
|
let mut exit = exit.fuse();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "panorama-imap"
|
name = "panorama-imap"
|
||||||
description = "IMAP protocol implementation with high-level async client."
|
description = "IMAP protocol implementation with high-level async client."
|
||||||
version = "0.0.3"
|
version = "0.0.4"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Michael Zhang <mail@mzhang.io>"]
|
authors = ["Michael Zhang <mail@mzhang.io>"]
|
||||||
keywords = ["imap", "email", "parser"]
|
keywords = ["imap", "email", "parser"]
|
||||||
|
@ -12,11 +12,6 @@ documentation = "https://docs.rs/panorama-imap"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
workspace = ".."
|
workspace = ".."
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "mzhang-test"
|
|
||||||
path = "bin/mzhang_test.rs"
|
|
||||||
required-features = ["stderrlog"]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rfc2177", "rfc6154"]
|
default = ["rfc2177", "rfc6154"]
|
||||||
low-level = []
|
low-level = []
|
||||||
|
|
1
imap/bin/.gitignore
vendored
1
imap/bin/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
/mzhang_test.rs
|
|
|
@ -236,12 +236,11 @@ impl ClientAuthenticated {
|
||||||
/// Runs the IDLE command
|
/// Runs the IDLE command
|
||||||
#[cfg(feature = "rfc2177")]
|
#[cfg(feature = "rfc2177")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
||||||
pub async fn idle<'a>(&'a mut self) -> Result<IdleToken<'a>> {
|
pub async fn idle(&mut self) -> Result<IdleToken> {
|
||||||
let cmd = Command::Idle;
|
let cmd = Command::Idle;
|
||||||
let stream = self.execute(cmd).await?;
|
let stream = self.execute(cmd).await?;
|
||||||
Ok(IdleToken {
|
Ok(IdleToken {
|
||||||
stream,
|
stream,
|
||||||
_client: self,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,15 +261,14 @@ pub struct SelectResponse {
|
||||||
/// DONE command will be sent to the server as a result.
|
/// DONE command will be sent to the server as a result.
|
||||||
#[cfg(feature = "rfc2177")]
|
#[cfg(feature = "rfc2177")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
||||||
pub struct IdleToken<'a> {
|
pub struct IdleToken {
|
||||||
pub stream: ResponseStream,
|
pub stream: ResponseStream,
|
||||||
// sender: mpsc::UnboundedSender<TaggedCommand>,
|
// sender: mpsc::UnboundedSender<TaggedCommand>,
|
||||||
_client: &'a mut ClientAuthenticated,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rfc2177")]
|
#[cfg(feature = "rfc2177")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
||||||
impl<'a> Drop for IdleToken<'a> {
|
impl Drop for IdleToken {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// TODO: put this into a channel instead
|
// TODO: put this into a channel instead
|
||||||
// tokio::spawn(self.client.execute(Command::Done));
|
// tokio::spawn(self.client.execute(Command::Done));
|
||||||
|
@ -279,7 +277,7 @@ impl<'a> Drop for IdleToken<'a> {
|
||||||
|
|
||||||
#[cfg(feature = "rfc2177")]
|
#[cfg(feature = "rfc2177")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rfc2177")))]
|
||||||
impl<'a> Stream for IdleToken<'a> {
|
impl Stream for IdleToken {
|
||||||
type Item = Response;
|
type Item = Response;
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
|
||||||
let stream = Pin::new(&mut self.stream);
|
let stream = Pin::new(&mut self.stream);
|
||||||
|
|
Loading…
Reference in a new issue