diff --git a/CHANGELOG.md b/CHANGELOG.md index 2704c89..1164458 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog - [Changelog](#changelog) + - [0.13.0](#0130) - [0.12.3](#0123) - [0.12.2](#0122) - [0.12.1](#0121) @@ -34,6 +35,21 @@ --- +## 0.13.0 + +Released on 03/03/2024 + +- Added CLI subcommands + - Changed `-t` to `theme` + - Changed `-u` to `update` + - Changed `-c` to `config` +- Introduced support for [WebDAV](https://www.rfc-editor.org/rfc/rfc4918) + - It is now possible also to connect directly to WebDAV server with the syntax `http(s)://username:password@google.com` +- Bugfix: + - [Issue 232](https://github.com/veeso/termscp/issues/232): AWS S3 wasn't working anymore due to rust-s3 outdate +- Dependencies: + - Added `remotefs-webdav 0.1.1` + ## 0.12.3 Released on 06/10/2023 diff --git a/Cargo.lock b/Cargo.lock index 47046b8..0da61f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,12 +29,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "ahash" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" - [[package]] name = "ahash" version = "0.7.6" @@ -70,12 +64,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anyhow" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" - [[package]] name = "argh" version = "0.1.10" @@ -206,7 +194,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -223,7 +211,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -234,19 +222,17 @@ checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "attohttpc" -version = "0.18.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072" +checksum = "0f77d243921b0979fbbd728dd2d5162e68ac8252976797c24eb5b3a6af9090dc" dependencies = [ - "http", + "http 0.2.9", "log", - "rustls 0.20.8", + "rustls", "serde", "serde_json", "url", - "webpki", - "webpki-roots", - "wildmatch", + "webpki-roots 0.25.4", ] [[package]] @@ -257,27 +243,28 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aws-creds" -version = "0.27.1" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460a75eac8f3cb7683e0a9a588a83c3ff039331ea7bfbfbfcecf1dacab276e11" +checksum = "390ad3b77f3e21e01a4a0355865853b681daf1988510b0b15e31c0c4ae7eb0f6" dependencies = [ - "anyhow", "attohttpc", - "dirs 4.0.0", + "home", + "log", + "quick-xml 0.30.0", "rust-ini", "serde", - "serde-xml-rs", - "serde_derive", + "thiserror", + "time 0.3.34", "url", ] [[package]] name = "aws-region" -version = "0.23.5" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10110ddbd800fb47e6bef95e88fc13495795d252f585272a4fa3ac4f5b2e0a4d" +checksum = "42fed2b9fca70f2908268d057a607f2a906f47edbf856ea8587de9038d264e22" dependencies = [ - "anyhow", + "thiserror", ] [[package]] @@ -315,9 +302,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block" @@ -389,9 +376,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytesize" @@ -399,6 +386,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38fcc2979eff34a4b84e1cf9a1e3da42a7d44b3b690a40cdcb23e3d556cfb2e5" +[[package]] +name = "bytestring" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +dependencies = [ + "bytes", +] + [[package]] name = "cassowary" version = "0.3.0" @@ -429,6 +425,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" + [[package]] name = "chrono" version = "0.4.26" @@ -475,6 +477,26 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-random" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "content_inspector" version = "0.2.4" @@ -552,6 +574,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.4.2", + "crossterm_winapi", + "libc", + "mio 0.8.8", + "parking_lot 0.12.1", + "signal-hook", + "signal-hook-mio", + "winapi 0.3.9", +] + [[package]] name = "crossterm_winapi" version = "0.9.1" @@ -561,6 +599,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -571,16 +615,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "ctor" version = "0.1.26" @@ -621,6 +655,16 @@ version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -669,22 +713,13 @@ dependencies = [ "subtle", ] -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys 0.3.7", -] - [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys 0.4.1", + "dirs-sys", ] [[package]] @@ -697,17 +732,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -733,11 +757,11 @@ dependencies = [ [[package]] name = "dlv-list" -version = "0.2.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" dependencies = [ - "rand", + "const-random", ] [[package]] @@ -789,7 +813,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -992,7 +1016,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -1063,7 +1087,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -1071,29 +1095,32 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.7", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash", ] [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1113,17 +1140,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", + "hmac", ] [[package]] @@ -1135,6 +1152,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -1157,6 +1183,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1164,7 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] @@ -1176,9 +1213,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -1191,7 +1228,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "httparse", "httpdate", @@ -1211,13 +1248,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", + "http 0.2.9", "hyper", - "rustls 0.21.3", + "rustls", "tokio", "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1263,12 +1313,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] @@ -1284,6 +1334,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "indoc" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" + [[package]] name = "inotify" version = "0.7.1" @@ -1358,6 +1414,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.8" @@ -1403,7 +1468,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff63c423c68ea6814b7da9e88ce585f793c87ddd9e78f646970891769c8235d4" dependencies = [ - "lazy-regex-proc_macros", + "lazy-regex-proc_macros 2.4.1", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" +dependencies = [ + "lazy-regex-proc_macros 3.1.0", "once_cell", "regex", ] @@ -1420,6 +1496,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "lazy-regex-proc_macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.52", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1515,7 +1603,7 @@ dependencies = [ "dirs-next", "objc-foundation", "objc_id", - "time 0.3.22", + "time 0.3.34", ] [[package]] @@ -1705,6 +1793,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nonempty" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "995defdca0a589acfdd1bd2e8e3b896b4d4f7675a31fd14c32611440c7f608e6" + [[package]] name = "notify" version = "4.0.17" @@ -1769,6 +1863,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -1920,7 +2020,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -1959,12 +2059,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" -version = "0.3.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" dependencies = [ "dlv-list", - "hashbrown 0.9.1", + "hashbrown 0.13.2", ] [[package]] @@ -2040,6 +2140,12 @@ dependencies = [ "windows-targets 0.48.1", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "path-slash" version = "0.1.5" @@ -2064,7 +2170,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bcafb8d680c0b6750c095fbd3c9263fc0b3c315e6055cd1867db038641c1757" dependencies = [ - "cfg_aliases", + "cfg_aliases 0.1.1", "lazy_static", "libc", "log", @@ -2118,6 +2224,12 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2143,14 +2255,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.12", ] [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2165,10 +2277,29 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.29" +name = "quick-xml" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2203,6 +2334,23 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ratatui" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2e4cd95294a85c3b4446e63ef054eea43e0205b1fd60120c16b74ff7ff96ad" +dependencies = [ + "bitflags 2.4.2", + "cassowary", + "crossterm 0.27.0", + "indoc", + "itertools", + "paste", + "strum", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2275,9 +2423,9 @@ dependencies = [ [[package]] name = "remotefs-aws-s3" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896bc1b45d85d017e632b79faf8f78eccf5ca6f372baf541977b9274a1446b05" +checksum = "ff8527f19059c3246d85fa8e81be1b720eeae28099d9e6debe6d7d214875c2aa" dependencies = [ "chrono", "log", @@ -2332,6 +2480,27 @@ dependencies = [ "users", ] +[[package]] +name = "remotefs-webdav" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88503e1cd53067ab639150625718bb8d88e6bcd1e165205de0d941beca66bde" +dependencies = [ + "bytes", + "bytestring", + "http 1.0.0", + "httpdate", + "indexmap 2.2.5", + "log", + "mime", + "nonempty", + "quick-xml 0.31.0", + "remotefs", + "rustydav", + "thiserror", + "time 0.3.34", +] + [[package]] name = "reqwest" version = "0.11.18" @@ -2344,30 +2513,33 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.9", "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.3", + "rustls", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.22.6", "winreg", ] @@ -2409,9 +2581,9 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" dependencies = [ "cfg-if 1.0.0", "ordered-multimap", @@ -2419,30 +2591,31 @@ dependencies = [ [[package]] name = "rust-s3" -version = "0.28.1" +version = "0.34.0-rc4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc0e521d1084d6950e050d4e2595f0fbdaa2b96bb795bab3d90a282288c5e49" +checksum = "0533896b025761b23147ca1a168c436e1b87d14e460b1f19a6442882d2a3e07f" dependencies = [ - "anyhow", "async-trait", "attohttpc", "aws-creds", "aws-region", - "base64 0.13.1", + "base64 0.21.2", + "bytes", "cfg-if 1.0.0", - "chrono", "hex", - "hmac 0.11.0", - "http", + "hmac", + "http 0.2.9", "log", "maybe-async", "md5", "percent-encoding", + "quick-xml 0.30.0", "serde", - "serde-xml-rs", "serde_derive", - "sha2 0.9.9", - "tokio-stream", + "serde_json", + "sha2 0.10.7", + "thiserror", + "time 0.3.34", "url", ] @@ -2466,18 +2639,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rustls" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.3" @@ -2509,6 +2670,21 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rustydav" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4c86c47126ac8bfc573084610e93f4ca8726f3ae7bf6c64bd60476731b6e42" +dependencies = [ + "reqwest", +] + [[package]] name = "ryu" version = "1.0.14" @@ -2602,7 +2778,7 @@ dependencies = [ "hyper", "indicatif", "log", - "quick-xml", + "quick-xml 0.23.1", "regex", "reqwest", "semver", @@ -2621,34 +2797,22 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.166" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-xml-rs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" -dependencies = [ - "log", - "serde", - "thiserror", - "xml-rs", -] - [[package]] name = "serde_derive" -version = "1.0.166" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -2670,14 +2834,14 @@ checksum = "1d89a8107374290037607734c0b73a85db7ed80cae314b3c5791f192a496e731" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -2696,9 +2860,9 @@ dependencies = [ [[package]] name = "serial_test" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d" dependencies = [ "dashmap", "futures", @@ -2710,13 +2874,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -2756,9 +2920,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -2792,7 +2956,7 @@ checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369" dependencies = [ "log", "termcolor", - "time 0.3.22", + "time 0.3.34", ] [[package]] @@ -2850,8 +3014,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e31d9bb8e97972d6541ccf32ed51294e4e16feeef06a0e77a6272d041f0f5bc7" dependencies = [ - "bitflags 2.3.3", - "dirs 5.0.1", + "bitflags 2.4.2", + "dirs", "thiserror", "wildmatch", ] @@ -2862,6 +3026,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.52", +] + [[package]] name = "subtle" version = "2.4.1" @@ -2875,7 +3061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c84c5cecf19018f5f85ca3f2c7e2c974dfe07e7e4a85cbea4330bb1e7c578df" dependencies = [ "chrono", - "lazy-regex", + "lazy-regex 2.5.0", "log", "native-tls", "thiserror", @@ -2894,9 +3080,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -2920,7 +3106,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f5bff1d532fead7c43324a0fa33643b8621a47ce2944a633be4cb6c0240898f" dependencies = [ - "quick-xml", + "quick-xml 0.23.1", "windows 0.39.0", ] @@ -2949,20 +3135,20 @@ dependencies = [ [[package]] name = "termscp" -version = "0.12.3" +version = "0.13.0" dependencies = [ "argh", - "bitflags 2.3.3", + "bitflags 2.4.2", "bytesize", - "cfg_aliases", + "cfg_aliases 0.2.0", "chrono", "content_inspector", - "dirs 5.0.1", + "dirs", "edit", "filetime", "hostname", "keyring", - "lazy-regex", + "lazy-regex 3.1.0", "lazy_static", "log", "magic-crypt", @@ -2976,6 +3162,7 @@ dependencies = [ "remotefs-ftp", "remotefs-smb", "remotefs-ssh", + "remotefs-webdav", "rpassword", "self_update", "serde", @@ -2996,9 +3183,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", @@ -3007,22 +3194,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.41" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.41" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -3049,13 +3236,16 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", "libc", + "num-conv", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -3063,19 +3253,29 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3108,24 +3308,23 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.3", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", + "rustls", "tokio", ] @@ -3145,21 +3344,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.6", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -3170,11 +3369,22 @@ version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.5", + "toml_datetime", + "winnow 0.4.7", +] + +[[package]] +name = "toml_edit" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +dependencies = [ + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.5", ] [[package]] @@ -3203,7 +3413,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", ] [[package]] @@ -3229,16 +3439,16 @@ checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" dependencies = [ "bitflags 1.3.2", "cassowary", - "crossterm", + "crossterm 0.25.0", "unicode-segmentation", "unicode-width", ] [[package]] name = "tui-realm-stdlib" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66f252bf8b07c6fd708ddd6349b5f044ae5b488b26929c745728d9c7e2cebfa6" +checksum = "a14fa5a0376ef64b93b484f811716b73422803df91c9ce7f83c50cc391230426" dependencies = [ "textwrap", "tuirealm", @@ -3247,13 +3457,14 @@ dependencies = [ [[package]] name = "tuirealm" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265411b5606f400459af94fbc5aae6a7bc0e98094d08cb5868390c932be88e26" +checksum = "412447298ad477c25ff50c4a894ff5077b6ee3e25b913d42db30021d81b1af53" dependencies = [ - "bitflags 1.3.2", - "crossterm", - "lazy-regex", + "bitflags 2.4.2", + "crossterm 0.27.0", + "lazy-regex 3.1.0", + "ratatui", "thiserror", "tui", "tuirealm_derive", @@ -3438,7 +3649,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -3472,7 +3683,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3512,6 +3723,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "which" version = "4.4.0" @@ -3622,6 +3839,15 @@ dependencies = [ "windows-targets 0.48.1", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -3652,6 +3878,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -3664,6 +3905,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.39.0" @@ -3682,6 +3929,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.39.0" @@ -3700,6 +3953,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.39.0" @@ -3718,6 +3977,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.39.0" @@ -3736,6 +4001,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -3748,6 +4019,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.39.0" @@ -3766,6 +4043,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winnow" version = "0.4.7" @@ -3775,6 +4058,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -3813,12 +4105,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "xml-rs" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336" - [[package]] name = "yansi" version = "0.5.1" @@ -3901,7 +4187,7 @@ dependencies = [ "crc32fast", "crossbeam-utils", "flate2", - "time 0.3.22", + "time 0.3.34", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index deb6509..7e67195 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ license = "MIT" name = "termscp" readme = "README.md" repository = "https://github.com/veeso/termscp" -version = "0.12.3" +version = "0.13.0" [package.metadata.rpm] package = "termscp" @@ -47,7 +47,7 @@ edit = "^0.1" filetime = "^0.2" hostname = "^0.3" keyring = { version = "^2.0", optional = true } -lazy-regex = "^2.5" +lazy-regex = "^3.1" lazy_static = "^1.4" log = "^0.4" magic-crypt = "^3.1" @@ -56,10 +56,11 @@ notify-rust = { version = "^4.5", default-features = false, features = ["d"] } open = "^5.0" rand = "^0.8.5" remotefs = "^0.2.0" -remotefs-aws-s3 = { version = "^0.2.1", default-features = false, features = [ +remotefs-aws-s3 = { version = "^0.2.4", default-features = false, features = [ "find", "rustls", ] } +remotefs-webdav = "^0.1.1" rpassword = "^7.0" self_update = { version = "^0.37", default-features = false, features = [ "rustls", @@ -73,9 +74,9 @@ simplelog = "^0.12" ssh2-config = "^0.2" tempfile = "^3.4" thiserror = "^1" -toml = "^0.7" -tui-realm-stdlib = "=1.2" -tuirealm = "=1.8.0" +toml = "^0.8" +tui-realm-stdlib = "^1.3.1" +tuirealm = "^1.9.1" unicode-width = "^0.1" version-compare = "^0.1" whoami = "^1.4" @@ -83,10 +84,10 @@ wildmatch = "^2.1" [dev-dependencies] pretty_assertions = "^1.3" -serial_test = "^2.0" +serial_test = "^3" [build-dependencies] -cfg_aliases = "0.1" +cfg_aliases = "0.2" [features] default = ["smb", "with-keyring"] diff --git a/README.md b/README.md index 01c1544..9fe5422 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # termscp

- + termscp logo

~ A feature rich terminal file transfer ~

@@ -63,7 +63,7 @@

Developed by @veeso

-

Current version: 0.12.3 (06/10/2023)

+

Current version: 0.13.0 (03/03/2024)

Repo stars

Entwickelt von @veeso

-

Aktuelle Version: 0.12.3 (06/10/2023)

+

Aktuelle Version: 0.13.0 (03/03/2024)

` if address is provided, password will be this argument - `-b, --address-as-bookmark` resolve address argument as a bookmark name -- `-c, --config` Open termscp starting from the configuration page - `-q, --quiet` Disable logging -- `-t, --theme ` Import specified theme -- `-u, --update` Update termscp to latest version - `-v, --version` Print version info - `-h, --help` Print help page @@ -131,6 +131,17 @@ Password can be basically provided through 3 ways when address argument is provi - Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc. + +### Subcommands + +#### Import a theme + +Run termscp as `termscp theme ` + +#### Install latest version + +Run termscp as `termscp update` + --- ## S3 connection parameters diff --git a/docs/es/README.md b/docs/es/README.md index 0c7d860..43f24c0 100644 --- a/docs/es/README.md +++ b/docs/es/README.md @@ -63,7 +63,7 @@

Desarrollado por @veeso

-

Versión actual: 0.12.3 (06/10/2023)

+

Versión actual: 0.13.0 (03/03/2024)

` si se proporciona la dirección, la contraseña será este argumento - `-b, --address-as-bookmark` resuelve el argumento de la dirección como un nombre de marcador -- `-c, --config` Abrir termscp comenzando desde la página de configuración - `-q, --quiet` Deshabilitar el registro -- `-t, --theme ` Importar tema especificado -- `-u, --update` Actualizar termscp a la última versión - `-v, --version` Imprimir información de la versión - `-h, --help` Imprimir página de ayuda @@ -106,6 +104,20 @@ por ejemplo s3://buckethead@eu-central-1:default:/assets ``` +#### Argumento de dirección de WebDAV + +En caso de que quieras conectarte a WebDAV utiliza la siguiente sintaxis + +```txt +http://:@ +``` + +o en caso de que quieras usar https + +```txt +https://:@ +``` + #### Argumento dirección por SMB SMB tiene una sintaxis diferente para el argumento de la dirección CLI, que es diferente si está en Windows u otros sistemas: diff --git a/docs/fr/README.md b/docs/fr/README.md index 6d85380..e1c5b6e 100644 --- a/docs/fr/README.md +++ b/docs/fr/README.md @@ -63,7 +63,7 @@

Développé par @veeso

-

Version actuelle: 0.12.3 (06/10/2023)

+

Version actuelle: 0.13.0 (03/03/2024)

` si l'adresse est fournie, le mot de passe sera cet argument - `-b, --address-as-bookmark` résoudre l'argument d'adresse en tant que nom de signet -- `-c, --config` Ouvrir termscp à partir de la page de configuration - `-q, --quiet` Désactiver la journalisation -- `-t, --theme ` Importer le thème spécifié -- `-u, --update` Mettre à jour termscp vers la dernière version - `-v, --version` Imprimer les informations sur la version - `-h, --help` Imprimer la page d'aide @@ -104,6 +102,20 @@ e.g. s3://buckethead@eu-central-1:default:/assets ``` +#### Argument d'adresse WebDAV + +Dans le cas où vous souhaitez vous connecter à WebDAV, utilisez la syntaxe suivante + +```txt +http://:@ +``` + +ou dans le cas où vous souhaitez utiliser https + +```txt +https://:@ +``` + #### Argument d'adresse SMB SMB a une syntaxe différente pour l'argument d'adresse CLI, qui est différente que vous soyez sur Windows ou sur d'autres systèmes : diff --git a/docs/it/README.md b/docs/it/README.md index 09c0bb5..9305a23 100644 --- a/docs/it/README.md +++ b/docs/it/README.md @@ -63,7 +63,7 @@

Sviluppato da @veeso

-

Versione corrente: 0.12.3 (06/10/2023)

+

Versione corrente: 0.13.0 (03/03/2024)

` Se viene fornito l'argomento indirizzo, questa sarà la password utilizzata per autenticarsi - `-b, --address-as-bookmark` risolve l'argomento indirizzo come nome di un segnalibro -- `-c, --config` Apri la configurazione di termscp - `-q, --quiet` Disabilita i log -- `-t, --theme ` Importa il tema al percorso fornito -- `-u, --update` Aggiorna termscp all'ultima versione - `-v, --version` Mostra a video le informazioni sulla versione attualmente installata - `-h, --help` Mostra la pagina di aiuto. @@ -102,6 +100,20 @@ e.g. s3://buckethead@eu-central-1:default:/assets ``` +#### Argomento indirizzo per WebDAV + +Nel caso in cui si desideri connettersi a WebDAV utilizzare la seguente sintassi + +```txt +http://:@ +``` + +oppure nel caso in cui si desideri utilizzare https + +```txt +https://:@ +``` + #### Indirizzo SMB SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base al sistema operativo: diff --git a/docs/man.md b/docs/man.md index 4059f3f..a3bb8dc 100644 --- a/docs/man.md +++ b/docs/man.md @@ -4,8 +4,12 @@ - [Usage ❓](#usage-) - [Address argument 🌎](#address-argument-) - [AWS S3 address argument](#aws-s3-address-argument) + - [WebDAV address argument](#webdav-address-argument) - [SMB address argument](#smb-address-argument) - [How Password can be provided 🔐](#how-password-can-be-provided-) + - [Subcommands](#subcommands) + - [Import a theme](#import-a-theme) + - [Install latest version](#install-latest-version) - [S3 connection parameters](#s3-connection-parameters) - [S3 credentials 🦊](#s3-credentials-) - [File explorer 📂](#file-explorer-) @@ -43,10 +47,7 @@ OR - `-P, --password ` if address is provided, password will be this argument - `-b, --address-as-bookmark` resolve address argument as a bookmark name -- `-c, --config` Open termscp starting from the configuration page - `-q, --quiet` Disable logging -- `-t, --theme ` Import specified theme -- `-u, --update` Update termscp to latest version - `-v, --version` Print version info - `-h, --help` Print help page @@ -104,6 +105,20 @@ e.g. s3://buckethead@eu-central-1:default:/assets ``` +#### WebDAV address argument + +In case you want to connect to webDAV use the following syntax + +```txt +http://:@ +``` + +or in case you want to use https + +```txt +https://:@ +``` + #### SMB address argument SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems: @@ -129,6 +144,16 @@ Password can be basically provided through 3 ways when address argument is provi - Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc. +### Subcommands + +#### Import a theme + +Run termscp as `termscp theme ` + +#### Install latest version + +Run termscp as `termscp update` + --- ## S3 connection parameters diff --git a/docs/zh-CN/README.md b/docs/zh-CN/README.md index 080a970..6ddd4af 100644 --- a/docs/zh-CN/README.md +++ b/docs/zh-CN/README.md @@ -63,7 +63,7 @@

@veeso 开发

-

当前版本: 0.12.3 (06/10/2023)

+

当前版本: 0.13.0 (03/03/2024)

` 登陆密码 - `-b, --address-as-bookmark` 将地址参数解析为书签名称 -- `-c, --config` 打开termscp时打开配置页面 - `-q, --quiet` 禁用日志 -- `-t, --theme ` 导入自定义主题 - `-v, --version` 打印版本信息 - `-h, --help` 打开帮助 @@ -103,6 +102,19 @@ s3://@[:profile][:/wrkdir] s3://buckethead@eu-central-1:default:/assets ``` +#### WebDAV 地址参数 + +如果您想要连接到 WebDAV,请使用以下语法 + +```txt +http://:@ +或者如果您想要使用 https +``` + +```txt +https://:@ +``` + #### SMB 地址参数 SMB 对 CLI 地址参数有不同的语法,无论您是在 Windows 还是其他系统上,这都是不同的: diff --git a/site/changelog.html b/site/changelog.html index 83bfc69..c7ce21d 100644 --- a/site/changelog.html +++ b/site/changelog.html @@ -3,7 +3,7 @@ - termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB | termscp + termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB/WebDAV | termscp diff --git a/site/html/get-started.html b/site/html/get-started.html index 91dfc50..fc31ba9 100644 --- a/site/html/get-started.html +++ b/site/html/get-started.html @@ -35,7 +35,7 @@ Consider that Chocolatey moderation can take up to a few weeks since last release, so if the latest version is not available yet, you can install it downloading the ZIP file from - Github and then, from the ZIP directory, install it via

@@ -75,7 +75,7 @@ On Debian based distros, you can install termscp using the Deb package via:

-
wget -O termscp.deb https://github.com/veeso/termscp/releases/latest/download/termscp_0.12.3_amd64.deb
+          
wget -O termscp.deb https://github.com/veeso/termscp/releases/latest/download/termscp_0.13.0_amd64.deb
 sudo dpkg -i termscp.deb

@@ -87,7 +87,7 @@ sudo dpkg -i termscp.deb -
wget -O termscp.rpm https://github.com/veeso/termscp/releases/latest/download/termscp-0.12.3-1.x86_64.rpm
+          
wget -O termscp.rpm https://github.com/veeso/termscp/releases/latest/download/termscp-0.13.0-1.x86_64.rpm
 sudo rpm -U termscp.rpm

diff --git a/site/html/home.html b/site/html/home.html index cd9f604..40b8066 100644 --- a/site/html/home.html +++ b/site/html/home.html @@ -1,17 +1,18 @@ -
+

termscp

logo

A feature rich terminal UI file transfer and explorer with support for - SCP/SFTP/FTP/S3/SMB + SCP/SFTP/FTP/S3/SMB/WebDAV

- termscp 0.12.3 is NOW out! Download it from  + termscp 0.13.0 is NOW out! Download it from  here!

@@ -66,7 +67,8 @@ diff --git a/site/index.html b/site/index.html index 8d3f333..a8bfb5b 100644 --- a/site/index.html +++ b/site/index.html @@ -3,13 +3,14 @@ - termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB | termscp + termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3/SMB/WebDAV | termscp + content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." /> - + content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/S3/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." /> + @@ -40,7 +41,7 @@
- +
diff --git a/site/lang/en.json b/site/lang/en.json index a2f19dd..898ec6f 100644 --- a/site/lang/en.json +++ b/site/lang/en.json @@ -12,7 +12,7 @@ "intro": { "caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3", "getStarted": "Get started →", - "versionAlert": "termscp 0.12.3 is NOW out! Download it from", + "versionAlert": "termscp 0.13.0 is NOW out! Download it from", "here": "here", "features": { "handy": { diff --git a/site/lang/es.json b/site/lang/es.json index 0d21cd9..aedbda3 100644 --- a/site/lang/es.json +++ b/site/lang/es.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/S3", "getStarted": "Para iniciar →", - "versionAlert": "termscp 0.12.3 ya está disponible! Descárgalo desde", + "versionAlert": "termscp 0.13.0 ya está disponible! Descárgalo desde", "here": "aquì", "features": { "handy": { diff --git a/site/lang/fr.json b/site/lang/fr.json index a6a4416..6a9327e 100644 --- a/site/lang/fr.json +++ b/site/lang/fr.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/S3", "getStarted": "Pour commencer →", - "versionAlert": "termscp 0.12.3 est maintenant sorti! Télécharge-le depuis", + "versionAlert": "termscp 0.13.0 est maintenant sorti! Télécharge-le depuis", "here": "ici", "features": { "handy": { diff --git a/site/lang/it.json b/site/lang/it.json index cca9105..d490c2c 100644 --- a/site/lang/it.json +++ b/site/lang/it.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3", "getStarted": "Installa termscp →", - "versionAlert": "termscp 0.12.3 è ORA disponbile! Scaricalo da", + "versionAlert": "termscp 0.13.0 è ORA disponbile! Scaricalo da", "here": "qui", "features": { "handy": { diff --git a/site/lang/zh-CN.json b/site/lang/zh-CN.json index 254bd0e..5a1b194 100644 --- a/site/lang/zh-CN.json +++ b/site/lang/zh-CN.json @@ -12,7 +12,7 @@ "intro": { "caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/S3", "getStarted": "开始 →", - "versionAlert": "termscp 0.12.3 现已发布! 从下载", + "versionAlert": "termscp 0.13.0 现已发布! 从下载", "here": "这里", "features": { "handy": { diff --git a/src/cli_opts.rs b/src/cli_opts.rs index 44c7f0e..fddba55 100644 --- a/src/cli_opts.rs +++ b/src/cli_opts.rs @@ -34,36 +34,25 @@ Address syntax can be: Please, report issues to Please, consider supporting the author ")] pub struct Args { - #[argh( - switch, - short = 'b', - description = "resolve address argument as a bookmark name" - )] + #[argh(subcommand)] + pub nested: Option, + /// resolve address argument as a bookmark name + #[argh(switch, short = 'b')] pub address_as_bookmark: bool, - #[argh(switch, short = 'c', description = "open termscp configuration")] - pub config: bool, - #[argh(switch, short = 'D', description = "enable TRACE log level")] + /// enable TRACE log level + #[argh(switch, short = 'D')] pub debug: bool, - #[argh(option, short = 'P', description = "provide password from CLI")] + /// provide password from CLI + #[argh(option, short = 'P')] pub password: Option, - #[argh(switch, short = 'q', description = "disable logging")] + /// disable logging + #[argh(switch, short = 'q')] pub quiet: bool, - #[argh(option, short = 't', description = "import specified theme")] - pub theme: Option, - #[argh( - switch, - short = 'u', - description = "update termscp to the latest version" - )] - pub update: bool, - #[argh( - option, - short = 'T', - default = "10", - description = "set UI ticks; default 10ms" - )] + /// set UI ticks; default 10ms + #[argh(option, short = 'T', default = "10")] pub ticks: u64, - #[argh(switch, short = 'v', description = "print version")] + /// print version + #[argh(switch, short = 'v')] pub version: bool, // -- positional #[argh( @@ -73,6 +62,33 @@ pub struct Args { pub positional: Vec, } +#[derive(FromArgs)] +#[argh(subcommand)] +pub enum ArgsSubcommands { + Config(ConfigArgs), + LoadTheme(LoadThemeArgs), + Update(UpdateArgs), +} + +#[derive(FromArgs)] +/// open termscp configuration +#[argh(subcommand, name = "config")] +pub struct ConfigArgs {} + +#[derive(FromArgs)] +/// import the specified theme +#[argh(subcommand, name = "update")] +pub struct UpdateArgs {} + +#[derive(FromArgs)] +/// import the specified theme +#[argh(subcommand, name = "theme")] +pub struct LoadThemeArgs { + #[argh(positional)] + /// theme file + pub theme: PathBuf, +} + pub struct RunOpts { pub remote: Remote, pub ticks: Duration, @@ -80,6 +96,29 @@ pub struct RunOpts { pub task: Task, } +impl RunOpts { + pub fn config() -> Self { + Self { + task: Task::Activity(NextActivity::SetupActivity), + ..Default::default() + } + } + + pub fn update() -> Self { + Self { + task: Task::InstallUpdate, + ..Default::default() + } + } + + pub fn import_theme(theme: PathBuf) -> Self { + Self { + task: Task::ImportTheme(theme), + ..Default::default() + } + } +} + impl Default for RunOpts { fn default() -> Self { Self { diff --git a/src/config/bookmarks.rs b/src/config/bookmarks.rs index 117c152..4e71e66 100644 --- a/src/config/bookmarks.rs +++ b/src/config/bookmarks.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::filetransfer::params::{ AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams as TransferSmbParams, + WebDAVProtocolParams, }; use crate::filetransfer::{FileTransferParams, FileTransferProtocol}; @@ -114,6 +115,17 @@ impl From for Bookmark { local_path, s3: None, }, + ProtocolParams::WebDAV(parms) => Self { + protocol, + address: Some(parms.uri), + port: None, + username: Some(parms.username), + password: Some(parms.password), + remote_path, + local_path, + s3: None, + smb: None, + }, } } } @@ -161,6 +173,14 @@ impl From for FileTransferParams { Self::new(bookmark.protocol, ProtocolParams::Smb(params)) } + FileTransferProtocol::WebDAV => Self::new( + FileTransferProtocol::WebDAV, + ProtocolParams::WebDAV(WebDAVProtocolParams { + uri: bookmark.address.unwrap_or_default(), + username: bookmark.username.unwrap_or_default(), + password: bookmark.password.unwrap_or_default(), + }), + ), } .remote_path(bookmark.remote_path) // Set entry remote_path .local_path(bookmark.local_path) // Set entry local path @@ -390,6 +410,35 @@ mod tests { assert_eq!(gparams.password.as_deref().unwrap(), "password"); } + #[test] + fn ftparams_from_webdav() { + let bookmark: Bookmark = Bookmark { + address: Some(String::from("192.168.1.1")), + port: None, + protocol: FileTransferProtocol::WebDAV, + username: Some(String::from("root")), + password: Some(String::from("password")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), + s3: None, + smb: None, + }; + let params = FileTransferParams::from(bookmark); + assert_eq!(params.protocol, FileTransferProtocol::WebDAV); + assert_eq!( + params.remote_path.as_deref().unwrap(), + std::path::Path::new("/tmp") + ); + assert_eq!( + params.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); + let gparams = params.params.webdav_params().unwrap(); + assert_eq!(gparams.uri.as_str(), "192.168.1.1"); + assert_eq!(gparams.username, "root"); + assert_eq!(gparams.password, "password"); + } + #[test] fn ftparams_from_s3_bookmark() { let bookmark: Bookmark = Bookmark { diff --git a/src/config/mod.rs b/src/config/mod.rs index f279682..bbd7a8b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,6 @@ //! `config` is the module which provides access to all the termscp configurations // export -pub use params::*; pub mod bookmarks; pub mod params; diff --git a/src/filetransfer/builder.rs b/src/filetransfer/builder.rs index ee0f190..5c04eef 100644 --- a/src/filetransfer/builder.rs +++ b/src/filetransfer/builder.rs @@ -12,7 +12,9 @@ use remotefs_smb::SmbOptions; #[cfg(smb)] use remotefs_smb::{SmbCredentials, SmbFs}; use remotefs_ssh::{ScpFs, SftpFs, SshConfigParseRule, SshOpts}; +use remotefs_webdav::WebDAVFs; +use super::params::WebDAVProtocolParams; #[cfg(not(smb))] use super::params::{AwsS3Params, GenericProtocolParams}; #[cfg(smb)] @@ -51,6 +53,9 @@ impl Builder { (FileTransferProtocol::Smb, ProtocolParams::Smb(params)) => { Box::new(Self::smb_client(params)) } + (FileTransferProtocol::WebDAV, ProtocolParams::WebDAV(params)) => { + Box::new(Self::webdav_client(params)) + } (protocol, params) => { error!("Invalid params for protocol '{:?}'", protocol); panic!("Invalid protocol '{protocol:?}' with parameters of type {params:?}") @@ -154,6 +159,10 @@ impl Builder { SmbFs::new(credentials) } + fn webdav_client(params: WebDAVProtocolParams) -> WebDAVFs { + WebDAVFs::new(¶ms.username, ¶ms.password, ¶ms.uri) + } + /// Build ssh options from generic protocol params and client configuration fn build_ssh_opts(params: GenericProtocolParams, config_client: &ConfigClient) -> SshOpts { let mut opts = SshOpts::new(params.address.clone()) diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index 28255fc..a9d6cd2 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -18,6 +18,7 @@ pub enum FileTransferProtocol { Scp, Sftp, Smb, + WebDAV, } // Traits @@ -33,6 +34,7 @@ impl std::string::ToString for FileTransferProtocol { FileTransferProtocol::Scp => "SCP", FileTransferProtocol::Sftp => "SFTP", FileTransferProtocol::Smb => "SMB", + FileTransferProtocol::WebDAV => "WEBDAV", }) } } @@ -47,6 +49,7 @@ impl std::str::FromStr for FileTransferProtocol { "SCP" => Ok(FileTransferProtocol::Scp), "SFTP" => Ok(FileTransferProtocol::Sftp), "SMB" => Ok(FileTransferProtocol::Smb), + "WEBDAV" | "HTTP" | "HTTPS" => Ok(FileTransferProtocol::WebDAV), _ => Err(s.to_string()), } } @@ -134,9 +137,17 @@ mod tests { FileTransferProtocol::Ftp(false).to_string(), String::from("FTP") ); + assert_eq!( + FileTransferProtocol::WebDAV.to_string(), + String::from("WEBDAV") + ); assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP")); assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP")); assert_eq!(FileTransferProtocol::AwsS3.to_string(), String::from("S3")); assert_eq!(FileTransferProtocol::Smb.to_string(), String::from("SMB")); + assert_eq!( + FileTransferProtocol::WebDAV.to_string(), + String::from("WEBDAV") + ); } } diff --git a/src/filetransfer/params.rs b/src/filetransfer/params.rs index 7471ef2..c87f915 100644 --- a/src/filetransfer/params.rs +++ b/src/filetransfer/params.rs @@ -21,6 +21,7 @@ pub enum ProtocolParams { Generic(GenericProtocolParams), AwsS3(AwsS3Params), Smb(SmbParams), + WebDAV(WebDAVProtocolParams), } /// Protocol params used by most common protocols @@ -89,6 +90,7 @@ impl FileTransferParams { ProtocolParams::AwsS3(params) => params.password_missing(), ProtocolParams::Generic(params) => params.password_missing(), ProtocolParams::Smb(params) => params.password_missing(), + ProtocolParams::WebDAV(params) => params.password_missing(), } } @@ -98,10 +100,29 @@ impl FileTransferParams { ProtocolParams::AwsS3(params) => params.set_default_secret(secret), ProtocolParams::Generic(params) => params.set_default_secret(secret), ProtocolParams::Smb(params) => params.set_default_secret(secret), + ProtocolParams::WebDAV(params) => params.set_default_secret(secret), } } } +/// Protocol params used by WebDAV +#[derive(Debug, Clone)] +pub struct WebDAVProtocolParams { + pub uri: String, + pub username: String, + pub password: String, +} + +impl WebDAVProtocolParams { + fn set_default_secret(&mut self, secret: String) { + self.password = secret; + } + + fn password_missing(&self) -> bool { + self.password.is_empty() + } +} + impl Default for FileTransferParams { fn default() -> Self { Self::new(FileTransferProtocol::Sftp, ProtocolParams::default()) @@ -149,6 +170,15 @@ impl ProtocolParams { _ => None, } } + + #[cfg(test)] + /// Retrieve WebDAV parameters if any + pub fn webdav_params(&self) -> Option<&WebDAVProtocolParams> { + match self { + ProtocolParams::WebDAV(params) => Some(params), + _ => None, + } + } } // -- Generic protocol params @@ -512,6 +542,40 @@ mod test { ); } + #[test] + #[cfg(unix)] + fn set_default_secret_smb() { + let mut params = FileTransferParams::new( + FileTransferProtocol::Scp, + ProtocolParams::Smb(SmbParams::new("localhost", "temp")), + ); + params.set_default_secret(String::from("secret")); + assert_eq!( + params + .params + .smb_params() + .unwrap() + .password + .as_deref() + .unwrap(), + "secret" + ); + } + + #[test] + fn set_default_secret_webdav() { + let mut params = FileTransferParams::new( + FileTransferProtocol::Scp, + ProtocolParams::WebDAV(WebDAVProtocolParams { + uri: "http://localhost".to_string(), + username: "user".to_string(), + password: "pass".to_string(), + }), + ); + params.set_default_secret(String::from("secret")); + assert_eq!(params.params.webdav_params().unwrap().password, "secret"); + } + #[test] fn set_default_secret_generic() { let mut params = diff --git a/src/host/mod.rs b/src/host/mod.rs index b0d45f1..4679cd6 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -1081,10 +1081,7 @@ mod tests { let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap(); let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap(); // Execute - #[cfg(unix)] - assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\n"); - #[cfg(windows)] - assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\r\n"); + assert!(host.exec("echo 5").ok().unwrap().as_str().contains("5")); } #[test] diff --git a/src/main.rs b/src/main.rs index 9b39251..9e1e839 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ mod utils; // namespaces use activity_manager::{ActivityManager, NextActivity}; -use cli_opts::{Args, BookmarkParams, HostParams, Remote, RunOpts, Task}; +use cli_opts::{Args, ArgsSubcommands, BookmarkParams, HostParams, Remote, RunOpts, Task}; use filetransfer::FileTransferParams; use system::logging::{self, LogLevel}; @@ -63,59 +63,57 @@ fn main() { /// In case of success returns `RunOpts` /// in case something is wrong returns the error message fn parse_args(args: Args) -> Result { - let mut run_opts: RunOpts = RunOpts::default(); - // Version - if args.version { - return Err(format!( - "termscp - {TERMSCP_VERSION} - Developed by {TERMSCP_AUTHORS}", - )); - } - // Setup activity? - if args.config { - run_opts.task = Task::Activity(NextActivity::SetupActivity); - } - // Logging - if args.debug { - run_opts.log_level = LogLevel::Trace; - } else if args.quiet { - run_opts.log_level = LogLevel::Off; - } - // Match ticks - run_opts.ticks = Duration::from_millis(args.ticks); - // @! extra modes - if let Some(theme) = args.theme.as_deref() { - run_opts.task = Task::ImportTheme(PathBuf::from(theme)); - } - if args.update { - run_opts.task = Task::InstallUpdate; - } - // @! Ordinary mode - // Remote argument - match parse_address_arg(&args) { - Err(err) => return Err(err), - Ok(Remote::None) => {} - Ok(remote) => { - // Set params - run_opts.remote = remote; - // In this case the first activity will be FileTransfer - run_opts.task = Task::Activity(NextActivity::FileTransfer); - } - } + let run_opts = match args.nested { + Some(ArgsSubcommands::Update(_)) => RunOpts::update(), + Some(ArgsSubcommands::LoadTheme(args)) => RunOpts::import_theme(args.theme), + Some(ArgsSubcommands::Config(_)) => RunOpts::config(), + None => { + let mut run_opts: RunOpts = RunOpts::default(); + // Version + if args.version { + return Err(format!( + "termscp - {TERMSCP_VERSION} - Developed by {TERMSCP_AUTHORS}", + )); + } + // Logging + if args.debug { + run_opts.log_level = LogLevel::Trace; + } else if args.quiet { + run_opts.log_level = LogLevel::Off; + } + // Match ticks + run_opts.ticks = Duration::from_millis(args.ticks); + // Remote argument + match parse_address_arg(&args) { + Err(err) => return Err(err), + Ok(Remote::None) => {} + Ok(remote) => { + // Set params + run_opts.remote = remote; + // In this case the first activity will be FileTransfer + run_opts.task = Task::Activity(NextActivity::FileTransfer); + } + } - // Local directory - if let Some(localdir) = args.positional.get(1) { - // Change working directory if local dir is set - let localdir: PathBuf = PathBuf::from(localdir); - if let Err(err) = env::set_current_dir(localdir.as_path()) { - return Err(format!("Bad working directory argument: {err}")); + // Local directory + if let Some(localdir) = args.positional.get(1) { + // Change working directory if local dir is set + let localdir: PathBuf = PathBuf::from(localdir); + if let Err(err) = env::set_current_dir(localdir.as_path()) { + return Err(format!("Bad working directory argument: {err}")); + } + } + + run_opts } - } + }; + Ok(run_opts) } /// Parse address argument from cli args fn parse_address_arg(args: &Args) -> Result { - if let Some(remote) = args.positional.get(0) { + if let Some(remote) = args.positional.first() { if args.address_as_bookmark { Ok(Remote::Bookmark(BookmarkParams::new( remote, @@ -197,5 +195,6 @@ fn run_activity(activity: NextActivity, ticks: Duration, remote: Remote) -> i32 Remote::None => {} } manager.run(activity); + 0 } diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 716f91f..7d79999 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -419,7 +419,7 @@ mod tests { use tempfile::TempDir; use super::*; - use crate::config::UserConfig; + use crate::config::params::UserConfig; use crate::utils::random::random_alphanumeric_with_len; #[test] diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index 60cf63d..477b378 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -48,7 +48,7 @@ impl SshKeyStorage { .query(host) .identity_file .as_ref() - .and_then(|x| x.get(0).cloned()); + .and_then(|x| x.first().cloned()); key }) diff --git a/src/ui/activities/auth/bookmarks.rs b/src/ui/activities/auth/bookmarks.rs index 7cb7e19..e970aa3 100644 --- a/src/ui/activities/auth/bookmarks.rs +++ b/src/ui/activities/auth/bookmarks.rs @@ -4,7 +4,9 @@ // Locals use super::{AuthActivity, FileTransferParams}; -use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams}; +use crate::filetransfer::params::{ + AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams, +}; impl AuthActivity { /// Delete bookmark @@ -164,6 +166,7 @@ impl AuthActivity { ProtocolParams::AwsS3(params) => self.load_bookmark_s3_into_gui(params), ProtocolParams::Generic(params) => self.load_bookmark_generic_into_gui(params), ProtocolParams::Smb(params) => self.load_bookmark_smb_into_gui(params), + ProtocolParams::WebDAV(params) => self.load_bookmark_webdav_into_gui(params), } } @@ -196,4 +199,10 @@ impl AuthActivity { #[cfg(unix)] self.mount_smb_workgroup(params.workgroup.as_deref().unwrap_or("")); } + + fn load_bookmark_webdav_into_gui(&mut self, params: WebDAVProtocolParams) { + self.mount_webdav_uri(¶ms.uri); + self.mount_username(¶ms.username); + self.mount_password(¶ms.password); + } } diff --git a/src/ui/activities/auth/components/form.rs b/src/ui/activities/auth/components/form.rs index d5590d5..5ffd349 100644 --- a/src/ui/activities/auth/components/form.rs +++ b/src/ui/activities/auth/components/form.rs @@ -11,7 +11,7 @@ use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue}; use super::{FileTransferProtocol, FormMsg, Msg, UiMsg}; use crate::ui::activities::auth::{ RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP, - RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, + RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV, }; // -- protocol @@ -31,9 +31,9 @@ impl ProtocolRadio { .modifiers(BorderType::Rounded), ) .choices(if cfg!(smb) { - &["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB"] + &["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV", "SMB"] } else { - &["SFTP", "SCP", "FTP", "FTPS", "S3"] + &["SFTP", "SCP", "FTP", "FTPS", "S3", "WebDAV"] }) .foreground(color) .rewind(true) @@ -50,6 +50,7 @@ impl ProtocolRadio { RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true), RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3, RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb, + RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV, _ => FileTransferProtocol::Sftp, } } @@ -63,6 +64,7 @@ impl ProtocolRadio { FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS, FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3, FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB, + FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV, } } } @@ -788,3 +790,40 @@ impl Component for InputSmbWorkgroup { ) } } + +#[derive(MockComponent)] +pub struct InputWebDAVUri { + component: Input, +} + +impl InputWebDAVUri { + pub fn new(host: &str, color: Color) -> Self { + Self { + component: Input::default() + .borders( + Borders::default() + .color(color) + .modifiers(BorderType::Rounded), + ) + .foreground(color) + .placeholder( + "http://localhost:8080", + Style::default().fg(Color::Rgb(128, 128, 128)), + ) + .title("HTTP url", Alignment::Left) + .input_type(InputType::Text) + .value(host), + } + } +} + +impl Component for InputWebDAVUri { + fn on(&mut self, ev: Event) -> Option { + handle_input_ev( + self, + ev, + Msg::Ui(UiMsg::WebDAVUriBlurDown), + Msg::Ui(UiMsg::WebDAVUriBlurUp), + ) + } +} diff --git a/src/ui/activities/auth/components/mod.rs b/src/ui/activities/auth/components/mod.rs index 313ae64..37139ca 100644 --- a/src/ui/activities/auth/components/mod.rs +++ b/src/ui/activities/auth/components/mod.rs @@ -19,7 +19,7 @@ pub use form::{ InputAddress, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory, InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region, InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare, - InputUsername, ProtocolRadio, RadioS3NewPathStyle, + InputUsername, InputWebDAVUri, ProtocolRadio, RadioS3NewPathStyle, }; pub use popup::{ ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup, diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index e54d706..35e8e5b 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -15,6 +15,7 @@ impl AuthActivity { FileTransferProtocol::Ftp(_) => 21, FileTransferProtocol::AwsS3 => 22, // Doesn't matter, since not used FileTransferProtocol::Smb => 445, + FileTransferProtocol::WebDAV => 80, // Doesn't matter, since not used } } @@ -41,6 +42,7 @@ impl AuthActivity { FileTransferProtocol::Ftp(_) | FileTransferProtocol::Scp | FileTransferProtocol::Sftp => self.collect_generic_host_params(self.protocol), + FileTransferProtocol::WebDAV => self.collect_webdav_host_params(), } } @@ -98,6 +100,19 @@ impl AuthActivity { }) } + pub(super) fn collect_webdav_host_params(&self) -> Result { + let params = self.get_webdav_params_input(); + if params.uri.is_empty() { + return Err("Invalid URI"); + } + Ok(FileTransferParams { + protocol: FileTransferProtocol::WebDAV, + params: ProtocolParams::WebDAV(params), + local_path: self.get_input_local_directory(), + remote_path: self.get_input_remote_directory(), + }) + } + // -- update install /// If enabled in configuration, check for updates from Github diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index 82227a6..7c24e83 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -29,7 +29,8 @@ const RADIO_PROTOCOL_SCP: usize = 1; const RADIO_PROTOCOL_FTP: usize = 2; const RADIO_PROTOCOL_FTPS: usize = 3; const RADIO_PROTOCOL_S3: usize = 4; -const RADIO_PROTOCOL_SMB: usize = 5; +const RADIO_PROTOCOL_WEBDAV: usize = 5; +const RADIO_PROTOCOL_SMB: usize = 6; // -- components #[derive(Debug, Eq, PartialEq, Clone, Hash)] @@ -71,6 +72,7 @@ pub enum Id { Title, Username, WaitPopup, + WebDAVUri, WindowSizeError, } @@ -155,6 +157,8 @@ pub enum UiMsg { ShowSaveBookmarkPopup, UsernameBlurDown, UsernameBlurUp, + WebDAVUriBlurDown, + WebDAVUriBlurUp, WindowResized, } @@ -164,6 +168,7 @@ enum InputMask { Generic, AwsS3, Smb, + WebDAV, } // Store keys @@ -240,6 +245,7 @@ impl AuthActivity { | FileTransferProtocol::Scp | FileTransferProtocol::Sftp => InputMask::Generic, FileTransferProtocol::Smb => InputMask::Smb, + FileTransferProtocol::WebDAV => InputMask::WebDAV, } } } diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index 10dfda3..eb02b0d 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -70,6 +70,7 @@ impl AuthActivity { InputMask::Generic => &Id::Password, InputMask::Smb => &Id::Password, InputMask::AwsS3 => &Id::S3Bucket, + InputMask::WebDAV => &Id::Password, }) .is_ok()); } @@ -82,6 +83,7 @@ impl AuthActivity { InputMask::Generic => &Id::Password, InputMask::Smb => &Id::Password, InputMask::AwsS3 => &Id::S3Bucket, + InputMask::WebDAV => &Id::Password, }) .is_ok()); } @@ -177,6 +179,7 @@ impl AuthActivity { #[cfg(windows)] InputMask::Smb => &Id::RemoteDirectory, InputMask::AwsS3 => panic!("this shouldn't happen (password on s3)"), + InputMask::WebDAV => &Id::RemoteDirectory, }) .is_ok()); } @@ -189,7 +192,8 @@ impl AuthActivity { .active(match self.input_mask() { InputMask::Generic => &Id::Username, InputMask::Smb => &Id::SmbShare, - InputMask::AwsS3 => panic!("this shouldn't happen (port on s3)"), + InputMask::AwsS3 | InputMask::WebDAV => + panic!("this shouldn't happen (port on s3)"), }) .is_ok()); } @@ -203,6 +207,7 @@ impl AuthActivity { InputMask::Generic => &Id::Address, InputMask::Smb => &Id::Address, InputMask::AwsS3 => &Id::S3Bucket, + InputMask::WebDAV => &Id::WebDAVUri, }) .is_ok()); } @@ -225,6 +230,7 @@ impl AuthActivity { #[cfg(windows)] InputMask::Smb => &Id::Password, InputMask::AwsS3 => &Id::S3NewPathStyle, + InputMask::WebDAV => &Id::Password, }) .is_ok()); } @@ -332,9 +338,16 @@ impl AuthActivity { InputMask::Generic => &Id::Port, InputMask::Smb => &Id::SmbShare, InputMask::AwsS3 => panic!("this shouldn't happen (username on s3)"), + InputMask::WebDAV => &Id::WebDAVUri, }) .is_ok()); } + UiMsg::WebDAVUriBlurDown => { + assert!(self.app.active(&Id::Username).is_ok()); + } + UiMsg::WebDAVUriBlurUp => { + assert!(self.app.active(&Id::Protocol).is_ok()); + } UiMsg::WindowResized => { self.redraw = true; } diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index 42b0dbd..a680606 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -12,7 +12,9 @@ use tuirealm::tui::widgets::Clear; use tuirealm::{State, StateValue, Sub, SubClause, SubEventClause}; use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask}; -use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams}; +use crate::filetransfer::params::{ + AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams, WebDAVProtocolParams, +}; use crate::filetransfer::FileTransferParams; use crate::utils::ui::{Popup, Size}; @@ -61,6 +63,7 @@ impl AuthActivity { self.mount_smb_share(""); #[cfg(unix)] self.mount_smb_workgroup(""); + self.mount_webdav_uri(""); // Version notice if let Some(version) = self .context() @@ -195,6 +198,18 @@ impl AuthActivity { ) .direction(Direction::Vertical) .split(auth_chunks[4]), + InputMask::WebDAV => Layout::default() + .constraints( + [ + Constraint::Length(3), // uri + Constraint::Length(3), // username + Constraint::Length(3), // password + Constraint::Length(3), // dir + ] + .as_ref(), + ) + .direction(Direction::Vertical) + .split(auth_chunks[4]), }; // Create bookmark chunks let bookmark_chunks = Layout::default() @@ -230,6 +245,13 @@ impl AuthActivity { self.app.view(&view_ids[2], f, input_mask[2]); self.app.view(&view_ids[3], f, input_mask[3]); } + InputMask::WebDAV => { + let view_ids = self.get_webdav_view(); + self.app.view(&view_ids[0], f, input_mask[0]); + self.app.view(&view_ids[1], f, input_mask[1]); + self.app.view(&view_ids[2], f, input_mask[2]); + self.app.view(&view_ids[3], f, input_mask[3]); + } } // Bookmark chunks self.app.view(&Id::BookmarksList, f, bookmark_chunks[0]); @@ -794,6 +816,18 @@ impl AuthActivity { .is_ok()); } + pub(super) fn mount_webdav_uri(&mut self, uri: &str) { + let addr_color = self.theme().auth_address; + assert!(self + .app + .remount( + Id::WebDAVUri, + Box::new(components::InputWebDAVUri::new(uri, addr_color)), + vec![] + ) + .is_ok()); + } + // -- query /// Collect input values from view @@ -860,6 +894,18 @@ impl AuthActivity { .password(password) } + pub(super) fn get_webdav_params_input(&self) -> WebDAVProtocolParams { + let uri: String = self.get_webdav_uri(); + let username = self.get_input_username().unwrap_or_default(); + let password = self.get_input_password().unwrap_or_default(); + + WebDAVProtocolParams { + uri, + username, + password, + } + } + pub(super) fn get_input_remote_directory(&self) -> Option { match self.app.state(&Id::RemoteDirectory) { Ok(State::One(StateValue::String(x))) if !x.is_empty() => { @@ -878,6 +924,13 @@ impl AuthActivity { } } + pub(super) fn get_webdav_uri(&self) -> String { + match self.app.state(&Id::WebDAVUri) { + Ok(State::One(StateValue::String(x))) => x, + _ => String::new(), + } + } + pub(super) fn get_input_addr(&self) -> String { match self.app.state(&Id::Address) { Ok(State::One(StateValue::String(x))) => x, @@ -1011,6 +1064,7 @@ impl AuthActivity { InputMask::AwsS3 => 12, InputMask::Generic => 12, InputMask::Smb => 12, + InputMask::WebDAV => 12, } } @@ -1069,6 +1123,7 @@ impl AuthActivity { }; format!("\\\\{username}{}\\{}", params.address, params.share) } + ProtocolParams::WebDAV(params) => params.uri, } } @@ -1180,6 +1235,23 @@ impl AuthActivity { } } + fn get_webdav_view(&self) -> [Id; 4] { + match self.app.focus() { + Some(&Id::LocalDirectory) => [ + Id::Username, + Id::Password, + Id::RemoteDirectory, + Id::LocalDirectory, + ], + _ => [ + Id::WebDAVUri, + Id::Username, + Id::Password, + Id::RemoteDirectory, + ], + } + } + fn init_global_listener(&mut self) { use tuirealm::event::{Key, KeyEvent, KeyModifiers}; assert!(self diff --git a/src/ui/activities/filetransfer/components/transfer/file_list.rs b/src/ui/activities/filetransfer/components/transfer/file_list.rs index d17cc2d..011d9e1 100644 --- a/src/ui/activities/filetransfer/components/transfer/file_list.rs +++ b/src/ui/activities/filetransfer/components/transfer/file_list.rs @@ -7,7 +7,7 @@ use tuirealm::props::{ Alignment, AttrValue, Attribute, Borders, Color, Style, Table, TextModifiers, }; use tuirealm::tui::layout::Corner; -use tuirealm::tui::text::{Span, Spans}; +use tuirealm::tui::text::{Line, Span}; use tuirealm::tui::widgets::{List as TuiList, ListItem, ListState}; use tuirealm::{MockComponent, Props, State, StateValue}; @@ -211,7 +211,7 @@ impl MockComponent for FileList { ) }) .collect(); - ListItem::new(Spans::from(columns)) + ListItem::new(Line::from(columns)) }) .collect(), // Make List item from TextSpan _ => Vec::new(), @@ -245,7 +245,7 @@ impl MockComponent for FileList { if matches!(attr, Attribute::Content) { self.states.init_list_states( match self.props.get(Attribute::Content).map(|x| x.unwrap_table()) { - Some(spans) => spans.len(), + Some(line) => line.len(), _ => 0, }, ); diff --git a/src/ui/activities/filetransfer/misc.rs b/src/ui/activities/filetransfer/misc.rs index 2035c8f..8505019 100644 --- a/src/ui/activities/filetransfer/misc.rs +++ b/src/ui/activities/filetransfer/misc.rs @@ -112,6 +112,7 @@ impl FileTransferActivity { ProtocolParams::Generic(params) => params.address.clone(), ProtocolParams::AwsS3(params) => params.bucket_name.clone(), ProtocolParams::Smb(params) => params.address.clone(), + ProtocolParams::WebDAV(params) => params.uri.clone(), } } @@ -141,6 +142,13 @@ impl FileTransferActivity { ); format!("Connecting to \\\\{}\\{}…", params.address, params.share) } + ProtocolParams::WebDAV(params) => { + info!( + "Client is not connected to remote; connecting to {}", + params.uri + ); + format!("Connecting to {}…", params.uri) + } } } diff --git a/src/ui/activities/setup/components/config.rs b/src/ui/activities/setup/components/config.rs index afebffc..525f4dc 100644 --- a/src/ui/activities/setup/components/config.rs +++ b/src/ui/activities/setup/components/config.rs @@ -13,7 +13,7 @@ use crate::explorer::GroupDirs as GroupDirsEnum; use crate::filetransfer::FileTransferProtocol; use crate::ui::activities::setup::{ RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP, - RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, + RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, RADIO_PROTOCOL_WEBDAV, }; use crate::utils::parser::parse_bytesize; @@ -67,7 +67,7 @@ impl DefaultProtocol { .color(Color::Cyan) .modifiers(BorderType::Rounded), ) - .choices(&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB"]) + .choices(&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB", "WebDAV"]) .foreground(Color::Cyan) .rewind(true) .title("Default protocol", Alignment::Left) @@ -78,6 +78,7 @@ impl DefaultProtocol { FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS, FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3, FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB, + FileTransferProtocol::WebDAV => RADIO_PROTOCOL_WEBDAV, }), } } diff --git a/src/ui/activities/setup/mod.rs b/src/ui/activities/setup/mod.rs index 9448070..86c960d 100644 --- a/src/ui/activities/setup/mod.rs +++ b/src/ui/activities/setup/mod.rs @@ -31,6 +31,7 @@ const RADIO_PROTOCOL_FTP: usize = 2; const RADIO_PROTOCOL_FTPS: usize = 3; const RADIO_PROTOCOL_S3: usize = 4; const RADIO_PROTOCOL_SMB: usize = 5; +const RADIO_PROTOCOL_WEBDAV: usize = 6; // -- components #[derive(Debug, Eq, PartialEq, Clone, Hash)] diff --git a/src/ui/activities/setup/view/mod.rs b/src/ui/activities/setup/view/mod.rs index 1e9b174..2cd56bb 100644 --- a/src/ui/activities/setup/view/mod.rs +++ b/src/ui/activities/setup/view/mod.rs @@ -7,9 +7,6 @@ pub mod setup; pub mod ssh_keys; pub mod theme; -pub use setup::*; -pub use ssh_keys::*; -pub use theme::*; use tuirealm::event::{Key, KeyEvent, KeyModifiers}; use tuirealm::tui::widgets::Clear; use tuirealm::{Frame, Sub, SubClause, SubEventClause}; diff --git a/src/ui/activities/setup/view/setup.rs b/src/ui/activities/setup/view/setup.rs index f218dd4..a264943 100644 --- a/src/ui/activities/setup/view/setup.rs +++ b/src/ui/activities/setup/view/setup.rs @@ -10,7 +10,9 @@ use std::path::PathBuf; use tuirealm::tui::layout::{Constraint, Direction, Layout}; use tuirealm::{State, StateValue}; -use super::{components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout}; +use super::{ + components, Context, Id, IdCommon, IdConfig, SetupActivity, ViewLayout, RADIO_PROTOCOL_WEBDAV, +}; use crate::explorer::GroupDirs; use crate::filetransfer::FileTransferProtocol; use crate::ui::activities::setup::{ @@ -277,6 +279,7 @@ impl SetupActivity { RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true), RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3, RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb, + RADIO_PROTOCOL_WEBDAV => FileTransferProtocol::WebDAV, _ => FileTransferProtocol::Sftp, }; self.config_mut().set_default_protocol(protocol); diff --git a/src/utils/parser.rs b/src/utils/parser.rs index e3ec11e..83cbac9 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -14,7 +14,9 @@ use tuirealm::utils::parser as tuirealm_parser; #[cfg(smb)] use crate::filetransfer::params::SmbParams; -use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams}; +use crate::filetransfer::params::{ + AwsS3Params, GenericProtocolParams, ProtocolParams, WebDAVProtocolParams, +}; use crate::filetransfer::{FileTransferParams, FileTransferProtocol}; #[cfg(not(test))] // NOTE: don't use configuration during tests use crate::system::config_client::ConfigClient; @@ -43,6 +45,16 @@ static REMOTE_GENERIC_OPT_REGEX: Lazy = lazy_regex!( r"(?:([^@]+)@)?(?:([^:]+))(?::((?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])))?(?::([^:]+))?" ); +/** + * Regex matches: + * - group 1: Username + * - group 2: Password + * - group 2: Uri + * - group 4: Some(path) | None + */ +static REMOTE_WEBDAV_OPT_REGEX: Lazy = + lazy_regex!(r"(?:([^:]+):)(?:([^@]+)@)(?:([^/]+))(?:/(.+))?"); + /** * Regex matches: * - group 1: Bucket @@ -145,14 +157,24 @@ pub fn parse_remote_opt(s: &str) -> Result { #[cfg(test)] // NOTE: during test set protocol just to Sftp let default_protocol: FileTransferProtocol = FileTransferProtocol::Sftp; // Get protocol - let (protocol, s): (FileTransferProtocol, String) = + let (protocol, remote): (FileTransferProtocol, String) = parse_remote_opt_protocol(s, default_protocol)?; // Match against regex for protocol type match protocol { - FileTransferProtocol::AwsS3 => parse_s3_remote_opt(s.as_str()), + FileTransferProtocol::AwsS3 => parse_s3_remote_opt(remote.as_str()), #[cfg(smb)] - FileTransferProtocol::Smb => parse_smb_remote_opts(s.as_str()), - protocol => parse_generic_remote_opt(s.as_str(), protocol), + FileTransferProtocol::Smb => parse_smb_remote_opts(remote.as_str()), + FileTransferProtocol::WebDAV => { + // get the differnece between s and remote + let prefix = if s.starts_with("https") { + "https" + } else { + "http" + }; + + parse_webdav_remote_opt(remote.as_str(), prefix) + } + protocol => parse_generic_remote_opt(remote.as_str(), protocol), } } @@ -232,6 +254,29 @@ fn parse_generic_remote_opt( } } +fn parse_webdav_remote_opt(s: &str, prefix: &str) -> Result { + match REMOTE_WEBDAV_OPT_REGEX.captures(s) { + Some(groups) => { + let username = groups.get(1).map(|x| x.as_str().to_string()).unwrap(); + let password = groups.get(2).map(|x| x.as_str().to_string()).unwrap(); + let uri = groups.get(3).map(|x| x.as_str().to_string()).unwrap(); + let remote_path: Option = + groups.get(4).map(|group| PathBuf::from(group.as_str())); + + let params = ProtocolParams::WebDAV(WebDAVProtocolParams { + uri: format!("{}://{}", prefix, uri), + username, + password, + }); + Ok( + FileTransferParams::new(FileTransferProtocol::WebDAV, params) + .remote_path(remote_path), + ) + } + None => Err(String::from("Bad remote host syntax!")), + } +} + /// Parse remote options for s3 protocol fn parse_s3_remote_opt(s: &str) -> Result { match REMOTE_S3_OPT_REGEX.captures(s) { @@ -553,6 +598,25 @@ mod tests { assert!(parse_remote_opt(&String::from("scp://172.26.104.1:650000")).is_err()); } + #[test] + fn test_should_parse_webdav_opt() { + let result = + parse_remote_opt("https://omar:password@myserver:4445/myshare/dir/subdir").unwrap(); + + let params = result.params.webdav_params().unwrap(); + assert_eq!(params.uri.as_str(), "https://myserver:4445"); + assert_eq!(params.username.as_str(), "omar"); + assert_eq!(params.password.as_str(), "password"); + + let result = + parse_remote_opt("http://omar:password@myserver:4445/myshare/dir/subdir").unwrap(); + + let params = result.params.webdav_params().unwrap(); + assert_eq!(params.uri.as_str(), "http://myserver:4445"); + assert_eq!(params.username.as_str(), "omar"); + assert_eq!(params.password.as_str(), "password"); + } + #[test] fn parse_aws_s3_opt() { // Simple diff --git a/src/utils/path.rs b/src/utils/path.rs index f121833..ea90e73 100644 --- a/src/utils/path.rs +++ b/src/utils/path.rs @@ -60,8 +60,8 @@ where } (None, _) => comps.push(Component::ParentDir), (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == Component::CurDir => comps.push(a), - (Some(_), Some(b)) if b == Component::ParentDir => return None, + (Some(a), Some(Component::CurDir)) => comps.push(a), + (Some(_), Some(Component::ParentDir)) => return None, (Some(a), Some(_)) => { comps.push(Component::ParentDir); for _ in itb { diff --git a/src/utils/ui.rs b/src/utils/ui.rs index 3791c8e..f92e43a 100644 --- a/src/utils/ui.rs +++ b/src/utils/ui.rs @@ -67,7 +67,7 @@ mod tests { let child: Rect = Popup(Size::Percentage(75), Size::Percentage(30)).draw_in(area); assert_eq!(child.x, 43); assert_eq!(child.y, 63); - assert_eq!(child.width, 271); - assert_eq!(child.height, 54); + assert_eq!(child.width, 272); + assert_eq!(child.height, 55); } }