Fix capability parsing

This commit is contained in:
Michael Zhang 2021-10-25 18:42:14 -05:00
parent b6301fd6ef
commit c75113d97f
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
17 changed files with 541 additions and 196 deletions

366
Cargo.lock generated
View file

@ -28,15 +28,6 @@ dependencies = [
"version_check", "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]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.44" version = "1.0.44"
@ -95,7 +86,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -112,7 +103,7 @@ checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc", "cc",
"cfg-if", "cfg-if 1.0.0",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object", "object",
@ -198,6 +189,12 @@ version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -214,7 +211,7 @@ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
"time", "time",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -284,7 +281,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
] ]
@ -294,7 +291,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
] ]
@ -304,10 +301,35 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"lazy_static", "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]] [[package]]
name = "darling" name = "darling"
version = "0.12.4" version = "0.12.4"
@ -413,7 +435,7 @@ checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [ dependencies = [
"libc", "libc",
"redox_users", "redox_users",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -429,16 +451,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "env_logger" name = "filetime"
version = "0.9.0" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
dependencies = [ dependencies = [
"atty", "cfg-if 1.0.0",
"humantime", "libc",
"log", "redox_syscall 0.2.10",
"regex", "winapi 0.3.9",
"termcolor",
] ]
[[package]] [[package]]
@ -479,6 +500,41 @@ dependencies = [
"syn", "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]] [[package]]
name = "funty" name = "funty"
version = "1.1.0" version = "1.1.0"
@ -606,7 +662,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"libc", "libc",
"wasi 0.9.0+wasi-snapshot-preview1", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"libc", "libc",
"wasi 0.10.0+wasi-snapshot-preview1", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.13" version = "0.14.13"
@ -781,15 +831,13 @@ dependencies = [
[[package]] [[package]]
name = "inotify" name = "inotify"
version = "0.9.5" 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 = "9e5fc8f41dbaa9c8492a96c8afffda4f76896ee041d6a57606e70581b80c901f" checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"futures-core",
"inotify-sys", "inotify-sys",
"libc", "libc",
"tokio",
] ]
[[package]] [[package]]
@ -807,7 +855,16 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd"
dependencies = [ 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]] [[package]]
@ -834,12 +891,28 @@ dependencies = [
"wasm-bindgen", "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]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "lexical-core" name = "lexical-core"
version = "0.7.6" version = "0.7.6"
@ -848,7 +921,7 @@ checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags", "bitflags",
"cfg-if", "cfg-if 1.0.0",
"ryu", "ryu",
"static_assertions", "static_assertions",
] ]
@ -885,7 +958,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]] [[package]]
@ -916,6 +989,25 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "mio" name = "mio"
version = "0.7.13" version = "0.7.13"
@ -924,9 +1016,33 @@ checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
"miow", "miow 0.3.7",
"ntapi", "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]] [[package]]
@ -935,7 +1051,18 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [ 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]] [[package]]
@ -962,13 +1089,31 @@ dependencies = [
"version_check", "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]] [[package]]
name = "ntapi" name = "ntapi"
version = "0.3.6" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [ dependencies = [
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1034,8 +1179,8 @@ dependencies = [
"derivative", "derivative",
"futures", "futures",
"hyper", "hyper",
"inotify",
"log", "log",
"notify",
"panorama-imap", "panorama-imap",
"panorama-smtp", "panorama-smtp",
"serde", "serde",
@ -1071,24 +1216,6 @@ dependencies = [
"webpki-roots", "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]] [[package]]
name = "panorama-proto-common" name = "panorama-proto-common"
version = "0.0.1" version = "0.0.1"
@ -1111,6 +1238,13 @@ dependencies = [
"panorama-proto-common", "panorama-proto-common",
] ]
[[package]]
name = "panorama-tui"
version = "0.1.0"
dependencies = [
"crossterm",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.2" version = "0.11.2"
@ -1128,12 +1262,12 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"instant", "instant",
"libc", "libc",
"redox_syscall 0.2.10", "redox_syscall 0.2.10",
"smallvec", "smallvec",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1246,29 +1380,12 @@ dependencies = [
"rust-argon2", "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]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.20" version = "0.16.20"
@ -1281,7 +1398,7 @@ dependencies = [
"spin", "spin",
"untrusted", "untrusted",
"web-sys", "web-sys",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1321,6 +1438,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 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]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1376,12 +1502,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"cfg-if", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"digest", "digest",
"opaque-debug", "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]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.0" version = "1.4.0"
@ -1393,9 +1540,9 @@ dependencies = [
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
@ -1616,7 +1763,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.10.0+wasi-snapshot-preview1", "wasi 0.10.0+wasi-snapshot-preview1",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1644,21 +1791,21 @@ dependencies = [
"bytes", "bytes",
"libc", "libc",
"memchr", "memchr",
"mio", "mio 0.7.13",
"num_cpus", "num_cpus",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"tokio-macros", "tokio-macros",
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.4.1" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "154794c8f499c2619acd19e839294703e9e32e7630ef5f46ea80d4ef0fbee5eb" checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1722,7 +1869,7 @@ version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"pin-project-lite", "pin-project-lite",
"tracing-core", "tracing-core",
] ]
@ -1823,6 +1970,17 @@ 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 = "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]] [[package]]
name = "want" name = "want"
version = "0.3.0" version = "0.3.0"
@ -1851,7 +2009,7 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
@ -1938,6 +2096,12 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -1948,6 +2112,12 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu", "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]] [[package]]
name = "winapi-i686-pc-windows-gnu" name = "winapi-i686-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@ -1960,7 +2130,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [ dependencies = [
"winapi", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -1969,6 +2139,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 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]] [[package]]
name = "wyz" name = "wyz"
version = "0.2.0" version = "0.2.0"

View file

@ -2,10 +2,11 @@
members = [ members = [
"daemon", "daemon",
"imap", "imap",
"smtp", # "mbsync",
"proto-common", "proto-common",
"mbsync", "smtp",
"tui",
] ]
[profile.release] [profile.release]
lto = true lto = true

1
daemon/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/test.db*

View file

@ -3,6 +3,10 @@ name = "panorama-daemon"
version = "0.0.1" version = "0.0.1"
edition = "2018" edition = "2018"
[features]
default = ["config-watch"]
config-watch = ["notify"]
[dependencies] [dependencies]
anyhow = { version = "1.0.42", features = ["backtrace"] } anyhow = { version = "1.0.42", features = ["backtrace"] }
async-trait = "0.1.50" async-trait = "0.1.50"
@ -10,7 +14,6 @@ clap = "3.0.0-beta.2"
derivative = "2.2.0" derivative = "2.2.0"
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"] }
inotify = { version = "0.9.3", features = ["stream"] }
log = "0.4.14" log = "0.4.14"
panorama-imap = { path = "../imap" } panorama-imap = { path = "../imap" }
panorama-smtp = { path = "../smtp" } panorama-smtp = { path = "../smtp" }
@ -21,6 +24,8 @@ tokio-rustls = "0.22.0"
toml = "0.5.8" toml = "0.5.8"
xdg = "2.2.0" xdg = "2.2.0"
notify = { version = "4.0.17", optional = true }
[dependencies.sqlx] [dependencies.sqlx]
version = "0.5.9" version = "0.5.9"
features = ["runtime-tokio-rustls", "sqlite", "json", "chrono"] features = ["runtime-tokio-rustls", "sqlite", "json", "chrono"]

View file

@ -1,5 +1,5 @@
CREATE TABLE "accounts" ( CREATE TABLE "accounts" (
"id" PRIMARY KEY AUTOINCREMENT "id" INTEGER PRIMARY KEY AUTOINCREMENT
); );
CREATE TABLE "mailboxes" ( CREATE TABLE "mailboxes" (

View file

@ -1,3 +1,4 @@
#[cfg(feature = "config-watch")]
mod watcher; mod watcher;
use std::collections::HashMap; use std::collections::HashMap;
@ -7,7 +8,8 @@ use std::path::{Path, PathBuf};
use anyhow::Result; 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 /// Configuration
#[derive(Default, Serialize, Deserialize, Clone, Debug)] #[derive(Default, Serialize, Deserialize, Clone, Debug)]

View file

@ -1,10 +1,17 @@
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::mpsc as stdmpsc;
use std::time::Duration;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use futures::{future::TryFutureExt, stream::StreamExt}; use futures::future::TryFutureExt;
use inotify::{Inotify, WatchMask}; use notify::{
use tokio::{sync::watch, task::JoinHandle}; watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher,
};
use tokio::{
sync::{mpsc, watch},
task::JoinHandle,
};
use xdg::BaseDirectories; use xdg::BaseDirectories;
use super::Config; use super::Config;
@ -16,33 +23,34 @@ pub type ConfigWatcher = watch::Receiver<Config>;
/// config update events. /// 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 (tx, rx) = stdmpsc::channel();
let mut dir_watcher = watcher(tx, Duration::from_secs(10))?;
let xdg = BaseDirectories::new()?; let xdg = BaseDirectories::new()?;
let config_home = xdg.get_config_home().join("panorama"); let config_home = xdg.get_config_home().join("panorama");
if !config_home.exists() { if !config_home.exists() {
fs::create_dir_all(&config_home)?; fs::create_dir_all(&config_home)?;
} }
inotify dir_watcher
.add_watch(&config_home, WatchMask::CLOSE_WRITE) .watch(&config_home, RecursiveMode::Recursive)
.context("adding watch for config home")?; .context("adding watch for config home")?;
debug!("watching {:?}", config_home); debug!("watching {:?}", config_home);
let (config_tx, config_update) = watch::channel(Config::default()); let (config_tx, config_update) = watch::channel(Config::default());
let handle = tokio::spawn( 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!()), .unwrap_or_else(|_err| todo!()),
); );
Ok((handle, config_update)) Ok((handle, config_update))
} }
async fn start_inotify_stream( async fn start_notify_stream(
mut inotify: Inotify, mut watcher: RecommendedWatcher,
rx: stdmpsc::Receiver<DebouncedEvent>,
config_home: impl AsRef<Path>, config_home: impl AsRef<Path>,
config_tx: watch::Sender<Config>, config_tx: watch::Sender<Config>,
) -> Result<()> { ) -> 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_home = config_home.as_ref().to_path_buf();
let config_path = config_home.join("panorama.toml"); let config_path = config_home.join("panorama.toml");
@ -53,33 +61,42 @@ async fn start_inotify_stream(
} }
debug!("listening for inotify events"); debug!("listening for inotify events");
while let Some(v) = event_stream.next().await { loop {
let event = v.context("event")?; let event = rx.recv()?;
debug!("inotify event: {:?}", event); debug!("notify event: {:?}", event);
if let Some(name) = event.name {
let path = PathBuf::from(name); match event {
let path_c = config_home DebouncedEvent::NoticeRemove(_)
.clone() | DebouncedEvent::NoticeWrite(_) => {
.join(path.clone()) // TODO: should this be handled somehow?
.canonicalize() // neovim sends these since it's writing to a temp buffer
.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); DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => {
let config = Config::from_file(path_c).await.context("read")?; let path_c = config_home
// debug!("sending config {:?}", config); .clone()
config_tx.send(config)?; .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(())
} }

View file

@ -9,7 +9,3 @@ extern crate derivative;
pub mod config; pub mod config;
pub mod mail; pub mod mail;
use sqlx::migrate::Migrator;
static MIGRATOR: Migrator = sqlx::migrate!();

View file

@ -11,12 +11,16 @@ use panorama_imap::{
response::{MailboxData, Response}, response::{MailboxData, Response},
}, },
}; };
use sqlx::migrate::Migrator;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
use crate::config::{ImapAuth, MailAccountConfig, TlsMethod}; 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 {} pub enum MailEvent {}
/// The main function for the IMAP syncing thread /// The main function for the IMAP syncing thread
@ -26,7 +30,9 @@ pub async fn sync_main(
_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();
debug!("Starting main synchronization procedure for {}", acct_name);
// loop ensures that the connection is retried after it dies // loop ensures that the connection is retried after it dies
loop { loop {
let client = ConfigBuilder::default() let client = ConfigBuilder::default()
@ -36,16 +42,22 @@ pub async fn sync_main(
.open() .open()
.await .await
.map_err(|err| anyhow!("err: {}", err))?; .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) { let unauth = if matches!(acct.imap.tls, TlsMethod::Starttls) {
debug!("attempting to upgrade"); debug!("attempting to upgrade");
let client = client.upgrade().await?; let client = client
.upgrade()
.await
.context("could not upgrade connection")?;
debug!("upgrade successful"); debug!("upgrade successful");
client client
} else { } else {
warn!("Continuing with unencrypted connection!");
client 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 {
@ -57,12 +69,14 @@ pub async fn sync_main(
unauth.auth(login).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);
@ -102,10 +116,12 @@ pub async fn sync_main(
} }
} }
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 // let's just select INBOX for now, maybe have a config for default
// mailbox later? // 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);
@ -127,8 +143,10 @@ pub async fn sync_main(
// attrs); 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
// TODO: check if IDLE is supported
let supports_idle = true; // 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 {
@ -136,6 +154,7 @@ pub async fn sync_main(
Some(v) => v, Some(v) => v,
None => break, None => break,
}; };
debug!("got an event: {:?}", evt); debug!("got an event: {:?}", evt);
match evt { match evt {
Response::MailboxData(MailboxData::Exists(uid)) => { Response::MailboxData(MailboxData::Exists(uid)) => {

View file

@ -1,7 +1,7 @@
use anyhow::Result; use anyhow::Result;
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
use crate::MIGRATOR; use super::MIGRATOR;
pub struct MailStore { pub struct MailStore {
pool: SqlitePool, pool: SqlitePool,

View file

@ -3,16 +3,23 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate futures; extern crate futures;
use anyhow::Result; use anyhow::{Context, Result};
use clap::Clap; use clap::Clap;
use futures::future::{ use futures::future::{
select, select,
Either::{Left, Right}, Either::{Left, Right},
FutureExt, 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 panorama_imap::client::ConfigBuilder;
use tokio::sync::oneshot; use tokio::{
fs::{self, OpenOptions},
sync::{mpsc, oneshot},
};
use xdg::BaseDirectories;
type ExitListener = oneshot::Receiver<()>; type ExitListener = oneshot::Receiver<()>;
@ -34,31 +41,68 @@ async fn main() -> Result<()> {
stderrlog::new() stderrlog::new()
.module(module_path!()) .module(module_path!())
.module("panorama_daemon")
.module("panorama_imap")
.verbosity(opt.verbose) .verbosity(opt.verbose)
.init() .init()
.unwrap(); .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 (_, mut config_watcher) = config::spawn_config_watcher_system()?;
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 loop {
// stop let (exit_tx, exit_rx) = oneshot::channel();
config_watcher.changed().await?; let new_config = config_watcher.borrow().clone();
let _ = exit_tx.send(()); 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<()> { 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(); let mut notify_mail_threads = Vec::new();
for (account_name, account) in config.mail_accounts { for (account_name, account) in config.mail_accounts {
let (exit_tx, exit_rx) = oneshot::channel(); 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); notify_mail_threads.push(exit_tx);
} }
@ -79,30 +123,59 @@ async fn run_single_mail_account(
account: MailAccountConfig, account: MailAccountConfig,
exit: ExitListener, exit: ExitListener,
) -> Result<()> { ) -> Result<()> {
debug!("connecting to account {}", account_name); debug!("run_single_mail_account({}, {:?})", account_name, account);
// 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?;
let mut exit = exit.fuse(); 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 { loop {
select! { 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 // we're being told to exit the loop
_ = exit => break, _ = exit => break,
} }

View file

@ -4,7 +4,7 @@ use std::sync::{
Arc, Arc,
}; };
use anyhow::Result; use anyhow::{Context, Result};
use futures::{ use futures::{
future::{self, FutureExt, TryFutureExt}, future::{self, FutureExt, TryFutureExt},
stream::StreamExt, stream::StreamExt,
@ -134,8 +134,17 @@ where
&mut self, &mut self,
cap: impl AsRef<str>, cap: impl AsRef<str>,
) -> Result<bool> { ) -> Result<bool> {
let cap_bytes = cap.as_ref().as_bytes().to_vec(); let mut cap_slice = cap.as_ref().as_bytes().to_vec();
let (_, cap) = parse_capability(Bytes::from(cap_bytes))?;
// 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 contains = {
let read = self.capabilities.read().await; let read = self.capabilities.read().await;
@ -145,10 +154,21 @@ where
std::mem::drop(read); std::mem::drop(read);
let cmd = self.execute(Command::Capability).await?; let cmd = self.execute(Command::Capability).await?;
let done = cmd.done().await?; let (done, res) = cmd.wait().await?;
todo!("done: {:?}", done);
// 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 // check that this capability exists
// if it doesn't exist, then it's not an IMAP4-compliant server // 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"); bail!("Server does not have the STARTTLS capability");
} }
// issue the STARTTLS command to the server // issue the STARTTLS command to the server
let resp = self.execute(Command::Starttls).await?; let resp = self
dbg!(resp.wait().await?); .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"); debug!("received OK from server");
// issue exit to the read loop and retrieve the read half // issue exit to the read loop and retrieve the read half
let _ = self.read_exit.send(()); 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 // issue exit to the write loop and retrieve the write half
let _ = self.write_exit.send(()); 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 // put the read half and write half back together
let stream = read_half.unsplit(write_half); 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<()> { pub async fn wait_for_greeting(&mut self) -> Result<()> {

View file

@ -62,6 +62,7 @@ pub enum Response {
impl DisplayBytes for Response { impl DisplayBytes for Response {
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> { fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
#[allow(unreachable_patterns)]
match self { match self {
Response::Capabilities(caps) => { Response::Capabilities(caps) => {
write_bytes!(w, b"CAPABILITY")?; write_bytes!(w, b"CAPABILITY")?;
@ -72,7 +73,7 @@ impl DisplayBytes for Response {
} }
Response::Continue(cont) => write_bytes!(w, b"+ {}\r\n", cont), Response::Continue(cont) => write_bytes!(w, b"+ {}\r\n", cont),
Response::Condition(cond) => write_bytes!(w, b"* {}\r\n", cond), 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::MailboxData(data) => write_bytes!(w, b"* {}\r\n", data),
Response::Fetch(n, attrs) => { Response::Fetch(n, attrs) => {
write_bytes!(w, b"{} FETCH (", n)?; write_bytes!(w, b"{} FETCH (", n)?;
@ -127,7 +128,7 @@ pub enum MessageAttribute {
} }
impl DisplayBytes for 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 { match self {
_ => todo!(), _ => todo!(),
} }
@ -245,7 +246,7 @@ pub enum UidSetMember {
Uid(u32), Uid(u32),
} }
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "fuzzing", derive(Arbitrary))] #[cfg_attr(feature = "fuzzing", derive(Arbitrary))]
pub enum Capability { pub enum Capability {
Imap4rev1, Imap4rev1,

View file

@ -9,7 +9,6 @@ license = "GPL-3.0-or-later"
categories = ["email"] categories = ["email"]
repository = "https://git.mzhang.io/michael/panorama" repository = "https://git.mzhang.io/michael/panorama"
readme = "README.md" readme = "README.md"
workspace = ".."
[dependencies] [dependencies]
anyhow = { version = "1.0.42", features = ["backtrace"] } anyhow = { version = "1.0.42", features = ["backtrace"] }

7
tui/Cargo.toml Normal file
View 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
View file

@ -0,0 +1 @@

3
tui/src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}