Fix capability parsing
This commit is contained in:
parent
b6301fd6ef
commit
c75113d97f
17 changed files with 541 additions and 196 deletions
366
Cargo.lock
generated
366
Cargo.lock
generated
|
@ -28,15 +28,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.44"
|
||||
|
@ -95,7 +86,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
|||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -112,7 +103,7 @@ checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
|
|||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
|
@ -198,6 +189,12 @@ version = "1.0.71"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -214,7 +211,7 @@ dependencies = [
|
|||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -284,7 +281,7 @@ version = "0.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
|
@ -294,7 +291,7 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
|
@ -304,10 +301,35 @@ version = "0.8.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio 0.7.13",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.12.4"
|
||||
|
@ -413,7 +435,7 @@ checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -429,16 +451,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
name = "filetime"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall 0.2.10",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -479,6 +500,41 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fsevent-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
|
@ -606,7 +662,7 @@ version = "0.1.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
@ -617,7 +673,7 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
@ -723,12 +779,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.13"
|
||||
|
@ -781,15 +831,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.5"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5fc8f41dbaa9c8492a96c8afffda4f76896ee041d6a57606e70581b80c901f"
|
||||
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures-core",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -807,7 +855,16 @@ version = "0.1.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -834,12 +891,28 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.6"
|
||||
|
@ -848,7 +921,7 @@ checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
|
|||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
@ -885,7 +958,7 @@ version = "0.4.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -916,6 +989,25 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow 0.2.2",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.13"
|
||||
|
@ -924,9 +1016,33 @@ checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"miow 0.3.7",
|
||||
"ntapi",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||
dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"mio 0.6.23",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -935,7 +1051,18 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -962,13 +1089,31 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"filetime",
|
||||
"fsevent",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"libc",
|
||||
"mio 0.6.23",
|
||||
"mio-extras",
|
||||
"walkdir",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1034,8 +1179,8 @@ dependencies = [
|
|||
"derivative",
|
||||
"futures",
|
||||
"hyper",
|
||||
"inotify",
|
||||
"log",
|
||||
"notify",
|
||||
"panorama-imap",
|
||||
"panorama-smtp",
|
||||
"serde",
|
||||
|
@ -1071,24 +1216,6 @@ dependencies = [
|
|||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panorama-mbsync"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"bitflags",
|
||||
"clap",
|
||||
"derivative",
|
||||
"derive_builder",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"log",
|
||||
"panorama-imap",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panorama-proto-common"
|
||||
version = "0.0.1"
|
||||
|
@ -1111,6 +1238,13 @@ dependencies = [
|
|||
"panorama-proto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panorama-tui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
|
@ -1128,12 +1262,12 @@ version = "0.8.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.10",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1246,29 +1380,12 @@ dependencies = [
|
|||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
|
@ -1281,7 +1398,7 @@ dependencies = [
|
|||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1321,6 +1438,15 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
|
@ -1376,12 +1502,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio 0.7.13",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
|
@ -1393,9 +1540,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
|
||||
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
|
@ -1616,7 +1763,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1644,21 +1791,21 @@ dependencies = [
|
|||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio 0.7.13",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "154794c8f499c2619acd19e839294703e9e32e7630ef5f46ea80d4ef0fbee5eb"
|
||||
checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1722,7 +1869,7 @@ version = "0.1.29"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
@ -1823,6 +1970,17 @@ version = "0.9.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi 0.3.9",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
|
@ -1851,7 +2009,7 @@ version = "0.2.78"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
|
@ -1938,6 +2096,12 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -1948,6 +2112,12 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -1960,7 +2130,7 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1969,6 +2139,16 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
members = [
|
||||
"daemon",
|
||||
"imap",
|
||||
"smtp",
|
||||
# "mbsync",
|
||||
"proto-common",
|
||||
"mbsync",
|
||||
"smtp",
|
||||
"tui",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
lto = true
|
||||
|
|
1
daemon/.gitignore
vendored
Normal file
1
daemon/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/test.db*
|
|
@ -3,6 +3,10 @@ name = "panorama-daemon"
|
|||
version = "0.0.1"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["config-watch"]
|
||||
config-watch = ["notify"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.42", features = ["backtrace"] }
|
||||
async-trait = "0.1.50"
|
||||
|
@ -10,7 +14,6 @@ clap = "3.0.0-beta.2"
|
|||
derivative = "2.2.0"
|
||||
futures = "0.3.16"
|
||||
hyper = { version = "0.14.11", features = ["server", "http2", "stream"] }
|
||||
inotify = { version = "0.9.3", features = ["stream"] }
|
||||
log = "0.4.14"
|
||||
panorama-imap = { path = "../imap" }
|
||||
panorama-smtp = { path = "../smtp" }
|
||||
|
@ -21,6 +24,8 @@ tokio-rustls = "0.22.0"
|
|||
toml = "0.5.8"
|
||||
xdg = "2.2.0"
|
||||
|
||||
notify = { version = "4.0.17", optional = true }
|
||||
|
||||
[dependencies.sqlx]
|
||||
version = "0.5.9"
|
||||
features = ["runtime-tokio-rustls", "sqlite", "json", "chrono"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
CREATE TABLE "accounts" (
|
||||
"id" PRIMARY KEY AUTOINCREMENT
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
);
|
||||
|
||||
CREATE TABLE "mailboxes" (
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#[cfg(feature = "config-watch")]
|
||||
mod watcher;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -7,7 +8,8 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
pub use self::watcher::spawn_config_watcher_system;
|
||||
#[cfg(feature = "config-watch")]
|
||||
pub use self::watcher::{spawn_config_watcher_system, ConfigWatcher};
|
||||
|
||||
/// Configuration
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::mpsc as stdmpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use futures::{future::TryFutureExt, stream::StreamExt};
|
||||
use inotify::{Inotify, WatchMask};
|
||||
use tokio::{sync::watch, task::JoinHandle};
|
||||
use futures::future::TryFutureExt;
|
||||
use notify::{
|
||||
watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher,
|
||||
};
|
||||
use tokio::{
|
||||
sync::{mpsc, watch},
|
||||
task::JoinHandle,
|
||||
};
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use super::Config;
|
||||
|
@ -16,33 +23,34 @@ pub type ConfigWatcher = watch::Receiver<Config>;
|
|||
/// config update events.
|
||||
pub fn spawn_config_watcher_system() -> Result<(JoinHandle<()>, ConfigWatcher)>
|
||||
{
|
||||
let mut inotify = Inotify::init()?;
|
||||
let (tx, rx) = stdmpsc::channel();
|
||||
let mut dir_watcher = watcher(tx, Duration::from_secs(10))?;
|
||||
|
||||
let xdg = BaseDirectories::new()?;
|
||||
let config_home = xdg.get_config_home().join("panorama");
|
||||
if !config_home.exists() {
|
||||
fs::create_dir_all(&config_home)?;
|
||||
}
|
||||
|
||||
inotify
|
||||
.add_watch(&config_home, WatchMask::CLOSE_WRITE)
|
||||
dir_watcher
|
||||
.watch(&config_home, RecursiveMode::Recursive)
|
||||
.context("adding watch for config home")?;
|
||||
|
||||
debug!("watching {:?}", config_home);
|
||||
let (config_tx, config_update) = watch::channel(Config::default());
|
||||
let handle = tokio::spawn(
|
||||
start_inotify_stream(inotify, config_home, config_tx)
|
||||
start_notify_stream(dir_watcher, rx, config_home, config_tx)
|
||||
.unwrap_or_else(|_err| todo!()),
|
||||
);
|
||||
Ok((handle, config_update))
|
||||
}
|
||||
|
||||
async fn start_inotify_stream(
|
||||
mut inotify: Inotify,
|
||||
async fn start_notify_stream(
|
||||
mut watcher: RecommendedWatcher,
|
||||
rx: stdmpsc::Receiver<DebouncedEvent>,
|
||||
config_home: impl AsRef<Path>,
|
||||
config_tx: watch::Sender<Config>,
|
||||
) -> Result<()> {
|
||||
let mut buffer = vec![0u8; 1024];
|
||||
let mut event_stream = inotify.event_stream(&mut buffer)?;
|
||||
let config_home = config_home.as_ref().to_path_buf();
|
||||
let config_path = config_home.join("panorama.toml");
|
||||
|
||||
|
@ -53,33 +61,42 @@ async fn start_inotify_stream(
|
|||
}
|
||||
|
||||
debug!("listening for inotify events");
|
||||
while let Some(v) = event_stream.next().await {
|
||||
let event = v.context("event")?;
|
||||
debug!("inotify event: {:?}", event);
|
||||
if let Some(name) = event.name {
|
||||
let path = PathBuf::from(name);
|
||||
let path_c = config_home
|
||||
.clone()
|
||||
.join(path.clone())
|
||||
.canonicalize()
|
||||
.context("osu")?;
|
||||
if !path_c.exists() {
|
||||
debug!("path {:?} doesn't exist", path_c);
|
||||
continue;
|
||||
}
|
||||
// TODO: any better way to do this?
|
||||
let config_path_c =
|
||||
config_path.canonicalize().context("cfg_path")?;
|
||||
if config_path_c != path_c {
|
||||
debug!("did not match {:?} {:?}", config_path_c, path_c);
|
||||
continue;
|
||||
loop {
|
||||
let event = rx.recv()?;
|
||||
debug!("notify event: {:?}", event);
|
||||
|
||||
match event {
|
||||
DebouncedEvent::NoticeRemove(_)
|
||||
| DebouncedEvent::NoticeWrite(_) => {
|
||||
// TODO: should this be handled somehow?
|
||||
// neovim sends these since it's writing to a temp buffer
|
||||
}
|
||||
|
||||
debug!("reading config from {:?}", path_c);
|
||||
let config = Config::from_file(path_c).await.context("read")?;
|
||||
// debug!("sending config {:?}", config);
|
||||
config_tx.send(config)?;
|
||||
DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => {
|
||||
let path_c = config_home
|
||||
.clone()
|
||||
.join(path.clone())
|
||||
.canonicalize()
|
||||
.context("osu")?;
|
||||
if !path_c.exists() {
|
||||
debug!("path {:?} doesn't exist", path_c);
|
||||
continue;
|
||||
}
|
||||
// TODO: any better way to do this?
|
||||
let config_path_c =
|
||||
config_path.canonicalize().context("cfg_path")?;
|
||||
if config_path_c != path_c {
|
||||
debug!("did not match {:?} {:?}", config_path_c, path_c);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!("reading config from {:?}", path_c);
|
||||
let config = Config::from_file(path_c).await.context("read")?;
|
||||
// debug!("sending config {:?}", config);
|
||||
config_tx.send(config)?;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,7 +9,3 @@ extern crate derivative;
|
|||
|
||||
pub mod config;
|
||||
pub mod mail;
|
||||
|
||||
use sqlx::migrate::Migrator;
|
||||
|
||||
static MIGRATOR: Migrator = sqlx::migrate!();
|
||||
|
|
|
@ -11,12 +11,16 @@ use panorama_imap::{
|
|||
response::{MailboxData, Response},
|
||||
},
|
||||
};
|
||||
use sqlx::migrate::Migrator;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
use crate::config::{ImapAuth, MailAccountConfig, TlsMethod};
|
||||
|
||||
use self::store::MailStore;
|
||||
pub use self::store::MailStore;
|
||||
|
||||
static MIGRATOR: Migrator = sqlx::migrate!();
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MailEvent {}
|
||||
|
||||
/// The main function for the IMAP syncing thread
|
||||
|
@ -26,7 +30,9 @@ pub async fn sync_main(
|
|||
_mail2ui_tx: UnboundedSender<MailEvent>,
|
||||
_mail_store: MailStore,
|
||||
) -> Result<()> {
|
||||
let _acct_name = acct_name.as_ref().to_owned();
|
||||
let acct_name = acct_name.as_ref();
|
||||
debug!("Starting main synchronization procedure for {}", acct_name);
|
||||
|
||||
// loop ensures that the connection is retried after it dies
|
||||
loop {
|
||||
let client = ConfigBuilder::default()
|
||||
|
@ -36,16 +42,22 @@ pub async fn sync_main(
|
|||
.open()
|
||||
.await
|
||||
.map_err(|err| anyhow!("err: {}", err))?;
|
||||
debug!("Connected to {}:{}.", &acct.imap.server, acct.imap.port);
|
||||
|
||||
debug!("connected to {}:{}", &acct.imap.server, acct.imap.port);
|
||||
debug!("TLS Upgrade option: {:?}", acct.imap.tls);
|
||||
let unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
|
||||
debug!("attempting to upgrade");
|
||||
let client = client.upgrade().await?;
|
||||
let client = client
|
||||
.upgrade()
|
||||
.await
|
||||
.context("could not upgrade connection")?;
|
||||
debug!("upgrade successful");
|
||||
client
|
||||
} else {
|
||||
warn!("Continuing with unencrypted connection!");
|
||||
client
|
||||
};
|
||||
|
||||
debug!("preparing to auth");
|
||||
// check if the authentication method is supported
|
||||
let mut authed = match &acct.imap.auth {
|
||||
|
@ -57,12 +69,14 @@ pub async fn sync_main(
|
|||
unauth.auth(login).await?
|
||||
}
|
||||
};
|
||||
|
||||
debug!("authentication successful!");
|
||||
let folder_list = authed.list().await?;
|
||||
// let _ = mail2ui_tx.send(MailEvent::FolderList(
|
||||
// acct_name.clone(),
|
||||
// folder_list.clone(),
|
||||
// ));
|
||||
|
||||
debug!("mailbox list: {:?}", folder_list);
|
||||
for folder in folder_list.iter() {
|
||||
debug!("folder: {:?}", folder);
|
||||
|
@ -102,10 +116,12 @@ pub async fn sync_main(
|
|||
}
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_secs(50)).await;
|
||||
|
||||
// TODO: remove this later
|
||||
// continue;
|
||||
// let's just select INBOX for now, maybe have a config for default
|
||||
// mailbox later?
|
||||
|
||||
debug!("selecting the INBOX mailbox");
|
||||
let select = authed.select("INBOX").await?;
|
||||
debug!("select result: {:?}", select);
|
||||
|
@ -127,8 +143,10 @@ pub async fn sync_main(
|
|||
// attrs); TODO: probably odn't care about this?
|
||||
// let _ = mail2ui_tx.send(evt);
|
||||
}
|
||||
// check if IDLE is supported
|
||||
|
||||
// TODO: check if IDLE is supported
|
||||
let supports_idle = true; // authed.has_capability("IDLE").await?;
|
||||
|
||||
if supports_idle {
|
||||
let mut idle_stream = authed.idle().await?;
|
||||
loop {
|
||||
|
@ -136,6 +154,7 @@ pub async fn sync_main(
|
|||
Some(v) => v,
|
||||
None => break,
|
||||
};
|
||||
|
||||
debug!("got an event: {:?}", evt);
|
||||
match evt {
|
||||
Response::MailboxData(MailboxData::Exists(uid)) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
|
||||
|
||||
use crate::MIGRATOR;
|
||||
use super::MIGRATOR;
|
||||
|
||||
pub struct MailStore {
|
||||
pool: SqlitePool,
|
||||
|
|
|
@ -3,16 +3,23 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate futures;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use clap::Clap;
|
||||
use futures::future::{
|
||||
select,
|
||||
Either::{Left, Right},
|
||||
FutureExt,
|
||||
};
|
||||
use panorama_daemon::config::{self, Config, MailAccountConfig, TlsMethod};
|
||||
use panorama_daemon::{
|
||||
config::{Config, MailAccountConfig, TlsMethod},
|
||||
mail::{sync_main, MailStore},
|
||||
};
|
||||
use panorama_imap::client::ConfigBuilder;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::{
|
||||
fs::{self, OpenOptions},
|
||||
sync::{mpsc, oneshot},
|
||||
};
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
type ExitListener = oneshot::Receiver<()>;
|
||||
|
||||
|
@ -34,31 +41,68 @@ async fn main() -> Result<()> {
|
|||
|
||||
stderrlog::new()
|
||||
.module(module_path!())
|
||||
.module("panorama_daemon")
|
||||
.module("panorama_imap")
|
||||
.verbosity(opt.verbose)
|
||||
.init()
|
||||
.unwrap();
|
||||
|
||||
let (_, mut config_watcher) = config::spawn_config_watcher_system()?;
|
||||
// if we're using a config-watcher, then start the watcher system
|
||||
#[cfg(feature = "config-watch")]
|
||||
{
|
||||
use panorama_daemon::config;
|
||||
|
||||
loop {
|
||||
let (exit_tx, exit_rx) = oneshot::channel();
|
||||
let new_config = config_watcher.borrow().clone();
|
||||
tokio::spawn(run_with_config(new_config, exit_rx));
|
||||
let (_, mut config_watcher) = config::spawn_config_watcher_system()?;
|
||||
|
||||
// wait till the config has changed, then tell the current thread to
|
||||
// stop
|
||||
config_watcher.changed().await?;
|
||||
let _ = exit_tx.send(());
|
||||
loop {
|
||||
let (exit_tx, exit_rx) = oneshot::channel();
|
||||
let new_config = config_watcher.borrow().clone();
|
||||
tokio::spawn(run_with_config(new_config, exit_rx));
|
||||
|
||||
// wait till the config has changed, then tell the current thread to
|
||||
// stop
|
||||
config_watcher.changed().await?;
|
||||
let _ = exit_tx.send(());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle SIGHUP on Unix? pretty common for systemd to send this when
|
||||
// reloading config files
|
||||
|
||||
// if not, just read the config once and run the daemon
|
||||
#[cfg(not(feature = "config-watch"))]
|
||||
{
|
||||
let xdg = BaseDirectories::new()?;
|
||||
let config_home = xdg.get_config_home().join("panorama");
|
||||
if !config_home.exists() {
|
||||
fs::create_dir_all(&config_home).await?;
|
||||
}
|
||||
|
||||
let config_path = config_home.join("panorama.toml");
|
||||
let config_path_c = config_path.canonicalize().context("cfg_path")?;
|
||||
let config = Config::from_file(config_path_c).await.context("read")?;
|
||||
|
||||
let (_, exit_rx) = oneshot::channel();
|
||||
run_with_config(config, exit_rx).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_config(config: Config, exit: ExitListener) -> Result<()> {
|
||||
debug!("new config");
|
||||
debug!("New config: {:?}", config);
|
||||
|
||||
// keep track of which threads need to be stopped when this function is
|
||||
// stopped
|
||||
let mut notify_mail_threads = Vec::new();
|
||||
|
||||
for (account_name, account) in config.mail_accounts {
|
||||
let (exit_tx, exit_rx) = oneshot::channel();
|
||||
tokio::spawn(run_single_mail_account(account_name, account, exit_rx));
|
||||
tokio::spawn(async {
|
||||
match run_single_mail_account(account_name, account, exit_rx).await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("failed: {:?}", err),
|
||||
}
|
||||
});
|
||||
notify_mail_threads.push(exit_tx);
|
||||
}
|
||||
|
||||
|
@ -79,30 +123,59 @@ async fn run_single_mail_account(
|
|||
account: MailAccountConfig,
|
||||
exit: ExitListener,
|
||||
) -> Result<()> {
|
||||
debug!("connecting to account {}", account_name);
|
||||
|
||||
// set up the connection
|
||||
let mut builder = ConfigBuilder::default();
|
||||
let imap_cookie = builder
|
||||
.hostname(account.imap.server.clone())
|
||||
.port(account.imap.port)
|
||||
.tls(matches!(account.imap.tls, TlsMethod::On))
|
||||
.open();
|
||||
|
||||
pin_mut!(imap_cookie);
|
||||
pin_mut!(exit);
|
||||
|
||||
let (imap, exit) = match select(imap_cookie, exit).await {
|
||||
Left(res) => res,
|
||||
Right(_) => return Ok(()),
|
||||
};
|
||||
|
||||
debug!("connected to {}", account.imap.server);
|
||||
let _imap = imap?;
|
||||
debug!("run_single_mail_account({}, {:?})", account_name, account);
|
||||
let mut exit = exit.fuse();
|
||||
|
||||
let xdg = BaseDirectories::new()?;
|
||||
let data_home = xdg.get_data_home().join("panorama");
|
||||
if !data_home.exists() {
|
||||
fs::create_dir_all(&data_home)
|
||||
.await
|
||||
.context("could not create config directory")?;
|
||||
}
|
||||
let db_path = data_home.join("db.sqlite3");
|
||||
debug!("Opening database at path: {:?}", db_path);
|
||||
if !db_path.exists() {
|
||||
OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(&db_path)
|
||||
.await
|
||||
.context("could not touch db path")?;
|
||||
}
|
||||
let db_path = db_path
|
||||
.canonicalize()
|
||||
.context("could not canonicalize db path")?;
|
||||
let store =
|
||||
MailStore::open(format!("sqlite://{}", db_path.to_string_lossy()))
|
||||
.await
|
||||
.context("couldn't open mail store")?;
|
||||
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
let sync_fut = sync_main(&account_name, account, tx, store).fuse();
|
||||
pin_mut!(sync_fut);
|
||||
|
||||
debug!("Mail account loop for {}.", account_name);
|
||||
loop {
|
||||
select! {
|
||||
res = sync_fut => match res {
|
||||
Ok(_) => {},
|
||||
Err(err) => {
|
||||
error!("sync_main died with: {:?}", err);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
evt_opt = rx.recv().fuse() => {
|
||||
let evt = match evt_opt {
|
||||
Some(evt) => evt,
|
||||
None => break,
|
||||
};
|
||||
|
||||
debug!("Event: {:?}", evt);
|
||||
},
|
||||
|
||||
// we're being told to exit the loop
|
||||
_ = exit => break,
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::{
|
|||
Arc,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use futures::{
|
||||
future::{self, FutureExt, TryFutureExt},
|
||||
stream::StreamExt,
|
||||
|
@ -134,8 +134,17 @@ where
|
|||
&mut self,
|
||||
cap: impl AsRef<str>,
|
||||
) -> Result<bool> {
|
||||
let cap_bytes = cap.as_ref().as_bytes().to_vec();
|
||||
let (_, cap) = parse_capability(Bytes::from(cap_bytes))?;
|
||||
let mut cap_slice = cap.as_ref().as_bytes().to_vec();
|
||||
|
||||
// since we're doing incremental parsing, we have to finish this off
|
||||
// with something that's invalid
|
||||
cap_slice.push(b'\n');
|
||||
|
||||
let cap_bytes = Bytes::from(cap_slice);
|
||||
trace!("CAP_BYTES: {:?}", cap_bytes);
|
||||
|
||||
let (_, cap) = parse_capability(cap_bytes)
|
||||
.context("could not parse capability")?;
|
||||
|
||||
let contains = {
|
||||
let read = self.capabilities.read().await;
|
||||
|
@ -145,10 +154,21 @@ where
|
|||
std::mem::drop(read);
|
||||
|
||||
let cmd = self.execute(Command::Capability).await?;
|
||||
let done = cmd.done().await?;
|
||||
todo!("done: {:?}", done);
|
||||
let (done, res) = cmd.wait().await?;
|
||||
|
||||
// todo!()
|
||||
let mut capabilities = HashSet::new();
|
||||
// todo!("done: {:?} {:?}", done, res);
|
||||
|
||||
for caps in res.iter().filter_map(|res| match res {
|
||||
Response::Capabilities(caps) => Some(caps),
|
||||
_ => None,
|
||||
}) {
|
||||
capabilities.extend(caps.clone());
|
||||
}
|
||||
|
||||
let mut write = self.capabilities.write().await;
|
||||
*write = Some(capabilities);
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -160,28 +180,48 @@ where
|
|||
|
||||
// check that this capability exists
|
||||
// if it doesn't exist, then it's not an IMAP4-compliant server
|
||||
if !self.has_capability("STARTTLS").await? {
|
||||
if !self
|
||||
.has_capability("STARTTLS")
|
||||
.await
|
||||
.context("could not check starttls capability")?
|
||||
{
|
||||
bail!("Server does not have the STARTTLS capability");
|
||||
}
|
||||
|
||||
// issue the STARTTLS command to the server
|
||||
let resp = self.execute(Command::Starttls).await?;
|
||||
dbg!(resp.wait().await?);
|
||||
let resp = self
|
||||
.execute(Command::Starttls)
|
||||
.await
|
||||
.context("could not send starttls command")?;
|
||||
dbg!(resp
|
||||
.wait()
|
||||
.await
|
||||
.context("could not receive starttls response")?);
|
||||
debug!("received OK from server");
|
||||
|
||||
// issue exit to the read loop and retrieve the read half
|
||||
let _ = self.read_exit.send(());
|
||||
let read_half = self.read_handle.await?;
|
||||
let read_half = self
|
||||
.read_handle
|
||||
.await
|
||||
.context("could not retrieve read half of connection")?;
|
||||
|
||||
// issue exit to the write loop and retrieve the write half
|
||||
let _ = self.write_exit.send(());
|
||||
let write_half = self.write_handle.await?;
|
||||
let write_half = self
|
||||
.write_handle
|
||||
.await
|
||||
.context("could not retrieve write half of connection")?;
|
||||
|
||||
// put the read half and write half back together
|
||||
let stream = read_half.unsplit(write_half);
|
||||
let tls_stream = wrap_tls(stream, &self.config.hostname).await?;
|
||||
let tls_stream = wrap_tls(stream, &self.config.hostname)
|
||||
.await
|
||||
.context("could not initialize tls stream")?;
|
||||
|
||||
Inner::new(tls_stream, self.config).await
|
||||
Inner::new(tls_stream, self.config)
|
||||
.await
|
||||
.context("could not construct new client")
|
||||
}
|
||||
|
||||
pub async fn wait_for_greeting(&mut self) -> Result<()> {
|
||||
|
|
|
@ -62,6 +62,7 @@ pub enum Response {
|
|||
|
||||
impl DisplayBytes for Response {
|
||||
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
|
||||
#[allow(unreachable_patterns)]
|
||||
match self {
|
||||
Response::Capabilities(caps) => {
|
||||
write_bytes!(w, b"CAPABILITY")?;
|
||||
|
@ -72,7 +73,7 @@ impl DisplayBytes for Response {
|
|||
}
|
||||
Response::Continue(cont) => write_bytes!(w, b"+ {}\r\n", cont),
|
||||
Response::Condition(cond) => write_bytes!(w, b"* {}\r\n", cond),
|
||||
Response::Done(done) => write_bytes!(w, b""),
|
||||
Response::Done(_) => write_bytes!(w, b""),
|
||||
Response::MailboxData(data) => write_bytes!(w, b"* {}\r\n", data),
|
||||
Response::Fetch(n, attrs) => {
|
||||
write_bytes!(w, b"{} FETCH (", n)?;
|
||||
|
@ -127,7 +128,7 @@ pub enum MessageAttribute {
|
|||
}
|
||||
|
||||
impl DisplayBytes for MessageAttribute {
|
||||
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
|
||||
fn display_bytes(&self, _: &mut dyn Write) -> io::Result<()> {
|
||||
match self {
|
||||
_ => todo!(),
|
||||
}
|
||||
|
@ -245,7 +246,7 @@ pub enum UidSetMember {
|
|||
Uid(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "fuzzing", derive(Arbitrary))]
|
||||
pub enum Capability {
|
||||
Imap4rev1,
|
||||
|
|
|
@ -9,7 +9,6 @@ license = "GPL-3.0-or-later"
|
|||
categories = ["email"]
|
||||
repository = "https://git.mzhang.io/michael/panorama"
|
||||
readme = "README.md"
|
||||
workspace = ".."
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.42", features = ["backtrace"] }
|
||||
|
|
7
tui/Cargo.toml
Normal file
7
tui/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "panorama-tui"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.20"
|
1
tui/src/lib.rs
Normal file
1
tui/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
3
tui/src/main.rs
Normal file
3
tui/src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
Loading…
Reference in a new issue