From 7202b19d453d714130e7486563cab1489db2db30 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 22 Dec 2020 17:14:44 +0100 Subject: [PATCH 01/64] Working on 0.3.0 --- CHANGELOG.md | 5 +++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d3f22..d7a3e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog - [Changelog](#changelog) + - [0.3.0](#030) - [0.2.0](#020) - [0.1.3](#013) - [0.1.2](#012) @@ -9,6 +10,10 @@ --- +## 0.3.0 + +FIXME: Released on + ## 0.2.0 Released on 21/12/2020 diff --git a/Cargo.lock b/Cargo.lock index 9718481..3e76a2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1029,7 +1029,7 @@ dependencies = [ [[package]] name = "termscp" -version = "0.2.0" +version = "0.3.0" dependencies = [ "bytesize", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 1d3601a..c0ae1a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "termscp" -version = "0.2.0" +version = "0.3.0" authors = ["Christian Visintin"] edition = "2018" license = "GPL-3.0" From b5abe4538f3c7828818ce1a6270e24473dc20b4d Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 22 Dec 2020 17:23:16 +0100 Subject: [PATCH 02/64] Replaced sha256 sum with last modification time check, to verify if a file has been changed in the text editor --- CHANGELOG.md | 3 + Cargo.lock | 41 ---------- Cargo.toml | 5 -- README.md | 2 +- .../filetransfer_activity/session.rs | 29 +++---- src/utils/hash.rs | 75 ------------------- src/utils/mod.rs | 1 - 7 files changed, 19 insertions(+), 137 deletions(-) delete mode 100644 src/utils/hash.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a3e42..56c0f21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ FIXME: Released on +- Enhancements: + - Replaced sha256 sum with last modification time check, to verify if a file has been changed in the text editor + ## 0.2.0 Released on 21/12/2020 diff --git a/Cargo.lock b/Cargo.lock index 3e76a2e..f0da32c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,12 +272,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "data-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908" - [[package]] name = "debug-helper" version = "0.3.10" @@ -622,12 +616,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "once_cell" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" - [[package]] name = "opaque-debug" version = "0.3.0" @@ -831,21 +819,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ring" -version = "0.16.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - [[package]] name = "rpassword" version = "5.0.0" @@ -984,12 +957,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "ssh2" version = "0.9.0" @@ -1035,7 +1002,6 @@ dependencies = [ "chrono", "content_inspector", "crossterm", - "data-encoding", "dirs", "edit", "ftp4", @@ -1045,7 +1011,6 @@ dependencies = [ "magic-crypt", "rand", "regex", - "ring", "rpassword", "serde", "ssh2", @@ -1145,12 +1110,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "users" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index c0ae1a1..ab67057 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,15 +37,10 @@ toml = "0.5.7" tui = { version = "0.13.0", features = ["crossterm"], default-features = false } unicode-width = "0.1.7" whoami = "1.0.0" -ring = "0.16.19" -data-encoding = "2.3.1" [target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies] users = "0.11.0" -#[patch.crates-io] -#ftp = { git = "https://github.com/ChristianVisintin/rust-ftp" } - [[bin]] name = "termscp" path = "src/main.rs" diff --git a/README.md b/README.md index f053973..ec488da 100644 --- a/README.md +++ b/README.md @@ -228,7 +228,7 @@ As said before, bookmarks are saved in your configuration directory along with p ## Text Editor โœ TermSCP has, as you might have noticed, many features, one of these is the possibility to view and edit text file. It doesn't matter if the file is located on the local host or on the remote host, termscp provides the possibility to open a file in your favourite text editor. -In case the file is located on remote host, the file will be first downloaded into your temporary file directory and then, **only** if changes were made to the file, re-uploaded to the remote host. TermSCP checks if you made changes to the file calculating the digest of the file using `sha256`. +In case the file is located on remote host, the file will be first downloaded into your temporary file directory and then, **only** if changes were made to the file, re-uploaded to the remote host. TermSCP checks if you made changes to the file verifying the last modification time of the file. Just a reminder: **you can edit only textual file**; binary files are not supported. diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index 7f7263a..e090f06 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -29,7 +29,6 @@ extern crate tempfile; use super::{FileTransferActivity, InputMode, LogLevel, PopupType}; use crate::fs::{FsEntry, FsFile}; use crate::utils::fmt::fmt_millis; -use crate::utils::hash::hash_sha256_file; // Ext use bytesize::ByteSize; @@ -37,7 +36,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use std::fs::OpenOptions; use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; -use std::time::Instant; +use std::time::{Instant, SystemTime}; use tui::style::Color; impl FileTransferActivity { @@ -781,13 +780,14 @@ impl FileTransferActivity { if let Err(err) = self.filetransfer_recv_file(tmpfile.path(), file) { return Err(err); } - // Get current file hash - let prev_hash: String = match hash_sha256_file(tmpfile.path()) { - Ok(s) => s, + // Get current file modification time + let prev_mtime: SystemTime = match self.context.as_ref().unwrap().local.stat(tmpfile.path()) + { + Ok(e) => e.get_last_change_time(), Err(err) => { return Err(format!( - "Could not get sha256 for \"{}\": {}", - file.abs_path.display(), + "Could not stat \"{}\": {}", + tmpfile.path().display(), err )) } @@ -796,19 +796,20 @@ impl FileTransferActivity { if let Err(err) = self.edit_local_file(tmpfile.path()) { return Err(err); } - // Check if file has changed - let new_hash: String = match hash_sha256_file(tmpfile.path()) { - Ok(s) => s, + // Get local fs entry + let tmpfile_entry: FsEntry = match self.context.as_ref().unwrap().local.stat(tmpfile.path()) + { + Ok(e) => e, Err(err) => { return Err(format!( - "Could not get sha256 for \"{}\": {}", - file.abs_path.display(), + "Could not stat \"{}\": {}", + tmpfile.path().display(), err )) } }; - // If hash is different, write changes - match new_hash != prev_hash { + // Check if file has changed + match prev_mtime != tmpfile_entry.get_last_change_time() { true => { self.log( LogLevel::Info, diff --git a/src/utils/hash.rs b/src/utils/hash.rs deleted file mode 100644 index ea87645..0000000 --- a/src/utils/hash.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! ## Hash -//! -//! `hash` is the module which provides utilities for calculating digests - -/* -* -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com -* -* This file is part of "TermSCP" -* -* TermSCP is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* TermSCP is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with TermSCP. If not, see . -* -*/ - -extern crate data_encoding; -extern crate ring; - -use data_encoding::HEXLOWER; -use ring::digest::{Context, Digest, SHA256}; -use std::fs::File; -use std::io::Read; -use std::path::Path; - -/// ### hash_sha256_file -/// -/// Get SHA256 of provided path -pub fn hash_sha256_file(file: &Path) -> Result { - // Open file - let mut reader: File = File::open(file)?; - let mut context = Context::new(&SHA256); - let mut buffer = [0; 8192]; - loop { - let count = reader.read(&mut buffer)?; - if count == 0 { - break; - } - context.update(&buffer[..count]); - } - // Finish context - let digest: Digest = context.finish(); - Ok(HEXLOWER.encode(digest.as_ref())) -} - -#[cfg(test)] -mod tests { - - use super::*; - - use std::io::Write; - - #[test] - fn test_utils_hash_sha256() { - let tmp: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); - // Write - let mut fhnd: File = File::create(tmp.path()).unwrap(); - assert!(fhnd.write_all(b"Hello world!\n").is_ok()); - assert_eq!( - *hash_sha256_file(tmp.path()).ok().as_ref().unwrap(), - String::from("0ba904eae8773b70c75333db4de2f3ac45a8ad4ddba1b242f0b3cfc199391dd8") - ); - // Bad file - assert!(hash_sha256_file(Path::new("/tmp/oiojjt5ig/aiehgoiwg")).is_err()); - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 7c02112..5a3dd3f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -25,5 +25,4 @@ // modules pub mod fmt; -pub mod hash; pub mod parser; From e761a908268a02ace46a19bd43b247c1f474db47 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 22 Dec 2020 17:34:52 +0100 Subject: [PATCH 03/64] Crypto as utility module --- src/system/bookmarks_client.rs | 9 ++--- src/utils/crypto.rs | 62 ++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 1 + 3 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/utils/crypto.rs diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 00803f0..4119ac4 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -24,16 +24,15 @@ */ // Deps -extern crate magic_crypt; extern crate rand; // Local use crate::bookmarks::serializer::BookmarkSerializer; use crate::bookmarks::{Bookmark, SerializerError, SerializerErrorKind, UserHosts}; use crate::filetransfer::FileTransferProtocol; +use crate::utils::crypto; use crate::utils::fmt::fmt_time; // Ext -use magic_crypt::MagicCryptTrait; use rand::{distributions::Alphanumeric, Rng}; use std::fs::{OpenOptions, Permissions}; use std::io::{Read, Write}; @@ -373,16 +372,14 @@ impl BookmarksClient { /// /// Encrypt provided string using AES-128. Encrypted buffer is then converted to BASE64 fn encrypt_str(&self, txt: &str) -> String { - let crypter = new_magic_crypt!(self.key.clone(), 128); - crypter.encrypt_str_to_base64(txt.to_string()) + crypto::aes128_b64_crypt(self.key.as_str(), txt) } /// ### decrypt_str /// /// Decrypt provided string using AES-128 fn decrypt_str(&self, secret: &str) -> Result { - let crypter = new_magic_crypt!(self.key.clone(), 128); - match crypter.decrypt_base64_to_string(secret.to_string()) { + match crypto::aes128_b64_decrypt(self.key.as_str(), secret) { Ok(txt) => Ok(txt), Err(err) => Err(SerializerError::new_ex( SerializerErrorKind::SyntaxError, diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs new file mode 100644 index 0000000..defb1de --- /dev/null +++ b/src/utils/crypto.rs @@ -0,0 +1,62 @@ +//! ## Crypto +//! +//! `crypto` is the module which provides utilities for crypting + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Deps +extern crate magic_crypt; + +// Ext +use magic_crypt::MagicCryptTrait; + +/// ### aes128_b64_crypt +/// +/// Crypt a string using AES128; output is returned as a BASE64 string +pub fn aes128_b64_crypt(key: &str, input: &str) -> String { + let crypter = new_magic_crypt!(key.to_string(), 128); + crypter.encrypt_str_to_base64(input.to_string()) +} + +/// ### aes128_b64_decrypt +/// +/// Decrypt a string using AES128 +pub fn aes128_b64_decrypt(key: &str, secret: &str) -> Result { + let crypter = new_magic_crypt!(key.to_string(), 128); + crypter.decrypt_base64_to_string(secret.to_string()) +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_utils_crypto_aes128() { + let key: &str = "MYSUPERSECRETKEY"; + let input: &str = "Hello world!"; + let secret: String = aes128_b64_crypt(&key, input); + assert_eq!(secret.as_str(), "z4Z6LpcpYqBW4+bkIok+5A=="); + assert_eq!(aes128_b64_decrypt(key, secret.as_str()).ok().unwrap().as_str(), input); + } + +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5a3dd3f..1162e25 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -24,5 +24,6 @@ */ // modules +pub mod crypto; pub mod fmt; pub mod parser; From d23fe09f863dba1a90764093fccc7f17ac373fd1 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 22 Dec 2020 17:35:07 +0100 Subject: [PATCH 04/64] fmt --- src/utils/crypto.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs index defb1de..cf5ace9 100644 --- a/src/utils/crypto.rs +++ b/src/utils/crypto.rs @@ -30,7 +30,7 @@ extern crate magic_crypt; use magic_crypt::MagicCryptTrait; /// ### aes128_b64_crypt -/// +/// /// Crypt a string using AES128; output is returned as a BASE64 string pub fn aes128_b64_crypt(key: &str, input: &str) -> String { let crypter = new_magic_crypt!(key.to_string(), 128); @@ -38,7 +38,7 @@ pub fn aes128_b64_crypt(key: &str, input: &str) -> String { } /// ### aes128_b64_decrypt -/// +/// /// Decrypt a string using AES128 pub fn aes128_b64_decrypt(key: &str, secret: &str) -> Result { let crypter = new_magic_crypt!(key.to_string(), 128); @@ -56,7 +56,12 @@ mod tests { let input: &str = "Hello world!"; let secret: String = aes128_b64_crypt(&key, input); assert_eq!(secret.as_str(), "z4Z6LpcpYqBW4+bkIok+5A=="); - assert_eq!(aes128_b64_decrypt(key, secret.as_str()).ok().unwrap().as_str(), input); + assert_eq!( + aes128_b64_decrypt(key, secret.as_str()) + .ok() + .unwrap() + .as_str(), + input + ); } - } From c35a5590b5c0d5503fcf3499500701e39aa4f69a Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Tue, 22 Dec 2020 18:33:38 +0100 Subject: [PATCH 05/64] Updated dependencies --- CHANGELOG.md | 5 ++ Cargo.lock | 83 +++++++++++++++++++++++++++------- Cargo.toml | 8 ++-- src/system/bookmarks_client.rs | 12 +++-- 4 files changed, 83 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c0f21..2558017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ FIXME: Released on - Enhancements: - Replaced sha256 sum with last modification time check, to verify if a file has been changed in the text editor +- dependencies: + - updated `rand` to `0.8.0` + - updated `textwrap` to `0.13.1` + - updated `toml` to `0.5.8` + - updated `whoami` to `1.0.1` ## 0.2.0 diff --git a/Cargo.lock b/Cargo.lock index f0da32c..87dfa7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,6 +412,17 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "hostname" version = "0.3.1" @@ -740,11 +751,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.0", + "rand_hc 0.3.0", ] [[package]] @@ -754,7 +777,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.0", ] [[package]] @@ -763,7 +796,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", +] + +[[package]] +name = "rand_core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18" +dependencies = [ + "getrandom 0.2.0", ] [[package]] @@ -772,7 +814,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.0", ] [[package]] @@ -787,7 +838,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom", + "getrandom 0.1.15", "redox_syscall", "rust-argon2", ] @@ -988,7 +1039,7 @@ checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ "cfg-if 0.1.10", "libc", - "rand", + "rand 0.7.3", "redox_syscall", "remove_dir_all", "winapi", @@ -1009,7 +1060,7 @@ dependencies = [ "hostname", "lazy_static", "magic-crypt", - "rand", + "rand 0.8.0", "regex", "rpassword", "serde", @@ -1025,9 +1076,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bca196a5c5a7bc57a5c92809cf5670e16bcbca3bf0d09ef47150bf97221f6f" +checksum = "7aca9e798437265144ddacce09343df0b3413a0aef54b1e212e640e472118b80" dependencies = [ "smawk", "unicode-width", @@ -1066,9 +1117,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] @@ -1219,9 +1270,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b81b8c1996f45197d8aad89b388f0a419afb4c5c876a23006d2d1435cb82d8" +checksum = "e35495e7faf4c657051a8e9725d9c37ac57879e915be3ed55bb401af84382035" dependencies = [ "wasm-bindgen", "web-sys", diff --git a/Cargo.toml b/Cargo.toml index ab67057..783df5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,17 +26,17 @@ getopts = "0.2.21" hostname = "0.3.1" lazy_static = "1.4.0" magic-crypt = "3.1.6" -rand = "0.7.3" +rand = "0.8.0" regex = "1.4.2" rpassword = "5.0.0" serde = { version = "1.0.118", features = ["derive"] } ssh2 = "0.9.0" tempfile = "3.1.0" -textwrap = "0.13.0" -toml = "0.5.7" +textwrap = "0.13.1" +toml = "0.5.8" tui = { version = "0.13.0", features = ["crossterm"], default-features = false } unicode-width = "0.1.7" -whoami = "1.0.0" +whoami = "1.0.1" [target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies] users = "0.11.0" diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 4119ac4..0f6a297 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -33,7 +33,7 @@ use crate::filetransfer::FileTransferProtocol; use crate::utils::crypto; use crate::utils::fmt::fmt_time; // Ext -use rand::{distributions::Alphanumeric, Rng}; +use rand::{distributions::Alphanumeric, thread_rng, Rng}; use std::fs::{OpenOptions, Permissions}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -284,10 +284,12 @@ impl BookmarksClient { /// Generate a new AES key and write it to key file fn generate_key(key_file: &Path) -> Result { // Generate 256 bytes (2048 bits) key - let key: String = rand::thread_rng() - .sample_iter(Alphanumeric) + let mut rng = thread_rng(); + let key: String = std::iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) .take(256) - .collect::(); + .collect(); // Write file match OpenOptions::new() .create(true) @@ -406,7 +408,7 @@ mod tests { // Verify client assert_eq!(client.hosts.bookmarks.len(), 0); assert_eq!(client.hosts.recents.len(), 0); - assert!(client.key.len() > 0); + assert_eq!(client.key.len(), 256); assert_eq!(client.bookmarks_file, cfg_path); assert_eq!(client.recents_size, 16); } From 53ee0f618ce034937fb275c44a14c2deb34051d0 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Wed, 23 Dec 2020 17:49:30 +0100 Subject: [PATCH 06/64] Updated known issues --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec488da..e0f2266 100644 --- a/README.md +++ b/README.md @@ -281,8 +281,8 @@ The developer documentation can be found on Rust Docs at Date: Thu, 24 Dec 2020 10:03:48 +0100 Subject: [PATCH 07/64] FileTransferProtocol ToString and FromStr traits --- src/filetransfer/mod.rs | 77 ++++++++++++++++++++++++++++++++++ src/system/bookmarks_client.rs | 27 ++++-------- 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index 243573c..0c04f7d 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -226,6 +226,34 @@ pub trait FileTransfer { fn on_recv(&mut self, readable: Box) -> Result<(), FileTransferError>; } +// Traits + +impl std::string::ToString for FileTransferProtocol { + fn to_string(&self) -> String { + String::from(match self { + FileTransferProtocol::Ftp(secure) => match secure { + true => "FTPS", + false => "FTP", + }, + FileTransferProtocol::Scp => "SCP", + FileTransferProtocol::Sftp => "SFTP", + }) + } +} + +impl std::str::FromStr for FileTransferProtocol { + type Err = (); + fn from_str(s: &str) -> Result { + match s.to_ascii_uppercase().as_str() { + "FTP" => Ok(FileTransferProtocol::Ftp(false)), + "FTPS" => Ok(FileTransferProtocol::Ftp(true)), + "SCP" => Ok(FileTransferProtocol::Scp), + "SFTP" => Ok(FileTransferProtocol::Sftp), + _ => Err(()), + } + } +} + // Tests #[cfg(test)] @@ -233,6 +261,9 @@ mod tests { use super::*; + use std::str::FromStr; + use std::string::ToString; + #[test] fn test_filetransfer_mod_protocol() { assert_eq!( @@ -243,6 +274,52 @@ mod tests { FileTransferProtocol::Ftp(false), FileTransferProtocol::Ftp(false) ); + // From str + assert_eq!( + FileTransferProtocol::from_str("FTPS").ok().unwrap(), + FileTransferProtocol::Ftp(true) + ); + assert_eq!( + FileTransferProtocol::from_str("ftps").ok().unwrap(), + FileTransferProtocol::Ftp(true) + ); + assert_eq!( + FileTransferProtocol::from_str("FTP").ok().unwrap(), + FileTransferProtocol::Ftp(false) + ); + assert_eq!( + FileTransferProtocol::from_str("ftp").ok().unwrap(), + FileTransferProtocol::Ftp(false) + ); + assert_eq!( + FileTransferProtocol::from_str("SFTP").ok().unwrap(), + FileTransferProtocol::Sftp + ); + assert_eq!( + FileTransferProtocol::from_str("sftp").ok().unwrap(), + FileTransferProtocol::Sftp + ); + assert_eq!( + FileTransferProtocol::from_str("SCP").ok().unwrap(), + FileTransferProtocol::Scp + ); + assert_eq!( + FileTransferProtocol::from_str("scp").ok().unwrap(), + FileTransferProtocol::Scp + ); + // Error + assert!(FileTransferProtocol::from_str("dummy").is_err()); + // To String + assert_eq!( + FileTransferProtocol::Ftp(true).to_string(), + String::from("FTPS") + ); + assert_eq!( + FileTransferProtocol::Ftp(false).to_string(), + String::from("FTP") + ); + assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP")); + assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP")); } #[test] diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 0f6a297..191877c 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -37,6 +37,8 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng}; use std::fs::{OpenOptions, Permissions}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::string::ToString; use std::time::SystemTime; /// ## BookmarksClient @@ -112,11 +114,9 @@ impl BookmarksClient { Some(( entry.address.clone(), entry.port, - match entry.protocol.to_ascii_uppercase().as_str() { - "FTP" => FileTransferProtocol::Ftp(false), - "FTPS" => FileTransferProtocol::Ftp(true), - "SCP" => FileTransferProtocol::Scp, - _ => FileTransferProtocol::Sftp, + match FileTransferProtocol::from_str(entry.protocol.as_str()) { + Ok(proto) => proto, + Err(_) => FileTransferProtocol::Sftp, // Default }, entry.username.clone(), match &entry.password { @@ -172,11 +172,9 @@ impl BookmarksClient { Some(( entry.address.clone(), entry.port, - match entry.protocol.to_ascii_uppercase().as_str() { - "FTP" => FileTransferProtocol::Ftp(false), - "FTPS" => FileTransferProtocol::Ftp(true), - "SCP" => FileTransferProtocol::Scp, - _ => FileTransferProtocol::Sftp, + match FileTransferProtocol::from_str(entry.protocol.as_str()) { + Ok(proto) => proto, + Err(_) => FileTransferProtocol::Sftp, // Default }, entry.username.clone(), )) @@ -333,14 +331,7 @@ impl BookmarksClient { address: addr, port, username, - protocol: match protocol { - FileTransferProtocol::Ftp(secure) => match secure { - true => String::from("FTPS"), - false => String::from("FTP"), - }, - FileTransferProtocol::Scp => String::from("SCP"), - FileTransferProtocol::Sftp => String::from("SFTP"), - }, + protocol: protocol.to_string(), password: match password { Some(p) => Some(self.encrypt_str(p.as_str())), // Encrypt password if provided None => None, From 797174446c952e5d967ab5b7749051dcba4b8bd9 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 11:12:02 +0100 Subject: [PATCH 08/64] Config module --- src/config/mod.rs | 223 +++++++++++++++++++++++++++++++++++++++ src/config/serializer.rs | 185 ++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 1 + 4 files changed, 410 insertions(+) create mode 100644 src/config/mod.rs create mode 100644 src/config/serializer.rs diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..9215f9c --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,223 @@ +//! ## Config +//! +//! `config` is the module which provides access to termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Modules +pub mod serializer; + +// Deps +extern crate edit; + +// Locals +use crate::filetransfer::FileTransferProtocol; + +// Ext +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Deserialize, Serialize, std::fmt::Debug)] +/// ## UserConfig +/// +/// UserConfig contains all the configurations for the user, +/// supported by termscp +pub struct UserConfig { + pub user_interface: UserInterfaceConfig, + pub remote: RemoteConfig, +} + +#[derive(Deserialize, Serialize, std::fmt::Debug)] +/// ## UserInterfaceConfig +/// +/// UserInterfaceConfig provides all the keys to configure the user interface +pub struct UserInterfaceConfig { + pub text_editor: PathBuf, + pub default_protocol: String, +} + +#[derive(Deserialize, Serialize, std::fmt::Debug)] +/// ## RemoteConfig +/// +/// Contains configuratio related to remote hosts +pub struct RemoteConfig { + pub ssh_keys: HashMap, // Association between host name and path to private key +} + +impl Default for UserConfig { + fn default() -> Self { + UserConfig { + user_interface: UserInterfaceConfig::default(), + remote: RemoteConfig::default(), + } + } +} + +impl Default for UserInterfaceConfig { + fn default() -> Self { + UserInterfaceConfig { + text_editor: match edit::get_editor() { + Ok(p) => p, + Err(_) => PathBuf::from("nano"), // Default to nano + }, + default_protocol: FileTransferProtocol::Sftp.to_string(), + } + } +} + +impl Default for RemoteConfig { + fn default() -> Self { + RemoteConfig { + ssh_keys: HashMap::new(), + } + } +} + +// Errors + +/// ## SerializerError +/// +/// Contains the error for serializer/deserializer +#[derive(std::fmt::Debug)] +pub struct SerializerError { + kind: SerializerErrorKind, + msg: Option, +} + +/// ## SerializerErrorKind +/// +/// Describes the kind of error for the serializer/deserializer +#[derive(std::fmt::Debug, PartialEq)] +pub enum SerializerErrorKind { + IoError, + SerializationError, + SyntaxError, +} + +impl SerializerError { + /// ### new + /// + /// Instantiate a new `SerializerError` + pub fn new(kind: SerializerErrorKind) -> SerializerError { + SerializerError { kind, msg: None } + } + + /// ### new_ex + /// + /// Instantiates a new `SerializerError` with description message + pub fn new_ex(kind: SerializerErrorKind, msg: String) -> SerializerError { + let mut err: SerializerError = SerializerError::new(kind); + err.msg = Some(msg); + err + } +} + +impl std::fmt::Display for SerializerError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let err: String = match &self.kind { + SerializerErrorKind::IoError => String::from("IO error"), + SerializerErrorKind::SerializationError => String::from("Serialization error"), + SerializerErrorKind::SyntaxError => String::from("Syntax error"), + }; + match &self.msg { + Some(msg) => write!(f, "{} ({})", err, msg), + None => write!(f, "{}", err), + } + } +} + +// Tests + +#[cfg(test)] +mod tests { + + use super::*; + use std::env; + + #[test] + fn test_config_mod_new() { + let mut keys: HashMap = HashMap::with_capacity(1); + keys.insert( + String::from("192.168.1.31"), + PathBuf::from("/tmp/private.key"), + ); + let remote: RemoteConfig = RemoteConfig { ssh_keys: keys }; + let ui: UserInterfaceConfig = UserInterfaceConfig { + default_protocol: String::from("SFTP"), + text_editor: PathBuf::from("nano"), + }; + let cfg: UserConfig = UserConfig { + user_interface: ui, + remote: remote, + }; + assert_eq!( + *cfg + .remote + .ssh_keys + .get(&String::from("192.168.1.31")) + .unwrap(), + PathBuf::from("/tmp/private.key") + ); + assert_eq!(cfg.user_interface.default_protocol, String::from("SFTP")); + assert_eq!(cfg.user_interface.text_editor, PathBuf::from("nano")); + } + + #[test] + fn test_config_mod_new_default() { + // Force vim editor + env::set_var(String::from("EDITOR"), String::from("vim")); + // Get default + let cfg: UserConfig = UserConfig::default(); + assert_eq!(cfg.user_interface.default_protocol, String::from("SFTP")); + assert_eq!(cfg.user_interface.text_editor, PathBuf::from("vim")); + assert_eq!(cfg.remote.ssh_keys.len(), 0); + } + + #[test] + fn test_config_mod_errors() { + let error: SerializerError = SerializerError::new(SerializerErrorKind::SyntaxError); + assert_eq!(error.kind, SerializerErrorKind::SyntaxError); + assert!(error.msg.is_none()); + assert_eq!(format!("{}", error), String::from("Syntax error")); + let error: SerializerError = + SerializerError::new_ex(SerializerErrorKind::SyntaxError, String::from("bad syntax")); + assert_eq!(error.kind, SerializerErrorKind::SyntaxError); + assert!(error.msg.is_some()); + assert_eq!( + format!("{}", error), + String::from("Syntax error (bad syntax)") + ); + // Fmt + assert_eq!( + format!("{}", SerializerError::new(SerializerErrorKind::IoError)), + String::from("IO error") + ); + assert_eq!( + format!( + "{}", + SerializerError::new(SerializerErrorKind::SerializationError) + ), + String::from("Serialization error") + ); + } +} diff --git a/src/config/serializer.rs b/src/config/serializer.rs new file mode 100644 index 0000000..f96c58c --- /dev/null +++ b/src/config/serializer.rs @@ -0,0 +1,185 @@ +//! ## Serializer +//! +//! `serializer` is the module which provides the serializer/deserializer for configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +use super::{SerializerError, SerializerErrorKind, UserConfig}; + +use std::io::{Read, Write}; + +pub struct ConfigSerializer {} + +impl ConfigSerializer { + /// ### serialize + /// + /// Serialize `UserConfig` into TOML and write content to writable + pub fn serialize( + &self, + mut writable: Box, + cfg: &UserConfig, + ) -> Result<(), SerializerError> { + // Serialize content + let data: String = match toml::ser::to_string(cfg) { + Ok(dt) => dt, + Err(err) => { + return Err(SerializerError::new_ex( + SerializerErrorKind::SerializationError, + err.to_string(), + )) + } + }; + // Write file + match writable.write_all(data.as_bytes()) { + Ok(_) => Ok(()), + Err(err) => Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + err.to_string(), + )), + } + } + + /// ### deserialize + /// + /// Read data from readable and deserialize its content as TOML + pub fn deserialize(&self, mut readable: Box) -> Result { + // Read file content + let mut data: String = String::new(); + if let Err(err) = readable.read_to_string(&mut data) { + return Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + err.to_string(), + )); + } + // Deserialize + match toml::de::from_str(data.as_str()) { + Ok(hosts) => Ok(hosts), + Err(err) => Err(SerializerError::new_ex( + SerializerErrorKind::SyntaxError, + err.to_string(), + )), + } + } +} + +// Tests + +#[cfg(test)] +mod tests { + + use super::*; + + use std::io::{Seek, SeekFrom}; + use std::path::PathBuf; + + #[test] + fn test_config_serializer_deserialize_ok() { + let toml_file: tempfile::NamedTempFile = create_good_toml(); + toml_file.as_file().sync_all().unwrap(); + toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); + // Parse + let deserializer: ConfigSerializer = ConfigSerializer {}; + let cfg = deserializer.deserialize(Box::new(toml_file)); + println!("{:?}", cfg); + assert!(cfg.is_ok()); + let cfg: UserConfig = cfg.ok().unwrap(); + // Verify configuration + // Verify ui + assert_eq!(cfg.user_interface.default_protocol, String::from("SCP")); + assert_eq!(cfg.user_interface.text_editor, PathBuf::from("vim")); + // Verify keys + assert_eq!( + *cfg.remote + .ssh_keys + .get(&String::from("192.168.1.31")) + .unwrap(), + PathBuf::from("/home/omar/.ssh/raspberry.key") + ); + assert_eq!( + *cfg.remote + .ssh_keys + .get(&String::from("192.168.1.32")) + .unwrap(), + PathBuf::from("/home/omar/.ssh/beaglebone.key") + ); + assert!(cfg.remote.ssh_keys.get(&String::from("1.1.1.1")).is_none()); + } + + #[test] + fn test_config_serializer_deserialize_nok() { + let toml_file: tempfile::NamedTempFile = create_bad_toml(); + toml_file.as_file().sync_all().unwrap(); + toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); + // Parse + let deserializer: ConfigSerializer = ConfigSerializer {}; + assert!(deserializer.deserialize(Box::new(toml_file)).is_err()); + } + + #[test] + fn test_config_serializer_serialize() { + let mut cfg: UserConfig = UserConfig::default(); + let toml_file: tempfile::NamedTempFile = tempfile::NamedTempFile::new().ok().unwrap(); + // Insert key + cfg.remote.ssh_keys.insert( + String::from("192.168.1.31"), + PathBuf::from("/home/omar/.ssh/id_rsa"), + ); + // Serialize + let serializer: ConfigSerializer = ConfigSerializer {}; + let writer: Box = Box::new(std::fs::File::create(toml_file.path()).unwrap()); + assert!(serializer.serialize(writer, &cfg).is_ok()); + // Reload configuration and check if it's ok + toml_file.as_file().sync_all().unwrap(); + toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); + assert!(serializer.deserialize(Box::new(toml_file)).is_ok()); + } + + fn create_good_toml() -> tempfile::NamedTempFile { + // Write + let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); + let file_content: &str = r#" + [user_interface] + default_protocol = "SCP" + text_editor = "vim" + + [remote.ssh_keys] + "192.168.1.31" = "/home/omar/.ssh/raspberry.key" + "192.168.1.32" = "/home/omar/.ssh/beaglebone.key" + "#; + tmpfile.write_all(file_content.as_bytes()).unwrap(); + tmpfile + } + + fn create_bad_toml() -> tempfile::NamedTempFile { + // Write + let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); + let file_content: &str = r#" + [user_interface] + default_protocol = "SFTP" + + [remote.ssh_keys] + "192.168.1.31" = "/home/omar/.ssh/raspberry.key" + "#; + tmpfile.write_all(file_content.as_bytes()).unwrap(); + tmpfile + } +} diff --git a/src/lib.rs b/src/lib.rs index 9353ea5..087e803 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ extern crate magic_crypt; pub mod activity_manager; pub mod bookmarks; +pub mod config; pub mod filetransfer; pub mod fs; pub mod host; diff --git a/src/main.rs b/src/main.rs index 4682f1d..93eafb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ use std::time::Duration; // Include mod activity_manager; mod bookmarks; +mod config; mod filetransfer; mod fs; mod host; From ce924bb294a22e011110266d57a20f2d12adec8b Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 11:23:31 +0100 Subject: [PATCH 09/64] random utils --- src/system/bookmarks_client.rs | 12 ++------ src/utils/mod.rs | 1 + src/utils/random.rs | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 src/utils/random.rs diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 191877c..95c9829 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -23,17 +23,14 @@ * */ -// Deps -extern crate rand; - // Local use crate::bookmarks::serializer::BookmarkSerializer; use crate::bookmarks::{Bookmark, SerializerError, SerializerErrorKind, UserHosts}; use crate::filetransfer::FileTransferProtocol; use crate::utils::crypto; use crate::utils::fmt::fmt_time; +use crate::utils::random::random_alphanumeric_with_len; // Ext -use rand::{distributions::Alphanumeric, thread_rng, Rng}; use std::fs::{OpenOptions, Permissions}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -282,12 +279,7 @@ impl BookmarksClient { /// Generate a new AES key and write it to key file fn generate_key(key_file: &Path) -> Result { // Generate 256 bytes (2048 bits) key - let mut rng = thread_rng(); - let key: String = std::iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .map(char::from) - .take(256) - .collect(); + let key: String = random_alphanumeric_with_len(256); // Write file match OpenOptions::new() .create(true) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1162e25..5d20a9a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -27,3 +27,4 @@ pub mod crypto; pub mod fmt; pub mod parser; +pub mod random; diff --git a/src/utils/random.rs b/src/utils/random.rs new file mode 100644 index 0000000..0c17c11 --- /dev/null +++ b/src/utils/random.rs @@ -0,0 +1,52 @@ +//! ## Random +//! +//! `random` is the module which provides utilities for rand + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Deps +extern crate rand; +// Ext +use rand::{distributions::Alphanumeric, thread_rng, Rng}; + +/// ## random_alphanumeric_with_len +/// +/// Generate a random alphanumeric string with provided length +pub fn random_alphanumeric_with_len(len: usize) -> String { + let mut rng = thread_rng(); + std::iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(len) + .collect() +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_utils_random_alphanumeric_with_len() { + assert_eq!(random_alphanumeric_with_len(256).len(), 256); + } +} From f0144e3bc282a65b78dc7b1dd39dd82f24954bc8 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 16:21:53 +0100 Subject: [PATCH 10/64] ConfigClient --- src/system/config_client.rs | 453 ++++++++++++++++++++++++++++++++++++ src/system/mod.rs | 1 + 2 files changed, 454 insertions(+) create mode 100644 src/system/config_client.rs diff --git a/src/system/config_client.rs b/src/system/config_client.rs new file mode 100644 index 0000000..28d2636 --- /dev/null +++ b/src/system/config_client.rs @@ -0,0 +1,453 @@ +//! ## ConfigClient +//! +//! `config_client` is the module which provides an API between the Config module and the system + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Deps +extern crate rand; +// Locals +use crate::config::serializer::ConfigSerializer; +use crate::config::{SerializerError, SerializerErrorKind, UserConfig}; +use crate::filetransfer::FileTransferProtocol; +// Ext +use std::fs::{create_dir, remove_file, File, OpenOptions}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::string::ToString; + +// Types +pub type SshHost = (String, String, String); // 0: host, 1: username, 2: RSA key + +/// ## ConfigClient +/// +/// ConfigClient provides a high level API to communicate with the termscp configuration +pub struct ConfigClient { + config: UserConfig, // Configuration loaded + config_path: PathBuf, // Configuration TOML Path + ssh_key_dir: PathBuf, // SSH Key storage directory +} + +impl ConfigClient { + /// ### new + /// + /// Instantiate a new `ConfigClient` with provided path + pub fn new(config_path: &Path, ssh_key_dir: &Path) -> Result { + // Initialize a default configuration + let default_config: UserConfig = UserConfig::default(); + // Create client + let mut client: ConfigClient = ConfigClient { + config: default_config, + config_path: PathBuf::from(config_path), + ssh_key_dir: PathBuf::from(ssh_key_dir), + }; + // If ssh key directory doesn't exist, create it + if !ssh_key_dir.exists() { + if let Err(err) = create_dir(ssh_key_dir) { + return Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + format!( + "Could not create SSH key directory \"{}\": {}", + ssh_key_dir.display(), + err + ), + )); + } + } + // If Config file doesn't exist, create it + if !config_path.exists() { + if let Err(err) = client.write_config() { + return Err(err); + } + } else { + // otherwise Load configuration from file + if let Err(err) = client.read_config() { + return Err(err); + } + } + Ok(client) + } + + // Text editor + + /// ### get_text_editor + /// + /// Get text editor from configuration + pub fn get_text_editor(&self) -> PathBuf { + self.config.user_interface.text_editor.clone() + } + + /// ### set_text_editor + /// + /// Set text editor path + pub fn set_text_editor(&mut self, path: PathBuf) { + self.config.user_interface.text_editor = path; + } + + // Default protocol + + /// ### get_default_protocol + /// + /// Get default protocol from configuration + pub fn get_default_protcol(&self) -> FileTransferProtocol { + match FileTransferProtocol::from_str(self.config.user_interface.default_protocol.as_str()) { + Ok(p) => p, + Err(_) => FileTransferProtocol::Sftp, + } + } + + /// ### set_default_protocol + /// + /// Set default protocol to configuration + pub fn set_default_protocol(&mut self, proto: FileTransferProtocol) { + self.config.user_interface.default_protocol = proto.to_string(); + } + + // SSH Keys + + /// ### save_ssh_key + /// + /// Save a SSH key into configuration. + /// This operation also creates the key file in `ssh_key_dir` + /// and also commits changes to configuration, to prevent incoerent data + pub fn add_ssh_key( + &mut self, + host: &str, + username: &str, + ssh_key: &str, + ) -> Result<(), SerializerError> { + let host_name: String = Self::make_ssh_host_key(host, username); + // Get key path + let ssh_key_path: PathBuf = { + let mut p: PathBuf = self.ssh_key_dir.clone(); + p.push(format!("{}.key", host_name)); + p + }; + // Write key to file + let mut f: File = match File::create(ssh_key_path.as_path()) { + Ok(f) => f, + Err(err) => return Self::make_io_err(err), + }; + if let Err(err) = f.write_all(ssh_key.as_bytes()) { + return Self::make_io_err(err); + } + // Add host to keys + self.config.remote.ssh_keys.insert(host_name, ssh_key_path); + // Write config + self.write_config() + } + + /// ### del_ssh_key + /// + /// Delete a ssh key from configuration, using host as key. + /// This operation also unlinks the key file in `ssh_key_dir` + /// and also commits changes to configuration, to prevent incoerent data + pub fn del_ssh_key(&mut self, host: &str, username: &str) -> Result<(), SerializerError> { + // Remove key from configuration and get key path + let key_path: PathBuf = match self + .config + .remote + .ssh_keys + .remove(&Self::make_ssh_host_key(host, username)) + { + Some(p) => p, + None => return Ok(()), // Return ok if host doesn't exist + }; + // Remove file + if let Err(err) = remove_file(key_path.as_path()) { + return Self::make_io_err(err); + } + // Commit changes to configuration + self.write_config() + } + + /// ### get_ssh_key + /// + /// Get ssh key from host. + /// None is returned if key doesn't exist + /// `std::io::Error` is returned in case it was not possible to read the key file + pub fn get_ssh_key(&self, mkey: &str) -> std::io::Result> { + // Check if Key exists + match self.config.remote.ssh_keys.get(mkey) { + None => Ok(None), + Some(key_path) => { + // Read key path + let mut key_file: File = File::open(key_path)?; + // Read + let mut key: String = String::new(); + key_file.read_to_string(&mut key)?; + // Get host and username + let (host, username): (String, String) = Self::get_ssh_tokens(mkey); + // Return key + Ok(Some((host, username, key))) + } + } + } + + /// ### iter_ssh_keys + /// + /// Get an iterator through hosts in the ssh key storage + pub fn iter_ssh_keys(&self) -> Box + '_> { + Box::new(self.config.remote.ssh_keys.keys()) + } + + // I/O + + /// ### write_config + /// + /// Write configuration to file + pub fn write_config(&self) -> Result<(), SerializerError> { + // Open file + match OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(self.config_path.as_path()) + { + Ok(writer) => { + let serializer: ConfigSerializer = ConfigSerializer {}; + serializer.serialize(Box::new(writer), &self.config) + } + Err(err) => Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + err.to_string(), + )), + } + } + + /// ### read_config + /// + /// Read configuration from file (or reload it if already read) + pub fn read_config(&mut self) -> Result<(), SerializerError> { + // Open bookmarks file for read + match OpenOptions::new() + .read(true) + .open(self.config_path.as_path()) + { + Ok(reader) => { + // Deserialize + let deserializer: ConfigSerializer = ConfigSerializer {}; + match deserializer.deserialize(Box::new(reader)) { + Ok(config) => { + self.config = config; + Ok(()) + } + Err(err) => Err(err), + } + } + Err(err) => Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + err.to_string(), + )), + } + } + + /// ### make_ssh_host_key + /// + /// Hosts are saved as `username@host` into configuration. + /// This method creates the key name, starting from host and username + fn make_ssh_host_key(host: &str, username: &str) -> String { + format!("{}@{}", username, host) + } + + /// ### get_ssh_tokens + /// + /// Get ssh tokens starting from ssh host key + /// Panics if key has invalid syntax + /// Returns: (host, username) + fn get_ssh_tokens(host_key: &str) -> (String, String) { + let tokens: Vec<&str> = host_key.split('@').collect(); + assert_eq!(tokens.len(), 2); + (String::from(tokens[1]), String::from(tokens[0])) + } + + /// ### make_io_err + /// + /// Make serializer error from `std::io::Error` + fn make_io_err(err: std::io::Error) -> Result<(), SerializerError> { + Err(SerializerError::new_ex( + SerializerErrorKind::IoError, + err.to_string(), + )) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::config::UserConfig; + use crate::utils::random::random_alphanumeric_with_len; + + #[test] + fn test_system_config_new() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, ssh_keys_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let client: ConfigClient = ConfigClient::new(cfg_path.as_path(), ssh_keys_path.as_path()) + .ok() + .unwrap(); + // Verify parameters + let default_config: UserConfig = UserConfig::default(); + assert_eq!(client.config.remote.ssh_keys.len(), 0); + assert_eq!( + client.config.user_interface.default_protocol, + default_config.user_interface.default_protocol + ); + assert_eq!( + client.config.user_interface.text_editor, + default_config.user_interface.text_editor + ); + assert_eq!(client.config_path, cfg_path); + assert_eq!(client.ssh_key_dir, ssh_keys_path); + } + + #[test] + fn test_system_config_new_err() { + assert!( + ConfigClient::new(Path::new("/tmp/oifoif/omar"), Path::new("/tmp/efnnu/omar"),) + .is_err() + ); + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, _): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + assert!(ConfigClient::new(cfg_path.as_path(), Path::new("/tmp/efnnu/omar")).is_err()); + } + + #[test] + fn test_system_config_from_existing() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + // Change some stuff + client.set_text_editor(PathBuf::from("/usr/bin/vim")); + client.set_default_protocol(FileTransferProtocol::Scp); + assert!(client + .add_ssh_key("192.168.1.31", "pi", "piroporopero") + .is_ok()); + assert!(client.write_config().is_ok()); + // Istantiate a new client + let client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + // Verify client has updated parameters + assert_eq!(client.get_default_protcol(), FileTransferProtocol::Scp); + assert_eq!(client.get_text_editor(), PathBuf::from("/usr/bin/vim")); + assert_eq!( + client.get_ssh_key("pi@192.168.1.31").unwrap().unwrap(), + ( + String::from("192.168.1.31"), + String::from("pi"), + String::from("piroporopero") + ) + ); + } + + #[test] + fn test_system_config_text_editor() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + client.set_text_editor(PathBuf::from("mcedit")); + assert_eq!(client.get_text_editor(), PathBuf::from("mcedit")); + } + + #[test] + fn test_system_config_default_protocol() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + client.set_default_protocol(FileTransferProtocol::Ftp(true)); + assert_eq!( + client.get_default_protcol(), + FileTransferProtocol::Ftp(true) + ); + } + + #[test] + fn test_system_config_ssh_keys() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + // Add a new key + let rsa_key: String = get_sample_rsa_key(); + assert!(client + .add_ssh_key("192.168.1.31", "pi", rsa_key.as_str()) + .is_ok()); + // Iterate keys + for key in client.iter_ssh_keys() { + let host: SshHost = client.get_ssh_key(key).ok().unwrap().unwrap(); + println!("{:?}", host); + assert_eq!(host.0, String::from("192.168.1.31")); + assert_eq!(host.1, String::from("pi")); + assert_eq!(host.2, rsa_key); + } + // Unexisting key + assert!(client.get_ssh_key("test").ok().unwrap().is_none()); + // Delete key + assert!(client.del_ssh_key("192.168.1.31", "pi").is_ok()); + } + + #[test] + fn test_system_config_make_key() { + assert_eq!( + ConfigClient::make_ssh_host_key("192.168.1.31", "pi"), + String::from("pi@192.168.1.31") + ); + assert_eq!( + ConfigClient::get_ssh_tokens("pi@192.168.1.31"), + (String::from("192.168.1.31"), String::from("pi")) + ); + } + + /// ### get_paths + /// + /// Get paths for configuration and keys directory + fn get_paths(dir: &Path) -> (PathBuf, PathBuf) { + let mut k: PathBuf = PathBuf::from(dir); + let mut c: PathBuf = k.clone(); + k.push("ssh-keys/"); + c.push("config.toml"); + (c, k) + } + + /// ### create_tmp_dir + /// + /// Create temporary directory + fn create_tmp_dir() -> tempfile::TempDir { + tempfile::TempDir::new().ok().unwrap() + } + + fn get_sample_rsa_key() -> String { + format!( + "-----BEGIN OPENSSH PRIVATE KEY-----\n{}\n-----END OPENSSH PRIVATE KEY-----", + random_alphanumeric_with_len(2536) + ) + } +} diff --git a/src/system/mod.rs b/src/system/mod.rs index d0fe5be..f5a69a7 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -25,4 +25,5 @@ // modules pub mod bookmarks_client; +pub mod config_client; pub mod environment; From fbb60c7cbc4a1789fc356b2db3d3ab490c2d49c6 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 16:42:42 +0100 Subject: [PATCH 11/64] ConfigClient: return key path, not content --- src/system/config_client.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 28d2636..a0b0a9a 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -31,13 +31,13 @@ use crate::config::{SerializerError, SerializerErrorKind, UserConfig}; use crate::filetransfer::FileTransferProtocol; // Ext use std::fs::{create_dir, remove_file, File, OpenOptions}; -use std::io::{Read, Write}; +use std::io::Write; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::string::ToString; // Types -pub type SshHost = (String, String, String); // 0: host, 1: username, 2: RSA key +pub type SshHost = (String, String, PathBuf); // 0: host, 1: username, 2: RSA key path /// ## ConfigClient /// @@ -191,15 +191,10 @@ impl ConfigClient { match self.config.remote.ssh_keys.get(mkey) { None => Ok(None), Some(key_path) => { - // Read key path - let mut key_file: File = File::open(key_path)?; - // Read - let mut key: String = String::new(); - key_file.read_to_string(&mut key)?; // Get host and username let (host, username): (String, String) = Self::get_ssh_tokens(mkey); // Return key - Ok(Some((host, username, key))) + Ok(Some((host, username, PathBuf::from(key_path)))) } } } @@ -299,6 +294,8 @@ mod tests { use crate::config::UserConfig; use crate::utils::random::random_alphanumeric_with_len; + use std::io::Read; + #[test] fn test_system_config_new() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); @@ -353,12 +350,14 @@ mod tests { // Verify client has updated parameters assert_eq!(client.get_default_protcol(), FileTransferProtocol::Scp); assert_eq!(client.get_text_editor(), PathBuf::from("/usr/bin/vim")); + let mut expected_key_path: PathBuf = key_path.clone(); + expected_key_path.push("pi@192.168.1.31.key"); assert_eq!( client.get_ssh_key("pi@192.168.1.31").unwrap().unwrap(), ( String::from("192.168.1.31"), String::from("pi"), - String::from("piroporopero") + expected_key_path, ) ); } @@ -406,7 +405,16 @@ mod tests { println!("{:?}", host); assert_eq!(host.0, String::from("192.168.1.31")); assert_eq!(host.1, String::from("pi")); - assert_eq!(host.2, rsa_key); + let mut expected_key_path: PathBuf = key_path.clone(); + expected_key_path.push("pi@192.168.1.31.key"); + assert_eq!(host.2, expected_key_path); + // Read rsa key + let mut key_file: File = File::open(expected_key_path.as_path()).ok().unwrap(); + // Read + let mut key: String = String::new(); + assert!(key_file.read_to_string(&mut key).is_ok()); + // Verify rsa key + assert_eq!(key, rsa_key); } // Unexisting key assert!(client.get_ssh_key("test").ok().unwrap().is_none()); From 1449b5a524d8f7f0420bc982f576cb4a65bb2939 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 16:49:02 +0100 Subject: [PATCH 12/64] SSH Key Storage --- src/system/mod.rs | 1 + src/system/sshkey_storage.rs | 122 +++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/system/sshkey_storage.rs diff --git a/src/system/mod.rs b/src/system/mod.rs index f5a69a7..089987a 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -27,3 +27,4 @@ pub mod bookmarks_client; pub mod config_client; pub mod environment; +pub mod sshkey_storage; diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs new file mode 100644 index 0000000..b684e4a --- /dev/null +++ b/src/system/sshkey_storage.rs @@ -0,0 +1,122 @@ +//! ## SshKeyStorage +//! +//! `SshKeyStorage` is the module which behaves a storage for ssh keys + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::config_client::ConfigClient; +// Ext +use std::collections::HashMap; +use std::path::PathBuf; + +pub struct SshKeyStorage { + hosts: HashMap, // Association between {user}@{host} and RSA key path +} + +impl SshKeyStorage { + /// ### storage_from_config + /// + /// Create a `SshKeyStorage` starting from a `ConfigClient` + pub fn storage_from_config(cfg_client: &ConfigClient) -> Self { + let mut hosts: HashMap = + HashMap::with_capacity(cfg_client.iter_ssh_keys().count()); + // Iterate over keys + for key in cfg_client.iter_ssh_keys() { + match cfg_client.get_ssh_key(key) { + Ok(host) => match host { + Some((addr, username, rsa_key_path)) => { + let key_name: String = Self::make_mapkey(&addr, &username); + hosts.insert(key_name, rsa_key_path); + } + None => continue, + }, + Err(_) => continue, + } + } + // Return storage + SshKeyStorage { hosts } + } + + /// ### resolve + /// + /// Return RSA key path from host and username + pub fn resolve(&self, host: &str, username: &str) -> Option<&PathBuf> { + let key: String = Self::make_mapkey(host, username); + self.hosts.get(&key) + } + + /// ### make_mapkey + /// + /// Make mapkey from host and username + fn make_mapkey(host: &str, username: &str) -> String { + format!("{}@{}", username, host) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + use crate::system::config_client::ConfigClient; + use std::path::Path; + + #[test] + fn test_system_sshkey_storage_new() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + // Add ssh key + assert!(client + .add_ssh_key("192.168.1.31", "pi", "piroporopero") + .is_ok()); + // Create ssh key storage + let storage: SshKeyStorage = SshKeyStorage::storage_from_config(&client); + // Verify key exists + let mut exp_key_path: PathBuf = key_path.clone(); + exp_key_path.push("pi@192.168.1.31.key"); + assert_eq!(*storage.resolve("192.168.1.31", "pi").unwrap(), exp_key_path); + // Verify unexisting key + assert!(storage.resolve("deskichup", "veeso").is_none()); + } + + /// ### get_paths + /// + /// Get paths for configuration and keys directory + fn get_paths(dir: &Path) -> (PathBuf, PathBuf) { + let mut k: PathBuf = PathBuf::from(dir); + let mut c: PathBuf = k.clone(); + k.push("ssh-keys/"); + c.push("config.toml"); + (c, k) + } + + /// ### create_tmp_dir + /// + /// Create temporary directory + fn create_tmp_dir() -> tempfile::TempDir { + tempfile::TempDir::new().ok().unwrap() + } +} From 841db02b30afc52951bdcd4a85686b06ecd20b24 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 16:57:04 +0100 Subject: [PATCH 13/64] empty method sshkey_storage --- src/system/sshkey_storage.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index b684e4a..016e688 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -57,6 +57,15 @@ impl SshKeyStorage { SshKeyStorage { hosts } } + /// ### empty + /// + /// Create an empty ssh key storage; used in case `ConfigClient` is not available + pub fn empty() -> Self { + SshKeyStorage { + hosts: HashMap::new(), + } + } + /// ### resolve /// /// Return RSA key path from host and username @@ -97,11 +106,20 @@ mod tests { // Verify key exists let mut exp_key_path: PathBuf = key_path.clone(); exp_key_path.push("pi@192.168.1.31.key"); - assert_eq!(*storage.resolve("192.168.1.31", "pi").unwrap(), exp_key_path); + assert_eq!( + *storage.resolve("192.168.1.31", "pi").unwrap(), + exp_key_path + ); // Verify unexisting key assert!(storage.resolve("deskichup", "veeso").is_none()); } + #[test] + fn test_system_sshkey_storage_empty() { + let storage: SshKeyStorage = SshKeyStorage::empty(); + assert_eq!(storage.hosts.len(), 0); + } + /// ### get_paths /// /// Get paths for configuration and keys directory From f601a0451c6bcd9048a64f19fbe1880498864978 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 17:01:11 +0100 Subject: [PATCH 14/64] fix relative paths codecov --- codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codecov.yml b/codecov.yml index c6feafe..1852ca8 100644 --- a/codecov.yml +++ b/codecov.yml @@ -3,3 +3,5 @@ ignore: - src/lib.rs - src/activity_manager.rs - src/ui/ +fixes: + - "/::" From 920d3b4af455a72ca1310d8bf0b1cd84a42debc6 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 17:19:47 +0100 Subject: [PATCH 15/64] get_bookmarks_paths; get_config_paths --- src/system/environment.rs | 50 +++++++++++++++++++- src/ui/activities/auth_activity/bookmarks.rs | 8 +--- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/system/environment.rs b/src/system/environment.rs index b569f64..8a5ef34 100644 --- a/src/system/environment.rs +++ b/src/system/environment.rs @@ -27,7 +27,7 @@ extern crate dirs; // Ext -use std::path::PathBuf; +use std::path::{Path, PathBuf}; /// ### get_config_dir /// @@ -56,6 +56,32 @@ pub fn init_config_dir() -> Result, String> { } } +/// ### get_bookmarks_paths +/// +/// Get paths for bookmarks client +/// Returns: path of bookmarks.toml and path of key +pub fn get_bookmarks_paths(config_dir: &Path) -> (PathBuf, PathBuf) { + // Prepare paths + let mut bookmarks_file: PathBuf = PathBuf::from(config_dir); + bookmarks_file.push("bookmarks.toml"); + let mut key_file: PathBuf = PathBuf::from(config_dir); + key_file.push(".bookmarks.key"); // key file is hidden + (bookmarks_file, key_file) +} + +/// ### get_config_paths +/// +/// Returns paths for config client +/// Returns: path of config.toml and path for ssh keys +pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) { + // Prepare paths + let mut bookmarks_file: PathBuf = PathBuf::from(config_dir); + bookmarks_file.push("config.toml"); + let mut keys_dir: PathBuf = PathBuf::from(config_dir); + keys_dir.push(".ssh/"); // Path where keys are stored + (bookmarks_file, keys_dir) +} + #[cfg(test)] mod tests { @@ -92,4 +118,26 @@ mod tests { // Remove file assert!(std::fs::remove_file(conf_dir.as_path()).is_ok()); } + + #[test] + fn test_system_environment_get_bookmarks_paths() { + assert_eq!( + get_bookmarks_paths(&Path::new("/home/omar/.config/termscp/")), + ( + PathBuf::from("/home/omar/.config/termscp/bookmarks.toml"), + PathBuf::from("/home/omar/.config/termscp/.bookmarks.key") + ) + ); + } + + #[test] + fn test_system_environment_get_config_paths() { + assert_eq!( + get_config_paths(&Path::new("/home/omar/.config/termscp/")), + ( + PathBuf::from("/home/omar/.config/termscp/config.toml"), + PathBuf::from("/home/omar/.config/termscp/.ssh/") + ) + ); + } } diff --git a/src/ui/activities/auth_activity/bookmarks.rs b/src/ui/activities/auth_activity/bookmarks.rs index ac10aeb..7526d72 100644 --- a/src/ui/activities/auth_activity/bookmarks.rs +++ b/src/ui/activities/auth_activity/bookmarks.rs @@ -225,12 +225,8 @@ impl AuthActivity { Ok(path) => { // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. if let Some(path) = path { - // Prepare paths - let mut bookmarks_file: PathBuf = path.clone(); - bookmarks_file.push("bookmarks.toml"); - let mut key_file: PathBuf = path; - key_file.push(".bookmarks.key"); // key file is hidden - // Initialize client + let (bookmarks_file, key_file): (PathBuf, PathBuf) = environment::get_bookmarks_paths(path.as_path()); + // Initialize client match BookmarksClient::new(bookmarks_file.as_path(), key_file.as_path(), 16) { Ok(cli) => self.bookmarks_client = Some(cli), Err(err) => { From 6bf503331e69381f6b1496ad710506edcec8e1ad Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 17:27:57 +0100 Subject: [PATCH 16/64] SSH key storage in scp/sftp file transfers --- src/filetransfer/scp_transfer.rs | 80 ++++++++++-------- src/filetransfer/sftp_transfer.rs | 82 +++++++++++-------- .../activities/filetransfer_activity/mod.rs | 38 +++++++-- 3 files changed, 129 insertions(+), 71 deletions(-) diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index b7a1deb..3eae73e 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -30,6 +30,7 @@ extern crate ssh2; // Locals use super::{FileTransfer, FileTransferError, FileTransferErrorType}; use crate::fs::{FsDirectory, FsEntry, FsFile}; +use crate::system::sshkey_storage::SshKeyStorage; use crate::utils::parser::parse_lstime; // Includes @@ -46,22 +47,18 @@ use std::time::SystemTime; pub struct ScpFileTransfer { session: Option, wrkdir: PathBuf, -} - -impl Default for ScpFileTransfer { - fn default() -> Self { - Self::new() - } + key_storage: SshKeyStorage, } impl ScpFileTransfer { /// ### new /// /// Instantiates a new ScpFileTransfer - pub fn new() -> ScpFileTransfer { + pub fn new(key_storage: SshKeyStorage) -> ScpFileTransfer { ScpFileTransfer { session: None, wrkdir: PathBuf::from("~"), + key_storage, } } @@ -345,17 +342,36 @@ impl FileTransfer for ScpFileTransfer { Some(u) => u, None => String::from(""), }; - // Try authenticating with user agent - if session.userauth_agent(username.as_str()).is_err() { - // Try authentication with password then - if let Err(err) = session.userauth_password( - username.as_str(), - password.unwrap_or_else(|| String::from("")).as_str(), - ) { - return Err(FileTransferError::new_ex( - FileTransferErrorType::AuthenticationFailed, - format!("{}", err), - )); + // Check if it is possible to authenticate using a RSA key + match self + .key_storage + .resolve(address.as_str(), username.as_str()) + { + Some(rsa_key) => { + // Authenticate with RSA key + if let Err(err) = session.userauth_pubkey_file( + username.as_str(), + None, + rsa_key.as_path(), + password.as_deref(), + ) { + return Err(FileTransferError::new_ex( + FileTransferErrorType::AuthenticationFailed, + format!("{}", err), + )); + } + } + None => { + // Proceeed with username/password authentication + if let Err(err) = session.userauth_password( + username.as_str(), + password.unwrap_or_else(|| String::from("")).as_str(), + ) { + return Err(FileTransferError::new_ex( + FileTransferErrorType::AuthenticationFailed, + format!("{}", err), + )); + } } } // Get banner @@ -823,14 +839,14 @@ mod tests { #[test] fn test_filetransfer_scp_new() { - let client: ScpFileTransfer = ScpFileTransfer::new(); + let client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client.session.is_none()); assert_eq!(client.is_connected(), false); } #[test] fn test_filetransfer_scp_connect() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert_eq!(client.is_connected(), false); assert!(client .connect( @@ -849,7 +865,7 @@ mod tests { } #[test] fn test_filetransfer_scp_bad_auth() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -862,7 +878,7 @@ mod tests { #[test] fn test_filetransfer_scp_no_credentials() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect(String::from("test.rebex.net"), 22, None, None) .is_err()); @@ -870,7 +886,7 @@ mod tests { #[test] fn test_filetransfer_scp_bad_server() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("mybadserver.veryverybad.awful"), @@ -882,7 +898,7 @@ mod tests { } #[test] fn test_filetransfer_scp_pwd() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -902,7 +918,7 @@ mod tests { #[test] #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] fn test_filetransfer_scp_cwd() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -923,7 +939,7 @@ mod tests { #[test] fn test_filetransfer_scp_cwd_error() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -946,7 +962,7 @@ mod tests { #[test] fn test_filetransfer_scp_ls() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -967,7 +983,7 @@ mod tests { #[test] fn test_filetransfer_scp_stat() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -991,7 +1007,7 @@ mod tests { #[test] fn test_filetransfer_scp_recv() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -1023,7 +1039,7 @@ mod tests { } #[test] fn test_filetransfer_scp_recv_failed_nosuchfile() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -1058,7 +1074,7 @@ mod tests { /* NOTE: the server doesn't allow you to create directories #[test] fn test_filetransfer_scp_mkdir() { - let mut client: ScpFileTransfer = ScpFileTransfer::new(); + let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(client.connect(String::from("test.rebex.net"), 22, Some(String::from("demo")), Some(String::from("password"))).is_ok()); let dir: String = String::from("foo"); // Mkdir @@ -1087,7 +1103,7 @@ mod tests { group: Some(0), // UNIX only unix_pex: Some((6, 4, 4)), // UNIX only }; - let mut scp: ScpFileTransfer = ScpFileTransfer::new(); + let mut scp: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty()); assert!(scp.change_dir(Path::new("/tmp")).is_err()); assert!(scp.disconnect().is_err()); assert!(scp.list_dir(Path::new("/tmp")).is_err()); diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index 421d149..f17f75f 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -29,6 +29,7 @@ extern crate ssh2; // Locals use super::{FileTransfer, FileTransferError, FileTransferErrorType}; use crate::fs::{FsDirectory, FsEntry, FsFile}; +use crate::system::sshkey_storage::SshKeyStorage; // Includes use ssh2::{FileStat, OpenFlags, OpenType, Session, Sftp}; @@ -44,23 +45,19 @@ pub struct SftpFileTransfer { session: Option, sftp: Option, wrkdir: PathBuf, -} - -impl Default for SftpFileTransfer { - fn default() -> Self { - Self::new() - } + key_storage: SshKeyStorage, } impl SftpFileTransfer { /// ### new /// /// Instantiates a new SftpFileTransfer - pub fn new() -> SftpFileTransfer { + pub fn new(key_storage: SshKeyStorage) -> SftpFileTransfer { SftpFileTransfer { session: None, sftp: None, wrkdir: PathBuf::from("~"), + key_storage, } } @@ -238,17 +235,36 @@ impl FileTransfer for SftpFileTransfer { Some(u) => u, None => String::from(""), }; - // Try authenticating with user agent - if session.userauth_agent(username.as_str()).is_err() { - // Try authentication with password then - if let Err(err) = session.userauth_password( - username.as_str(), - password.unwrap_or_else(|| String::from("")).as_str(), - ) { - return Err(FileTransferError::new_ex( - FileTransferErrorType::AuthenticationFailed, - format!("{}", err), - )); + // Check if it is possible to authenticate using a RSA key + match self + .key_storage + .resolve(address.as_str(), username.as_str()) + { + Some(rsa_key) => { + // Authenticate with RSA key + if let Err(err) = session.userauth_pubkey_file( + username.as_str(), + None, + rsa_key.as_path(), + password.as_deref(), + ) { + return Err(FileTransferError::new_ex( + FileTransferErrorType::AuthenticationFailed, + format!("{}", err), + )); + } + } + None => { + // Proceeed with username/password authentication + if let Err(err) = session.userauth_password( + username.as_str(), + password.unwrap_or_else(|| String::from("")).as_str(), + ) { + return Err(FileTransferError::new_ex( + FileTransferErrorType::AuthenticationFailed, + format!("{}", err), + )); + } } } // Set blocking to true @@ -600,7 +616,7 @@ mod tests { #[test] fn test_filetransfer_sftp_new() { - let client: SftpFileTransfer = SftpFileTransfer::new(); + let client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client.session.is_none()); assert!(client.sftp.is_none()); assert_eq!(client.wrkdir, PathBuf::from("~")); @@ -609,7 +625,7 @@ mod tests { #[test] fn test_filetransfer_sftp_connect() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert_eq!(client.is_connected(), false); assert!(client .connect( @@ -631,7 +647,7 @@ mod tests { #[test] fn test_filetransfer_sftp_bad_auth() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -644,7 +660,7 @@ mod tests { #[test] fn test_filetransfer_sftp_no_credentials() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect(String::from("test.rebex.net"), 22, None, None) .is_err()); @@ -652,7 +668,7 @@ mod tests { #[test] fn test_filetransfer_sftp_bad_server() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("mybadserver.veryverybad.awful"), @@ -665,7 +681,7 @@ mod tests { #[test] fn test_filetransfer_sftp_pwd() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -686,7 +702,7 @@ mod tests { #[test] fn test_filetransfer_sftp_cwd() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -713,7 +729,7 @@ mod tests { #[test] fn test_filetransfer_sftp_copy() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -748,7 +764,7 @@ mod tests { #[test] fn test_filetransfer_sftp_cwd_error() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -771,7 +787,7 @@ mod tests { #[test] fn test_filetransfer_sftp_ls() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -794,7 +810,7 @@ mod tests { #[test] fn test_filetransfer_sftp_stat() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -820,7 +836,7 @@ mod tests { #[test] fn test_filetransfer_sftp_recv() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -854,7 +870,7 @@ mod tests { } #[test] fn test_filetransfer_sftp_recv_failed_nosuchfile() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client .connect( String::from("test.rebex.net"), @@ -892,7 +908,7 @@ mod tests { /* NOTE: the server doesn't allow you to create directories #[test] fn test_filetransfer_sftp_mkdir() { - let mut client: SftpFileTransfer = SftpFileTransfer::new(); + let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(client.connect(String::from("test.rebex.net"), 22, Some(String::from("demo")), Some(String::from("password"))).is_ok()); let dir: String = String::from("foo"); // Mkdir @@ -921,7 +937,7 @@ mod tests { group: Some(0), // UNIX only unix_pex: Some((6, 4, 4)), // UNIX only }; - let mut sftp: SftpFileTransfer = SftpFileTransfer::new(); + let mut sftp: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty()); assert!(sftp.change_dir(Path::new("/tmp")).is_err()); assert!(sftp.disconnect().is_err()); assert!(sftp.list_dir(Path::new("/tmp")).is_err()); diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index 56ecd29..d138fa2 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -39,14 +39,14 @@ extern crate unicode_width; // locals use super::{Activity, Context}; -use crate::filetransfer::FileTransferProtocol; - -// File transfer use crate::filetransfer::ftp_transfer::FtpFileTransfer; use crate::filetransfer::scp_transfer::ScpFileTransfer; use crate::filetransfer::sftp_transfer::SftpFileTransfer; -use crate::filetransfer::FileTransfer; +use crate::filetransfer::{FileTransfer, FileTransferProtocol}; use crate::fs::FsEntry; +use crate::system::config_client::ConfigClient; +use crate::system::environment; +use crate::system::sshkey_storage::SshKeyStorage; // Includes use chrono::{DateTime, Local}; @@ -311,9 +311,13 @@ impl FileTransferActivity { quit: false, context: None, client: match protocol { - FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new()), + FileTransferProtocol::Sftp => { + Box::new(SftpFileTransfer::new(Self::make_ssh_storage())) + } FileTransferProtocol::Ftp(ftps) => Box::new(FtpFileTransfer::new(ftps)), - FileTransferProtocol::Scp => Box::new(ScpFileTransfer::new()), + FileTransferProtocol::Scp => { + Box::new(ScpFileTransfer::new(Self::make_ssh_storage())) + } }, params, local: FileExplorer::new(), @@ -329,6 +333,28 @@ impl FileTransferActivity { transfer: TransferStates::default(), } } + + /// ### make_ssh_storage + /// + /// Make ssh storage using ConfigClient if possible, otherwise provide an empty storage. + /// This activity doesn't care of errors related to config client. + fn make_ssh_storage() -> SshKeyStorage { + match environment::init_config_dir() { + Ok(termscp_dir) => match termscp_dir { + Some(termscp_dir) => { + // Make configuration file path and ssh keys path + let (config_path, ssh_keys_path): (PathBuf, PathBuf) = + environment::get_config_paths(termscp_dir.as_path()); + match ConfigClient::new(config_path.as_path(), ssh_keys_path.as_path()) { + Ok(config_client) => SshKeyStorage::storage_from_config(&config_client), + Err(_) => SshKeyStorage::empty(), + } + } + None => SshKeyStorage::empty(), + }, + Err(_) => SshKeyStorage::empty(), + } + } } /** From 39e8d1f704b74543ff62ef1cc5a0f29d95d88308 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 18:27:38 +0100 Subject: [PATCH 17/64] AuthActivity: enter setup with --- src/ui/activities/auth_activity/input.rs | 12 ++++++++++++ src/ui/activities/auth_activity/layout.rs | 10 ++++++++++ src/ui/activities/auth_activity/mod.rs | 2 ++ 3 files changed, 24 insertions(+) diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index 64d587c..b46f2fd 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -159,6 +159,10 @@ impl AuthActivity { // Show help self.input_mode = InputMode::Popup(PopupType::Help); } + 'C' | 'c' => { + // Show setup + self.setup = true; + } 'S' | 's' => { // Default choice option to no self.choice_opt = DialogYesNoOption::No; @@ -268,6 +272,10 @@ impl AuthActivity { self.selected_field = InputField::Password; } KeyCode::Char(ch) => match ch { + 'C' | 'c' => { + // Show setup + self.setup = true; + } 'E' | 'e' => { // Ask if user wants to delete bookmark; NOTE: same as self.input_mode = InputMode::Popup(PopupType::YesNo( @@ -348,6 +356,10 @@ impl AuthActivity { self.selected_field = InputField::Password; } KeyCode::Char(ch) => match ch { + 'C' | 'c' => { + // Show setup + self.setup = true; + } 'E' | 'e' => { // Ask if user wants to delete bookmark; NOTE: same as self.input_mode = InputMode::Popup(PopupType::YesNo( diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 069b613..6e0c4b9 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -581,6 +581,16 @@ impl AuthActivity { Span::raw(" "), Span::raw("Delete selected bookmark"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Enter setup"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "", diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index 7c148e5..8a4a458 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -109,6 +109,7 @@ pub struct AuthActivity { pub password: String, pub submit: bool, // becomes true after user has submitted fields pub quit: bool, // Becomes true if user has pressed esc + pub setup: bool, // Becomes true if user has requested setup context: Option, bookmarks_client: Option, selected_field: InputField, // Selected field in AuthCredentials Form @@ -141,6 +142,7 @@ impl AuthActivity { password: String::new(), submit: false, quit: false, + setup: false, context: None, bookmarks_client: None, selected_field: InputField::Address, From 82d8bd03424eefb222d6a68b73235f842f28e545 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 18:47:00 +0100 Subject: [PATCH 18/64] Read default protocol in auth activity --- src/ui/activities/auth_activity/mod.rs | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index 8a4a458..ce9be44 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -38,10 +38,13 @@ extern crate unicode_width; use super::{Activity, Context}; use crate::filetransfer::FileTransferProtocol; use crate::system::bookmarks_client::BookmarksClient; +use crate::system::config_client::ConfigClient; +use crate::system::environment; // Includes use crossterm::event::Event as InputEvent; use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; +use std::path::PathBuf; use tui::style::Color; // Types @@ -112,6 +115,7 @@ pub struct AuthActivity { pub setup: bool, // Becomes true if user has requested setup context: Option, bookmarks_client: Option, + config_client: Option, selected_field: InputField, // Selected field in AuthCredentials Form input_mode: InputMode, input_form: InputForm, @@ -145,6 +149,7 @@ impl AuthActivity { setup: false, context: None, bookmarks_client: None, + config_client: None, selected_field: InputField::Address, input_mode: InputMode::Form, input_form: InputForm::AuthCredentials, @@ -156,6 +161,42 @@ impl AuthActivity { recents_idx: 0, } } + + /// ### init_config_client + /// + /// Initialize config client + fn init_config_client(&mut self) { + // Get config dir + match environment::init_config_dir() { + Ok(config_dir) => { + if let Some(config_dir) = config_dir { + // Get config client paths + let (config_path, ssh_dir): (PathBuf, PathBuf) = + environment::get_config_paths(config_dir.as_path()); + match ConfigClient::new(config_path.as_path(), ssh_dir.as_path()) { + Ok(cli) => { + // Set default protocol + self.protocol = cli.get_default_protcol(); + // Set client + self.config_client = Some(cli); + } + Err(err) => { + self.input_mode = InputMode::Popup(PopupType::Alert( + Color::Red, + format!("Could not initialize user configuration: {}", err), + )) + } + } + } + } + Err(err) => { + self.input_mode = InputMode::Popup(PopupType::Alert( + Color::Red, + format!("Could not initialize configuration directory: {}", err), + )) + } + } + } } impl Activity for AuthActivity { @@ -176,6 +217,10 @@ impl Activity for AuthActivity { if self.bookmarks_client.is_none() { self.init_bookmarks_client(); } + // init config client + if self.config_client.is_none() { + self.init_config_client(); + } } /// ### on_draw From 96a395615b66805ea67d07953887c81e7ca36ca9 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Thu, 24 Dec 2020 19:01:42 +0100 Subject: [PATCH 19/64] FileTransferActivity: load ConfigClient; set text editor to configuration's value --- .../activities/filetransfer_activity/misc.rs | 53 ++++++++++++++++++- .../activities/filetransfer_activity/mod.rs | 33 +++--------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 0bbbde4..9931519 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -19,7 +19,16 @@ * */ -use super::{Color, FileTransferActivity, InputField, InputMode, LogLevel, LogRecord, PopupType}; +// Locals +use super::{ + Color, ConfigClient, FileTransferActivity, InputField, InputMode, LogLevel, LogRecord, + PopupType, +}; +use crate::system::environment; +use crate::system::sshkey_storage::SshKeyStorage; +// Ext +use std::env; +use std::path::PathBuf; impl FileTransferActivity { /// ### log @@ -83,4 +92,46 @@ impl FileTransferActivity { InputField::Logs => InputField::Explorer, } } + + /// ### init_config_client + /// + /// Initialize configuration client if possible. + /// This function doesn't return errors. + pub(super) fn init_config_client() -> Option { + match environment::init_config_dir() { + Ok(termscp_dir) => match termscp_dir { + Some(termscp_dir) => { + // Make configuration file path and ssh keys path + let (config_path, ssh_keys_path): (PathBuf, PathBuf) = + environment::get_config_paths(termscp_dir.as_path()); + match ConfigClient::new(config_path.as_path(), ssh_keys_path.as_path()) { + Ok(config_client) => Some(config_client), + Err(_) => None, + } + } + None => None, + }, + Err(_) => None, + } + } + + /// ### make_ssh_storage + /// + /// Make ssh storage from `ConfigClient` if possible, empty otherwise + pub(super) fn make_ssh_storage(cli: Option<&ConfigClient>) -> SshKeyStorage { + match cli { + Some(cli) => SshKeyStorage::storage_from_config(cli), + None => SshKeyStorage::empty(), + } + } + + /// ### setup_text_editor + /// + /// Set text editor to use + pub(super) fn setup_text_editor(&self) { + if let Some(config_cli) = &self.config_cli { + // Set text editor + env::set_var("EDITOR", config_cli.get_text_editor()); + } + } } diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index d138fa2..9431699 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -45,8 +45,6 @@ use crate::filetransfer::sftp_transfer::SftpFileTransfer; use crate::filetransfer::{FileTransfer, FileTransferProtocol}; use crate::fs::FsEntry; use crate::system::config_client::ConfigClient; -use crate::system::environment; -use crate::system::sshkey_storage::SshKeyStorage; // Includes use chrono::{DateTime, Local}; @@ -287,6 +285,7 @@ pub struct FileTransferActivity { context: Option, // Context holder params: FileTransferParams, // FT connection params client: Box, // File transfer client + config_cli: Option, // Config Client local: FileExplorer, // Local File explorer state remote: FileExplorer, // Remote File explorer state tab: FileExplorerTab, // Current selected tab @@ -306,19 +305,22 @@ impl FileTransferActivity { /// Instantiates a new FileTransferActivity pub fn new(params: FileTransferParams) -> FileTransferActivity { let protocol: FileTransferProtocol = params.protocol; + // Get config client + let config_client: Option = Self::init_config_client(); FileTransferActivity { disconnected: false, quit: false, context: None, client: match protocol { FileTransferProtocol::Sftp => { - Box::new(SftpFileTransfer::new(Self::make_ssh_storage())) + Box::new(SftpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref()))) } FileTransferProtocol::Ftp(ftps) => Box::new(FtpFileTransfer::new(ftps)), FileTransferProtocol::Scp => { - Box::new(ScpFileTransfer::new(Self::make_ssh_storage())) + Box::new(ScpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref()))) } }, + config_cli: config_client, params, local: FileExplorer::new(), remote: FileExplorer::new(), @@ -334,27 +336,6 @@ impl FileTransferActivity { } } - /// ### make_ssh_storage - /// - /// Make ssh storage using ConfigClient if possible, otherwise provide an empty storage. - /// This activity doesn't care of errors related to config client. - fn make_ssh_storage() -> SshKeyStorage { - match environment::init_config_dir() { - Ok(termscp_dir) => match termscp_dir { - Some(termscp_dir) => { - // Make configuration file path and ssh keys path - let (config_path, ssh_keys_path): (PathBuf, PathBuf) = - environment::get_config_paths(termscp_dir.as_path()); - match ConfigClient::new(config_path.as_path(), ssh_keys_path.as_path()) { - Ok(config_client) => SshKeyStorage::storage_from_config(&config_client), - Err(_) => SshKeyStorage::empty(), - } - } - None => SshKeyStorage::empty(), - }, - Err(_) => SshKeyStorage::empty(), - } - } } /** @@ -380,6 +361,8 @@ impl Activity for FileTransferActivity { // Get files at current wd self.local_scan(pwd.as_path()); self.local.wrkdir = pwd; + // Configure text editor + self.setup_text_editor(); } /// ### on_draw From 76c4f1b67f6ce7de48b8d297c17a1f5e72401086 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 10:00:24 +0100 Subject: [PATCH 20/64] Close popups also with --- src/ui/activities/auth_activity/input.rs | 11 ++++------ .../activities/filetransfer_activity/input.rs | 22 +++++++------------ 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index b46f2fd..24458de 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -405,7 +405,7 @@ impl AuthActivity { pub(super) fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { // Only enter should be allowed here if let InputEvent::Key(key) = ev { - if let KeyCode::Enter = key.code { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { self.input_mode = InputMode::Form; // Hide popup } } @@ -417,12 +417,9 @@ impl AuthActivity { pub(super) fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { - match key.code { - KeyCode::Enter | KeyCode::Esc => { - // Set input mode back to form - self.input_mode = InputMode::Form; - } - _ => { /* Nothing to do */ } + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + // Set input mode back to form + self.input_mode = InputMode::Form; } } } diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 0b728aa..2455b58 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -605,7 +605,7 @@ impl FileTransferActivity { pub(super) fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { - if let KeyCode::Enter = key.code { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set input mode back to explorer self.input_mode = InputMode::Explorer; } @@ -618,12 +618,9 @@ impl FileTransferActivity { pub(super) fn handle_input_event_mode_popup_fileinfo(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { - match key.code { - KeyCode::Enter | KeyCode::Esc => { - // Set input mode back to explorer - self.input_mode = InputMode::Explorer; - } - _ => { /* Nothing to do */ } + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + // Set input mode back to explorer + self.input_mode = InputMode::Explorer; } } } @@ -634,12 +631,9 @@ impl FileTransferActivity { pub(super) fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { - match key.code { - KeyCode::Enter | KeyCode::Esc => { - // Set input mode back to explorer - self.input_mode = InputMode::Explorer; - } - _ => { /* Nothing to do */ } + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + // Set input mode back to explorer + self.input_mode = InputMode::Explorer; } } } @@ -650,7 +644,7 @@ impl FileTransferActivity { pub(super) fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { - if let KeyCode::Enter = key.code { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set quit to true; since a fatal error happened self.disconnect(); } From 264b5afad66263b6a4b3640bfb28b8395e631c2a Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 11:43:32 +0100 Subject: [PATCH 21/64] Typo in system --- src/system/config_client.rs | 6 +++--- src/ui/activities/auth_activity/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/system/config_client.rs b/src/system/config_client.rs index a0b0a9a..915b2e6 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -109,7 +109,7 @@ impl ConfigClient { /// ### get_default_protocol /// /// Get default protocol from configuration - pub fn get_default_protcol(&self) -> FileTransferProtocol { + pub fn get_default_protocol(&self) -> FileTransferProtocol { match FileTransferProtocol::from_str(self.config.user_interface.default_protocol.as_str()) { Ok(p) => p, Err(_) => FileTransferProtocol::Sftp, @@ -348,7 +348,7 @@ mod tests { .ok() .unwrap(); // Verify client has updated parameters - assert_eq!(client.get_default_protcol(), FileTransferProtocol::Scp); + assert_eq!(client.get_default_protocol(), FileTransferProtocol::Scp); assert_eq!(client.get_text_editor(), PathBuf::from("/usr/bin/vim")); let mut expected_key_path: PathBuf = key_path.clone(); expected_key_path.push("pi@192.168.1.31.key"); @@ -382,7 +382,7 @@ mod tests { .unwrap(); client.set_default_protocol(FileTransferProtocol::Ftp(true)); assert_eq!( - client.get_default_protcol(), + client.get_default_protocol(), FileTransferProtocol::Ftp(true) ); } diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index ce9be44..376be4e 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -176,7 +176,7 @@ impl AuthActivity { match ConfigClient::new(config_path.as_path(), ssh_dir.as_path()) { Ok(cli) => { // Set default protocol - self.protocol = cli.get_default_protcol(); + self.protocol = cli.get_default_protocol(); // Set client self.config_client = Some(cli); } From e354d17c70b52525922a9782e0d51c93824a33c8 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 16:41:49 +0100 Subject: [PATCH 22/64] SetupActivity logic --- src/activity_manager.rs | 54 +- src/ui/activities/mod.rs | 1 + src/ui/activities/setup_activity/callbacks.rs | 131 +++++ src/ui/activities/setup_activity/config.rs | 165 ++++++ src/ui/activities/setup_activity/input.rs | 470 ++++++++++++++++++ src/ui/activities/setup_activity/layout.rs | 49 ++ src/ui/activities/setup_activity/misc.rs | 38 ++ src/ui/activities/setup_activity/mod.rs | 200 ++++++++ 8 files changed, 1098 insertions(+), 10 deletions(-) create mode 100644 src/ui/activities/setup_activity/callbacks.rs create mode 100644 src/ui/activities/setup_activity/config.rs create mode 100644 src/ui/activities/setup_activity/input.rs create mode 100644 src/ui/activities/setup_activity/layout.rs create mode 100644 src/ui/activities/setup_activity/misc.rs create mode 100644 src/ui/activities/setup_activity/mod.rs diff --git a/src/activity_manager.rs b/src/activity_manager.rs index de81411..f8c49d7 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -29,9 +29,8 @@ use std::path::PathBuf; use crate::filetransfer::FileTransferProtocol; use crate::host::Localhost; use crate::ui::activities::{ - auth_activity::AuthActivity, - filetransfer_activity::FileTransferActivity, filetransfer_activity::FileTransferParams, - Activity, + auth_activity::AuthActivity, filetransfer_activity::FileTransferActivity, + filetransfer_activity::FileTransferParams, setup_activity::SetupActivity, Activity, }; use crate::ui::context::Context; @@ -45,6 +44,7 @@ use std::time::Duration; pub enum NextActivity { Authentication, FileTransfer, + SetupActivity, } /// ### ActivityManager @@ -60,10 +60,7 @@ impl ActivityManager { /// ### new /// /// Initializes a new Activity Manager - pub fn new( - local_dir: &PathBuf, - interval: Duration, - ) -> Result { + pub fn new(local_dir: &PathBuf, interval: Duration) -> Result { // Prepare Context let host: Localhost = match Localhost::new(local_dir.clone()) { Ok(h) => h, @@ -109,6 +106,7 @@ impl ActivityManager { Some(activity) => match activity { NextActivity::Authentication => self.run_authentication(), NextActivity::FileTransfer => self.run_filetransfer(), + NextActivity::SetupActivity => self.run_setup(), }, None => break, // Exit } @@ -126,13 +124,13 @@ impl ActivityManager { /// Returns the next activity to run fn run_authentication(&mut self) -> Option { // Prepare activity - let mut activity: AuthActivity = AuthActivity::new(); + let mut activity: AuthActivity = AuthActivity::default(); // Prepare result let result: Option; // Get context let ctx: Context = match self.context.take() { Some(ctx) => ctx, - None => return None + None => return None, }; // Create activity activity.on_create(ctx); @@ -145,6 +143,11 @@ impl ActivityManager { result = None; break; } + if activity.setup { + // User requested activity + result = Some(NextActivity::SetupActivity); + break; + } if activity.submit { // User submitted, set next activity result = Some(NextActivity::FileTransfer); @@ -189,7 +192,7 @@ impl ActivityManager { // Get context let ctx: Context = match self.context.take() { Some(ctx) => ctx, - None => return None + None => return None, }; // Create activity activity.on_create(ctx); @@ -214,4 +217,35 @@ impl ActivityManager { self.context = activity.on_destroy(); result } + + /// ### run_setup + /// + /// `SetupActivity` run loop. + /// Returns when activity terminates. + /// Returns the next activity to run + fn run_setup(&mut self) -> Option { + // Prepare activity + let mut activity: SetupActivity = SetupActivity::default(); + // Get context + let ctx: Context = match self.context.take() { + Some(ctx) => ctx, + None => return None, + }; + // Create activity + activity.on_create(ctx); + loop { + // Draw activity + activity.on_draw(); + // Check if activity has terminated + if activity.quit { + break; + } + // Sleep for ticks + sleep(self.interval); + } + // Destroy activity + self.context = activity.on_destroy(); + // This activity always returns to AuthActivity + Some(NextActivity::Authentication) + } } diff --git a/src/ui/activities/mod.rs b/src/ui/activities/mod.rs index 2ce9ffb..dbc95bb 100644 --- a/src/ui/activities/mod.rs +++ b/src/ui/activities/mod.rs @@ -30,6 +30,7 @@ use super::context::Context; // Activities pub mod auth_activity; pub mod filetransfer_activity; +pub mod setup_activity; // Activity trait diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs new file mode 100644 index 0000000..479a046 --- /dev/null +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -0,0 +1,131 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::{Color, Popup, SetupActivity}; +// Ext +use std::env; + +impl SetupActivity { + /// ### callback_nothing_to_do + /// + /// Self titled + pub(super) fn callback_nothing_to_do(&mut self) {} + + /// ### callback_save_config_and_quit + /// + /// Save configuration and quit + pub(super) fn callback_save_config_and_quit(&mut self) { + match self.save_config() { + Ok(_) => self.quit = true, // Quit after successful save + Err(err) => self.popup = Some(Popup::Alert(Color::Red, err)), // Show error and don't quit + } + } + + /// ### callback_save_config + /// + /// Save configuration callback + pub(super) fn callback_save_config(&mut self) { + if let Err(err) = self.save_config() { + self.popup = Some(Popup::Alert(Color::Red, err)); // Show save error + } + } + + /// ### callback_reset_config_changes + /// + /// Reset config changes callback + pub(super) fn callback_reset_config_changes(&mut self) { + if let Err(err) = self.reset_config_changes() { + self.popup = Some(Popup::Alert(Color::Red, err)); // Show reset error + } + } + + /// ### callback_delete_ssh_key + /// + /// Callback for performing the delete of a ssh key + pub(super) fn callback_delete_ssh_key(&mut self) { + // Get key + if let Some(config_cli) = self.config_cli.as_mut() { + let key: Option = match config_cli.iter_ssh_keys().nth(self.ssh_key_idx) { + Some(k) => Some(k.clone()), + None => None, + }; + if let Some(key) = key { + match config_cli.get_ssh_key(&key) { + Ok(opt) => { + if let Some((host, username, _)) = opt { + if let Err(err) = self.delete_ssh_key(host.as_str(), username.as_str()) + { + // Report error + self.popup = Some(Popup::Alert(Color::Red, err)); + } + } + } + Err(err) => { + self.popup = Some(Popup::Alert( + Color::Red, + format!("Could not get ssh key \"{}\": {}", key, err), + )) + } // Report error + } + } + } + } + + /// ### callback_new_ssh_key + /// + /// Create a new ssh key with provided parameters + pub(super) fn callback_new_ssh_key(&mut self, host: String, username: String) { + if let Some(cli) = self.config_cli.as_ref() { + // Prepare text editor + env::set_var("EDITOR", cli.get_text_editor()); + let placeholder: String = format!("# Type private SSH key for {}@{}", username, host); + // Write key to file + match edit::edit(placeholder.as_bytes()) { + Ok(rsa_key) => { + // Remove placeholder from `rsa_key` + let rsa_key: String = rsa_key.as_str().replace(placeholder.as_str(), ""); + // Add key + if let Err(err) = + self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str()) + { + self.popup = Some(Popup::Alert( + Color::Red, + format!("Could not create new private key: {}", err), + )) + } + } + Err(err) => { + // Report error + self.popup = Some(Popup::Alert( + Color::Red, + format!("Could not write private key to file: {}", err), + )) + } + } + } + } +} diff --git a/src/ui/activities/setup_activity/config.rs b/src/ui/activities/setup_activity/config.rs new file mode 100644 index 0000000..84c53da --- /dev/null +++ b/src/ui/activities/setup_activity/config.rs @@ -0,0 +1,165 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::{ConfigClient, Popup, SetupActivity}; +use crate::system::environment; +// Ext +use std::env; +use std::path::PathBuf; + +impl SetupActivity { + /// ### init_config_dir + /// + /// Initialize configuration directory + pub(super) fn init_config_client(&mut self) { + match environment::init_config_dir() { + Ok(config_dir) => match config_dir { + Some(config_dir) => { + // Get paths + let (config_file, ssh_dir): (PathBuf, PathBuf) = + environment::get_config_paths(config_dir.as_path()); + // Create config client + match ConfigClient::new(config_file.as_path(), ssh_dir.as_path()) { + Ok(cli) => self.config_cli = Some(cli), + Err(err) => { + self.popup = Some(Popup::Fatal(format!( + "Could not initialize configuration client: {}", + err + ))) + } + } + } + None => { + self.popup = Some(Popup::Fatal(format!( + "No configuration directory is available on your system" + ))) + } + }, + Err(err) => { + self.popup = Some(Popup::Fatal(format!( + "Could not initialize configuration directory: {}", + err + ))) + } + } + } + + /// ### save_config + /// + /// Save configuration + pub(super) fn save_config(&mut self) -> Result<(), String> { + match &self.config_cli { + Some(cli) => match cli.write_config() { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not save configuration: {}", err)), + }, + None => Ok(()), + } + } + + /// ### reset_config_changes + /// + /// Reset configuration changes; pratically read config from file, overwriting any change made + /// since last write action + pub(super) fn reset_config_changes(&mut self) -> Result<(), String> { + match self.config_cli.as_mut() { + Some(cli) => match cli.read_config() { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not restore configuration: {}", err)), + }, + None => Ok(()), + } + } + + /// ### delete_ssh_key + /// + /// Delete ssh key from config cli + pub(super) fn delete_ssh_key(&mut self, host: &str, username: &str) -> Result<(), String> { + match self.config_cli.as_mut() { + Some(cli) => match cli.del_ssh_key(host, username) { + Ok(_) => Ok(()), + Err(err) => Err(format!( + "Could not delete ssh key \"{}@{}\": {}", + host, username, err + )), + }, + None => Ok(()), + } + } + + /// ### edit_ssh_key + /// + /// Edit selected ssh key + pub(super) fn edit_ssh_key(&mut self) -> Result<(), String> { + match self.config_cli.as_ref() { + Some(cli) => { + // Set text editor + env::set_var("EDITOR", cli.get_text_editor()); + // Check if key exists + match cli.iter_ssh_keys().nth(self.ssh_key_idx) { + Some(key) => { + // Get key path + match cli.get_ssh_key(key) { + Ok(ssh_key) => match ssh_key { + None => Ok(()), + Some((_, _, key_path)) => match edit::edit_file(key_path.as_path()) + { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not edit ssh key: {}", err)), + }, + }, + Err(err) => Err(format!("Could not read ssh key: {}", err)), + } + } + None => Ok(()), + } + } + None => Ok(()), + } + } + + /// ### add_ssh_key + /// + /// Add provided ssh key to config client + pub(super) fn add_ssh_key( + &mut self, + host: &str, + username: &str, + rsa_key: &str, + ) -> Result<(), String> { + match self.config_cli.as_mut() { + Some(cli) => { + // Add key to client + match cli.add_ssh_key(host, username, rsa_key) { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not add SSH key: {}", err)), + } + } + None => Ok(()), + } + } +} diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs new file mode 100644 index 0000000..6d42e41 --- /dev/null +++ b/src/ui/activities/setup_activity/input.rs @@ -0,0 +1,470 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::{ + InputEvent, OnChoiceCallback, Popup, QuitDialogOption, SetupActivity, SetupTab, + UserInterfaceInputField, YesNoDialogOption, +}; +use crate::filetransfer::FileTransferProtocol; +// Ext +use crossterm::event::{KeyCode, KeyModifiers}; +use std::path::PathBuf; +use tui::style::Color; + +impl SetupActivity { + /// ### handle_input_event + /// + /// Handle input event, based on current input mode + pub(super) fn handle_input_event(&mut self, ev: &InputEvent) { + let popup: Option = match &self.popup { + Some(ptype) => Some(ptype.clone()), + None => None, + }; + match &self.popup { + Some(_) => self.handle_input_event_popup(ev, popup.unwrap()), + None => self.handle_input_event_forms(ev), + } + } + + /// ### handle_input_event_forms + /// + /// Handle input event when popup is not visible. + /// InputEvent is handled based on current tab + fn handle_input_event_forms(&mut self, ev: &InputEvent) { + // Match tab + match &self.tab { + SetupTab::SshConfig => self.handle_input_event_forms_ssh_config(ev), + SetupTab::UserInterface(_) => self.handle_input_event_forms_ui(ev), + } + } + + /// ### handle_input_event_forms_ssh_config + /// + /// Handle input event when in ssh config tab + fn handle_input_event_forms_ssh_config(&mut self, ev: &InputEvent) { + // Match input event + if let InputEvent::Key(key) = ev { + // Match key code + match key.code { + KeyCode::Esc => self.popup = Some(Popup::Quit), // Prompt quit + KeyCode::Tab => { + self.tab = SetupTab::UserInterface(UserInterfaceInputField::DefaultProtocol) + } // Switch tab to user interface config + KeyCode::Up => { + if let Some(config_cli) = self.config_cli.as_ref() { + // Move ssh key index up + let ssh_key_size: usize = config_cli.iter_ssh_keys().count(); + if self.ssh_key_idx > 0 { + // Decrement + self.ssh_key_idx -= 1; + } else { + // Set ssh key index to `ssh_key_size -1` + self.ssh_key_idx = ssh_key_size - 1; + } + } + } + KeyCode::Down => { + if let Some(config_cli) = self.config_cli.as_ref() { + // Move ssh key index down + let ssh_key_size: usize = config_cli.iter_ssh_keys().count(); + if self.ssh_key_idx + 1 < ssh_key_size { + // Increment index + self.ssh_key_idx += 1; + } else { + // Wrap to 0 + self.ssh_key_idx = 0; + } + } + } + KeyCode::Delete => { + // Prompt to delete selected key + self.yesno_opt = YesNoDialogOption::No; // Default to no + self.popup = Some(Popup::YesNo( + String::from("Delete key?"), + Self::callback_delete_ssh_key, + Self::callback_nothing_to_do, + )); + } + KeyCode::Enter => { + // Edit selected key + if let Err(err) = self.edit_ssh_key() { + self.popup = Some(Popup::Alert(Color::Red, err)); // Report error + } + } + KeyCode::Char(ch) => { + // Check if is enabled + if key.modifiers.intersects(KeyModifiers::CONTROL) { + // Match char + match ch { + 'h' | 'H' => { + // Show help + self.popup = Some(Popup::Help); + } + 'n' | 'N' => { + // New ssh key + self.popup = Some(Popup::NewSshKey); + } + 'r' | 'R' => { + // Show reset changes dialog + self.popup = Some(Popup::YesNo( + String::from("Reset changes?"), + Self::callback_reset_config_changes, + Self::callback_nothing_to_do, + )); + } + 's' | 'S' => { + // Show save dialog + self.popup = Some(Popup::YesNo( + String::from("Save changes to configuration?"), + Self::callback_save_config, + Self::callback_nothing_to_do, + )); + } + _ => { /* Nothing to do */ } + } + } + } + _ => { /* Nothing to do */ } + } + } + } + + /// ### handle_input_event_forms_ui + /// + /// Handle input event when in UserInterface config tab + fn handle_input_event_forms_ui(&mut self, ev: &InputEvent) { + // Get `UserInterfaceInputField` + let field: UserInterfaceInputField = match &self.tab { + SetupTab::UserInterface(field) => field.clone(), + _ => return, + }; + // Match input event + if let InputEvent::Key(key) = ev { + // Match key code + match key.code { + KeyCode::Esc => self.popup = Some(Popup::Quit), // Prompt quit + KeyCode::Tab => self.tab = SetupTab::SshConfig, // Switch tab to ssh config + KeyCode::Backspace => { + // Pop character from selected input + if let Some(config_cli) = self.config_cli.as_mut() { + // NOTE: replace with match if other text fields are added + if matches!(field, UserInterfaceInputField::TextEditor) { + // Pop from text editor + let mut input: String = String::from( + config_cli.get_text_editor().as_path().to_string_lossy(), + ); + input.pop(); + // Update text editor value + config_cli.set_text_editor(PathBuf::from(input.as_str())); + } + } + } + KeyCode::Left => { + // Move left on fields which are tabs + if let Some(config_cli) = self.config_cli.as_mut() { + if matches!(field, UserInterfaceInputField::DefaultProtocol) { + // Move left + config_cli.set_default_protocol( + match config_cli.get_default_protocol() { + FileTransferProtocol::Ftp(secure) => match secure { + true => FileTransferProtocol::Ftp(false), + false => FileTransferProtocol::Scp, + }, + FileTransferProtocol::Scp => FileTransferProtocol::Sftp, + FileTransferProtocol::Sftp => FileTransferProtocol::Ftp(true), // Wrap + }, + ); + } + } + } + KeyCode::Right => { + // Move right on fields which are tabs + if let Some(config_cli) = self.config_cli.as_mut() { + if matches!(field, UserInterfaceInputField::DefaultProtocol) { + // Move left + config_cli.set_default_protocol( + match config_cli.get_default_protocol() { + FileTransferProtocol::Sftp => FileTransferProtocol::Scp, + FileTransferProtocol::Scp => FileTransferProtocol::Ftp(false), + FileTransferProtocol::Ftp(secure) => match secure { + false => FileTransferProtocol::Ftp(true), + true => FileTransferProtocol::Sftp, // Wrap + }, + }, + ); + } + } + } + KeyCode::Up => { + // Change selected field + self.tab = SetupTab::UserInterface(match field { + UserInterfaceInputField::TextEditor => { + UserInterfaceInputField::DefaultProtocol + } + UserInterfaceInputField::DefaultProtocol => { + UserInterfaceInputField::TextEditor + } // Wrap + }); + } + KeyCode::Down => { + // Change selected field + self.tab = SetupTab::UserInterface(match field { + UserInterfaceInputField::DefaultProtocol => { + UserInterfaceInputField::TextEditor + } + UserInterfaceInputField::TextEditor => { + UserInterfaceInputField::DefaultProtocol + } // Wrap + }); + } + KeyCode::Char(ch) => { + // Check if is enabled + if key.modifiers.intersects(KeyModifiers::CONTROL) { + // Match char + match ch { + 'h' | 'H' => { + // Show help + self.popup = Some(Popup::Help); + } + 'r' | 'R' => { + // Show reset changes dialog + self.popup = Some(Popup::YesNo( + String::from("Reset changes?"), + Self::callback_reset_config_changes, + Self::callback_nothing_to_do, + )); + } + 's' | 'S' => { + // Show save dialog + self.popup = Some(Popup::YesNo( + String::from("Save changes to configuration?"), + Self::callback_save_config, + Self::callback_nothing_to_do, + )); + } + _ => { /* Nothing to do */ } + } + } else { + // Push character to input field + if let Some(config_cli) = self.config_cli.as_mut() { + // NOTE: change to match if other fields are added + if matches!(field, UserInterfaceInputField::TextEditor) { + // Get current text editor and push character + let mut input: String = String::from( + config_cli.get_text_editor().as_path().to_string_lossy(), + ); + input.push(ch); + // Update text editor value + config_cli.set_text_editor(PathBuf::from(input.as_str())); + } + } + } + } + _ => { /* Nothing to do */ } + } + } + } + + /// ### handle_input_event_popup + /// + /// Handler for input event when popup is visible + fn handle_input_event_popup(&mut self, ev: &InputEvent, ptype: Popup) { + match ptype { + Popup::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), + Popup::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev), + Popup::Help => self.handle_input_event_mode_popup_help(ev), + Popup::NewSshKey => self.handle_input_event_mode_popup_newsshkey(ev), + Popup::Quit => self.handle_input_event_mode_popup_quit(ev), + Popup::YesNo(_, yes_cb, no_cb) => { + self.handle_input_event_mode_popup_yesno(ev, yes_cb, no_cb) + } + } + } + + /// ### handle_input_event_mode_popup_alert + /// + /// Handle input event when the input mode is popup, and popup type is alert + fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { + // Only enter should be allowed here + if let InputEvent::Key(key) = ev { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + self.popup = None; // Hide popup + } + } + } + + /// ### handle_input_event_mode_popup_fatal + /// + /// Handle input event when the input mode is popup, and popup type is fatal + fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) { + // Only enter should be allowed here + if let InputEvent::Key(key) = ev { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + // Quit after acknowelding fatal error + self.quit = true; + } + } + } + + /// ### handle_input_event_mode_popup_help + /// + /// Input event handler for popup help + fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { + // If enter, close popup + if let InputEvent::Key(key) = ev { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + self.popup = None; // Hide popup + } + } + } + + /// ### handle_input_event_mode_popup_newsshkey + /// + /// Handle input events for `Popup::NewSshKey` + fn handle_input_event_mode_popup_newsshkey(&mut self, ev: &InputEvent) { + // If enter, close popup, otherwise push chars to input + if let InputEvent::Key(key) = ev { + match key.code { + KeyCode::Esc => { + // Abort input + // Clear buffer + self.clear_user_input(); + // Hide popup + self.popup = None; + } + KeyCode::Enter => { + // Submit + let address: String = self.user_input.get(0).unwrap().to_string(); + let username: String = self.user_input.get(1).unwrap().to_string(); + // Clear buffer + self.clear_user_input(); + // Close popup BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? + self.popup = None; + // Reset user ptr + self.user_input_ptr = 0; + // Call cb + self.callback_new_ssh_key(address, username); + } + KeyCode::Up => { + // Move ptr up, or to maximum index (1) + self.user_input_ptr = match self.user_input_ptr { + 1 => 0, + _ => 1, // Wrap + }; + } + KeyCode::Down => { + // Move ptr down, or to minimum index (0) + self.user_input_ptr = match self.user_input_ptr { + 0 => 1, + _ => 0, // Wrap + } + } + KeyCode::Char(ch) => { + // Get current input + let input: &mut String = + self.user_input.get_mut(self.user_input_ptr).unwrap(); + input.push(ch); + } + KeyCode::Backspace => { + let input: &mut String = + self.user_input.get_mut(self.user_input_ptr).unwrap(); + input.pop(); + } + _ => { /* Nothing to do */ } + } + } + } + + /// ### handle_input_event_mode_popup_quit + /// + /// Handle input events for `Popup::Quit` + fn handle_input_event_mode_popup_quit(&mut self, ev: &InputEvent) { + if let InputEvent::Key(key) = ev { + match key.code { + KeyCode::Esc => { + // Hide popup + self.popup = None; + } + KeyCode::Enter => { + // Perform enter, based on current choice + match self.quit_opt { + QuitDialogOption::Cancel => self.popup = None, // Hide popup + QuitDialogOption::DontSave => self.quit = true, // Just quit + QuitDialogOption::Save => self.callback_save_config_and_quit(), // Save and quit + } + } + KeyCode::Right => { + // Change option + self.quit_opt = match self.quit_opt { + QuitDialogOption::Save => QuitDialogOption::DontSave, + QuitDialogOption::DontSave => QuitDialogOption::Cancel, + QuitDialogOption::Cancel => QuitDialogOption::Save, // Wrap + } + } + KeyCode::Left => { + // Change option + self.quit_opt = match self.quit_opt { + QuitDialogOption::Cancel => QuitDialogOption::DontSave, + QuitDialogOption::DontSave => QuitDialogOption::Save, + QuitDialogOption::Save => QuitDialogOption::Cancel, // Wrap + } + } + _ => { /* Nothing to do */ } + } + } + } + + /// ### handle_input_event_mode_popup_yesno + /// + /// Input event handler for popup alert + pub(super) fn handle_input_event_mode_popup_yesno( + &mut self, + ev: &InputEvent, + yes_cb: OnChoiceCallback, + no_cb: OnChoiceCallback, + ) { + // If enter, close popup, otherwise move dialog option + if let InputEvent::Key(key) = ev { + match key.code { + KeyCode::Enter => { + // Hide popup BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? + self.popup = None; + // Check if user selected yes or not + match self.yesno_opt { + YesNoDialogOption::No => no_cb(self), + YesNoDialogOption::Yes => yes_cb(self), + } + // Reset choice option to yes + self.yesno_opt = YesNoDialogOption::Yes; + } + KeyCode::Right => self.yesno_opt = YesNoDialogOption::No, // Set to NO + KeyCode::Left => self.yesno_opt = YesNoDialogOption::Yes, // Set to YES + _ => { /* Nothing to do */ } + } + } + } +} diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs new file mode 100644 index 0000000..3349179 --- /dev/null +++ b/src/ui/activities/setup_activity/layout.rs @@ -0,0 +1,49 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +use super::{Context, Popup, QuitDialogOption, SetupActivity, SetupTab}; +use crate::utils::fmt::align_text_center; + +use tui::{ + layout::{Constraint, Corner, Direction, Layout, Rect}, + style::{Color, Modifier, Style}, + text::{Span, Spans, Text}, + widgets::{Block, BorderType, Borders, Clear, List, ListItem, ListState, Paragraph, Tabs}, +}; +use unicode_width::UnicodeWidthStr; + +impl SetupActivity { + /// ### draw + /// + /// Draw UI + pub(super) fn draw(&mut self) { + let mut ctx: Context = self.context.take().unwrap(); + let _ = ctx.terminal.draw(|f| { + // TODO: prepare layout + }); + self.context = Some(ctx); + } +} diff --git a/src/ui/activities/setup_activity/misc.rs b/src/ui/activities/setup_activity/misc.rs new file mode 100644 index 0000000..4903c60 --- /dev/null +++ b/src/ui/activities/setup_activity/misc.rs @@ -0,0 +1,38 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +use super::SetupActivity; + +impl SetupActivity { + /// ### clear_user_input + /// + /// Clear user input buffers + pub(super) fn clear_user_input(&mut self) { + for s in self.user_input.iter_mut() { + s.clear(); + } + } +} diff --git a/src/ui/activities/setup_activity/mod.rs b/src/ui/activities/setup_activity/mod.rs new file mode 100644 index 0000000..5e9401a --- /dev/null +++ b/src/ui/activities/setup_activity/mod.rs @@ -0,0 +1,200 @@ +//! ## SetupActivity +//! +//! `setup_activity` is the module which implements the Setup activity, which is the activity to +//! work on termscp configuration + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Submodules +mod callbacks; +mod config; +mod input; +mod layout; +mod misc; + +// Deps +extern crate crossterm; +extern crate tui; + +// Locals +use super::{Activity, Context}; +use crate::system::config_client::ConfigClient; +// Ext +use crossterm::event::Event as InputEvent; +use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; +use tui::style::Color; + +// Types +type OnChoiceCallback = fn(&mut SetupActivity); + +/// ### UserInterfaceInputField +/// +/// Input field selected in user interface +#[derive(std::cmp::PartialEq, Clone)] +enum UserInterfaceInputField { + DefaultProtocol, + TextEditor, +} + +/// ### SetupTab +/// +/// Selected setup tab +#[derive(std::cmp::PartialEq)] +enum SetupTab { + UserInterface(UserInterfaceInputField), + SshConfig, +} + +/// ### QuitDialogOption +/// +/// Quit dialog options +#[derive(std::cmp::PartialEq, Clone)] +enum QuitDialogOption { + Save, + DontSave, + Cancel, +} + +/// ### YesNoDialogOption +/// +/// YesNo dialog options +#[derive(std::cmp::PartialEq, Clone)] +enum YesNoDialogOption { + Yes, + No, +} + +/// ## Popup +/// +/// Popup describes the type of popup +#[derive(Clone)] +enum Popup { + Alert(Color, String), // Block color; Block text + Fatal(String), // Must quit after being hidden + Help, // Show Help + NewSshKey, // + Quit, // Quit dialog + YesNo(String, OnChoiceCallback, OnChoiceCallback), // Yes/No Dialog +} + +/// ## SetupActivity +/// +/// Setup activity states holder +pub struct SetupActivity { + pub quit: bool, // Becomes true when user requests the activity to terminate + context: Option, // Context holder + config_cli: Option, // Config client + tab: SetupTab, // Current setup tab + popup: Option, // Active popup + user_input: Vec, // User input holder + user_input_ptr: usize, // Selected user input + quit_opt: QuitDialogOption, // Popup::Quit selected option + yesno_opt: YesNoDialogOption, // Popup::YesNo selected option + ssh_key_idx: usize, // Index of selected ssh key in list +} + +impl Default for SetupActivity { + fn default() -> Self { + // Initialize user input + let mut user_input_buffer: Vec = Vec::with_capacity(16); + for _ in 0..16 { + user_input_buffer.push(String::new()); + } + SetupActivity { + quit: false, + context: None, + config_cli: None, + tab: SetupTab::UserInterface(UserInterfaceInputField::TextEditor), + popup: None, + user_input: user_input_buffer, // Max 16 + user_input_ptr: 0, + quit_opt: QuitDialogOption::Save, + yesno_opt: YesNoDialogOption::Yes, + ssh_key_idx: 0, + } + } +} + +impl Activity for SetupActivity { + /// ### on_create + /// + /// `on_create` is the function which must be called to initialize the activity. + /// `on_create` must initialize all the data structures used by the activity + /// Context is taken from activity manager and will be released only when activity is destroyed + fn on_create(&mut self, context: Context) { + // Set context + self.context = Some(context); + // Clear terminal + self.context.as_mut().unwrap().clear_screen(); + // Put raw mode on enabled + let _ = enable_raw_mode(); + // Initialize config client + if self.config_cli.is_none() { + self.init_config_client(); + } + } + + /// ### on_draw + /// + /// `on_draw` is the function which draws the graphical interface. + /// This function must be called at each tick to refresh the interface + fn on_draw(&mut self) { + // Context must be something + if self.context.is_none() { + return; + } + let mut redraw: bool = false; + // Read one event + if let Ok(event) = self.context.as_ref().unwrap().input_hnd.read_event() { + if let Some(event) = event { + // Set redraw to true + redraw = true; + // Handle event + self.handle_input_event(&event); + } + } + // Redraw if necessary + if redraw { + // Draw + self.draw(); + } + } + + /// ### on_destroy + /// + /// `on_destroy` is the function which cleans up runtime variables and data before terminating the activity. + /// This function must be called once before terminating the activity. + /// This function finally releases the context + fn on_destroy(&mut self) -> Option { + // Disable raw mode + let _ = disable_raw_mode(); + self.context.as_ref()?; + // Clear terminal and return + match self.context.take() { + Some(mut ctx) => { + ctx.clear_screen(); + Some(ctx) + } + None => None, + } + } +} From 00731d67d2ea99a1d5a7e8191db97c9858214954 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 16:44:01 +0100 Subject: [PATCH 23/64] ToString for protocol in AuthActivity --- src/ui/activities/auth_activity/layout.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 6e0c4b9..ac5dd04 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -23,12 +23,14 @@ * */ +// Locals use super::{ AuthActivity, Context, DialogYesNoOption, FileTransferProtocol, InputField, InputForm, InputMode, PopupType, }; use crate::utils::fmt::align_text_center; - +// Ext +use std::string::ToString; use tui::{ layout::{Constraint, Corner, Direction, Layout, Rect}, style::{Color, Modifier, Style}, @@ -321,7 +323,7 @@ impl AuthActivity { ListItem::new(Span::from(format!( "{} ({}://{}@{}:{})", key, - AuthActivity::protocol_to_str(entry.2), + entry.2.to_string().to_lowercase(), entry.3, entry.0, entry.1 @@ -368,7 +370,7 @@ impl AuthActivity { .unwrap(); ListItem::new(Span::from(format!( "{}://{}@{}:{}", - AuthActivity::protocol_to_str(entry.2), + entry.2.to_string().to_lowercase(), entry.3, entry.0, entry.1 @@ -622,18 +624,4 @@ impl AuthActivity { ) .start_corner(Corner::TopLeft) } - - /// ### protocol_to_str - /// - /// Convert protocol to str for layouts - fn protocol_to_str(proto: FileTransferProtocol) -> &'static str { - match proto { - FileTransferProtocol::Ftp(secure) => match secure { - true => "ftps", - false => "ftp", - }, - FileTransferProtocol::Scp => "scp", - FileTransferProtocol::Sftp => "sftp", - } - } } From 226ad8cc50d6ea96b2245dec3a39f64a469d476e Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 17:25:35 +0100 Subject: [PATCH 24/64] Show CTRL+C to enter setup in auth activity --- src/ui/activities/auth_activity/layout.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index ac5dd04..6438e06 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -293,8 +293,20 @@ impl AuthActivity { let (footer, h_style) = ( vec![ Span::raw("Press "), - Span::styled("", Style::default().add_modifier(Modifier::BOLD)), - Span::raw(" to show keybindings"), + Span::styled( + "", + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::Cyan), + ), + Span::raw(" to show keybindings; "), + Span::styled( + "", + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::Cyan), + ), + Span::raw(" to enter setup"), ], Style::default().add_modifier(Modifier::BOLD), ); @@ -507,9 +519,9 @@ impl AuthActivity { ) } - /// ### draw_footer + /// ### draw_popup_help /// - /// Draw authentication page footer + /// Draw authentication page help popup pub(super) fn draw_popup_help(&self) -> List { // Write header let cmds: Vec = vec![ From 9e66207bf7d51944ea692e4d82e98ed07b207e71 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 18:20:30 +0100 Subject: [PATCH 25/64] SetupActivity layout --- src/ui/activities/setup_activity/input.rs | 8 +- src/ui/activities/setup_activity/layout.rs | 551 ++++++++++++++++++++- src/ui/activities/setup_activity/mod.rs | 9 +- 3 files changed, 559 insertions(+), 9 deletions(-) diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs index 6d42e41..11dbd9e 100644 --- a/src/ui/activities/setup_activity/input.rs +++ b/src/ui/activities/setup_activity/input.rs @@ -385,13 +385,11 @@ impl SetupActivity { } KeyCode::Char(ch) => { // Get current input - let input: &mut String = - self.user_input.get_mut(self.user_input_ptr).unwrap(); + let input: &mut String = self.user_input.get_mut(self.user_input_ptr).unwrap(); input.push(ch); } KeyCode::Backspace => { - let input: &mut String = - self.user_input.get_mut(self.user_input_ptr).unwrap(); + let input: &mut String = self.user_input.get_mut(self.user_input_ptr).unwrap(); input.pop(); } _ => { /* Nothing to do */ } @@ -416,6 +414,8 @@ impl SetupActivity { QuitDialogOption::DontSave => self.quit = true, // Just quit QuitDialogOption::Save => self.callback_save_config_and_quit(), // Save and quit } + // Reset choice + self.quit_opt = QuitDialogOption::Save; } KeyCode::Right => { // Change option diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index 3349179..4ef84c2 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -24,7 +24,11 @@ * */ -use super::{Context, Popup, QuitDialogOption, SetupActivity, SetupTab}; +use super::{ + Context, Popup, QuitDialogOption, SetupActivity, SetupTab, UserInterfaceInputField, + YesNoDialogOption, +}; +use crate::filetransfer::FileTransferProtocol; use crate::utils::fmt::align_text_center; use tui::{ @@ -42,8 +46,551 @@ impl SetupActivity { pub(super) fn draw(&mut self) { let mut ctx: Context = self.context.take().unwrap(); let _ = ctx.terminal.draw(|f| { - // TODO: prepare layout + // Prepare main chunks + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(1) + .constraints( + [ + Constraint::Length(3), // Current tab + Constraint::Percentage(90), // Main body + Constraint::Length(3), // Help footer + ] + .as_ref(), + ) + .split(f.size()); + // Prepare selected tab + f.render_widget(self.draw_selected_tab(), chunks[0]); + // Draw main layout + match &self.tab { + SetupTab::SshConfig => { + // Draw ssh config + // Create explorer chunks + let sshcfg_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Percentage(100)].as_ref()) + .split(chunks[1]); + if let Some(ssh_key_tab) = self.draw_ssh_keys_list() { + // Create ssh list state + let mut ssh_key_state: ListState = ListState::default(); + ssh_key_state.select(Some(self.ssh_key_idx)); + // Render ssh keys + f.render_stateful_widget(ssh_key_tab, sshcfg_chunks[0], &mut ssh_key_state); + } + } + SetupTab::UserInterface(form_field) => { + // Create chunks + let ui_cfg_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(3), + Constraint::Length(3), + Constraint::Length(1), + ] + .as_ref(), + ) + .split(chunks[1]); + // Render input forms + if let Some(field) = self.draw_text_editor_input() { + f.render_widget(field, ui_cfg_chunks[0]); + } + if let Some(tab) = self.draw_default_protocol_tab() { + f.render_widget(tab, ui_cfg_chunks[1]); + } + // Set cursor + if let Some(cli) = &self.config_cli { + if matches!(form_field, UserInterfaceInputField::TextEditor) { + let editor_text: String = + String::from(cli.get_text_editor().as_path().to_string_lossy()); + f.set_cursor( + ui_cfg_chunks[0].x + editor_text.width() as u16 + 1, + ui_cfg_chunks[0].y + 1, + ) + } + } + } + } + // Draw footer + f.render_widget(self.draw_footer(), chunks[2]); + // Draw popup + if let Some(popup) = &self.popup { + // Calculate popup size + let (width, height): (u16, u16) = match popup { + Popup::Alert(_, _) | Popup::Fatal(_) => (50, 10), + Popup::Help => (50, 70), + Popup::NewSshKey => (50, 20), + Popup::Quit => (40, 10), + Popup::YesNo(_, _, _) => (30, 10), + }; + let popup_area: Rect = self.draw_popup_area(f.size(), width, height); + f.render_widget(Clear, popup_area); //this clears out the background + match popup { + Popup::Alert(color, txt) => f.render_widget( + self.draw_popup_alert(*color, txt.clone(), popup_area.width), + popup_area, + ), + Popup::Fatal(txt) => f.render_widget( + self.draw_popup_fatal(txt.clone(), popup_area.width), + popup_area, + ), + Popup::Help => f.render_widget(self.draw_popup_help(), popup_area), + Popup::NewSshKey => { + let popup_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(3), // Address form + Constraint::Length(3), // Username form + ] + .as_ref(), + ) + .split(popup_area); + let (address_form, username_form): (Paragraph, Paragraph) = + self.draw_popup_new_ssh_key(); + // Render parts + f.render_widget(address_form, popup_chunks[0]); + f.render_widget(username_form, popup_chunks[1]); + // Set cursor to popup form + if self.user_input_ptr < 2 { + if let Some(selected_text) = self.user_input.get(self.user_input_ptr) { + // Set cursor + f.set_cursor( + popup_chunks[self.user_input_ptr].x + + selected_text.width() as u16 + + 1, + popup_chunks[self.user_input_ptr].y + 1, + ) + } + } + } + Popup::Quit => f.render_widget(self.draw_popup_quit(), popup_area), + Popup::YesNo(txt, _, _) => { + f.render_widget(self.draw_popup_yesno(txt.clone()), popup_area) + } + } + } }); self.context = Some(ctx); } + + /// ### draw_selecte_tab + /// + /// Draw selected tab tab + fn draw_selected_tab(&self) -> Tabs { + let choices: Vec = vec![Spans::from("User Interface"), Spans::from("SSH Keys")]; + let index: usize = match self.tab { + SetupTab::UserInterface(_) => 0, + SetupTab::SshConfig => 1, + }; + Tabs::new(choices) + .block(Block::default().borders(Borders::BOTTOM).title("Setup")) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::Yellow), + ) + } + + /// ### draw_footer + /// + /// Draw authentication page footer + fn draw_footer(&self) -> Paragraph { + // Write header + let (footer, h_style) = ( + vec![ + Span::raw("Press "), + Span::styled( + "", + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::Cyan), + ), + Span::raw(" to show keybindings"), + ], + Style::default().add_modifier(Modifier::BOLD), + ); + let mut footer_text = Text::from(Spans::from(footer)); + footer_text.patch_style(h_style); + Paragraph::new(footer_text) + } + + /// ### draw_default_protocol_tab + /// + /// Draw default protocol input tab + fn draw_default_protocol_tab(&self) -> Option { + // Check if config client is some + match &self.config_cli { + Some(cli) => { + let choices: Vec = vec![ + Spans::from("SFTP"), + Spans::from("SCP"), + Spans::from("FTP"), + Spans::from("FTPS"), + ]; + let index: usize = match cli.get_default_protocol() { + FileTransferProtocol::Sftp => 0, + FileTransferProtocol::Scp => 1, + FileTransferProtocol::Ftp(secure) => match secure { + false => 2, + true => 3, + }, + }; + let (bg, fg, block_fg): (Color, Color, Color) = match &self.tab { + SetupTab::UserInterface(field) => match field { + UserInterfaceInputField::DefaultProtocol => { + (Color::Cyan, Color::Black, Color::Cyan) + } + _ => (Color::Reset, Color::Cyan, Color::Reset), + }, + _ => (Color::Reset, Color::Reset, Color::Reset), + }; + Some( + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .style(Style::default().fg(block_fg)) + .title("Default File Transfer Protocol"), + ) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default().add_modifier(Modifier::BOLD).fg(fg).bg(bg), + ), + ) + } + None => None, + } + } + + /// ### draw_text_editor_input + /// + /// Draw input text field for text editor parameter + fn draw_text_editor_input(&self) -> Option { + match &self.config_cli { + Some(cli) => Some( + Paragraph::new(String::from( + cli.get_text_editor().as_path().to_string_lossy(), + )) + .style(Style::default().fg(match &self.tab { + SetupTab::SshConfig => Color::White, + SetupTab::UserInterface(field) => match field { + UserInterfaceInputField::TextEditor => Color::LightGreen, + _ => Color::White, + }, + })) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title("Text Editor"), + ), + ), + None => None, + } + } + + /// ### draw_ssh_keys_list + /// + /// Draw ssh keys list + fn draw_ssh_keys_list(&self) -> Option { + // Check if config client is some + match &self.config_cli { + Some(cli) => { + // Iterate over ssh keys + let mut ssh_keys: Vec = Vec::with_capacity(cli.iter_ssh_keys().count()); + for key in cli.iter_ssh_keys() { + if let Ok(host) = cli.get_ssh_key(key) { + if let Some((addr, username, _)) = host { + ssh_keys.push(ListItem::new(Span::from(format!( + "{} at {}", + username, addr, + )))); + } else { + continue; + } + } else { + continue; + } + } + // Return list + Some( + List::new(ssh_keys) + .block( + Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(Color::LightGreen)) + .title("SSH Keys"), + ) + .start_corner(Corner::TopLeft) + .highlight_style( + Style::default() + .fg(Color::Black) + .bg(Color::LightGreen) + .add_modifier(Modifier::BOLD), + ), + ) + } + None => None, + } + } + + /// ### draw_popup_area + /// + /// Draw popup area + fn draw_popup_area(&self, area: Rect, width: u16, height: u16) -> Rect { + let popup_layout = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage((100 - height) / 2), + Constraint::Percentage(height), + Constraint::Percentage((100 - height) / 2), + ] + .as_ref(), + ) + .split(area); + Layout::default() + .direction(Direction::Horizontal) + .constraints( + [ + Constraint::Percentage((100 - width) / 2), + Constraint::Percentage(width), + Constraint::Percentage((100 - width) / 2), + ] + .as_ref(), + ) + .split(popup_layout[1])[1] + } + + /// ### draw_popup_alert + /// + /// Draw alert popup + fn draw_popup_alert(&self, color: Color, text: String, width: u16) -> List { + // Wraps texts + let message_rows = textwrap::wrap(text.as_str(), width as usize); + let mut lines: Vec = Vec::new(); + for msg in message_rows.iter() { + lines.push(ListItem::new(Spans::from(align_text_center(msg, width)))); + } + List::new(lines) + .block( + Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(color)) + .border_type(BorderType::Rounded) + .title("Alert"), + ) + .start_corner(Corner::TopLeft) + .style(Style::default().fg(color)) + } + + /// ### draw_popup_fatal + /// + /// Draw fatal error popup + fn draw_popup_fatal(&self, text: String, width: u16) -> List { + self.draw_popup_alert(Color::Red, text, width) + } + + /// ### draw_popup_new_ssh_key + /// + /// Draw new ssh key form popup + fn draw_popup_new_ssh_key(&self) -> (Paragraph, Paragraph) { + let address: Paragraph = Paragraph::new(self.user_input.get(0).unwrap().as_str()) + .style(Style::default().fg(match self.user_input_ptr { + 0 => Color::LightCyan, + _ => Color::White, + })) + .block( + Block::default() + .borders(Borders::TOP | Borders::RIGHT | Borders::LEFT) + .border_type(BorderType::Rounded) + .title("Host name or address"), + ); + let username: Paragraph = Paragraph::new(self.user_input.get(1).unwrap().as_str()) + .style(Style::default().fg(match self.user_input_ptr { + 1 => Color::LightMagenta, + _ => Color::White, + })) + .block( + Block::default() + .borders(Borders::TOP | Borders::RIGHT | Borders::LEFT) + .border_type(BorderType::Rounded) + .title("Username"), + ); + (address, username) + } + + /// ### draw_popup_quit + /// + /// Draw quit select popup + fn draw_popup_quit(&self) -> Tabs { + let choices: Vec = vec![ + Spans::from("Save"), + Spans::from("Don't save"), + Spans::from("Cancel"), + ]; + let index: usize = match self.quit_opt { + QuitDialogOption::Save => 0, + QuitDialogOption::DontSave => 1, + QuitDialogOption::Cancel => 2, + }; + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title("Exit setup?"), + ) + .select(index) + .style(Style::default()) + .highlight_style(Style::default().add_modifier(Modifier::BOLD).fg(Color::Red)) + } + + /// ### draw_popup_yesno + /// + /// Draw yes/no select popup + fn draw_popup_yesno(&self, text: String) -> Tabs { + let choices: Vec = vec![Spans::from("Yes"), Spans::from("No")]; + let index: usize = match self.yesno_opt { + YesNoDialogOption::Yes => 0, + YesNoDialogOption::No => 1, + }; + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title(text), + ) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::Yellow), + ) + } + + /// ### draw_popup_help + /// + /// Draw authentication page help popup + pub(super) fn draw_popup_help(&self) -> List { + // Write header + let cmds: Vec = vec![ + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Exit setup"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Change setup page"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Change selected element in tab"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Change input field"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Submit / Dismiss popup"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Delete entry"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Show help"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("New SSH key"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Revert changes"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Save configuration"), + ])), + ]; + List::new(cmds) + .block( + Block::default() + .borders(Borders::ALL) + .border_style(Style::default()) + .border_type(BorderType::Rounded) + .title("Help"), + ) + .start_corner(Corner::TopLeft) + } } diff --git a/src/ui/activities/setup_activity/mod.rs b/src/ui/activities/setup_activity/mod.rs index 5e9401a..1d085f4 100644 --- a/src/ui/activities/setup_activity/mod.rs +++ b/src/ui/activities/setup_activity/mod.rs @@ -110,6 +110,7 @@ pub struct SetupActivity { quit_opt: QuitDialogOption, // Popup::Quit selected option yesno_opt: YesNoDialogOption, // Popup::YesNo selected option ssh_key_idx: usize, // Index of selected ssh key in list + redraw: bool, // Redraw ui? } impl Default for SetupActivity { @@ -130,6 +131,7 @@ impl Default for SetupActivity { quit_opt: QuitDialogOption::Save, yesno_opt: YesNoDialogOption::Yes, ssh_key_idx: 0, + redraw: true, // Draw at first `on_draw` } } } @@ -162,20 +164,21 @@ impl Activity for SetupActivity { if self.context.is_none() { return; } - let mut redraw: bool = false; // Read one event if let Ok(event) = self.context.as_ref().unwrap().input_hnd.read_event() { if let Some(event) = event { // Set redraw to true - redraw = true; + self.redraw = true; // Handle event self.handle_input_event(&event); } } // Redraw if necessary - if redraw { + if self.redraw { // Draw self.draw(); + // Redraw back to false + self.redraw = false; } } From 2e4ff78124f35164bd16848153be1374093d6ebb Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 18:22:12 +0100 Subject: [PATCH 26/64] Refuse empty ssh key --- src/ui/activities/setup_activity/callbacks.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs index 479a046..d6d5c1d 100644 --- a/src/ui/activities/setup_activity/callbacks.rs +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -102,12 +102,17 @@ impl SetupActivity { if let Some(cli) = self.config_cli.as_ref() { // Prepare text editor env::set_var("EDITOR", cli.get_text_editor()); - let placeholder: String = format!("# Type private SSH key for {}@{}", username, host); + let placeholder: String = format!("# Type private SSH key for {}@{}\n", username, host); // Write key to file match edit::edit(placeholder.as_bytes()) { Ok(rsa_key) => { // Remove placeholder from `rsa_key` let rsa_key: String = rsa_key.as_str().replace(placeholder.as_str(), ""); + if rsa_key.is_empty() { + // Report error: empty key + self.popup = Some(Popup::Alert(Color::Red, format!("SSH Key is empty"))); + return; + } // Add key if let Err(err) = self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str()) From 90f28d9f2709c089b3b1ffaf72baee354791df87 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 18:39:18 +0100 Subject: [PATCH 27/64] SetupActivity ok --- src/ui/activities/setup_activity/callbacks.rs | 36 +++++++++++++------ src/ui/activities/setup_activity/config.rs | 33 +++++++++++++++-- src/ui/activities/setup_activity/layout.rs | 4 ++- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs index d6d5c1d..4150cbb 100644 --- a/src/ui/activities/setup_activity/callbacks.rs +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -27,6 +27,7 @@ // Locals use super::{Color, Popup, SetupActivity}; // Ext +use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use std::env; impl SetupActivity { @@ -103,6 +104,14 @@ impl SetupActivity { // Prepare text editor env::set_var("EDITOR", cli.get_text_editor()); let placeholder: String = format!("# Type private SSH key for {}@{}\n", username, host); + // Put input mode back to normal + let _ = disable_raw_mode(); + // Leave alternate mode + if let Some(ctx) = self.context.as_mut() { + ctx.leave_alternate_screen(); + } + // Re-enable raw mode + let _ = enable_raw_mode(); // Write key to file match edit::edit(placeholder.as_bytes()) { Ok(rsa_key) => { @@ -111,16 +120,16 @@ impl SetupActivity { if rsa_key.is_empty() { // Report error: empty key self.popup = Some(Popup::Alert(Color::Red, format!("SSH Key is empty"))); - return; - } - // Add key - if let Err(err) = - self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str()) - { - self.popup = Some(Popup::Alert( - Color::Red, - format!("Could not create new private key: {}", err), - )) + } else { + // Add key + if let Err(err) = + self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str()) + { + self.popup = Some(Popup::Alert( + Color::Red, + format!("Could not create new private key: {}", err), + )) + } } } Err(err) => { @@ -131,6 +140,13 @@ impl SetupActivity { )) } } + // Restore terminal + if let Some(ctx) = self.context.as_mut() { + // Clear screen + ctx.clear_screen(); + // Enter alternate mode + ctx.enter_alternate_screen(); + } } } } diff --git a/src/ui/activities/setup_activity/config.rs b/src/ui/activities/setup_activity/config.rs index 84c53da..7975a67 100644 --- a/src/ui/activities/setup_activity/config.rs +++ b/src/ui/activities/setup_activity/config.rs @@ -28,6 +28,7 @@ use super::{ConfigClient, Popup, SetupActivity}; use crate::system::environment; // Ext +use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use std::env; use std::path::PathBuf; @@ -119,6 +120,12 @@ impl SetupActivity { Some(cli) => { // Set text editor env::set_var("EDITOR", cli.get_text_editor()); + // Prepare terminal + let _ = disable_raw_mode(); + // Leave alternate mode + if let Some(ctx) = self.context.as_mut() { + ctx.leave_alternate_screen(); + } // Check if key exists match cli.iter_ssh_keys().nth(self.ssh_key_idx) { Some(key) => { @@ -128,8 +135,30 @@ impl SetupActivity { None => Ok(()), Some((_, _, key_path)) => match edit::edit_file(key_path.as_path()) { - Ok(_) => Ok(()), - Err(err) => Err(format!("Could not edit ssh key: {}", err)), + Ok(_) => { + // Restore terminal + if let Some(ctx) = self.context.as_mut() { + // Clear screen + ctx.clear_screen(); + // Enter alternate mode + ctx.enter_alternate_screen(); + } + // Re-enable raw mode + let _ = enable_raw_mode(); + Ok(()) + } + Err(err) => { + // Restore terminal + if let Some(ctx) = self.context.as_mut() { + // Clear screen + ctx.clear_screen(); + // Enter alternate mode + ctx.enter_alternate_screen(); + } + // Re-enable raw mode + let _ = enable_raw_mode(); + Err(format!("Could not edit ssh key: {}", err)) + } }, }, Err(err) => Err(format!("Could not read ssh key: {}", err)), diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index 4ef84c2..7964b78 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -409,6 +409,7 @@ impl SetupActivity { Block::default() .borders(Borders::TOP | Borders::RIGHT | Borders::LEFT) .border_type(BorderType::Rounded) + .style(Style::default().fg(Color::White)) .title("Host name or address"), ); let username: Paragraph = Paragraph::new(self.user_input.get(1).unwrap().as_str()) @@ -418,8 +419,9 @@ impl SetupActivity { })) .block( Block::default() - .borders(Borders::TOP | Borders::RIGHT | Borders::LEFT) + .borders(Borders::BOTTOM | Borders::RIGHT | Borders::LEFT) .border_type(BorderType::Rounded) + .style(Style::default().fg(Color::White)) .title("Username"), ); (address, username) From 16a011e81e45ac800407b96bb523e2190ca5e100 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 19:10:28 +0100 Subject: [PATCH 28/64] Use default protocol also in opt parser --- src/utils/parser.rs | 58 +++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 1410e5c..72b447f 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -27,10 +27,15 @@ extern crate chrono; extern crate whoami; +// Locals use crate::filetransfer::FileTransferProtocol; +use crate::system::config_client::ConfigClient; +use crate::system::environment; +// Ext use chrono::format::ParseError; use chrono::prelude::*; +use std::str::FromStr; use std::time::{Duration, SystemTime}; /// ### parse_remote_opt @@ -58,8 +63,22 @@ pub fn parse_remote_opt( let mut wrkstr: String = remote.to_string(); let address: String; let mut port: u16 = 22; - let mut protocol: FileTransferProtocol = FileTransferProtocol::Sftp; let mut username: Option = None; + // Set protocol to default protocol + let mut protocol: FileTransferProtocol = match environment::init_config_dir() { + Ok(p) => match p { + Some(p) => { + // Create config client + let (config_path, ssh_key_path) = environment::get_config_paths(p.as_path()); + match ConfigClient::new(config_path.as_path(), ssh_key_path.as_path()) { + Ok(cli) => cli.get_default_protocol(), + Err(_) => FileTransferProtocol::Sftp, + } + } + None => FileTransferProtocol::Sftp, + }, + Err(_) => FileTransferProtocol::Sftp, + }; // Split string by '://' let tokens: Vec<&str> = wrkstr.split("://").collect(); // If length is > 1, then token[0] is protocol @@ -67,33 +86,16 @@ pub fn parse_remote_opt( 1 => {} 2 => { // Parse protocol - match tokens[0] { - "sftp" => { - // Set protocol to sftp - protocol = FileTransferProtocol::Sftp; - // Set port to default (22) - port = 22; - } - "scp" => { - // Set protocol to scp - protocol = FileTransferProtocol::Scp; - // Set port to default (22) - port = 22; - } - "ftp" => { - // Set protocol to fpt - protocol = FileTransferProtocol::Ftp(false); - // Set port to default (21) - port = 21; - } - "ftps" => { - // Set protocol to fpt - protocol = FileTransferProtocol::Ftp(true); - // Set port to default (21) - port = 21; - } - _ => return Err(format!("Unknown protocol '{}'", tokens[0])), - } + let (m_protocol, m_port) = match FileTransferProtocol::from_str(tokens[0]) { + Ok(proto) => match proto { + FileTransferProtocol::Ftp(_) => (proto, 21), + FileTransferProtocol::Scp => (proto, 22), + FileTransferProtocol::Sftp => (proto, 22), + }, + Err(_) => return Err(format!("Unknown protocol '{}'", tokens[0])), + }; + protocol = m_protocol; + port = m_port; wrkstr = String::from(tokens[1]); // Wrkstr becomes tokens[1] } _ => return Err(String::from("Bad syntax")), // Too many tokens... From 46ee01e07306b4cbba23968ce57cbd208877cafc Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 19:38:17 +0100 Subject: [PATCH 29/64] SetupActivity: as --- src/ui/activities/setup_activity/input.rs | 9 +++++++++ src/ui/activities/setup_activity/layout.rs | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs index 11dbd9e..42b47dd 100644 --- a/src/ui/activities/setup_activity/input.rs +++ b/src/ui/activities/setup_activity/input.rs @@ -120,6 +120,15 @@ impl SetupActivity { if key.modifiers.intersects(KeyModifiers::CONTROL) { // Match char match ch { + 'e' | 'E' => { + // Prompt to delete selected key + self.yesno_opt = YesNoDialogOption::No; // Default to no + self.popup = Some(Popup::YesNo( + String::from("Delete key?"), + Self::callback_delete_ssh_key, + Self::callback_nothing_to_do, + )); + } 'h' | 'H' => { // Show help self.popup = Some(Popup::Help); diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index 7964b78..d58aaf0 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -544,6 +544,16 @@ impl SetupActivity { Span::raw(" "), Span::raw("Delete entry"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Delete entry"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "", From 22a9eb03b6742c029c06655a20662c21bf971d92 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 19:45:49 +0100 Subject: [PATCH 30/64] Added configuration and ssh key storage features to docs --- CHANGELOG.md | 25 +++++++++++++++++++++++-- README.md | 48 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2558017..088c0c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,31 @@ FIXME: Released on +> The SSH Key Storage Update + +- **SSH Key Storage** + - Added the possibility to store SSH private keys to access to remote hosts; this feature is supported in both SFTP and SCP. + - SSH Keys can be manipulated through the new **Setup Interface** +- **Setup Interface** + - Added a new area in the interface, where is possible to customize termscp. Access to this interface is achieved pressing `` from the home page (`AuthActivity`). +- **Configuration**: + - Added configuration; configuration is stored at + - Linux: `/home/alice/.config/termscp/config.toml` + - MacOS: `/Users/Alice/Library/Application Support/termscp/config.toml` + - Windows: `C:\Users\Alice\AppData\Roaming\termscp\config.toml` + - Added Text editor to configuration + - Added Default File transfer protocol to configuration + - Added SSH keys to configuration; SSH keys will be stored at + - Linux: `/home/alice/.config/termscp/.ssh/` + - MacOS: `/Users/Alice/Library/Application Support/termscp/.ssh/` + - Windows: `C:\Users\Alice\AppData\Roaming\termscp\.ssh\` - Enhancements: - - Replaced sha256 sum with last modification time check, to verify if a file has been changed in the text editor + - Replaced `sha256` sum with last modification time check, to verify if a file has been changed in the text editor + - Default protocol changed to default protocol in configuration when providing address as CLI argument - dependencies: + - removed `data-encoding` - updated `rand` to `0.8.0` + - removed `ring` - updated `textwrap` to `0.13.1` - updated `toml` to `0.5.8` - updated `whoami` to `1.0.1` @@ -32,8 +53,8 @@ Released on 21/12/2020 - Bookmarks and recent connections are now displayed in the home page - Bookmarks are saved at - Linux: `/home/alice/.config/termscp/bookmarks.toml` - - Windows: `C:\Users\Alice\AppData\Roaming\termscp\bookmarks.toml` - MacOS: `/Users/Alice/Library/Application Support/termscp/bookmarks.toml` + - Windows: `C:\Users\Alice\AppData\Roaming\termscp\bookmarks.toml` - **Text Editor** - Added text editor feature to explorer view - Added `o` to keybindings to open a text file diff --git a/README.md b/README.md index e0f2266..9713970 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Current version: 0.2.0 (21/12/2020) - [Are my passwords Safe ๐Ÿ˜ˆ](#are-my-passwords-safe-) - [Text Editor โœ](#text-editor-) - [How do I configure the text editor ๐Ÿฆฅ](#how-do-i-configure-the-text-editor-) + - [Configuration โš™๏ธ](#configuration-๏ธ) + - [SSH Key Storage ๐Ÿ”](#ssh-key-storage-) - [Keybindings โŒจ](#keybindings-) - [Documentation ๐Ÿ“š](#documentation-) - [Known issues ๐Ÿงป](#known-issues-) @@ -50,7 +52,7 @@ TermSCP is basically a porting of WinSCP to terminal. So basically is a terminal ### Why TermSCP ๐Ÿค” -It happens quite often to me, when using SCP at work to forget the path of a file on a remote machine, which forces me then to connect through SSH, gather the file path and finally download it through SCP. I could use WinSCP, but I use Linux and I pratically use the terminal for everything, so I wanted something like WinSCP on my terminal. Yeah, I know there midnight commander too, but actually I don't like it very much tbh (and hasn't a decent support for scp). +It happens quite often to me, when using SCP at work to forget the path of a file on a remote machine, which forces me then to connect through SSH, gather the file path and finally download it through SCP. I could use WinSCP, but I use Linux and I pratically use the terminal for everything, so I wanted something like WinSCP on my terminal. Yeah, I know there is midnight commander too, but actually I don't like it very much tbh (and hasn't a decent support for scp). ## Features ๐ŸŽ @@ -61,6 +63,8 @@ It happens quite often to me, when using SCP at work to forget the path of a fil - Practical user interface to explore and operate on the remote and on the local machine file system - Bookmarks and recent connections can be saved to access quickly to your favourite hosts - Supports text editors to view and edit text files +- Supports both SFTP/SCP authentication through SSH keys and username/password +- User customization directly from the user interface - Compatible with Windows, Linux, BSD and MacOS - Written in Rust - Easy to extend with new file transfers protocols @@ -164,13 +168,13 @@ The address argument has the following syntax: Let's see some example of this particular syntax, since it's very comfortable and you'll probably going to use this instead of the other one... -- Connect using default protocol (sftp) to 192.168.1.31, port is default for this protocol (22); username is current user's name +- Connect using default protocol (*defined in configuration*) to 192.168.1.31, port is default for this protocol (22); username is current user's name ```sh termscp 192.168.1.31 ``` -- Connect using default protocol (sftp) to 192.168.1.31, port is default for this protocol (22); username is `root` +- Connect using default protocol (*defined in configuration*) to 192.168.1.31, port is default for this protocol (22); username is `root` ```sh termscp root@192.168.1.31 @@ -201,9 +205,9 @@ This feature allows you to load all the parameters required to connect to a cert Bookmarks will be saved, if possible at: -- `$HOME/.config/termscp/` on Linux -- `FOLDERID_RoamingAppData\termscp\` on Windows +- `$HOME/.config/termscp/` on Linux/BSD - `$HOME/Library/Application Support/termscp` on MacOs +- `FOLDERID_RoamingAppData\termscp\` on Windows For bookmarks only (this won't apply to recent hosts) it is also possible to save the password used to authenticate. The password is not saved by default and must be specified through the prompt when saving a new Bookmark. @@ -234,9 +238,37 @@ Just a reminder: **you can edit only textual file**; binary files are not suppor ### How do I configure the text editor ๐Ÿฆฅ -Text editor is automatically found using this [awesome crate](https://github.com/milkey-mouse/edit), if you want to change the text editor it has chosen for you, just set the `EDITOR` variable in your environment. +Text editor is automatically found using this [awesome crate](https://github.com/milkey-mouse/edit), if you want to change the text editor to use, change it in termscp configuration. [View more](#configuration-๏ธ) -> This mechanism will probably change in 0.3.0, since I'm going to introduce the possibility to configure directly in termscp's settings. +--- + +## Configuration โš™๏ธ + +TermSCP supports some user defined parameters, which can be defined in the configuration. +Underhood termscp has a TOML file and some other directories where all the parameters will be saved, but don't worry, you won't touch any of these files, since I made possible to configure termscp from its user interface entirely. + +termscp, like for bookmarks, just requires to have these paths accessible: + +- `$HOME/.config/termscp/` on Linux/BSD +- `$HOME/Library/Application Support/termscp` on MacOs +- `FOLDERID_RoamingAppData\termscp\` on Windows + +To access configuration, you just have to press `` from the home of termscp. + +These parameters can be changed: + +- **Default Protocol**: the default protocol is the default value for the file transfer protocol to be used in termscp. This applies for the login page and for the address CLI argument. +- **Text Editor**: the text editor to use. By default termscp will find the default editor for you; with this option you can force an editor to be used (e.g. `vim`). **Also GUI editors are supported**, unless they `nohup` from the parent process so if you ask: yes, you can use `notepad.exe`, and no: **Visual Studio Code doesn't work**. + +### SSH Key Storage ๐Ÿ” + +Along with configuration, termscp provides also an **essential** feature for **SFTP/SCP clients**: the SSH key storage. + +You can access the SSH key storage, from configuration moving to the `SSH Keys` tab, once there you can: + +- **Add a new key**: just press `` and you will be prompted to create a new key. Provide the hostname/ip address and the username associated to the key and finally a text editor will open up: paste the **PRIVATE** ssh key into the text editor, save and quit. +- **Remove an existing key**: just press `` or `` on the key you want to remove, to delete persistently the key from termscp. +- **Edit an existing key**: just press `` on the key you want to edit, to change the private key. --- @@ -288,8 +320,6 @@ The developer documentation can be found on Rust Docs at Date: Fri, 25 Dec 2020 21:35:28 +0100 Subject: [PATCH 31/64] Docs: private keys with passwords --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9713970..b9c1482 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,9 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys` - **Remove an existing key**: just press `` or `` on the key you want to remove, to delete persistently the key from termscp. - **Edit an existing key**: just press `` on the key you want to edit, to change the private key. +> Q: Wait, my private key is protected with password, can I use it? +> A: Of course you can. The password provided for authentication in termscp, is valid both for username/password authentication and for RSA key authentication. + --- ## Keybindings โŒจ From c9a4706c2405718b17f853901edf43130d73104e Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Fri, 25 Dec 2020 21:54:10 +0100 Subject: [PATCH 32/64] Fixed paths --- CONTRIBUTING.md | 9 ++++----- README.md | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d48e747..afb35d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing Before contributing to this repository, please first discuss the change you wish to make via issue of this repository before making a change. -Please note we have a [code of conduct](./CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. +Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. - [Contributing](#contributing) - [Preferred contributions](#preferred-contributions) @@ -17,9 +17,8 @@ Please note we have a [code of conduct](./CODE_OF_CONDUCT.md), please follow it At the moment, these kind of contributions are more appreciated and should be preferred: -- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/ChristianVisintin/TermSCP/issues) +- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/ChristianVisintin/termscp/issues) - New file transfers: for further details see [Implementing File Transfer](#implementing-file-transfers) -- Improvements to translators: any improvement to transliteration is accepted if makes sense, consider that my implementations could be not 100% correct (and probably they're not), indeed consider that I don't speak all these languages (tbh I only can speak Russian as a language with a different alphabet from latin - and I can't even speak it very well). - Code optimizations: any optimization to the code is welcome For any other kind of contribution, especially for new features, please submit an issue first. @@ -30,9 +29,9 @@ Let's make it simple and clear: 1. Open an issue with an **appropriate label** (e.g. bug, enhancement, ...). 2. Write a **properly documentation** compliant with **rustdoc** standard. -3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui`). +3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui`) and (if a test server is not available) for file transfers. 4. Report changes to the issue you opened, writing a report of what you changed and what you have introduced. -5. Update the `CHANGELOG.md` file with details of changes to the application. +5. Update the `CHANGELOG.md` file with details of changes to the application. In changelog report changes under a chapter called `PR{PULL_REQUEST_NUMBER}` (e.g. PR12). 6. Request maintainers to merge your changes. ## Developer contributions guide diff --git a/README.md b/README.md index b9c1482..f963ec3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # TermSCP -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/ChristianVisintin/TermSCP.svg)](https://github.com/ChristianVisintin/TermSCP) [![Issues](https://img.shields.io/github/issues/ChristianVisintin/TermSCP.svg)](https://github.com/ChristianVisintin/TermSCP/issues) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp) [![Issues](https://img.shields.io/github/issues/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp/issues) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) -[![Build](https://github.com/ChristianVisintin/TermSCP/workflows/Linux/badge.svg)](https://github.com/ChristianVisintin/TermSCP/actions) [![Build](https://github.com/ChristianVisintin/TermSCP/workflows/MacOS/badge.svg)](https://github.com/ChristianVisintin/TermSCP/actions) [![Build](https://github.com/ChristianVisintin/TermSCP/workflows/Windows/badge.svg)](https://github.com/ChristianVisintin/TermSCP/actions) [![codecov](https://codecov.io/gh/ChristianVisintin/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/ChristianVisintin/termscp) +[![Build](https://github.com/ChristianVisintin/termscp/workflows/Linux/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/MacOS/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/Windows/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![codecov](https://codecov.io/gh/ChristianVisintin/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/ChristianVisintin/termscp) ~ Basically, WinSCP on a terminal ~ Developed by Christian Visintin From f6d1f24b60f355716e29187e5e3e9946eb4deb02 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 09:40:24 +0100 Subject: [PATCH 33/64] cargo clippy --- src/ui/activities/setup_activity/callbacks.rs | 2 +- src/ui/activities/setup_activity/config.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs index 4150cbb..85410fd 100644 --- a/src/ui/activities/setup_activity/callbacks.rs +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -119,7 +119,7 @@ impl SetupActivity { let rsa_key: String = rsa_key.as_str().replace(placeholder.as_str(), ""); if rsa_key.is_empty() { // Report error: empty key - self.popup = Some(Popup::Alert(Color::Red, format!("SSH Key is empty"))); + self.popup = Some(Popup::Alert(Color::Red, "SSH Key is empty".to_string())); } else { // Add key if let Err(err) = diff --git a/src/ui/activities/setup_activity/config.rs b/src/ui/activities/setup_activity/config.rs index 7975a67..7a8f63c 100644 --- a/src/ui/activities/setup_activity/config.rs +++ b/src/ui/activities/setup_activity/config.rs @@ -55,9 +55,9 @@ impl SetupActivity { } } None => { - self.popup = Some(Popup::Fatal(format!( - "No configuration directory is available on your system" - ))) + self.popup = Some(Popup::Fatal( + "No configuration directory is available on your system".to_string(), + )) } }, Err(err) => { From 644ea1566cfc1bc3eb787171b0105fd23b29a8a2 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 10:16:01 +0100 Subject: [PATCH 34/64] Create new file with --- CHANGELOG.md | 4 +- README.md | 1 + .../filetransfer_activity/callbacks.rs | 97 ++++++++++++++++++- .../activities/filetransfer_activity/input.rs | 14 +++ 4 files changed, 114 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 088c0c1..42ac483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,9 @@ FIXME: Released on - Enhancements: - Replaced `sha256` sum with last modification time check, to verify if a file has been changed in the text editor - Default protocol changed to default protocol in configuration when providing address as CLI argument -- dependencies: +- Keybindings: + - `N`: New file +- Dependencies: - removed `data-encoding` - updated `rand` to `0.8.0` - removed `ring` diff --git a/README.md b/README.md index f963ec3..42c1a0c 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys` | `` | Show help | Help | | `` | Show info about selected file or directory | Info | | `` | Reload current directory's content | List | +| `` | Create new file with provided name | New | | `` | Edit file; see [Text editor](#text-editor-) | Open | | `` | Quit TermSCP | Quit | | `` | Rename file | Rename | diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index e6330a2..15a83a7 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -19,8 +19,9 @@ * */ +// Locals use super::{FileExplorerTab, FileTransferActivity, FsEntry, LogLevel}; - +// Ext use std::path::PathBuf; impl FileTransferActivity { @@ -371,4 +372,98 @@ impl FileTransferActivity { } } } + + /// ### callback_new_file + /// + /// Create a new file in current directory with `input` as name + pub(super) fn callback_new_file(&mut self, input: String) { + match self.tab { + FileExplorerTab::Local => { + // Check if file exists + for file in self.local.files.iter() { + if input == file.get_name() { + self.log_and_alert( + LogLevel::Warn, + format!("File \"{}\" already exists", input,), + ); + return; + } + } + // Create file + let file_path: PathBuf = PathBuf::from(input.as_str()); + if let Some(ctx) = self.context.as_mut() { + if let Err(err) = ctx.local.open_file_write(file_path.as_path()) { + self.log_and_alert( + LogLevel::Error, + format!("Could not create file \"{}\": {}", file_path.display(), err), + ); + } + // Reload files + let path: PathBuf = self.local.wrkdir.clone(); + self.local_scan(path.as_path()); + } + } + FileExplorerTab::Remote => { + // Check if file exists + for file in self.remote.files.iter() { + if input == file.get_name() { + self.log_and_alert( + LogLevel::Warn, + format!("File \"{}\" already exists", input,), + ); + return; + } + } + // Get path on remote + let file_path: PathBuf = PathBuf::from(input.as_str()); + // Create file (on local) + match tempfile::NamedTempFile::new() { + Err(err) => self.log_and_alert( + LogLevel::Error, + format!("Could not create tempfile: {}", err), + ), + Ok(tfile) => { + // Stat tempfile + if let Some(ctx) = self.context.as_mut() { + let local_file: FsEntry = match ctx.local.stat(tfile.path()) { + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!("Could not stat tempfile: {}", err), + ); + return; + } + Ok(f) => f, + }; + if let FsEntry::File(local_file) = local_file { + // Create file + match self.client.send_file(&local_file, file_path.as_path()) { + Err(err) => self.log_and_alert( + LogLevel::Error, + format!( + "Could not create file \"{}\": {}", + file_path.display(), + err + ), + ), + Ok(writer) => { + // Finalize write + if let Err(err) = self.client.on_sent(writer) { + self.log_and_alert( + LogLevel::Warn, + format!("Could not finalize file: {}", err), + ); + } + // Reload files + let path: PathBuf = self.remote.wrkdir.clone(); + self.remote_scan(path.as_path()); + } + } + } + } + } + } + } + } + } } diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 2455b58..af5b4d7 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -228,6 +228,13 @@ impl FileTransferActivity { let pwd: PathBuf = self.local.wrkdir.clone(); self.local_scan(pwd.as_path()); } + 'n' | 'N' => { + // New file + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("New file"), + Self::callback_new_file, + )); + } 'o' | 'O' => { // Edit local file if self.local.files.get(self.local.index).is_some() { @@ -446,6 +453,13 @@ impl FileTransferActivity { // Reload file entries self.reload_remote_dir(); } + 'n' | 'N' => { + // New file + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("New file"), + Self::callback_new_file, + )); + } 'o' | 'O' => { // Edit remote file if self.remote.files.get(self.remote.index).is_some() { From 545544ebe2ed5b4866e48662e39feeb8c2266ebd Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 10:33:23 +0100 Subject: [PATCH 35/64] Added test to config client --- src/system/config_client.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 915b2e6..9b219fc 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -434,6 +434,15 @@ mod tests { ); } + #[test] + fn test_system_config_make_io_err() { + let err: SerializerError = + ConfigClient::make_io_err(std::io::Error::from(std::io::ErrorKind::PermissionDenied)) + .err() + .unwrap(); + assert_eq!(err.to_string(), "IO error (permission denied)"); + } + /// ### get_paths /// /// Get paths for configuration and keys directory From c0fdc9b8f8bbc324d7ef3794e632fa9a09d270f9 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 10:40:45 +0100 Subject: [PATCH 36/64] Added new keybindings to help; log new file created --- .../filetransfer_activity/callbacks.rs | 9 +++++++ .../filetransfer_activity/layout.rs | 25 ++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index 15a83a7..b7439d1 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -398,6 +398,10 @@ impl FileTransferActivity { format!("Could not create file \"{}\": {}", file_path.display(), err), ); } + self.log( + LogLevel::Info, + format!("Created file \"{}\"", file_path.display()).as_str(), + ); // Reload files let path: PathBuf = self.local.wrkdir.clone(); self.local_scan(path.as_path()); @@ -454,6 +458,11 @@ impl FileTransferActivity { format!("Could not finalize file: {}", err), ); } + self.log( + LogLevel::Info, + format!("Created file \"{}\"", file_path.display()) + .as_str(), + ); // Reload files let path: PathBuf = self.remote.wrkdir.clone(); self.remote_scan(path.as_path()); diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index f6d79e0..dddd36b 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -101,7 +101,7 @@ impl FileTransferActivity { PopupType::Alert(_, _) => (50, 10), PopupType::Fatal(_) => (50, 10), PopupType::FileInfo => (50, 50), - PopupType::Help => (50, 70), + PopupType::Help => (50, 80), PopupType::Input(_, _) => (40, 10), PopupType::Progress(_) => (40, 10), PopupType::Wait(_) => (50, 10), @@ -485,8 +485,7 @@ impl FileTransferActivity { let abs_path: PathBuf = fsentry.get_abs_path(); let name: String = fsentry.get_name(); let ctime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S"); - let atime: String = - fmt_time(fsentry.get_last_access_time(), "%b %d %Y %H:%M:%S"); + let atime: String = fmt_time(fsentry.get_last_access_time(), "%b %d %Y %H:%M:%S"); let mtime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S"); let (bsize, size): (ByteSize, usize) = (ByteSize(fsentry.get_size() as u64), fsentry.get_size()); @@ -786,6 +785,26 @@ impl FileTransferActivity { Span::raw(" "), Span::raw("Reload directory content"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("New file"), + ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Open text file"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "", From 8ccf5eb0bb3ab996bf3696b0b99d930005c37873 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 10:51:01 +0100 Subject: [PATCH 37/64] FsEntry::get_name() returns &str --- src/fs/mod.rs | 12 ++++++------ src/ui/activities/filetransfer_activity/input.rs | 4 ++-- src/ui/activities/filetransfer_activity/layout.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 4ce73f9..468bfe9 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -97,10 +97,10 @@ impl FsEntry { /// ### get_name /// /// Get file name from `FsEntry` - pub fn get_name(&self) -> String { + pub fn get_name(&self) -> &'_ str { match self { - FsEntry::Directory(dir) => dir.name.clone(), - FsEntry::File(file) => file.name.clone(), + FsEntry::Directory(dir) => dir.name.as_ref(), + FsEntry::File(file) => file.name.as_ref(), } } @@ -273,10 +273,10 @@ impl std::fmt::Display for FsEntry { // Get date let datetime: String = fmt_time(self.get_last_change_time(), "%b %d %Y %H:%M"); // Set file name (or elide if too long) - let name: String = self.get_name(); + let name: &str = self.get_name(); let name: String = match name.len() >= 24 { - false => name, - true => format!("{}...", &name.as_str()[0..20]), + false => name.to_string(), + true => format!("{}...", &name[0..20]), }; write!( f, diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index af5b4d7..8b7c224 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -297,7 +297,7 @@ impl FileTransferActivity { if self.local.files.get(self.local.index).is_some() { let file: FsEntry = self.local.files.get(self.local.index).unwrap().clone(); - let name: String = file.get_name(); + let name: String = file.get_name().to_string(); // Call upload; pass realfile, keep link name self.filetransfer_send( &file.get_realfile(), @@ -519,7 +519,7 @@ impl FileTransferActivity { if self.remote.files.get(self.remote.index).is_some() { let file: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone(); - let name: String = file.get_name(); + let name: String = file.get_name().to_string(); // Call upload; pass realfile, keep link name let wrkdir: PathBuf = self.local.wrkdir.clone(); self.filetransfer_recv( diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index dddd36b..e611ef1 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -483,7 +483,7 @@ impl FileTransferActivity { Some(fsentry) => { // Get name and path let abs_path: PathBuf = fsentry.get_abs_path(); - let name: String = fsentry.get_name(); + let name: String = fsentry.get_name().to_string(); let ctime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S"); let atime: String = fmt_time(fsentry.get_last_access_time(), "%b %d %Y %H:%M:%S"); let mtime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S"); From 5b042e86efc8147ec613697b8c3f904048f54843 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 11:58:28 +0100 Subject: [PATCH 38/64] FsEntry::is_hidden() method --- src/fs/mod.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 468bfe9..a7dae6c 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -208,6 +208,13 @@ impl FsEntry { matches!(self, FsEntry::File(_)) } + /// ### is_hidden + /// + /// Returns whether FsEntry is hidden + pub fn is_hidden(&self) -> bool { + self.get_name().starts_with(".") + } + /// ### get_realfile /// /// Return the real file pointed by a `FsEntry` @@ -353,6 +360,54 @@ mod tests { assert_eq!(entry.is_file(), true); } + #[test] + fn test_fs_fsentry_hidden_files() { + let t_now: SystemTime = SystemTime::now(); + let entry: FsEntry = FsEntry::File(FsFile { + name: String::from("bar.txt"), + abs_path: PathBuf::from("/bar.txt"), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + size: 8192, + readonly: false, + ftype: Some(String::from("txt")), + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }); + assert_eq!(entry.is_hidden(), false); + let entry: FsEntry = FsEntry::File(FsFile { + name: String::from(".gitignore"), + abs_path: PathBuf::from("/.gitignore"), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + size: 8192, + readonly: false, + ftype: Some(String::from("txt")), + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }); + assert_eq!(entry.is_hidden(), true); + let entry: FsEntry = FsEntry::Directory(FsDirectory { + name: String::from(".git"), + abs_path: PathBuf::from("/.git"), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + readonly: false, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((7, 5, 5)), // UNIX only + }); + assert_eq!(entry.is_hidden(), true); + } + #[test] fn test_fs_fsentry_realfile_none() { let t_now: SystemTime = SystemTime::now(); From e0d9ac2ed8411371ad4305bb4c9a0cd3f77bcf95 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 15:50:57 +0100 Subject: [PATCH 39/64] FileTransferActivity::Explorer refactoring; toggle hidden files with --- CHANGELOG.md | 3 + README.md | 3 +- src/fs/mod.rs | 2 +- .../filetransfer_activity/callbacks.rs | 60 +- .../filetransfer_activity/explorer.rs | 532 ++++++++++++++++++ .../activities/filetransfer_activity/input.rs | 118 ++-- .../filetransfer_activity/layout.rs | 28 +- .../activities/filetransfer_activity/mod.rs | 74 +-- .../filetransfer_activity/session.rs | 44 +- 9 files changed, 679 insertions(+), 185 deletions(-) create mode 100644 src/ui/activities/filetransfer_activity/explorer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ac483..cf6ae61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,10 @@ FIXME: Released on - Enhancements: - Replaced `sha256` sum with last modification time check, to verify if a file has been changed in the text editor - Default protocol changed to default protocol in configuration when providing address as CLI argument + - Explorers: + - Hidden files are now not shown by default; use `A` to show hidden files. - Keybindings: + - `A`: Toggle hidden files - `N`: New file - Dependencies: - removed `data-encoding` diff --git a/README.md b/README.md index 42c1a0c..ed7f1f2 100644 --- a/README.md +++ b/README.md @@ -290,9 +290,10 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys` | `` | Move down in selected list by 8 rows | | | `` | Enter directory | | | `` | Upload / download selected file | | +| `` | Toggle hidden files | All | | `` | Copy file/directory | Copy | | `` | Make directory | Directory | -| `` | Delete file (Same as `CANC`) | Erase | +| `` | Delete file (Same as `DEL`) | Erase | | `` | Go to supplied path | Go to | | `` | Show help | Help | | `` | Show info about selected file or directory | Info | diff --git a/src/fs/mod.rs b/src/fs/mod.rs index a7dae6c..0e62298 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -212,7 +212,7 @@ impl FsEntry { /// /// Returns whether FsEntry is hidden pub fn is_hidden(&self) -> bool { - self.get_name().starts_with(".") + self.get_name().starts_with('.') } /// ### get_realfile diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index b7439d1..4d6e525 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -1,3 +1,7 @@ +//! ## FileTransferActivity +//! +//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall + /* * * Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com @@ -71,8 +75,8 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => { // Get selected entry - if self.local.files.get(self.local.index).is_some() { - let entry: FsEntry = self.local.files.get(self.local.index).unwrap().clone(); + if self.local.get_current_file().is_some() { + let entry: FsEntry = self.local.get_current_file().unwrap().clone(); if let Some(ctx) = self.context.as_mut() { match ctx.local.copy(&entry, dest_path.as_path()) { Ok(_) => { @@ -104,8 +108,8 @@ impl FileTransferActivity { } FileExplorerTab::Remote => { // Get selected entry - if self.remote.files.get(self.remote.index).is_some() { - let entry: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone(); + if self.remote.get_current_file().is_some() { + let entry: FsEntry = self.remote.get_current_file().unwrap().clone(); match self.client.as_mut().copy(&entry, dest_path.as_path()) { Ok(_) => { self.log( @@ -205,7 +209,7 @@ impl FileTransferActivity { dst_path = wrkdir; } // Check if file entry exists - if let Some(entry) = self.local.files.get(self.local.index) { + if let Some(entry) = self.local.get_current_file() { let full_path: PathBuf = entry.get_abs_path(); // Rename file or directory and report status as popup match self @@ -245,7 +249,7 @@ impl FileTransferActivity { } FileExplorerTab::Remote => { // Check if file entry exists - if let Some(entry) = self.remote.files.get(self.remote.index) { + if let Some(entry) = self.remote.get_current_file() { let full_path: PathBuf = entry.get_abs_path(); // Rename file or directory and report status as popup let dst_path: PathBuf = PathBuf::from(input); @@ -289,7 +293,7 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => { // Check if file entry exists - if let Some(entry) = self.local.files.get(self.local.index) { + if let Some(entry) = self.local.get_current_file() { let full_path: PathBuf = entry.get_abs_path(); // Delete file or directory and report status as popup match self.context.as_mut().unwrap().local.remove(entry) { @@ -318,7 +322,7 @@ impl FileTransferActivity { } FileExplorerTab::Remote => { // Check if file entry exists - if let Some(entry) = self.remote.files.get(self.remote.index) { + if let Some(entry) = self.remote.get_current_file() { let full_path: PathBuf = entry.get_abs_path(); // Delete file match self.client.remove(entry) { @@ -355,16 +359,16 @@ impl FileTransferActivity { // Get pwd let wrkdir: PathBuf = self.remote.wrkdir.clone(); // Get file and clone (due to mutable / immutable stuff...) - if self.local.files.get(self.local.index).is_some() { - let file: FsEntry = self.local.files.get(self.local.index).unwrap().clone(); + if self.local.get_current_file().is_some() { + let file: FsEntry = self.local.get_current_file().unwrap().clone(); // Call upload; pass realfile, keep link name self.filetransfer_send(&file.get_realfile(), wrkdir.as_path(), Some(input)); } } FileExplorerTab::Remote => { // Get file and clone (due to mutable / immutable stuff...) - if self.remote.files.get(self.remote.index).is_some() { - let file: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone(); + if self.remote.get_current_file().is_some() { + let file: FsEntry = self.remote.get_current_file().unwrap().clone(); // Call upload; pass realfile, keep link name let wrkdir: PathBuf = self.local.wrkdir.clone(); self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(input)); @@ -380,15 +384,19 @@ impl FileTransferActivity { match self.tab { FileExplorerTab::Local => { // Check if file exists - for file in self.local.files.iter() { + let mut file_exists: bool = false; + for file in self.local.iter_files_all() { if input == file.get_name() { - self.log_and_alert( - LogLevel::Warn, - format!("File \"{}\" already exists", input,), - ); - return; + file_exists = true; } } + if file_exists { + self.log_and_alert( + LogLevel::Warn, + format!("File \"{}\" already exists", input,), + ); + return; + } // Create file let file_path: PathBuf = PathBuf::from(input.as_str()); if let Some(ctx) = self.context.as_mut() { @@ -409,15 +417,19 @@ impl FileTransferActivity { } FileExplorerTab::Remote => { // Check if file exists - for file in self.remote.files.iter() { + let mut file_exists: bool = false; + for file in self.remote.iter_files_all() { if input == file.get_name() { - self.log_and_alert( - LogLevel::Warn, - format!("File \"{}\" already exists", input,), - ); - return; + file_exists = true; } } + if file_exists { + self.log_and_alert( + LogLevel::Warn, + format!("File \"{}\" already exists", input,), + ); + return; + } // Get path on remote let file_path: PathBuf = PathBuf::from(input.as_str()); // Create file (on local) diff --git a/src/ui/activities/filetransfer_activity/explorer.rs b/src/ui/activities/filetransfer_activity/explorer.rs new file mode 100644 index 0000000..cc5a481 --- /dev/null +++ b/src/ui/activities/filetransfer_activity/explorer.rs @@ -0,0 +1,532 @@ +//! ## FileTransferActivity +//! +//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::FsEntry; +// Ext +use std::collections::VecDeque; +use std::path::{Path, PathBuf}; + +/// ## FileExplorer +/// +/// File explorer states +pub struct FileExplorer { + pub wrkdir: PathBuf, // Current directory + index: usize, // Selected file + files: Vec, // Files in directory + dirstack: VecDeque, // Stack of visited directory (max 16) + stack_size: usize, // Directory stack size + hidden_files: bool, // Should hidden files be shown or not; hidden if false +} + +impl FileExplorer { + /// ### new + /// + /// Instantiates a new FileExplorer + pub fn new(stack_size: usize) -> FileExplorer { + FileExplorer { + wrkdir: PathBuf::from("/"), + index: 0, + files: Vec::new(), + dirstack: VecDeque::with_capacity(stack_size), + stack_size, + hidden_files: false, // Default: don't show hidden files + } + } + + /// ### pushd + /// + /// push directory to stack + pub fn pushd(&mut self, dir: &Path) { + // Check if stack would overflow the size + while self.dirstack.len() >= self.stack_size { + self.dirstack.pop_front(); // Start cleaning events from back + } + // Eventually push front the new record + self.dirstack.push_back(PathBuf::from(dir)); + } + + /// ### popd + /// + /// Pop directory from the stack and return the directory + pub fn popd(&mut self) -> Option { + self.dirstack.pop_back() + } + + /// ### set_files + /// + /// Set Explorer files + /// Index is then moved to first valid `FsEntry` for current setup + pub fn set_files(&mut self, files: Vec) { + self.files = files; + // Set index to first valid entry + self.index_at_first(); + } + + /// ### count + /// + /// Return amount of files + pub fn count(&self) -> usize { + self.files.len() + } + + /// ### iter_files + /// + /// Iterate over files + /// Filters are applied based on current options (e.g. hidden files not returned) + pub fn iter_files(&self) -> Box + '_> { + // Match options + match self.hidden_files { + false => Box::new(self.files.iter().filter(|x| !x.is_hidden())), // Show only visible files + true => self.iter_files_all(), // Show all + } + } + + /// ### iter_files_all + /// + /// Iterate all files; doesn't care about options + pub fn iter_files_all(&self) -> Box + '_> { + Box::new(self.files.iter()) + } + + /// ### get_current_file + /// + /// Get file at index + pub fn get_current_file(&self) -> Option<&FsEntry> { + self.files.get(self.index) + } + + /// ### sort_files_by_name + /// + /// Sort explorer files by their name. All names are converted to lowercase + pub fn sort_files_by_name(&mut self) { + self.files.sort_by_key(|x: &FsEntry| match x { + FsEntry::Directory(dir) => dir.name.as_str().to_lowercase(), + FsEntry::File(file) => file.name.as_str().to_lowercase(), + }); + // Reset index + self.index_at_first(); + } + + /// ### incr_index + /// + /// Increment index to the first visible FsEntry. + /// If index goes to `files.len() - 1`, the value will be seto to the minimum acceptable value + pub fn incr_index(&mut self) { + let sz: usize = self.files.len(); + // Increment or wrap + if self.index + 1 >= sz { + self.index = 0; // Wrap + } else { + self.index += 1; // Increment + } + // Validate + match self.files.get(self.index) { + Some(assoc_entry) => { + if !self.hidden_files { + // Check if file is hidden, otherwise increment + if assoc_entry.is_hidden() { + // Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS) + let hidden_files: usize = + self.files.iter().filter(|x| x.is_hidden()).count(); + // Only if there are more files, than hidden files keep incrementing + if sz > hidden_files { + self.incr_index(); + } + } + } + } + None => self.index = 0, // Reset to 0, for safety reasons + } + } + + /// ### incr_index_by + /// + /// Increment index by up to n + /// If index goes to `files.len() - 1`, the value will be seto to the minimum acceptable value + pub fn incr_index_by(&mut self, n: usize) { + for _ in 0..n { + let prev_idx: usize = self.index; + // Increment + self.incr_index(); + // If prev index is > index and break + if prev_idx > self.index { + self.index = prev_idx; + break; + } + } + } + + /// ### decr_index + /// + /// Decrement index to the first visible FsEntry. + /// If index is 0, its value will be set to the maximum acceptable value + pub fn decr_index(&mut self) { + let sz: usize = self.files.len(); + // Increment or wrap + if self.index > 0 { + self.index -= 1; // Decrement + } else { + self.index = sz - 1; // Wrap + } + // Validate index + match self.files.get(self.index) { + Some(assoc_entry) => { + if !self.hidden_files { + // Check if file is hidden, otherwise increment + if assoc_entry.is_hidden() { + // Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS) + let hidden_files: usize = + self.files.iter().filter(|x| x.is_hidden()).count(); + // Only if there are more files, than hidden files keep decrementing + if sz > hidden_files { + self.decr_index(); + } + } + } + } + None => self.index = 0, // Reset to 0, for safety reasons + } + } + + /// ### decr_index_by + /// + /// Decrement index by up to n + pub fn decr_index_by(&mut self, n: usize) { + for _ in 0..n { + let prev_idx: usize = self.index; + // Increment + self.decr_index(); + // If prev index is < index and break + if prev_idx < self.index { + self.index = prev_idx; + break; + } + } + } + + /// ### index_at_first + /// + /// Move index to first "visible" fs entry + pub fn index_at_first(&mut self) { + self.index = self.get_first_valid_index(); + } + + /// ### get_first_valid_index + /// + /// Return first valid index + fn get_first_valid_index(&self) -> usize { + match self.hidden_files { + true => 0, + false => { + // Look for first "non-hidden" entry + for (i, f) in self.files.iter().enumerate() { + if !f.is_hidden() { + return i; + } + } + // If all files are hidden, return 0 + 0 + } + } + } + + /// ### get_index + /// + /// Return index + pub fn get_index(&self) -> usize { + self.index + } + + /// ### get_relative_index + /// + /// Get relative index based on current options + pub fn get_relative_index(&self) -> usize { + match self.files.get(self.index) { + Some(abs_entry) => { + // Search abs entry in relative iterator + for (i, f) in self.iter_files().enumerate() { + if abs_entry.get_name() == f.get_name() { + // If abs entry is f, return index + return i; + } + } + // Return 0 if not found + 0 + } + None => 0, // Absolute entry doesn't exist + } + } + + /// ### set_index + /// + /// Set index to idx. + /// If index exceeds size, is set to count() - 1; or 0 + pub fn set_index(&mut self, idx: usize) { + let visible_sz: usize = self.iter_files().count(); + match idx >= visible_sz { + true => match visible_sz { + 0 => self.index_at_first(), + _ => self.index = visible_sz - 1, + }, + false => match self.get_first_valid_index() > idx { + true => self.index_at_first(), + false => self.index = idx, + }, + } + } + + /// ### toggle_hidden_files + /// + /// Enable/disable hidden files + pub fn toggle_hidden_files(&mut self) { + self.hidden_files = !self.hidden_files; + // Adjust index + if self.index < self.get_first_valid_index() { + self.index_at_first(); + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::fs::{FsDirectory, FsFile}; + + use std::time::SystemTime; + + #[test] + fn test_ui_filetransfer_activity_explorer_new() { + let explorer: FileExplorer = FileExplorer::new(16); + // Verify + assert_eq!(explorer.dirstack.len(), 0); + assert_eq!(explorer.files.len(), 0); + assert_eq!(explorer.hidden_files, false); + assert_eq!(explorer.wrkdir, PathBuf::from("/")); + assert_eq!(explorer.stack_size, 16); + assert_eq!(explorer.index, 0); + } + + #[test] + fn test_ui_filetransfer_activity_explorer_stack() { + let mut explorer: FileExplorer = FileExplorer::new(2); + // Push dir + explorer.pushd(&Path::new("/tmp")); + explorer.pushd(&Path::new("/home/omar")); + // Pop + assert_eq!(explorer.popd().unwrap(), PathBuf::from("/home/omar")); + assert_eq!(explorer.dirstack.len(), 1); + assert_eq!(explorer.popd().unwrap(), PathBuf::from("/tmp")); + assert_eq!(explorer.dirstack.len(), 0); + // Dirstack is empty now + assert!(explorer.popd().is_none()); + // Exceed limit + explorer.pushd(&Path::new("/tmp")); + explorer.pushd(&Path::new("/home/omar")); + explorer.pushd(&Path::new("/dev")); + assert_eq!(explorer.dirstack.len(), 2); + assert_eq!(*explorer.dirstack.get(1).unwrap(), PathBuf::from("/dev")); + assert_eq!( + *explorer.dirstack.get(0).unwrap(), + PathBuf::from("/home/omar") + ); + } + + #[test] + fn test_ui_filetransfer_activity_explorer_files() { + let mut explorer: FileExplorer = FileExplorer::new(16); + explorer.hidden_files = false; + // Create files + explorer.set_files(vec![ + make_fs_entry("README.md", false), + make_fs_entry("src/", true), + make_fs_entry(".git/", true), + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("codecov.yml", false), + make_fs_entry(".gitignore", false), + ]); + assert_eq!(explorer.count(), 6); + // Verify + assert_eq!( + explorer.files.get(0).unwrap().get_name(), + String::from("README.md") + ); + // Sort files + explorer.sort_files_by_name(); + // Verify + assert_eq!( + explorer.files.get(0).unwrap().get_name(), + String::from(".git/") + ); + // Iter files (all) + assert_eq!(explorer.iter_files_all().count(), 6); + // Iter files (hidden excluded) (.git, .gitignore are hidden) + assert_eq!(explorer.iter_files().count(), 4); + // Toggle hidden + explorer.toggle_hidden_files(); + assert_eq!(explorer.iter_files().count(), 6); // All files are returned now + } + + #[test] + fn test_ui_filetransfer_activity_explorer_index() { + let mut explorer: FileExplorer = FileExplorer::new(16); + explorer.hidden_files = false; + // Create files + explorer.set_files(vec![ + make_fs_entry("README.md", false), + make_fs_entry("src/", true), + make_fs_entry(".git/", true), + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("CODE_OF_CONDUCT.md", false), + make_fs_entry("CHANGELOG.md", false), + make_fs_entry("LICENSE", false), + make_fs_entry("Cargo.toml", false), + make_fs_entry("Cargo.lock", false), + make_fs_entry("codecov.yml", false), + make_fs_entry(".gitignore", false), + ]); + let sz: usize = explorer.count(); + // Sort by name + explorer.sort_files_by_name(); + // Get first index + assert_eq!(explorer.get_first_valid_index(), 2); + // Index should be 2 now; files hidden; this happens because `index_at_first` is called after loading files + assert_eq!(explorer.get_index(), 2); + assert_eq!(explorer.get_relative_index(), 0); // Relative index should be 0 + assert_eq!(explorer.hidden_files, false); + // Increment index + explorer.incr_index(); + // Index should now be 3 (was 0, + 2 + 1); first 2 files are hidden (.git, .gitignore) + assert_eq!(explorer.get_index(), 3); + // Relative index should be 1 instead + assert_eq!(explorer.get_relative_index(), 1); + // Increment by 2 + explorer.incr_index_by(2); + // Index should now be 5, 3 + assert_eq!(explorer.get_index(), 5); + assert_eq!(explorer.get_relative_index(), 3); + // Increment by (exceed size) + explorer.incr_index_by(20); + // Index should be at last element + assert_eq!(explorer.get_index(), sz - 1); + assert_eq!(explorer.get_relative_index(), sz - 3); + // Increment; should go to 2 + explorer.incr_index(); + assert_eq!(explorer.get_index(), 2); + assert_eq!(explorer.get_relative_index(), 0); + // Increment and then decrement + explorer.incr_index(); + explorer.decr_index(); + assert_eq!(explorer.get_index(), 2); + assert_eq!(explorer.get_relative_index(), 0); + // Decrement (and wrap) + explorer.decr_index(); + // Index should be at last element + assert_eq!(explorer.get_index(), sz - 1); + assert_eq!(explorer.get_relative_index(), sz - 3); + // Set index to 5 + explorer.set_index(5); + assert_eq!(explorer.get_index(), 5); + assert_eq!(explorer.get_relative_index(), 3); + // Decr by 2 + explorer.decr_index_by(2); + assert_eq!(explorer.get_index(), 3); + assert_eq!(explorer.get_relative_index(), 1); + // Decr by 2 + explorer.decr_index_by(2); + // Should decrement actually by 1 (since first two files are hidden) + assert_eq!(explorer.get_index(), 2); + assert_eq!(explorer.get_relative_index(), 0); + // Toggle hidden files + explorer.toggle_hidden_files(); + assert_eq!(explorer.hidden_files, true); + // Move index to 0 + explorer.set_index(0); + assert_eq!(explorer.get_index(), 0); + // Toggle hidden files + explorer.toggle_hidden_files(); + // Index should now have been moved to 2 + assert_eq!(explorer.get_index(), 2); + // Show hidden files + explorer.toggle_hidden_files(); + // Set index to 5 + explorer.set_index(5); + // Verify index + assert_eq!(explorer.get_index(), 5); + assert_eq!(explorer.get_relative_index(), 5); // Now relative matches + // Decrement by 6, goes to 0 + explorer.decr_index_by(6); + assert_eq!(explorer.get_index(), 0); + assert_eq!(explorer.get_relative_index(), 0); // Now relative matches + // Toggle; move at first + explorer.toggle_hidden_files(); + assert_eq!(explorer.hidden_files, false); + explorer.index_at_first(); + assert_eq!(explorer.get_index(), 2); + assert_eq!(explorer.get_relative_index(), 0); + // Verify set index if exceeds + let sz: usize = explorer.iter_files().count(); + explorer.set_index(sz); + assert_eq!(explorer.get_index(), sz - 1); // Should be at last element + // Empty files + explorer.files.clear(); + explorer.index_at_first(); + assert_eq!(explorer.get_index(), 0); + assert_eq!(explorer.get_relative_index(), 0); + } + + fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry { + let t_now: SystemTime = SystemTime::now(); + match is_dir { + false => FsEntry::File(FsFile { + name: name.to_string(), + abs_path: PathBuf::from(name), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + size: 64, + ftype: None, // File type + readonly: false, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }), + true => FsEntry::Directory(FsDirectory { + name: name.to_string(), + abs_path: PathBuf::from(name), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + readonly: false, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((7, 5, 5)), // UNIX only + }), + } + } +} diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 8b7c224..3e886c3 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -1,3 +1,7 @@ +//! ## FileTransferActivity +//! +//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall + /* * * Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com @@ -102,41 +106,28 @@ impl FileTransferActivity { KeyCode::Tab => self.switch_input_field(), // switch tab KeyCode::Right => self.tab = FileExplorerTab::Remote, // switch to right tab KeyCode::Up => { - // Move index up; or move to the last element if 0 - self.local.index = match self.local.index { - 0 => self.local.files.len() - 1, - _ => self.local.index - 1, - }; + // Decrement index + self.local.decr_index(); } KeyCode::Down => { - // Move index down - if self.local.index + 1 < self.local.files.len() { - self.local.index += 1; - } else { - self.local.index = 0; // Move at the beginning of the list - } + // Increment index + self.local.incr_index(); } KeyCode::PageUp => { - // Move index up (fast) - if self.local.index > 8 { - self.local.index -= 8; // Decrease by `8` if possible - } else { - self.local.index = 0; // Set to 0 otherwise - } + // Decrement index by 8 + self.local.decr_index_by(8); } KeyCode::PageDown => { - // Move index down (fast) - if self.local.index + 8 >= self.local.files.len() { - // If overflows, set to size - self.local.index = self.local.files.len() - 1; - } else { - self.local.index += 8; // Increase by `8` - } + // Increment index by 8 + self.local.incr_index_by(8); } KeyCode::Enter => { // Match selected file - let local_files: Vec = self.local.files.clone(); - if let Some(entry) = local_files.get(self.local.index) { + let mut entry: Option = None; + if let Some(e) = self.local.get_current_file() { + entry = Some(e.clone()); + } + if let Some(entry) = entry { // If directory, enter directory, otherwise check if symlink match entry { FsEntry::Directory(dir) => { @@ -162,7 +153,7 @@ impl FileTransferActivity { } KeyCode::Delete => { // Get file at index - if let Some(entry) = self.local.files.get(self.local.index) { + if let Some(entry) = self.local.get_current_file() { // Get file name let file_name: String = match entry { FsEntry::Directory(dir) => dir.name.clone(), @@ -177,6 +168,10 @@ impl FileTransferActivity { } } KeyCode::Char(ch) => match ch { + 'a' | 'A' => { + // Toggle hidden files + self.local.toggle_hidden_files(); + } 'c' | 'C' => { // Copy self.input_mode = InputMode::Popup(PopupType::Input( @@ -193,7 +188,7 @@ impl FileTransferActivity { } 'e' | 'E' => { // Get file at index - if let Some(entry) = self.local.files.get(self.local.index) { + if let Some(entry) = self.local.get_current_file() { // Get file name let file_name: String = match entry { FsEntry::Directory(dir) => dir.name.clone(), @@ -237,10 +232,9 @@ impl FileTransferActivity { } 'o' | 'O' => { // Edit local file - if self.local.files.get(self.local.index).is_some() { + if self.local.get_current_file().is_some() { // Clone entry due to mutable stuff... - let fsentry: FsEntry = - self.local.files.get(self.local.index).unwrap().clone(); + let fsentry: FsEntry = self.local.get_current_file().unwrap().clone(); // Check if file if fsentry.is_file() { self.log( @@ -294,9 +288,8 @@ impl FileTransferActivity { // Get pwd let wrkdir: PathBuf = self.remote.wrkdir.clone(); // Get file and clone (due to mutable / immutable stuff...) - if self.local.files.get(self.local.index).is_some() { - let file: FsEntry = - self.local.files.get(self.local.index).unwrap().clone(); + if self.local.get_current_file().is_some() { + let file: FsEntry = self.local.get_current_file().unwrap().clone(); let name: String = file.get_name().to_string(); // Call upload; pass realfile, keep link name self.filetransfer_send( @@ -328,41 +321,28 @@ impl FileTransferActivity { KeyCode::Tab => self.switch_input_field(), // switch tab KeyCode::Left => self.tab = FileExplorerTab::Local, // switch to local tab KeyCode::Up => { - // Move index up; or move to the last element if 0 - self.remote.index = match self.remote.index { - 0 => self.remote.files.len() - 1, - _ => self.remote.index - 1, - }; + // Decrement index + self.remote.decr_index(); } KeyCode::Down => { - // Move index down - if self.remote.index + 1 < self.remote.files.len() { - self.remote.index += 1; - } else { - self.remote.index = 0; // Move at the beginning of the list - } + // Increment index + self.remote.incr_index(); } KeyCode::PageUp => { - // Move index up (fast) - if self.remote.index > 8 { - self.remote.index -= 8; // Decrease by `8` if possible - } else { - self.remote.index = 0; // Set to 0 otherwise - } + // Decrement index by 8 + self.remote.decr_index_by(8); } KeyCode::PageDown => { - // Move index down (fast) - if self.remote.index + 8 >= self.remote.files.len() { - // If overflows, set to size - self.remote.index = self.remote.files.len() - 1; - } else { - self.remote.index += 8; // Increase by `8` - } + // Increment index by 8 + self.remote.incr_index_by(8); } KeyCode::Enter => { // Match selected file - let files: Vec = self.remote.files.clone(); - if let Some(entry) = files.get(self.remote.index) { + let mut entry: Option = None; + if let Some(e) = self.remote.get_current_file() { + entry = Some(e.clone()); + } + if let Some(entry) = entry { // If directory, enter directory; if file, check if is symlink match entry { FsEntry::Directory(dir) => { @@ -388,7 +368,7 @@ impl FileTransferActivity { } KeyCode::Delete => { // Get file at index - if let Some(entry) = self.remote.files.get(self.remote.index) { + if let Some(entry) = self.remote.get_current_file() { // Get file name let file_name: String = match entry { FsEntry::Directory(dir) => dir.name.clone(), @@ -403,6 +383,10 @@ impl FileTransferActivity { } } KeyCode::Char(ch) => match ch { + 'a' | 'A' => { + // Toggle hidden files + self.remote.toggle_hidden_files(); + } 'c' | 'C' => { // Copy self.input_mode = InputMode::Popup(PopupType::Input( @@ -419,7 +403,7 @@ impl FileTransferActivity { } 'e' | 'E' => { // Get file at index - if let Some(entry) = self.remote.files.get(self.remote.index) { + if let Some(entry) = self.remote.get_current_file() { // Get file name let file_name: String = match entry { FsEntry::Directory(dir) => dir.name.clone(), @@ -462,10 +446,9 @@ impl FileTransferActivity { } 'o' | 'O' => { // Edit remote file - if self.remote.files.get(self.remote.index).is_some() { + if self.remote.get_current_file().is_some() { // Clone entry due to mutable stuff... - let fsentry: FsEntry = - self.remote.files.get(self.remote.index).unwrap().clone(); + let fsentry: FsEntry = self.remote.get_current_file().unwrap().clone(); // Check if file if let FsEntry::File(file) = fsentry { self.log( @@ -516,9 +499,8 @@ impl FileTransferActivity { } ' ' => { // Get file and clone (due to mutable / immutable stuff...) - if self.remote.files.get(self.remote.index).is_some() { - let file: FsEntry = - self.remote.files.get(self.remote.index).unwrap().clone(); + if self.remote.get_current_file().is_some() { + let file: FsEntry = self.remote.get_current_file().unwrap().clone(); let name: String = file.get_name().to_string(); // Call upload; pass realfile, keep link name let wrkdir: PathBuf = self.local.wrkdir.clone(); diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index e611ef1..95afa4d 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -1,3 +1,7 @@ +//! ## FileTransferActivity +//! +//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall + /* * * Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com @@ -70,10 +74,10 @@ impl FileTransferActivity { .split(chunks[0]); // Set localhost state let mut localhost_state: ListState = ListState::default(); - localhost_state.select(Some(self.local.index)); + localhost_state.select(Some(self.local.get_relative_index())); // Set remote state let mut remote_state: ListState = ListState::default(); - remote_state.select(Some(self.remote.index)); + remote_state.select(Some(self.remote.get_relative_index())); // Draw tabs f.render_stateful_widget( self.draw_local_explorer(tabs_chunks[0].width), @@ -158,8 +162,7 @@ impl FileTransferActivity { }; let files: Vec = self .local - .files - .iter() + .iter_files() .map(|entry: &FsEntry| ListItem::new(Span::from(format!("{}", entry)))) .collect(); // Get colors to use; highlight element inverting fg/bg only when tab is active @@ -199,8 +202,7 @@ impl FileTransferActivity { pub(super) fn draw_remote_explorer(&self, width: u16) -> List { let files: Vec = self .remote - .files - .iter() + .iter_files() .map(|entry: &FsEntry| ListItem::new(Span::from(format!("{}", entry)))) .collect(); // Get colors to use; highlight element inverting fg/bg only when tab is active @@ -468,12 +470,12 @@ impl FileTransferActivity { let fsentry: Option<&FsEntry> = match self.tab { FileExplorerTab::Local => { // Get selected file - match self.local.files.get(self.local.index) { + match self.local.get_current_file() { Some(entry) => Some(entry), None => None, } } - FileExplorerTab::Remote => match self.remote.files.get(self.remote.index) { + FileExplorerTab::Remote => match self.remote.get_current_file() { Some(entry) => Some(entry), None => None, }, @@ -715,6 +717,16 @@ impl FileTransferActivity { Span::raw(" "), Span::raw("Delete file"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Toggle hidden files"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "", diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index 9431699..b8a9a77 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -25,6 +25,7 @@ // This module is split into files, cause it's just too big mod callbacks; +mod explorer; mod input; mod layout; mod misc; @@ -45,13 +46,14 @@ use crate::filetransfer::sftp_transfer::SftpFileTransfer; use crate::filetransfer::{FileTransfer, FileTransferProtocol}; use crate::fs::FsEntry; use crate::system::config_client::ConfigClient; +use explorer::FileExplorer; // Includes use chrono::{DateTime, Local}; use crossterm::event::Event as InputEvent; use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use std::collections::VecDeque; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::Instant; use tui::style::Color; @@ -113,59 +115,6 @@ enum InputMode { Popup(PopupType), } -/// ## FileExplorer -/// -/// File explorer states -struct FileExplorer { - pub wrkdir: PathBuf, // Current directory - pub index: usize, // Selected file - pub files: Vec, // Files in directory - dirstack: VecDeque, // Stack of visited directory (max 16) -} - -impl FileExplorer { - /// ### new - /// - /// Instantiates a new FileExplorer - pub fn new() -> FileExplorer { - FileExplorer { - wrkdir: PathBuf::from("/"), - index: 0, - files: Vec::new(), - dirstack: VecDeque::with_capacity(16), - } - } - - /// ### pushd - /// - /// push directory to stack - pub fn pushd(&mut self, dir: &Path) { - // Check if stack overflows the size - if self.dirstack.len() + 1 > 16 { - self.dirstack.pop_back(); // Start cleaning events from back - } - // Eventually push front the new record - self.dirstack.push_front(PathBuf::from(dir)); - } - - /// ### popd - /// - /// Pop directory from the stack and return the directory - pub fn popd(&mut self) -> Option { - self.dirstack.pop_front() - } - - /// ### sort_files_by_name - /// - /// Sort explorer files by their name - pub fn sort_files_by_name(&mut self) { - self.files.sort_by_key(|x: &FsEntry| match x { - FsEntry::Directory(dir) => dir.name.as_str().to_lowercase(), - FsEntry::File(file) => file.name.as_str().to_lowercase(), - }); - } -} - /// ## FileExplorerTab /// /// File explorer tab @@ -312,18 +261,18 @@ impl FileTransferActivity { quit: false, context: None, client: match protocol { - FileTransferProtocol::Sftp => { - Box::new(SftpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref()))) - } + FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new( + Self::make_ssh_storage(config_client.as_ref()), + )), FileTransferProtocol::Ftp(ftps) => Box::new(FtpFileTransfer::new(ftps)), - FileTransferProtocol::Scp => { - Box::new(ScpFileTransfer::new(Self::make_ssh_storage(config_client.as_ref()))) - } + FileTransferProtocol::Scp => Box::new(ScpFileTransfer::new( + Self::make_ssh_storage(config_client.as_ref()), + )), }, config_cli: config_client, params, - local: FileExplorer::new(), - remote: FileExplorer::new(), + local: FileExplorer::new(16), + remote: FileExplorer::new(16), tab: FileExplorerTab::Local, log_index: 0, log_records: VecDeque::with_capacity(256), // 256 events is enough I guess @@ -335,7 +284,6 @@ impl FileTransferActivity { transfer: TransferStates::default(), } } - } /** diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index e090f06..3a2c32d 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -1,3 +1,7 @@ +//! ## FileTransferActivity +//! +//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall + /* * * Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com @@ -599,17 +603,17 @@ impl FileTransferActivity { pub(super) fn local_scan(&mut self, path: &Path) { match self.context.as_ref().unwrap().local.scan_dir(path) { Ok(files) => { - self.local.files = files; - // Set index; keep if possible, otherwise set to last item - self.local.index = match self.local.files.get(self.local.index) { - Some(_) => self.local.index, - None => match self.local.files.len() { - 0 => 0, - _ => self.local.files.len() - 1, - }, - }; + self.local.set_files(files); // Sort files self.local.sort_files_by_name(); + // Set index; keep if possible, otherwise set to last item + self.local.set_index(match self.local.get_current_file() { + Some(_) => self.local.get_index(), + None => match self.local.count() { + 0 => 0, + _ => self.local.count() - 1, + }, + }); } Err(err) => { self.log_and_alert( @@ -626,17 +630,17 @@ impl FileTransferActivity { pub(super) fn remote_scan(&mut self, path: &Path) { match self.client.list_dir(path) { Ok(files) => { - self.remote.files = files; - // Set index; keep if possible, otherwise set to last item - self.remote.index = match self.remote.files.get(self.remote.index) { - Some(_) => self.remote.index, - None => match self.remote.files.len() { - 0 => 0, - _ => self.remote.files.len() - 1, - }, - }; + self.remote.set_files(files); // Sort files self.remote.sort_files_by_name(); + // Set index; keep if possible, otherwise set to last item + self.remote.set_index(match self.remote.get_current_file() { + Some(_) => self.remote.get_index(), + None => match self.remote.count() { + 0 => 0, + _ => self.remote.count() - 1, + }, + }); } Err(err) => { self.log_and_alert( @@ -663,7 +667,7 @@ impl FileTransferActivity { // Reload files self.local_scan(path); // Reset index - self.local.index = 0; + self.local.set_index(0); // Set wrkdir self.local.wrkdir = PathBuf::from(path); // Push prev_dir to stack @@ -694,7 +698,7 @@ impl FileTransferActivity { // Update files self.remote_scan(path); // Reset index - self.remote.index = 0; + self.remote.set_index(0); // Set wrkdir self.remote.wrkdir = PathBuf::from(path); // Push prev_dir to stack From 4911cc5410fc114b3cae1c91194d8fab0a2880f4 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 15:53:14 +0100 Subject: [PATCH 40/64] Removed issues badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed7f1f2..a8fdf56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TermSCP -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp) [![Issues](https://img.shields.io/github/issues/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp/issues) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) [![Build](https://github.com/ChristianVisintin/termscp/workflows/Linux/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/MacOS/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/Windows/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![codecov](https://codecov.io/gh/ChristianVisintin/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/ChristianVisintin/termscp) From 14125f673a6d7e062d9123495d7026f54d7fb0ce Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 17:29:12 +0100 Subject: [PATCH 41/64] Added options to explorer, in order to define sorting modes and other options. Added bitflags to dependencies; Moved Explorer to Fs module --- CHANGELOG.md | 1 + Cargo.lock | 1 + Cargo.toml | 1 + src/fs/explorer/builder.rs | 139 +++++++++++ .../explorer.rs => fs/explorer/mod.rs} | 236 ++++++++++++++---- src/fs/mod.rs | 8 +- src/lib.rs | 2 + src/main.rs | 2 + .../activities/filetransfer_activity/misc.rs | 12 + .../activities/filetransfer_activity/mod.rs | 9 +- .../filetransfer_activity/session.rs | 6 +- 11 files changed, 353 insertions(+), 64 deletions(-) create mode 100644 src/fs/explorer/builder.rs rename src/{ui/activities/filetransfer_activity/explorer.rs => fs/explorer/mod.rs} (68%) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf6ae61..c54bbc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ FIXME: Released on - `A`: Toggle hidden files - `N`: New file - Dependencies: + - added `bitflags 1.2.1` - removed `data-encoding` - updated `rand` to `0.8.0` - removed `ring` diff --git a/Cargo.lock b/Cargo.lock index 87dfa7d..05aeb57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1049,6 +1049,7 @@ dependencies = [ name = "termscp" version = "0.3.0" dependencies = [ + "bitflags", "bytesize", "chrono", "content_inspector", diff --git a/Cargo.toml b/Cargo.toml index 783df5f..b0d41c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bitflags = "1.2.1" bytesize = "1.0.1" chrono = "0.4.19" content_inspector = "0.2.4" diff --git a/src/fs/explorer/builder.rs b/src/fs/explorer/builder.rs new file mode 100644 index 0000000..28ff326 --- /dev/null +++ b/src/fs/explorer/builder.rs @@ -0,0 +1,139 @@ +//! ## Builder +//! +//! `builder` is the module which provides a builder for FileExplorer + +/* +* +* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* +* This file is part of "TermSCP" +* +* TermSCP is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* TermSCP is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with TermSCP. If not, see . +* +*/ + +// Locals +use super::{ExplorerOpts, FileExplorer}; +// Ext +use std::collections::VecDeque; + +/// ## FileExplorerBuilder +/// +/// Struct used to create a `FileExplorer` +pub struct FileExplorerBuilder { + explorer: Option, +} + +impl FileExplorerBuilder { + /// ### new + /// + /// Build a new `FileExplorerBuilder` + pub fn new() -> Self { + FileExplorerBuilder { + explorer: Some(FileExplorer::default()), + } + } + + /// ### build + /// + /// Take FileExplorer out of builder + pub fn build(&mut self) -> FileExplorer { + self.explorer.take().unwrap() + } + + /// ### with_hidden_files + /// + /// Enable HIDDEN_FILES option + pub fn with_hidden_files(&mut self) -> &mut FileExplorerBuilder { + if let Some(e) = self.explorer.as_mut() { + e.opts.insert(ExplorerOpts::SHOW_HIDDEN_FILES); + } + self + } + + /// ### sort_by_name + /// + /// Enable SORT_BY_NAME option + pub fn sort_by_name(&mut self) -> &mut FileExplorerBuilder { + if let Some(e) = self.explorer.as_mut() { + e.opts.insert(ExplorerOpts::SORT_BY_NAME); + } + self + } + + /// ### sort_by_mtime + /// + /// Enable SORT_BY_MTIME option + pub fn sort_by_mtime(&mut self) -> &mut FileExplorerBuilder { + if let Some(e) = self.explorer.as_mut() { + e.opts.insert(ExplorerOpts::SORT_BY_MTIME); + } + self + } + + /// ### with_dirs_first + /// + /// Enable DIRS_FIRST option + pub fn with_dirs_first(&mut self) -> &mut FileExplorerBuilder { + if let Some(e) = self.explorer.as_mut() { + e.opts.insert(ExplorerOpts::DIRS_FIRST); + } + self + } + + /// ### with_stack_size + /// + /// Set stack size for FileExplorer + pub fn with_stack_size(&mut self, sz: usize) -> &mut FileExplorerBuilder { + if let Some(e) = self.explorer.as_mut() { + e.stack_size = sz; + e.dirstack = VecDeque::with_capacity(sz); + } + self + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_fs_explorer_builder_new_default() { + let explorer: FileExplorer = FileExplorerBuilder::new().build(); + // Verify + assert!(!explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES)); + assert!(!explorer.opts.intersects(ExplorerOpts::SORT_BY_MTIME)); + assert!(!explorer.opts.intersects(ExplorerOpts::SORT_BY_NAME)); + assert!(!explorer.opts.intersects(ExplorerOpts::DIRS_FIRST)); + assert_eq!(explorer.stack_size, 16); + } + + #[test] + fn test_fs_explorer_builder_new_all() { + let explorer: FileExplorer = FileExplorerBuilder::new() + .sort_by_mtime() + .sort_by_name() + .with_dirs_first() + .with_hidden_files() + .with_stack_size(24) + .build(); + // Verify + assert!(explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES)); + assert!(explorer.opts.intersects(ExplorerOpts::SORT_BY_MTIME)); + assert!(explorer.opts.intersects(ExplorerOpts::SORT_BY_NAME)); + assert!(explorer.opts.intersects(ExplorerOpts::DIRS_FIRST)); + assert_eq!(explorer.stack_size, 24); + } +} diff --git a/src/ui/activities/filetransfer_activity/explorer.rs b/src/fs/explorer/mod.rs similarity index 68% rename from src/ui/activities/filetransfer_activity/explorer.rs rename to src/fs/explorer/mod.rs index cc5a481..07e40fe 100644 --- a/src/ui/activities/filetransfer_activity/explorer.rs +++ b/src/fs/explorer/mod.rs @@ -1,6 +1,6 @@ -//! ## FileTransferActivity +//! ## Explorer //! -//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall +//! `explorer` is the module which provides an Helper in handling Directory status through /* * @@ -23,39 +23,51 @@ * */ +// Mods +pub(crate) mod builder; +// Deps +extern crate bitflags; // Locals use super::FsEntry; // Ext use std::collections::VecDeque; use std::path::{Path, PathBuf}; +bitflags! { + pub(crate) struct ExplorerOpts: u32 { + const SHOW_HIDDEN_FILES = 0b00000001; + const SORT_BY_NAME = 0b00000010; + const SORT_BY_MTIME = 0b00000100; + const DIRS_FIRST = 0b00001000; + } +} + /// ## FileExplorer /// /// File explorer states pub struct FileExplorer { - pub wrkdir: PathBuf, // Current directory - index: usize, // Selected file - files: Vec, // Files in directory - dirstack: VecDeque, // Stack of visited directory (max 16) - stack_size: usize, // Directory stack size - hidden_files: bool, // Should hidden files be shown or not; hidden if false + pub wrkdir: PathBuf, // Current directory + index: usize, // Selected file + files: Vec, // Files in directory + pub(crate) dirstack: VecDeque, // Stack of visited directory (max 16) + pub(crate) stack_size: usize, // Directory stack size + pub(crate) opts: ExplorerOpts, // Explorer options } -impl FileExplorer { - /// ### new - /// - /// Instantiates a new FileExplorer - pub fn new(stack_size: usize) -> FileExplorer { +impl Default for FileExplorer { + fn default() -> Self { FileExplorer { wrkdir: PathBuf::from("/"), index: 0, files: Vec::new(), - dirstack: VecDeque::with_capacity(stack_size), - stack_size, - hidden_files: false, // Default: don't show hidden files + dirstack: VecDeque::with_capacity(16), + stack_size: 16, + opts: ExplorerOpts::empty(), } } +} +impl FileExplorer { /// ### pushd /// /// push directory to stack @@ -78,10 +90,13 @@ impl FileExplorer { /// ### set_files /// /// Set Explorer files - /// Index is then moved to first valid `FsEntry` for current setup + /// This method will also sort entries based on current options + /// Once all sorting have been performed, index is moved to first valid entry. pub fn set_files(&mut self, files: Vec) { self.files = files; - // Set index to first valid entry + // Sort + self.sort(); + // Reset index self.index_at_first(); } @@ -97,11 +112,17 @@ impl FileExplorer { /// Iterate over files /// Filters are applied based on current options (e.g. hidden files not returned) pub fn iter_files(&self) -> Box + '_> { - // Match options - match self.hidden_files { - false => Box::new(self.files.iter().filter(|x| !x.is_hidden())), // Show only visible files - true => self.iter_files_all(), // Show all - } + // Filter + let opts: ExplorerOpts = self.opts; + Box::new(self.files.iter().filter(move |x| { + // If true, element IS NOT filtered + let mut pass: bool = true; + // If hidden files SHOULDN'T be shown, AND pass with not hidden + if !opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES) { + pass &= !x.is_hidden(); + } + pass + })) } /// ### iter_files_all @@ -118,16 +139,46 @@ impl FileExplorer { self.files.get(self.index) } + // Sorting + + /// ### sort + /// + /// Sort files based on Explorer options. + fn sort(&mut self) { + // Sort by name + if self.opts.intersects(ExplorerOpts::SORT_BY_NAME) { + self.sort_files_by_name(); + } else if self.opts.intersects(ExplorerOpts::SORT_BY_MTIME) { + // Sort by mtime NOTE: else if cause exclusive + self.sort_files_by_name(); + } + // Directories first (MUST COME AFTER NAME) + if self.opts.intersects(ExplorerOpts::DIRS_FIRST) { + self.sort_files_directories_first(); + } + } + /// ### sort_files_by_name /// /// Sort explorer files by their name. All names are converted to lowercase - pub fn sort_files_by_name(&mut self) { - self.files.sort_by_key(|x: &FsEntry| match x { - FsEntry::Directory(dir) => dir.name.as_str().to_lowercase(), - FsEntry::File(file) => file.name.as_str().to_lowercase(), - }); - // Reset index - self.index_at_first(); + fn sort_files_by_name(&mut self) { + self.files + .sort_by_key(|x: &FsEntry| x.get_name().to_lowercase()); + } + + /// ### sort_files_by_mtime + /// + /// Sort files by mtime; the newest comes first + fn sort_files_by_mtime(&mut self) { + self.files + .sort_by_key(|x: &FsEntry| x.get_last_change_time()); + } + + /// ### sort_files_directories_first + /// + /// Sort files; directories come first + fn sort_files_directories_first(&mut self) { + self.files.sort_by_key(|x: &FsEntry| x.is_file()); } /// ### incr_index @@ -145,7 +196,7 @@ impl FileExplorer { // Validate match self.files.get(self.index) { Some(assoc_entry) => { - if !self.hidden_files { + if !self.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES) { // Check if file is hidden, otherwise increment if assoc_entry.is_hidden() { // Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS) @@ -194,7 +245,7 @@ impl FileExplorer { // Validate index match self.files.get(self.index) { Some(assoc_entry) => { - if !self.hidden_files { + if !self.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES) { // Check if file is hidden, otherwise increment if assoc_entry.is_hidden() { // Check if all files are hidden (NOTE: PREVENT STACK OVERFLOWS) @@ -238,7 +289,7 @@ impl FileExplorer { /// /// Return first valid index fn get_first_valid_index(&self) -> usize { - match self.hidden_files { + match self.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES) { true => 0, false => { // Look for first "non-hidden" entry @@ -302,7 +353,7 @@ impl FileExplorer { /// /// Enable/disable hidden files pub fn toggle_hidden_files(&mut self) { - self.hidden_files = !self.hidden_files; + self.opts.toggle(ExplorerOpts::SHOW_HIDDEN_FILES); // Adjust index if self.index < self.get_first_valid_index() { self.index_at_first(); @@ -316,23 +367,26 @@ mod tests { use super::*; use crate::fs::{FsDirectory, FsFile}; - use std::time::SystemTime; + use std::thread::sleep; + use std::time::{Duration, SystemTime}; #[test] - fn test_ui_filetransfer_activity_explorer_new() { - let explorer: FileExplorer = FileExplorer::new(16); + fn test_fs_explorer_new() { + let explorer: FileExplorer = FileExplorer::default(); // Verify assert_eq!(explorer.dirstack.len(), 0); assert_eq!(explorer.files.len(), 0); - assert_eq!(explorer.hidden_files, false); + assert_eq!(explorer.opts, ExplorerOpts::empty()); assert_eq!(explorer.wrkdir, PathBuf::from("/")); assert_eq!(explorer.stack_size, 16); assert_eq!(explorer.index, 0); } #[test] - fn test_ui_filetransfer_activity_explorer_stack() { - let mut explorer: FileExplorer = FileExplorer::new(2); + fn test_fs_explorer_stack() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.stack_size = 2; + explorer.dirstack = VecDeque::with_capacity(2); // Push dir explorer.pushd(&Path::new("/tmp")); explorer.pushd(&Path::new("/home/omar")); @@ -356,10 +410,10 @@ mod tests { } #[test] - fn test_ui_filetransfer_activity_explorer_files() { - let mut explorer: FileExplorer = FileExplorer::new(16); - explorer.hidden_files = false; - // Create files + fn test_fs_explorer_files() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES); // Don't show hidden files + // Create files explorer.set_files(vec![ make_fs_entry("README.md", false), make_fs_entry("src/", true), @@ -391,10 +445,11 @@ mod tests { } #[test] - fn test_ui_filetransfer_activity_explorer_index() { - let mut explorer: FileExplorer = FileExplorer::new(16); - explorer.hidden_files = false; - // Create files + fn test_fs_explorer_index() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES); + explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); + // Create files (files are then sorted by name) explorer.set_files(vec![ make_fs_entry("README.md", false), make_fs_entry("src/", true), @@ -409,14 +464,15 @@ mod tests { make_fs_entry(".gitignore", false), ]); let sz: usize = explorer.count(); - // Sort by name - explorer.sort_files_by_name(); // Get first index assert_eq!(explorer.get_first_valid_index(), 2); // Index should be 2 now; files hidden; this happens because `index_at_first` is called after loading files assert_eq!(explorer.get_index(), 2); assert_eq!(explorer.get_relative_index(), 0); // Relative index should be 0 - assert_eq!(explorer.hidden_files, false); + assert_eq!( + explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES), + false + ); // Increment index explorer.incr_index(); // Index should now be 3 (was 0, + 2 + 1); first 2 files are hidden (.git, .gitignore) @@ -462,7 +518,10 @@ mod tests { assert_eq!(explorer.get_relative_index(), 0); // Toggle hidden files explorer.toggle_hidden_files(); - assert_eq!(explorer.hidden_files, true); + assert_eq!( + explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES), + true + ); // Move index to 0 explorer.set_index(0); assert_eq!(explorer.get_index(), 0); @@ -483,7 +542,10 @@ mod tests { assert_eq!(explorer.get_relative_index(), 0); // Now relative matches // Toggle; move at first explorer.toggle_hidden_files(); - assert_eq!(explorer.hidden_files, false); + assert_eq!( + explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES), + false + ); explorer.index_at_first(); assert_eq!(explorer.get_index(), 2); assert_eq!(explorer.get_relative_index(), 0); @@ -498,6 +560,74 @@ mod tests { assert_eq!(explorer.get_relative_index(), 0); } + #[test] + fn test_fs_explorer_sort_by_name() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); + // Create files (files are then sorted by name) + explorer.set_files(vec![ + make_fs_entry("README.md", false), + make_fs_entry("src/", true), + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("CODE_OF_CONDUCT.md", false), + make_fs_entry("CHANGELOG.md", false), + make_fs_entry("LICENSE", false), + make_fs_entry("Cargo.toml", false), + make_fs_entry("Cargo.lock", false), + make_fs_entry("codecov.yml", false), + ]); + // First entry should be "Cargo.lock" + assert_eq!(explorer.files.get(0).unwrap().get_name(), "Cargo.lock"); + // Last should be "src/" + assert_eq!(explorer.files.get(8).unwrap().get_name(), "src/"); + } + + #[test] + fn test_fs_explorer_sort_by_mtime() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.opts.insert(ExplorerOpts::SORT_BY_MTIME); + let entry1: FsEntry = make_fs_entry("README.md", false); + // Wait 1 sec + sleep(Duration::from_secs(1)); + let entry2: FsEntry = make_fs_entry("CODE_OF_CONDUCT.md", false); + // Create files (files are then sorted by name) + explorer.set_files(vec![entry1, entry2]); + // First entry should be "CODE_OF_CONDUCT.md" + assert_eq!( + explorer.files.get(0).unwrap().get_name(), + "CODE_OF_CONDUCT.md" + ); + // Last should be "src/" + assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md"); + } + + #[test] + fn test_fs_explorer_sort_by_name_and_dir() { + let mut explorer: FileExplorer = FileExplorer::default(); + explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); + explorer.opts.insert(ExplorerOpts::DIRS_FIRST); + // Create files (files are then sorted by name) + explorer.set_files(vec![ + make_fs_entry("README.md", false), + make_fs_entry("src/", true), + make_fs_entry("docs/", true), + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("CODE_OF_CONDUCT.md", false), + make_fs_entry("CHANGELOG.md", false), + make_fs_entry("LICENSE", false), + make_fs_entry("Cargo.toml", false), + make_fs_entry("Cargo.lock", false), + make_fs_entry("codecov.yml", false), + ]); + // First entry should be "docs" + assert_eq!(explorer.files.get(0).unwrap().get_name(), "docs/"); + assert_eq!(explorer.files.get(1).unwrap().get_name(), "src/"); + // 3rd is file first for alphabetical order + assert_eq!(explorer.files.get(2).unwrap().get_name(), "Cargo.lock"); + // Last should be "README.md" (last file for alphabetical ordening) + assert_eq!(explorer.files.get(9).unwrap().get_name(), "README.md"); + } + fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry { let t_now: SystemTime = SystemTime::now(); match is_dir { diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 0e62298..b66ae1b 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -23,12 +23,16 @@ * */ +// Mod +pub mod explorer; + +// Deps extern crate bytesize; #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] extern crate users; - +// Locals use crate::utils::fmt::{fmt_pex, fmt_time}; - +// Ext use bytesize::ByteSize; use std::path::PathBuf; use std::time::SystemTime; diff --git a/src/lib.rs b/src/lib.rs index 087e803..a779075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,8 @@ * */ +#[macro_use] +extern crate bitflags; #[macro_use] extern crate lazy_static; #[macro_use] diff --git a/src/main.rs b/src/main.rs index 93eafb5..048c233 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,8 @@ const TERMSCP_AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); // Crates extern crate getopts; #[macro_use] +extern crate bitflags; +#[macro_use] extern crate lazy_static; #[macro_use] extern crate magic_crypt; diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 9931519..42c0562 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -24,6 +24,7 @@ use super::{ Color, ConfigClient, FileTransferActivity, InputField, InputMode, LogLevel, LogRecord, PopupType, }; +use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer}; use crate::system::environment; use crate::system::sshkey_storage::SshKeyStorage; // Ext @@ -125,6 +126,17 @@ impl FileTransferActivity { } } + /// ### build_explorer + /// + /// Build explorer reading configuration from `ConfigClient` + pub(super) fn build_explorer(cli: Option<&ConfigClient>) -> FileExplorer { + FileExplorerBuilder::new() + .sort_by_name() + .with_dirs_first() + .with_stack_size(16) + .build() + } + /// ### setup_text_editor /// /// Set text editor to use diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index b8a9a77..e727008 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -25,7 +25,6 @@ // This module is split into files, cause it's just too big mod callbacks; -mod explorer; mod input; mod layout; mod misc; @@ -44,9 +43,9 @@ use crate::filetransfer::ftp_transfer::FtpFileTransfer; use crate::filetransfer::scp_transfer::ScpFileTransfer; use crate::filetransfer::sftp_transfer::SftpFileTransfer; use crate::filetransfer::{FileTransfer, FileTransferProtocol}; +use crate::fs::explorer::FileExplorer; use crate::fs::FsEntry; use crate::system::config_client::ConfigClient; -use explorer::FileExplorer; // Includes use chrono::{DateTime, Local}; @@ -269,10 +268,10 @@ impl FileTransferActivity { Self::make_ssh_storage(config_client.as_ref()), )), }, - config_cli: config_client, params, - local: FileExplorer::new(16), - remote: FileExplorer::new(16), + local: Self::build_explorer(config_client.as_ref()), + remote: Self::build_explorer(config_client.as_ref()), + config_cli: config_client, tab: FileExplorerTab::Local, log_index: 0, log_records: VecDeque::with_capacity(256), // 256 events is enough I guess diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index 3a2c32d..381538e 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -603,9 +603,8 @@ impl FileTransferActivity { pub(super) fn local_scan(&mut self, path: &Path) { match self.context.as_ref().unwrap().local.scan_dir(path) { Ok(files) => { + // Set files and sort (sorting is implicit) self.local.set_files(files); - // Sort files - self.local.sort_files_by_name(); // Set index; keep if possible, otherwise set to last item self.local.set_index(match self.local.get_current_file() { Some(_) => self.local.get_index(), @@ -630,9 +629,8 @@ impl FileTransferActivity { pub(super) fn remote_scan(&mut self, path: &Path) { match self.client.list_dir(path) { Ok(files) => { + // Set files and sort (sorting is implicit) self.remote.set_files(files); - // Sort files - self.remote.sort_files_by_name(); // Set index; keep if possible, otherwise set to last item self.remote.set_index(match self.remote.get_current_file() { Some(_) => self.remote.get_index(), From b137fecc12c488a2beca07c9b74e58f2ae629022 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 18:55:14 +0100 Subject: [PATCH 42/64] FileSorting and GroupDirs as enums --- src/fs/explorer/builder.rs | 39 ++-- src/fs/explorer/mod.rs | 191 ++++++++++++++---- .../activities/filetransfer_activity/misc.rs | 6 +- 3 files changed, 168 insertions(+), 68 deletions(-) diff --git a/src/fs/explorer/builder.rs b/src/fs/explorer/builder.rs index 28ff326..daf9c5b 100644 --- a/src/fs/explorer/builder.rs +++ b/src/fs/explorer/builder.rs @@ -24,7 +24,7 @@ */ // Locals -use super::{ExplorerOpts, FileExplorer}; +use super::{ExplorerOpts, FileExplorer, FileSorting, GroupDirs}; // Ext use std::collections::VecDeque; @@ -62,22 +62,12 @@ impl FileExplorerBuilder { self } - /// ### sort_by_name + /// ### with_file_sorting /// - /// Enable SORT_BY_NAME option - pub fn sort_by_name(&mut self) -> &mut FileExplorerBuilder { + /// Set sorting method + pub fn with_file_sorting(&mut self, sorting: FileSorting) -> &mut FileExplorerBuilder { if let Some(e) = self.explorer.as_mut() { - e.opts.insert(ExplorerOpts::SORT_BY_NAME); - } - self - } - - /// ### sort_by_mtime - /// - /// Enable SORT_BY_MTIME option - pub fn sort_by_mtime(&mut self) -> &mut FileExplorerBuilder { - if let Some(e) = self.explorer.as_mut() { - e.opts.insert(ExplorerOpts::SORT_BY_MTIME); + e.sort_by(sorting); } self } @@ -85,9 +75,9 @@ impl FileExplorerBuilder { /// ### with_dirs_first /// /// Enable DIRS_FIRST option - pub fn with_dirs_first(&mut self) -> &mut FileExplorerBuilder { + pub fn with_group_dirs(&mut self, group_dirs: Option) -> &mut FileExplorerBuilder { if let Some(e) = self.explorer.as_mut() { - e.opts.insert(ExplorerOpts::DIRS_FIRST); + e.group_dirs_by(group_dirs); } self } @@ -114,26 +104,23 @@ mod tests { let explorer: FileExplorer = FileExplorerBuilder::new().build(); // Verify assert!(!explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES)); - assert!(!explorer.opts.intersects(ExplorerOpts::SORT_BY_MTIME)); - assert!(!explorer.opts.intersects(ExplorerOpts::SORT_BY_NAME)); - assert!(!explorer.opts.intersects(ExplorerOpts::DIRS_FIRST)); + assert_eq!(explorer.file_sorting, FileSorting::ByName); // Default + assert_eq!(explorer.group_dirs, None); assert_eq!(explorer.stack_size, 16); } #[test] fn test_fs_explorer_builder_new_all() { let explorer: FileExplorer = FileExplorerBuilder::new() - .sort_by_mtime() - .sort_by_name() - .with_dirs_first() + .with_file_sorting(FileSorting::ByModifyTime) + .with_group_dirs(Some(GroupDirs::First)) .with_hidden_files() .with_stack_size(24) .build(); // Verify assert!(explorer.opts.intersects(ExplorerOpts::SHOW_HIDDEN_FILES)); - assert!(explorer.opts.intersects(ExplorerOpts::SORT_BY_MTIME)); - assert!(explorer.opts.intersects(ExplorerOpts::SORT_BY_NAME)); - assert!(explorer.opts.intersects(ExplorerOpts::DIRS_FIRST)); + assert_eq!(explorer.file_sorting, FileSorting::ByModifyTime); // Default + assert_eq!(explorer.group_dirs, Some(GroupDirs::First)); assert_eq!(explorer.stack_size, 24); } } diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 07e40fe..43e0d7e 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -34,35 +34,58 @@ use std::collections::VecDeque; use std::path::{Path, PathBuf}; bitflags! { + /// ## ExplorerOpts + /// + /// ExplorerOpts are bit options which provides different behaviours to `FileExplorer` pub(crate) struct ExplorerOpts: u32 { - const SHOW_HIDDEN_FILES = 0b00000001; - const SORT_BY_NAME = 0b00000010; - const SORT_BY_MTIME = 0b00000100; - const DIRS_FIRST = 0b00001000; + const SHOW_HIDDEN_FILES = 0b00000001; } } +/// ## FileSorting +/// +/// FileSorting defines the criteria for sorting files +#[derive(Copy, Clone, PartialEq, std::fmt::Debug)] +pub enum FileSorting { + ByName, + ByModifyTime, + ByCreationTime, +} + +/// ## GroupDirs +/// +/// GroupDirs defines how directories should be grouped in sorting files +#[derive(PartialEq, std::fmt::Debug)] +pub enum GroupDirs { + First, + Last, +} + /// ## FileExplorer /// /// File explorer states pub struct FileExplorer { - pub wrkdir: PathBuf, // Current directory - index: usize, // Selected file - files: Vec, // Files in directory - pub(crate) dirstack: VecDeque, // Stack of visited directory (max 16) - pub(crate) stack_size: usize, // Directory stack size - pub(crate) opts: ExplorerOpts, // Explorer options + pub wrkdir: PathBuf, // Current directory + pub(crate) dirstack: VecDeque, // Stack of visited directory (max 16) + pub(crate) stack_size: usize, // Directory stack size + pub(crate) file_sorting: FileSorting, // File sorting criteria + pub(crate) group_dirs: Option, // If Some, defines how to group directories + pub(crate) opts: ExplorerOpts, // Explorer options + index: usize, // Selected file + files: Vec, // Files in directory } impl Default for FileExplorer { fn default() -> Self { FileExplorer { wrkdir: PathBuf::from("/"), - index: 0, - files: Vec::new(), dirstack: VecDeque::with_capacity(16), stack_size: 16, + file_sorting: FileSorting::ByName, + group_dirs: None, opts: ExplorerOpts::empty(), + index: 0, + files: Vec::new(), } } } @@ -141,20 +164,52 @@ impl FileExplorer { // Sorting + /// ### sort_by + /// + /// Choose sorting method; then sort files + pub fn sort_by(&mut self, sorting: FileSorting) { + // If method HAS ACTUALLY CHANGED, sort (performance!) + if self.file_sorting != sorting { + self.file_sorting = sorting; + self.sort(); + } + } + + /// ### get_file_sorting + /// + /// Get current file sorting method + pub fn get_file_sorting(&self) -> FileSorting { + self.file_sorting + } + + /// ### group_dirs_by + /// + /// Choose group dirs method; then sort files + pub fn group_dirs_by(&mut self, group_dirs: Option) { + // If method HAS ACTUALLY CHANGED, sort (performance!) + if self.group_dirs != group_dirs { + self.group_dirs = group_dirs; + self.sort(); + } + } + /// ### sort /// /// Sort files based on Explorer options. fn sort(&mut self) { - // Sort by name - if self.opts.intersects(ExplorerOpts::SORT_BY_NAME) { - self.sort_files_by_name(); - } else if self.opts.intersects(ExplorerOpts::SORT_BY_MTIME) { - // Sort by mtime NOTE: else if cause exclusive - self.sort_files_by_name(); + // Choose sorting method + match &self.file_sorting { + FileSorting::ByName => self.sort_files_by_name(), + FileSorting::ByCreationTime => self.sort_files_by_creation_time(), + FileSorting::ByModifyTime => self.sort_files_by_mtime(), } - // Directories first (MUST COME AFTER NAME) - if self.opts.intersects(ExplorerOpts::DIRS_FIRST) { - self.sort_files_directories_first(); + // Directories first (NOTE: MUST COME AFTER OTHER SORTING) + // Group directories if necessary + if let Some(group_dirs) = &self.group_dirs { + match group_dirs { + GroupDirs::First => self.sort_files_directories_first(), + GroupDirs::Last => self.sort_files_directories_last(), + } } } @@ -170,8 +225,17 @@ impl FileExplorer { /// /// Sort files by mtime; the newest comes first fn sort_files_by_mtime(&mut self) { + self.files.sort_by(|a: &FsEntry, b: &FsEntry| { + b.get_last_change_time().cmp(&a.get_last_change_time()) + }); + } + + /// ### sort_files_by_creation_time + /// + /// Sort files by creation time; the newest comes first + fn sort_files_by_creation_time(&mut self) { self.files - .sort_by_key(|x: &FsEntry| x.get_last_change_time()); + .sort_by(|a: &FsEntry, b: &FsEntry| b.get_creation_time().cmp(&a.get_creation_time())); } /// ### sort_files_directories_first @@ -181,6 +245,13 @@ impl FileExplorer { self.files.sort_by_key(|x: &FsEntry| x.is_file()); } + /// ### sort_files_directories_last + /// + /// Sort files; directories come last + fn sort_files_directories_last(&mut self) { + self.files.sort_by_key(|x: &FsEntry| x.is_dir()); + } + /// ### incr_index /// /// Increment index to the first visible FsEntry. @@ -380,6 +451,9 @@ mod tests { assert_eq!(explorer.wrkdir, PathBuf::from("/")); assert_eq!(explorer.stack_size, 16); assert_eq!(explorer.index, 0); + assert_eq!(explorer.group_dirs, None); + assert_eq!(explorer.file_sorting, FileSorting::ByName); + assert_eq!(explorer.get_file_sorting(), FileSorting::ByName); } #[test] @@ -412,8 +486,9 @@ mod tests { #[test] fn test_fs_explorer_files() { let mut explorer: FileExplorer = FileExplorer::default(); - explorer.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES); // Don't show hidden files - // Create files + // Don't show hidden files + explorer.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES); + // Create files explorer.set_files(vec![ make_fs_entry("README.md", false), make_fs_entry("src/", true), @@ -423,14 +498,7 @@ mod tests { make_fs_entry(".gitignore", false), ]); assert_eq!(explorer.count(), 6); - // Verify - assert_eq!( - explorer.files.get(0).unwrap().get_name(), - String::from("README.md") - ); - // Sort files - explorer.sort_files_by_name(); - // Verify + // Verify (files are sorted by name) assert_eq!( explorer.files.get(0).unwrap().get_name(), String::from(".git/") @@ -448,8 +516,7 @@ mod tests { fn test_fs_explorer_index() { let mut explorer: FileExplorer = FileExplorer::default(); explorer.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES); - explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); - // Create files (files are then sorted by name) + // Create files (files are then sorted by name DEFAULT) explorer.set_files(vec![ make_fs_entry("README.md", false), make_fs_entry("src/", true), @@ -563,7 +630,6 @@ mod tests { #[test] fn test_fs_explorer_sort_by_name() { let mut explorer: FileExplorer = FileExplorer::default(); - explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); // Create files (files are then sorted by name) explorer.set_files(vec![ make_fs_entry("README.md", false), @@ -576,6 +642,7 @@ mod tests { make_fs_entry("Cargo.lock", false), make_fs_entry("codecov.yml", false), ]); + explorer.sort_by(FileSorting::ByName); // First entry should be "Cargo.lock" assert_eq!(explorer.files.get(0).unwrap().get_name(), "Cargo.lock"); // Last should be "src/" @@ -585,13 +652,13 @@ mod tests { #[test] fn test_fs_explorer_sort_by_mtime() { let mut explorer: FileExplorer = FileExplorer::default(); - explorer.opts.insert(ExplorerOpts::SORT_BY_MTIME); let entry1: FsEntry = make_fs_entry("README.md", false); // Wait 1 sec sleep(Duration::from_secs(1)); let entry2: FsEntry = make_fs_entry("CODE_OF_CONDUCT.md", false); // Create files (files are then sorted by name) explorer.set_files(vec![entry1, entry2]); + explorer.sort_by(FileSorting::ByModifyTime); // First entry should be "CODE_OF_CONDUCT.md" assert_eq!( explorer.files.get(0).unwrap().get_name(), @@ -602,10 +669,27 @@ mod tests { } #[test] - fn test_fs_explorer_sort_by_name_and_dir() { + fn test_fs_explorer_sort_by_creation_time() { + let mut explorer: FileExplorer = FileExplorer::default(); + let entry1: FsEntry = make_fs_entry("README.md", false); + // Wait 1 sec + sleep(Duration::from_secs(1)); + let entry2: FsEntry = make_fs_entry("CODE_OF_CONDUCT.md", false); + // Create files (files are then sorted by name) + explorer.set_files(vec![entry1, entry2]); + explorer.sort_by(FileSorting::ByCreationTime); + // First entry should be "CODE_OF_CONDUCT.md" + assert_eq!( + explorer.files.get(0).unwrap().get_name(), + "CODE_OF_CONDUCT.md" + ); + // Last should be "src/" + assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md"); + } + + #[test] + fn test_fs_explorer_sort_by_name_and_dirs_first() { let mut explorer: FileExplorer = FileExplorer::default(); - explorer.opts.insert(ExplorerOpts::SORT_BY_NAME); - explorer.opts.insert(ExplorerOpts::DIRS_FIRST); // Create files (files are then sorted by name) explorer.set_files(vec![ make_fs_entry("README.md", false), @@ -619,6 +703,8 @@ mod tests { make_fs_entry("Cargo.lock", false), make_fs_entry("codecov.yml", false), ]); + explorer.sort_by(FileSorting::ByName); + explorer.group_dirs_by(Some(GroupDirs::First)); // First entry should be "docs" assert_eq!(explorer.files.get(0).unwrap().get_name(), "docs/"); assert_eq!(explorer.files.get(1).unwrap().get_name(), "src/"); @@ -628,6 +714,33 @@ mod tests { assert_eq!(explorer.files.get(9).unwrap().get_name(), "README.md"); } + #[test] + fn test_fs_explorer_sort_by_name_and_dirs_last() { + let mut explorer: FileExplorer = FileExplorer::default(); + // Create files (files are then sorted by name) + explorer.set_files(vec![ + make_fs_entry("README.md", false), + make_fs_entry("src/", true), + make_fs_entry("docs/", true), + make_fs_entry("CONTRIBUTING.md", false), + make_fs_entry("CODE_OF_CONDUCT.md", false), + make_fs_entry("CHANGELOG.md", false), + make_fs_entry("LICENSE", false), + make_fs_entry("Cargo.toml", false), + make_fs_entry("Cargo.lock", false), + make_fs_entry("codecov.yml", false), + ]); + explorer.sort_by(FileSorting::ByName); + explorer.group_dirs_by(Some(GroupDirs::Last)); + // Last entry should be "src" + assert_eq!(explorer.files.get(8).unwrap().get_name(), "docs/"); + assert_eq!(explorer.files.get(9).unwrap().get_name(), "src/"); + // first is file for alphabetical order + assert_eq!(explorer.files.get(0).unwrap().get_name(), "Cargo.lock"); + // Last in files should be "README.md" (last file for alphabetical ordening) + assert_eq!(explorer.files.get(7).unwrap().get_name(), "README.md"); + } + fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry { let t_now: SystemTime = SystemTime::now(); match is_dir { diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 42c0562..4d810a5 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -24,7 +24,7 @@ use super::{ Color, ConfigClient, FileTransferActivity, InputField, InputMode, LogLevel, LogRecord, PopupType, }; -use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer}; +use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSorting, GroupDirs}; use crate::system::environment; use crate::system::sshkey_storage::SshKeyStorage; // Ext @@ -131,8 +131,8 @@ impl FileTransferActivity { /// Build explorer reading configuration from `ConfigClient` pub(super) fn build_explorer(cli: Option<&ConfigClient>) -> FileExplorer { FileExplorerBuilder::new() - .sort_by_name() - .with_dirs_first() + .with_file_sorting(FileSorting::ByName) + .with_group_dirs(Some(GroupDirs::First)) .with_stack_size(16) .build() } From 740d906eb3b8f6b84501ce74862ce5d46e9703ff Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 19:03:54 +0100 Subject: [PATCH 43/64] ToString, FromStr for FileSorting and GroupDirs --- src/fs/explorer/mod.rs | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 43e0d7e..565fa35 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -32,6 +32,8 @@ use super::FsEntry; // Ext use std::collections::VecDeque; use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::string::ToString; bitflags! { /// ## ExplorerOpts @@ -432,6 +434,50 @@ impl FileExplorer { } } +// Traits + +impl ToString for FileSorting { + fn to_string(&self) -> String { + String::from(match self { + FileSorting::ByCreationTime => "by_creation_time", + FileSorting::ByModifyTime => "by_mtime", + FileSorting::ByName => "by_name", + }) + } +} + +impl FromStr for FileSorting { + type Err = (); + fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "by_creation_time" => Ok(FileSorting::ByCreationTime), + "by_mtime" => Ok(FileSorting::ByModifyTime), + "by_name" => Ok(FileSorting::ByName), + _ => Err(()), + } + } +} + +impl ToString for GroupDirs { + fn to_string(&self) -> String { + String::from(match self { + GroupDirs::First => "first", + GroupDirs::Last => "last", + }) + } +} + +impl FromStr for GroupDirs { + type Err = (); + fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "first" => Ok(GroupDirs::First), + "last" => Ok(GroupDirs::Last), + _ => Err(()), + } + } +} + #[cfg(test)] mod tests { @@ -741,6 +787,33 @@ mod tests { assert_eq!(explorer.files.get(7).unwrap().get_name(), "README.md"); } + #[test] + fn test_fs_explorer_to_string_from_str_traits() { + // File Sorting + assert_eq!(FileSorting::ByCreationTime.to_string(), "by_creation_time"); + assert_eq!(FileSorting::ByModifyTime.to_string(), "by_mtime"); + assert_eq!(FileSorting::ByName.to_string(), "by_name"); + assert_eq!( + FileSorting::from_str("by_creation_time").ok().unwrap(), + FileSorting::ByCreationTime + ); + assert_eq!( + FileSorting::from_str("by_mtime").ok().unwrap(), + FileSorting::ByModifyTime + ); + assert_eq!( + FileSorting::from_str("by_name").ok().unwrap(), + FileSorting::ByName + ); + assert!(FileSorting::from_str("omar").is_err()); + // Group dirs + assert_eq!(GroupDirs::First.to_string(), "first"); + assert_eq!(GroupDirs::Last.to_string(), "last"); + assert_eq!(GroupDirs::from_str("first").ok().unwrap(), GroupDirs::First); + assert_eq!(GroupDirs::from_str("last").ok().unwrap(), GroupDirs::Last); + assert!(GroupDirs::from_str("omar").is_err()); + } + fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry { let t_now: SystemTime = SystemTime::now(); match is_dir { From 99fd0b199d27a8f82716f1f6c718b46aab62831b Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sat, 26 Dec 2020 21:47:48 +0100 Subject: [PATCH 44/64] FileTransferActivity: sort files with --- CHANGELOG.md | 1 + README.md | 57 ++++---- src/fs/explorer/mod.rs | 65 +++++++++ .../activities/filetransfer_activity/input.rs | 137 +++++++++++++----- .../filetransfer_activity/layout.rs | 58 +++++++- .../activities/filetransfer_activity/mod.rs | 1 + 6 files changed, 256 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c54bbc0..baa080d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ FIXME: Released on - Hidden files are now not shown by default; use `A` to show hidden files. - Keybindings: - `A`: Toggle hidden files + - `B`: Sort files by (name, size, creation time, modify time) - `N`: New file - Dependencies: - added `bitflags 1.2.1` diff --git a/README.md b/README.md index a8fdf56..e2c8f9b 100644 --- a/README.md +++ b/README.md @@ -277,34 +277,35 @@ You can access the SSH key storage, from configuration moving to the `SSH Keys` ## Keybindings โŒจ -| Key | Command | Reminder | -|---------------|-------------------------------------------------------|-----------| -| `` | Disconnect from remote; return to authentication page | | -| `` | Switch between log tab and explorer | | -| `` | Go to previous directory in stack | | -| `` | Move to remote explorer tab | | -| `` | Move to local explorer tab | | -| `` | Move up in selected list | | -| `` | Move down in selected list | | -| `` | Move up in selected list by 8 rows | | -| `` | Move down in selected list by 8 rows | | -| `` | Enter directory | | -| `` | Upload / download selected file | | -| `` | Toggle hidden files | All | -| `` | Copy file/directory | Copy | -| `` | Make directory | Directory | -| `` | Delete file (Same as `DEL`) | Erase | -| `` | Go to supplied path | Go to | -| `` | Show help | Help | -| `` | Show info about selected file or directory | Info | -| `` | Reload current directory's content | List | -| `` | Create new file with provided name | New | -| `` | Edit file; see [Text editor](#text-editor-) | Open | -| `` | Quit TermSCP | Quit | -| `` | Rename file | Rename | -| `` | Go to parent directory | Upper | -| `` | Delete file | | -| `` | Abort file transfer process | | +| Key | Command | Reminder | +|---------------|-------------------------------------------------------|-------------| +| `` | Disconnect from remote; return to authentication page | | +| `` | Switch between log tab and explorer | | +| `` | Go to previous directory in stack | | +| `` | Move to remote explorer tab | | +| `` | Move to local explorer tab | | +| `` | Move up in selected list | | +| `` | Move down in selected list | | +| `` | Move up in selected list by 8 rows | | +| `` | Move down in selected list by 8 rows | | +| `` | Enter directory | | +| `` | Upload / download selected file | | +| `` | Toggle hidden files | All | +| `` | Sort files by | Bubblesort? | +| `` | Copy file/directory | Copy | +| `` | Make directory | Directory | +| `` | Delete file (Same as `DEL`) | Erase | +| `` | Go to supplied path | Go to | +| `` | Show help | Help | +| `` | Show info about selected file or directory | Info | +| `` | Reload current directory's content | List | +| `` | Create new file with provided name | New | +| `` | Edit file; see [Text editor](#text-editor-) | Open | +| `` | Quit TermSCP | Quit | +| `` | Rename file | Rename | +| `` | Go to parent directory | Upper | +| `` | Delete file | | +| `` | Abort file transfer process | | --- diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 565fa35..3d4e735 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -52,6 +52,7 @@ pub enum FileSorting { ByName, ByModifyTime, ByCreationTime, + BySize, } /// ## GroupDirs @@ -204,6 +205,7 @@ impl FileExplorer { FileSorting::ByName => self.sort_files_by_name(), FileSorting::ByCreationTime => self.sort_files_by_creation_time(), FileSorting::ByModifyTime => self.sort_files_by_mtime(), + FileSorting::BySize => self.sort_files_by_size(), } // Directories first (NOTE: MUST COME AFTER OTHER SORTING) // Group directories if necessary @@ -240,6 +242,14 @@ impl FileExplorer { .sort_by(|a: &FsEntry, b: &FsEntry| b.get_creation_time().cmp(&a.get_creation_time())); } + /// ### sort_files_by_size + /// + /// Sort files by size + fn sort_files_by_size(&mut self) { + self.files + .sort_by(|a: &FsEntry, b: &FsEntry| b.get_size().cmp(&a.get_size())); + } + /// ### sort_files_directories_first /// /// Sort files; directories come first @@ -442,6 +452,7 @@ impl ToString for FileSorting { FileSorting::ByCreationTime => "by_creation_time", FileSorting::ByModifyTime => "by_mtime", FileSorting::ByName => "by_name", + FileSorting::BySize => "by_size", }) } } @@ -453,6 +464,7 @@ impl FromStr for FileSorting { "by_creation_time" => Ok(FileSorting::ByCreationTime), "by_mtime" => Ok(FileSorting::ByModifyTime), "by_name" => Ok(FileSorting::ByName), + "by_size" => Ok(FileSorting::BySize), _ => Err(()), } } @@ -733,6 +745,22 @@ mod tests { assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md"); } + #[test] + fn test_fs_explorer_sort_by_size() { + let mut explorer: FileExplorer = FileExplorer::default(); + // Create files (files are then sorted by name) + explorer.set_files(vec![ + make_fs_entry_with_size("README.md", false, 1024), + make_fs_entry("src/", true), + make_fs_entry_with_size("CONTRIBUTING.md", false, 256), + ]); + explorer.sort_by(FileSorting::BySize); + // Directory has size 4096 + assert_eq!(explorer.files.get(0).unwrap().get_name(), "src/"); + assert_eq!(explorer.files.get(1).unwrap().get_name(), "README.md"); + assert_eq!(explorer.files.get(2).unwrap().get_name(), "CONTRIBUTING.md"); + } + #[test] fn test_fs_explorer_sort_by_name_and_dirs_first() { let mut explorer: FileExplorer = FileExplorer::default(); @@ -793,6 +821,7 @@ mod tests { assert_eq!(FileSorting::ByCreationTime.to_string(), "by_creation_time"); assert_eq!(FileSorting::ByModifyTime.to_string(), "by_mtime"); assert_eq!(FileSorting::ByName.to_string(), "by_name"); + assert_eq!(FileSorting::BySize.to_string(), "by_size"); assert_eq!( FileSorting::from_str("by_creation_time").ok().unwrap(), FileSorting::ByCreationTime @@ -805,6 +834,10 @@ mod tests { FileSorting::from_str("by_name").ok().unwrap(), FileSorting::ByName ); + assert_eq!( + FileSorting::from_str("by_size").ok().unwrap(), + FileSorting::BySize + ); assert!(FileSorting::from_str("omar").is_err()); // Group dirs assert_eq!(GroupDirs::First.to_string(), "first"); @@ -845,4 +878,36 @@ mod tests { }), } } + + fn make_fs_entry_with_size(name: &str, is_dir: bool, size: usize) -> FsEntry { + let t_now: SystemTime = SystemTime::now(); + match is_dir { + false => FsEntry::File(FsFile { + name: name.to_string(), + abs_path: PathBuf::from(name), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + size: size, + ftype: None, // File type + readonly: false, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((6, 4, 4)), // UNIX only + }), + true => FsEntry::Directory(FsDirectory { + name: name.to_string(), + abs_path: PathBuf::from(name), + last_change_time: t_now, + last_access_time: t_now, + creation_time: t_now, + readonly: false, + symlink: None, // UNIX only + user: Some(0), // UNIX only + group: Some(0), // UNIX only + unix_pex: Some((7, 5, 5)), // UNIX only + }), + } + } } diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 3e886c3..27b9c09 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -23,13 +23,15 @@ * */ +// Deps extern crate tempfile; - +// Local use super::{ DialogCallback, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputEvent, InputField, InputMode, LogLevel, OnInputSubmitCallback, PopupType, }; - +use crate::fs::explorer::{FileExplorer, FileSorting}; +// Ext use crossterm::event::{KeyCode, KeyModifiers}; use std::path::PathBuf; @@ -59,7 +61,7 @@ impl FileTransferActivity { /// ### handle_input_event /// /// Handle input event based on current input mode - pub(super) fn handle_input_event(&mut self, ev: &InputEvent) { + fn handle_input_event(&mut self, ev: &InputEvent) { // NOTE: this is necessary due to this // NOTE: Do you want my opinion about that issue? It's a bs and doesn't make any sense. let popup: Option = match &self.input_mode { @@ -79,7 +81,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer /// /// Input event handler for explorer mode - pub(super) fn handle_input_event_mode_explorer(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_explorer(&mut self, ev: &InputEvent) { // Match input field match self.input_field { InputField::Explorer => match self.tab { @@ -94,7 +96,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer_tab_local /// /// Input event handler for explorer mode when localhost tab is selected - pub(super) fn handle_input_event_mode_explorer_tab_local(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_explorer_tab_local(&mut self, ev: &InputEvent) { // Match events if let InputEvent::Key(key) = ev { match key.code { @@ -172,6 +174,10 @@ impl FileTransferActivity { // Toggle hidden files self.local.toggle_hidden_files(); } + 'b' | 'B' => { + // Choose file sorting type + self.input_mode = InputMode::Popup(PopupType::FileSortingDialog); + } 'c' | 'C' => { // Copy self.input_mode = InputMode::Popup(PopupType::Input( @@ -309,7 +315,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer_tab_local /// /// Input event handler for explorer mode when remote tab is selected - pub(super) fn handle_input_event_mode_explorer_tab_remote(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_explorer_tab_remote(&mut self, ev: &InputEvent) { // Match events if let InputEvent::Key(key) = ev { match key.code { @@ -387,6 +393,10 @@ impl FileTransferActivity { // Toggle hidden files self.remote.toggle_hidden_files(); } + 'b' | 'B' => { + // Choose file sorting type + self.input_mode = InputMode::Popup(PopupType::FileSortingDialog); + } 'c' | 'C' => { // Copy self.input_mode = InputMode::Popup(PopupType::Input( @@ -521,7 +531,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer_log /// /// Input even handler for explorer mode when log tab is selected - pub(super) fn handle_input_event_mode_explorer_log(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_explorer_log(&mut self, ev: &InputEvent) { // Match event let records_block: usize = 16; if let InputEvent::Key(key) = ev { @@ -580,12 +590,13 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer /// /// Input event handler for popup mode. Handler is then based on Popup type - pub(super) fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: PopupType) { + fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: PopupType) { match popup { PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), PopupType::FileInfo => self.handle_input_event_mode_popup_fileinfo(ev), - PopupType::Help => self.handle_input_event_mode_popup_help(ev), PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev), + PopupType::FileSortingDialog => self.handle_input_event_mode_popup_file_sorting(ev), + PopupType::Help => self.handle_input_event_mode_popup_help(ev), PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb), PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev), PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev), @@ -598,7 +609,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_popup_alert /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { @@ -611,20 +622,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_popup_fileinfo /// /// Input event handler for popup fileinfo - pub(super) fn handle_input_event_mode_popup_fileinfo(&mut self, ev: &InputEvent) { - // If enter, close popup - if let InputEvent::Key(key) = ev { - if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { - // Set input mode back to explorer - self.input_mode = InputMode::Explorer; - } - } - } - - /// ### handle_input_event_mode_popup_help - /// - /// Input event handler for popup help - pub(super) fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_fileinfo(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { @@ -637,7 +635,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_popup_fatal /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_fatal(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { @@ -647,14 +645,61 @@ impl FileTransferActivity { } } + /// ### handle_input_event_mode_popup_file_sorting + /// + /// Handle input event for file sorting dialog popup + fn handle_input_event_mode_popup_file_sorting(&mut self, ev: &InputEvent) { + // Match key code + if let InputEvent::Key(key) = ev { + match key.code { + KeyCode::Esc | KeyCode::Enter => { + // Exit + self.input_mode = InputMode::Explorer; + } + KeyCode::Right => { + // Update sorting mode + match self.tab { + FileExplorerTab::Local => { + Self::move_sorting_mode_opt_right(&mut self.local); + } + FileExplorerTab::Remote => { + Self::move_sorting_mode_opt_right(&mut self.remote); + } + } + } + KeyCode::Left => { + // Update sorting mode + match self.tab { + FileExplorerTab::Local => { + Self::move_sorting_mode_opt_left(&mut self.local); + } + FileExplorerTab::Remote => { + Self::move_sorting_mode_opt_left(&mut self.remote); + } + } + } + _ => { /* Nothing to do */ } + } + } + } + + /// ### handle_input_event_mode_popup_help + /// + /// Input event handler for popup help + fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { + // If enter, close popup + if let InputEvent::Key(key) = ev { + if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { + // Set input mode back to explorer + self.input_mode = InputMode::Explorer; + } + } + } + /// ### handle_input_event_mode_popup_input /// /// Input event handler for input popup - pub(super) fn handle_input_event_mode_popup_input( - &mut self, - ev: &InputEvent, - cb: OnInputSubmitCallback, - ) { + fn handle_input_event_mode_popup_input(&mut self, ev: &InputEvent, cb: OnInputSubmitCallback) { // If enter, close popup, otherwise push chars to input if let InputEvent::Key(key) = ev { match key.code { @@ -687,7 +732,7 @@ impl FileTransferActivity { /// ### handle_input_event_mode_popup_progress /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_progress(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_progress(&mut self, ev: &InputEvent) { if let InputEvent::Key(key) = ev { if let KeyCode::Char(ch) = key.code { // If is 'C' and CTRL @@ -702,14 +747,14 @@ impl FileTransferActivity { /// ### handle_input_event_mode_popup_wait /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_wait(&mut self, _ev: &InputEvent) { + fn handle_input_event_mode_popup_wait(&mut self, _ev: &InputEvent) { // There's nothing you can do here I guess... maybe ctrl+c in the future idk } /// ### handle_input_event_mode_popup_yesno /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_yesno( + fn handle_input_event_mode_popup_yesno( &mut self, ev: &InputEvent, yes_cb: DialogCallback, @@ -735,4 +780,30 @@ impl FileTransferActivity { } } } + + /// ### move_sorting_mode_opt_left + /// + /// Perform on file sorting dialog + fn move_sorting_mode_opt_left(explorer: &mut FileExplorer) { + let curr_sorting: FileSorting = explorer.get_file_sorting(); + explorer.sort_by(match curr_sorting { + FileSorting::BySize => FileSorting::ByCreationTime, + FileSorting::ByCreationTime => FileSorting::ByModifyTime, + FileSorting::ByModifyTime => FileSorting::ByName, + FileSorting::ByName => FileSorting::BySize, // Wrap + }); + } + + /// ### move_sorting_mode_opt_left + /// + /// Perform on file sorting dialog + fn move_sorting_mode_opt_right(explorer: &mut FileExplorer) { + let curr_sorting: FileSorting = explorer.get_file_sorting(); + explorer.sort_by(match curr_sorting { + FileSorting::ByName => FileSorting::ByModifyTime, + FileSorting::ByModifyTime => FileSorting::ByCreationTime, + FileSorting::ByCreationTime => FileSorting::BySize, + FileSorting::BySize => FileSorting::ByName, // Wrap + }); + } } diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index 95afa4d..fe6c33b 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -23,17 +23,19 @@ * */ +// Deps extern crate bytesize; extern crate hostname; #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] extern crate users; - +// Local use super::{ Context, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputField, InputMode, LogLevel, LogRecord, PopupType, }; +use crate::fs::explorer::{FileExplorer, FileSorting}; use crate::utils::fmt::{align_text_center, fmt_time}; - +// Ext use bytesize::ByteSize; use std::path::{Path, PathBuf}; use tui::{ @@ -105,6 +107,7 @@ impl FileTransferActivity { PopupType::Alert(_, _) => (50, 10), PopupType::Fatal(_) => (50, 10), PopupType::FileInfo => (50, 50), + PopupType::FileSortingDialog => (50, 10), PopupType::Help => (50, 80), PopupType::Input(_, _) => (40, 10), PopupType::Progress(_) => (40, 10), @@ -123,6 +126,9 @@ impl FileTransferActivity { popup_area, ), PopupType::FileInfo => f.render_widget(self.draw_popup_fileinfo(), popup_area), + PopupType::FileSortingDialog => { + f.render_widget(self.draw_popup_file_sorting_dialog(), popup_area) + } PopupType::Help => f.render_widget(self.draw_popup_help(), popup_area), PopupType::Input(txt, _) => { f.render_widget(self.draw_popup_input(txt.clone()), popup_area); @@ -367,6 +373,44 @@ impl FileTransferActivity { .start_corner(Corner::TopLeft) .style(Style::default().fg(Color::Red)) } + + /// ### draw_popup_file_sorting_dialog + /// + /// Draw FileSorting mode select popup + pub(super) fn draw_popup_file_sorting_dialog(&self) -> Tabs { + let choices: Vec = vec![ + Spans::from("Name"), + Spans::from("Modify time"), + Spans::from("Creation time"), + Spans::from("Size"), + ]; + let explorer: &FileExplorer = match self.tab { + FileExplorerTab::Local => &self.local, + FileExplorerTab::Remote => &self.remote, + }; + let index: usize = match explorer.get_file_sorting() { + FileSorting::ByCreationTime => 2, + FileSorting::ByModifyTime => 1, + FileSorting::ByName => 0, + FileSorting::BySize => 3, + }; + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title("Sort files by"), + ) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default() + .add_modifier(Modifier::BOLD) + .bg(Color::LightMagenta) + .fg(Color::DarkGray), + ) + } + /// ### draw_popup_input /// /// Draw input popup @@ -727,6 +771,16 @@ impl FileTransferActivity { Span::raw(" "), Span::raw("Toggle hidden files"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Change file sorting mode"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "", diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index e727008..c2029da 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -97,6 +97,7 @@ enum PopupType { Alert(Color, String), // Block color; Block text Fatal(String), // Must quit after being hidden FileInfo, // Show info about current file + FileSortingDialog, // Dialog for choosing file sorting type Help, // Show Help Input(String, OnInputSubmitCallback), // Input description; Callback for submit Progress(String), // Progress block text From 09bc8a92a273aaac1fc0facf062751b35df36331 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 10:31:33 +0100 Subject: [PATCH 45/64] show_hidden_files and group_dirs in termscp configuration; instantiate FileExplorer based on current configuration in FileTransferActivity --- CHANGELOG.md | 2 + README.md | 2 + src/config/mod.rs | 11 +- src/config/serializer.rs | 56 +++++++ src/fs/explorer/builder.rs | 9 +- src/system/config_client.rs | 64 ++++++++ src/ui/activities/auth_activity/input.rs | 18 +-- src/ui/activities/auth_activity/layout.rs | 10 +- .../activities/filetransfer_activity/misc.rs | 18 ++- src/ui/activities/setup_activity/input.rs | 105 +++++++++---- src/ui/activities/setup_activity/layout.rs | 140 +++++++++++++++--- src/ui/activities/setup_activity/mod.rs | 2 + 12 files changed, 363 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baa080d..cf0016d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ FIXME: Released on - Windows: `C:\Users\Alice\AppData\Roaming\termscp\config.toml` - Added Text editor to configuration - Added Default File transfer protocol to configuration + - Added "Show hidden files` to configuration + - Added "Group directories" to configuration - Added SSH keys to configuration; SSH keys will be stored at - Linux: `/home/alice/.config/termscp/.ssh/` - MacOS: `/Users/Alice/Library/Application Support/termscp/.ssh/` diff --git a/README.md b/README.md index e2c8f9b..64eb8d9 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,8 @@ These parameters can be changed: - **Default Protocol**: the default protocol is the default value for the file transfer protocol to be used in termscp. This applies for the login page and for the address CLI argument. - **Text Editor**: the text editor to use. By default termscp will find the default editor for you; with this option you can force an editor to be used (e.g. `vim`). **Also GUI editors are supported**, unless they `nohup` from the parent process so if you ask: yes, you can use `notepad.exe`, and no: **Visual Studio Code doesn't work**. +- **Show Hidden Files**: select whether hidden files shall be displayed by default. You will be able to decide whether to show or not hidden files at runtime pressing `A` anyway. +- **Group Dirs**: select whether directories should be groupped or not in file explorers. If `Display first` is selected, directories will be sorted using the configured method but displayed before files, viceversa if `Display last` is selected. ### SSH Key Storage ๐Ÿ” diff --git a/src/config/mod.rs b/src/config/mod.rs index 9215f9c..7e41f34 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -54,6 +54,8 @@ pub struct UserConfig { pub struct UserInterfaceConfig { pub text_editor: PathBuf, pub default_protocol: String, + pub show_hidden_files: bool, + pub group_dirs: Option, } #[derive(Deserialize, Serialize, std::fmt::Debug)] @@ -81,6 +83,8 @@ impl Default for UserInterfaceConfig { Err(_) => PathBuf::from("nano"), // Default to nano }, default_protocol: FileTransferProtocol::Sftp.to_string(), + show_hidden_files: false, + group_dirs: None, } } } @@ -165,14 +169,15 @@ mod tests { let ui: UserInterfaceConfig = UserInterfaceConfig { default_protocol: String::from("SFTP"), text_editor: PathBuf::from("nano"), + show_hidden_files: true, + group_dirs: Some(String::from("first")), }; let cfg: UserConfig = UserConfig { user_interface: ui, remote: remote, }; assert_eq!( - *cfg - .remote + *cfg.remote .ssh_keys .get(&String::from("192.168.1.31")) .unwrap(), @@ -180,6 +185,8 @@ mod tests { ); assert_eq!(cfg.user_interface.default_protocol, String::from("SFTP")); assert_eq!(cfg.user_interface.text_editor, PathBuf::from("nano")); + assert_eq!(cfg.user_interface.show_hidden_files, true); + assert_eq!(cfg.user_interface.group_dirs, Some(String::from("first"))); } #[test] diff --git a/src/config/serializer.rs b/src/config/serializer.rs index f96c58c..e4c7fc0 100644 --- a/src/config/serializer.rs +++ b/src/config/serializer.rs @@ -106,6 +106,43 @@ mod tests { // Verify ui assert_eq!(cfg.user_interface.default_protocol, String::from("SCP")); assert_eq!(cfg.user_interface.text_editor, PathBuf::from("vim")); + assert_eq!(cfg.user_interface.show_hidden_files, true); + assert_eq!(cfg.user_interface.group_dirs, Some(String::from("last"))); + // Verify keys + assert_eq!( + *cfg.remote + .ssh_keys + .get(&String::from("192.168.1.31")) + .unwrap(), + PathBuf::from("/home/omar/.ssh/raspberry.key") + ); + assert_eq!( + *cfg.remote + .ssh_keys + .get(&String::from("192.168.1.32")) + .unwrap(), + PathBuf::from("/home/omar/.ssh/beaglebone.key") + ); + assert!(cfg.remote.ssh_keys.get(&String::from("1.1.1.1")).is_none()); + } + + #[test] + fn test_config_serializer_deserialize_ok_no_opts() { + let toml_file: tempfile::NamedTempFile = create_good_toml_no_opts(); + toml_file.as_file().sync_all().unwrap(); + toml_file.as_file().seek(SeekFrom::Start(0)).unwrap(); + // Parse + let deserializer: ConfigSerializer = ConfigSerializer {}; + let cfg = deserializer.deserialize(Box::new(toml_file)); + println!("{:?}", cfg); + assert!(cfg.is_ok()); + let cfg: UserConfig = cfg.ok().unwrap(); + // Verify configuration + // Verify ui + assert_eq!(cfg.user_interface.default_protocol, String::from("SCP")); + assert_eq!(cfg.user_interface.text_editor, PathBuf::from("vim")); + assert_eq!(cfg.user_interface.show_hidden_files, true); + assert_eq!(cfg.user_interface.group_dirs, None); // Verify keys assert_eq!( *cfg.remote @@ -160,6 +197,25 @@ mod tests { [user_interface] default_protocol = "SCP" text_editor = "vim" + show_hidden_files = true + group_dirs = "last" + + [remote.ssh_keys] + "192.168.1.31" = "/home/omar/.ssh/raspberry.key" + "192.168.1.32" = "/home/omar/.ssh/beaglebone.key" + "#; + tmpfile.write_all(file_content.as_bytes()).unwrap(); + tmpfile + } + + fn create_good_toml_no_opts() -> tempfile::NamedTempFile { + // Write + let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap(); + let file_content: &str = r#" + [user_interface] + default_protocol = "SCP" + text_editor = "vim" + show_hidden_files = true [remote.ssh_keys] "192.168.1.31" = "/home/omar/.ssh/raspberry.key" diff --git a/src/fs/explorer/builder.rs b/src/fs/explorer/builder.rs index daf9c5b..4c2d1c9 100644 --- a/src/fs/explorer/builder.rs +++ b/src/fs/explorer/builder.rs @@ -55,9 +55,12 @@ impl FileExplorerBuilder { /// ### with_hidden_files /// /// Enable HIDDEN_FILES option - pub fn with_hidden_files(&mut self) -> &mut FileExplorerBuilder { + pub fn with_hidden_files(&mut self, val: bool) -> &mut FileExplorerBuilder { if let Some(e) = self.explorer.as_mut() { - e.opts.insert(ExplorerOpts::SHOW_HIDDEN_FILES); + match val { + true => e.opts.insert(ExplorerOpts::SHOW_HIDDEN_FILES), + false => e.opts.remove(ExplorerOpts::SHOW_HIDDEN_FILES), + } } self } @@ -114,7 +117,7 @@ mod tests { let explorer: FileExplorer = FileExplorerBuilder::new() .with_file_sorting(FileSorting::ByModifyTime) .with_group_dirs(Some(GroupDirs::First)) - .with_hidden_files() + .with_hidden_files(true) .with_stack_size(24) .build(); // Verify diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 9b219fc..0a1eb19 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -29,6 +29,7 @@ extern crate rand; use crate::config::serializer::ConfigSerializer; use crate::config::{SerializerError, SerializerErrorKind, UserConfig}; use crate::filetransfer::FileTransferProtocol; +use crate::fs::explorer::GroupDirs; // Ext use std::fs::{create_dir, remove_file, File, OpenOptions}; use std::io::Write; @@ -123,6 +124,45 @@ impl ConfigClient { self.config.user_interface.default_protocol = proto.to_string(); } + /// ### get_show_hidden_files + /// + /// Get value of `show_hidden_files` + pub fn get_show_hidden_files(&self) -> bool { + self.config.user_interface.show_hidden_files + } + + /// ### set_show_hidden_files + /// + /// Set new value for `show_hidden_files` + pub fn set_show_hidden_files(&mut self, value: bool) { + self.config.user_interface.show_hidden_files = value; + } + + /// ### get_group_dirs + /// + /// Get GroupDirs value from configuration (will be converted from string) + pub fn get_group_dirs(&self) -> Option { + // Convert string to `GroupDirs` + match &self.config.user_interface.group_dirs { + None => None, + Some(val) => match GroupDirs::from_str(val.as_str()) { + Ok(val) => Some(val), + Err(_) => None, + }, + } + } + + /// ### set_group_dirs + /// + /// Set value for group_dir in configuration. + /// Provided value, if `Some` will be converted to `GroupDirs` + pub fn set_group_dirs(&mut self, val: Option) { + self.config.user_interface.group_dirs = match val { + None => None, + Some(val) => Some(val.to_string()), + }; + } + // SSH Keys /// ### save_ssh_key @@ -387,6 +427,30 @@ mod tests { ); } + #[test] + fn test_system_config_show_hidden_files() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + client.set_show_hidden_files(true); + assert_eq!(client.get_show_hidden_files(), true); + } + + #[test] + fn test_system_config_group_dirs() { + let tmp_dir: tempfile::TempDir = create_tmp_dir(); + let (cfg_path, key_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path()); + let mut client: ConfigClient = ConfigClient::new(cfg_path.as_path(), key_path.as_path()) + .ok() + .unwrap(); + client.set_group_dirs(Some(GroupDirs::First)); + assert_eq!(client.get_group_dirs(), Some(GroupDirs::First),); + client.set_group_dirs(None); + assert_eq!(client.get_group_dirs(), None,); + } + #[test] fn test_system_config_ssh_keys() { let tmp_dir: tempfile::TempDir = create_tmp_dir(); diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index 24458de..38b638e 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -53,7 +53,7 @@ impl AuthActivity { /// ### handle_input_event_mode_form /// /// Handler for input event when in form mode - pub(super) fn handle_input_event_mode_form(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_form(&mut self, ev: &InputEvent) { match self.input_form { InputForm::AuthCredentials => self.handle_input_event_mode_form_auth(ev), InputForm::Bookmarks => self.handle_input_event_mode_form_bookmarks(ev), @@ -64,7 +64,7 @@ impl AuthActivity { /// ### handle_input_event_mode_form_auth /// /// Handle input event when input mode is Form and Tab is Auth - pub(super) fn handle_input_event_mode_form_auth(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_form_auth(&mut self, ev: &InputEvent) { if let InputEvent::Key(key) = ev { match key.code { KeyCode::Esc => { @@ -220,7 +220,7 @@ impl AuthActivity { /// ### handle_input_event_mode_form_bookmarks /// /// Handle input event when input mode is Form and Tab is Bookmarks - pub(super) fn handle_input_event_mode_form_bookmarks(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_form_bookmarks(&mut self, ev: &InputEvent) { if let InputEvent::Key(key) = ev { match key.code { KeyCode::Esc => { @@ -304,7 +304,7 @@ impl AuthActivity { /// ### handle_input_event_mode_form_recents /// /// Handle input event when input mode is Form and Tab is Recents - pub(super) fn handle_input_event_mode_form_recents(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_form_recents(&mut self, ev: &InputEvent) { if let InputEvent::Key(key) = ev { match key.code { KeyCode::Esc => { @@ -388,7 +388,7 @@ impl AuthActivity { /// ### handle_input_event_mode_text /// /// Handler for input event when in popup mode - pub(super) fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, ptype: PopupType) { + fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, ptype: PopupType) { match ptype { PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), PopupType::Help => self.handle_input_event_mode_popup_help(ev), @@ -402,7 +402,7 @@ impl AuthActivity { /// ### handle_input_event_mode_popup_alert /// /// Handle input event when the input mode is popup, and popup type is alert - pub(super) fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_alert(&mut self, ev: &InputEvent) { // Only enter should be allowed here if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { @@ -414,7 +414,7 @@ impl AuthActivity { /// ### handle_input_event_mode_popup_help /// /// Input event handler for popup help - pub(super) fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_help(&mut self, ev: &InputEvent) { // If enter, close popup if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { @@ -427,7 +427,7 @@ impl AuthActivity { /// ### handle_input_event_mode_popup_save_bookmark /// /// Input event handler for SaveBookmark popup - pub(super) fn handle_input_event_mode_popup_save_bookmark(&mut self, ev: &InputEvent) { + fn handle_input_event_mode_popup_save_bookmark(&mut self, ev: &InputEvent) { // If enter, close popup, otherwise push chars to input if let InputEvent::Key(key) = ev { match key.code { @@ -466,7 +466,7 @@ impl AuthActivity { /// ### handle_input_event_mode_popup_yesno /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_yesno( + fn handle_input_event_mode_popup_yesno( &mut self, ev: &InputEvent, yes_cb: DialogCallback, diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 6438e06..8907945 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -318,7 +318,7 @@ impl AuthActivity { /// ### draw_local_explorer /// /// Draw local explorer list - pub(super) fn draw_bookmarks_tab(&self) -> Option { + fn draw_bookmarks_tab(&self) -> Option { self.bookmarks_client.as_ref()?; let hosts: Vec = self .bookmarks_client @@ -366,7 +366,7 @@ impl AuthActivity { /// ### draw_local_explorer /// /// Draw local explorer list - pub(super) fn draw_recents_tab(&self) -> Option { + fn draw_recents_tab(&self) -> Option { self.bookmarks_client.as_ref()?; let hosts: Vec = self .bookmarks_client @@ -463,7 +463,7 @@ impl AuthActivity { /// ### draw_popup_input /// /// Draw input popup - pub(super) fn draw_popup_save_bookmark(&self) -> (Paragraph, Tabs) { + fn draw_popup_save_bookmark(&self) -> (Paragraph, Tabs) { let input: Paragraph = Paragraph::new(self.input_txt.as_ref()) .style(Style::default().fg(Color::White)) .block( @@ -497,7 +497,7 @@ impl AuthActivity { /// ### draw_popup_yesno /// /// Draw yes/no select popup - pub(super) fn draw_popup_yesno(&self, text: String) -> Tabs { + fn draw_popup_yesno(&self, text: String) -> Tabs { let choices: Vec = vec![Spans::from("Yes"), Spans::from("No")]; let index: usize = match self.choice_opt { DialogYesNoOption::Yes => 0, @@ -522,7 +522,7 @@ impl AuthActivity { /// ### draw_popup_help /// /// Draw authentication page help popup - pub(super) fn draw_popup_help(&self) -> List { + fn draw_popup_help(&self) -> List { // Write header let cmds: Vec = vec![ ListItem::new(Spans::from(vec![ diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 4d810a5..5dee089 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -130,11 +130,19 @@ impl FileTransferActivity { /// /// Build explorer reading configuration from `ConfigClient` pub(super) fn build_explorer(cli: Option<&ConfigClient>) -> FileExplorer { - FileExplorerBuilder::new() - .with_file_sorting(FileSorting::ByName) - .with_group_dirs(Some(GroupDirs::First)) - .with_stack_size(16) - .build() + match &cli { + Some(cli) => FileExplorerBuilder::new() // Build according to current configuration + .with_file_sorting(FileSorting::ByName) + .with_group_dirs(cli.get_group_dirs()) + .with_hidden_files(cli.get_show_hidden_files()) + .with_stack_size(16) + .build(), + None => FileExplorerBuilder::new() // Build default + .with_file_sorting(FileSorting::ByName) + .with_group_dirs(Some(GroupDirs::First)) + .with_stack_size(16) + .build(), + } } /// ### setup_text_editor diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs index 42b47dd..5819710 100644 --- a/src/ui/activities/setup_activity/input.rs +++ b/src/ui/activities/setup_activity/input.rs @@ -30,6 +30,7 @@ use super::{ UserInterfaceInputField, YesNoDialogOption, }; use crate::filetransfer::FileTransferProtocol; +use crate::fs::explorer::GroupDirs; // Ext use crossterm::event::{KeyCode, KeyModifiers}; use std::path::PathBuf; @@ -195,59 +196,105 @@ impl SetupActivity { KeyCode::Left => { // Move left on fields which are tabs if let Some(config_cli) = self.config_cli.as_mut() { - if matches!(field, UserInterfaceInputField::DefaultProtocol) { - // Move left - config_cli.set_default_protocol( - match config_cli.get_default_protocol() { - FileTransferProtocol::Ftp(secure) => match secure { - true => FileTransferProtocol::Ftp(false), - false => FileTransferProtocol::Scp, + match field { + UserInterfaceInputField::DefaultProtocol => { + // Move left + config_cli.set_default_protocol( + match config_cli.get_default_protocol() { + FileTransferProtocol::Ftp(secure) => match secure { + true => FileTransferProtocol::Ftp(false), + false => FileTransferProtocol::Scp, + }, + FileTransferProtocol::Scp => FileTransferProtocol::Sftp, + FileTransferProtocol::Sftp => { + FileTransferProtocol::Ftp(true) + } // Wrap }, - FileTransferProtocol::Scp => FileTransferProtocol::Sftp, - FileTransferProtocol::Sftp => FileTransferProtocol::Ftp(true), // Wrap - }, - ); + ); + } + UserInterfaceInputField::GroupDirs => { + // Move left + config_cli.set_group_dirs(match config_cli.get_group_dirs() { + None => Some(GroupDirs::Last), + Some(val) => match val { + GroupDirs::Last => Some(GroupDirs::First), + GroupDirs::First => None, + }, + }); + } + UserInterfaceInputField::ShowHiddenFiles => { + // Move left + config_cli.set_show_hidden_files(true); + } + _ => { /* Not a tab field */ } } } } KeyCode::Right => { // Move right on fields which are tabs if let Some(config_cli) = self.config_cli.as_mut() { - if matches!(field, UserInterfaceInputField::DefaultProtocol) { - // Move left - config_cli.set_default_protocol( - match config_cli.get_default_protocol() { - FileTransferProtocol::Sftp => FileTransferProtocol::Scp, - FileTransferProtocol::Scp => FileTransferProtocol::Ftp(false), - FileTransferProtocol::Ftp(secure) => match secure { - false => FileTransferProtocol::Ftp(true), - true => FileTransferProtocol::Sftp, // Wrap + match field { + UserInterfaceInputField::DefaultProtocol => { + // Move left + config_cli.set_default_protocol( + match config_cli.get_default_protocol() { + FileTransferProtocol::Sftp => FileTransferProtocol::Scp, + FileTransferProtocol::Scp => { + FileTransferProtocol::Ftp(false) + } + FileTransferProtocol::Ftp(secure) => match secure { + false => FileTransferProtocol::Ftp(true), + true => FileTransferProtocol::Sftp, // Wrap + }, }, - }, - ); + ); + } + UserInterfaceInputField::GroupDirs => { + // Move right + config_cli.set_group_dirs(match config_cli.get_group_dirs() { + Some(val) => match val { + GroupDirs::First => Some(GroupDirs::Last), + GroupDirs::Last => None, + }, + None => Some(GroupDirs::First), + }); + } + UserInterfaceInputField::ShowHiddenFiles => { + // Move right + config_cli.set_show_hidden_files(false); + } + _ => { /* Not a tab field */ } } } } KeyCode::Up => { // Change selected field self.tab = SetupTab::UserInterface(match field { - UserInterfaceInputField::TextEditor => { + UserInterfaceInputField::GroupDirs => { + UserInterfaceInputField::ShowHiddenFiles + } + UserInterfaceInputField::ShowHiddenFiles => { UserInterfaceInputField::DefaultProtocol } UserInterfaceInputField::DefaultProtocol => { UserInterfaceInputField::TextEditor - } // Wrap + } + UserInterfaceInputField::TextEditor => UserInterfaceInputField::GroupDirs, // Wrap }); } KeyCode::Down => { // Change selected field self.tab = SetupTab::UserInterface(match field { - UserInterfaceInputField::DefaultProtocol => { - UserInterfaceInputField::TextEditor - } UserInterfaceInputField::TextEditor => { UserInterfaceInputField::DefaultProtocol - } // Wrap + } + UserInterfaceInputField::DefaultProtocol => { + UserInterfaceInputField::ShowHiddenFiles + } + UserInterfaceInputField::ShowHiddenFiles => { + UserInterfaceInputField::GroupDirs + } + UserInterfaceInputField::GroupDirs => UserInterfaceInputField::TextEditor, // Wrap }); } KeyCode::Char(ch) => { @@ -450,7 +497,7 @@ impl SetupActivity { /// ### handle_input_event_mode_popup_yesno /// /// Input event handler for popup alert - pub(super) fn handle_input_event_mode_popup_yesno( + fn handle_input_event_mode_popup_yesno( &mut self, ev: &InputEvent, yes_cb: OnChoiceCallback, diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index d58aaf0..cee5655 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -29,8 +29,9 @@ use super::{ YesNoDialogOption, }; use crate::filetransfer::FileTransferProtocol; +use crate::fs::explorer::GroupDirs; use crate::utils::fmt::align_text_center; - +// Ext use tui::{ layout::{Constraint, Corner, Direction, Layout, Rect}, style::{Color, Modifier, Style}, @@ -84,6 +85,8 @@ impl SetupActivity { .direction(Direction::Vertical) .constraints( [ + Constraint::Length(3), + Constraint::Length(3), Constraint::Length(3), Constraint::Length(3), Constraint::Length(1), @@ -98,6 +101,12 @@ impl SetupActivity { if let Some(tab) = self.draw_default_protocol_tab() { f.render_widget(tab, ui_cfg_chunks[1]); } + if let Some(tab) = self.draw_hidden_files_tab() { + f.render_widget(tab, ui_cfg_chunks[2]); + } + if let Some(tab) = self.draw_default_group_dirs_tab() { + f.render_widget(tab, ui_cfg_chunks[3]); + } // Set cursor if let Some(cli) = &self.config_cli { if matches!(form_field, UserInterfaceInputField::TextEditor) { @@ -217,6 +226,33 @@ impl SetupActivity { Paragraph::new(footer_text) } + /// ### draw_text_editor_input + /// + /// Draw input text field for text editor parameter + fn draw_text_editor_input(&self) -> Option { + match &self.config_cli { + Some(cli) => Some( + Paragraph::new(String::from( + cli.get_text_editor().as_path().to_string_lossy(), + )) + .style(Style::default().fg(match &self.tab { + SetupTab::SshConfig => Color::White, + SetupTab::UserInterface(field) => match field { + UserInterfaceInputField::TextEditor => Color::LightGreen, + _ => Color::White, + }, + })) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .title("Text Editor"), + ), + ), + None => None, + } + } + /// ### draw_default_protocol_tab /// /// Draw default protocol input tab @@ -267,29 +303,91 @@ impl SetupActivity { } } - /// ### draw_text_editor_input + /// ### draw_default_protocol_tab /// - /// Draw input text field for text editor parameter - fn draw_text_editor_input(&self) -> Option { + /// Draw default protocol input tab + fn draw_hidden_files_tab(&self) -> Option { + // Check if config client is some match &self.config_cli { - Some(cli) => Some( - Paragraph::new(String::from( - cli.get_text_editor().as_path().to_string_lossy(), - )) - .style(Style::default().fg(match &self.tab { - SetupTab::SshConfig => Color::White, + Some(cli) => { + let choices: Vec = vec![Spans::from("Yes"), Spans::from("No")]; + let index: usize = match cli.get_show_hidden_files() { + true => 0, + false => 1, + }; + let (bg, fg, block_fg): (Color, Color, Color) = match &self.tab { SetupTab::UserInterface(field) => match field { - UserInterfaceInputField::TextEditor => Color::LightGreen, - _ => Color::White, + UserInterfaceInputField::ShowHiddenFiles => { + (Color::LightRed, Color::Black, Color::LightRed) + } + _ => (Color::Reset, Color::LightRed, Color::Reset), }, - })) - .block( - Block::default() - .borders(Borders::ALL) - .border_type(BorderType::Rounded) - .title("Text Editor"), - ), - ), + _ => (Color::Reset, Color::Reset, Color::Reset), + }; + Some( + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .style(Style::default().fg(block_fg)) + .title("Show hidden files (by default)"), + ) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default().add_modifier(Modifier::BOLD).fg(fg).bg(bg), + ), + ) + } + None => None, + } + } + + /// ### draw_default_group_dirs_tab + /// + /// Draw group dirs input tab + fn draw_default_group_dirs_tab(&self) -> Option { + // Check if config client is some + match &self.config_cli { + Some(cli) => { + let choices: Vec = vec![ + Spans::from("Display First"), + Spans::from("Display Last"), + Spans::from("No"), + ]; + let index: usize = match cli.get_group_dirs() { + None => 2, + Some(val) => match val { + GroupDirs::First => 0, + GroupDirs::Last => 1, + }, + }; + let (bg, fg, block_fg): (Color, Color, Color) = match &self.tab { + SetupTab::UserInterface(field) => match field { + UserInterfaceInputField::GroupDirs => { + (Color::LightMagenta, Color::Black, Color::LightMagenta) + } + _ => (Color::Reset, Color::LightMagenta, Color::Reset), + }, + _ => (Color::Reset, Color::Reset, Color::Reset), + }; + Some( + Tabs::new(choices) + .block( + Block::default() + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .style(Style::default().fg(block_fg)) + .title("Group directories"), + ) + .select(index) + .style(Style::default()) + .highlight_style( + Style::default().add_modifier(Modifier::BOLD).fg(fg).bg(bg), + ), + ) + } None => None, } } @@ -481,7 +579,7 @@ impl SetupActivity { /// ### draw_popup_help /// /// Draw authentication page help popup - pub(super) fn draw_popup_help(&self) -> List { + fn draw_popup_help(&self) -> List { // Write header let cmds: Vec = vec![ ListItem::new(Spans::from(vec![ diff --git a/src/ui/activities/setup_activity/mod.rs b/src/ui/activities/setup_activity/mod.rs index 1d085f4..b7f783c 100644 --- a/src/ui/activities/setup_activity/mod.rs +++ b/src/ui/activities/setup_activity/mod.rs @@ -53,6 +53,8 @@ type OnChoiceCallback = fn(&mut SetupActivity); enum UserInterfaceInputField { DefaultProtocol, TextEditor, + ShowHiddenFiles, + GroupDirs, } /// ### SetupTab From 655084c5f60ba75a266d2326d656bb39c4515450 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 10:36:48 +0100 Subject: [PATCH 46/64] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0016d..d587b3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ FIXME: Released on - Windows: `C:\Users\Alice\AppData\Roaming\termscp\config.toml` - Added Text editor to configuration - Added Default File transfer protocol to configuration - - Added "Show hidden files` to configuration + - Added "Show hidden files" to configuration - Added "Group directories" to configuration - Added SSH keys to configuration; SSH keys will be stored at - Linux: `/home/alice/.config/termscp/.ssh/` From 65e7ff22f7f3cd57731feea7d9f84c27a203cb06 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 10:47:11 +0100 Subject: [PATCH 47/64] Explorers: append '/' to directories name --- CHANGELOG.md | 1 + src/fs/mod.rs | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d587b3f..fcf8e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ FIXME: Released on - Default protocol changed to default protocol in configuration when providing address as CLI argument - Explorers: - Hidden files are now not shown by default; use `A` to show hidden files. + - Append `/` to directories name. - Keybindings: - `A`: Toggle hidden files - `B`: Sort files by (name, size, creation time, modify time) diff --git a/src/fs/mod.rs b/src/fs/mod.rs index b66ae1b..04468ce 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -285,10 +285,19 @@ impl std::fmt::Display for FsEntry { let datetime: String = fmt_time(self.get_last_change_time(), "%b %d %Y %H:%M"); // Set file name (or elide if too long) let name: &str = self.get_name(); - let name: String = match name.len() >= 24 { - false => name.to_string(), - true => format!("{}...", &name[0..20]), + let last_idx: usize = match self.is_dir() { + // NOTE: For directories is 19, since we push '/' to name + true => 19, + false => 20, }; + let mut name: String = match name.len() >= 24 { + false => name.to_string(), + true => format!("{}...", &name[0..last_idx]), + }; + // If is directory, append '/' + if self.is_dir() { + name.push('/'); + } write!( f, "{:24}\t{:12}\t{:12}\t{:10}\t{:17}", @@ -651,7 +660,7 @@ mod tests { assert_eq!( format!("{}", entry), format!( - "projects \tdrwxr-xr-x \troot \t4.1 KB \t{}", + "projects/ \tdrwxr-xr-x \troot \t4.1 KB \t{}", fmt_time(t_now, "%b %d %Y %H:%M") ) ); @@ -659,7 +668,7 @@ mod tests { assert_eq!( format!("{}", entry), format!( - "projects \tdrwxr-xr-x \t0 \t4.1 KB \t{}", + "projects/ \tdrwxr-xr-x \t0 \t4.1 KB \t{}", fmt_time(t_now, "%b %d %Y %H:%M") ) ); @@ -680,7 +689,7 @@ mod tests { assert_eq!( format!("{}", entry), format!( - "projects \td????????? \t0 \t4.1 KB \t{}", + "projects/ \td????????? \t0 \t4.1 KB \t{}", fmt_time(t_now, "%b %d %Y %H:%M") ) ); @@ -688,7 +697,7 @@ mod tests { assert_eq!( format!("{}", entry), format!( - "projects \td????????? \t0 \t4.1 KB \t{}", + "projects/ \td????????? \t0 \t4.1 KB \t{}", fmt_time(t_now, "%b %d %Y %H:%M") ) ); From d756bf7786e66ef1e83cda62f9a11fd381ff35aa Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 10:59:12 +0100 Subject: [PATCH 48/64] InputMode as Option in FileTransferActivity --- .../activities/filetransfer_activity/input.rs | 104 +++++++++--------- .../filetransfer_activity/layout.rs | 40 +++---- .../activities/filetransfer_activity/misc.rs | 15 +-- .../activities/filetransfer_activity/mod.rs | 27 ++--- .../filetransfer_activity/session.rs | 28 ++--- 5 files changed, 98 insertions(+), 116 deletions(-) diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 27b9c09..9df1256 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -28,7 +28,7 @@ extern crate tempfile; // Local use super::{ DialogCallback, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputEvent, - InputField, InputMode, LogLevel, OnInputSubmitCallback, PopupType, + InputField, LogLevel, OnInputSubmitCallback, Popup, }; use crate::fs::explorer::{FileExplorer, FileSorting}; // Ext @@ -64,13 +64,13 @@ impl FileTransferActivity { fn handle_input_event(&mut self, ev: &InputEvent) { // NOTE: this is necessary due to this // NOTE: Do you want my opinion about that issue? It's a bs and doesn't make any sense. - let popup: Option = match &self.input_mode { - InputMode::Popup(ptype) => Some(ptype.clone()), + let popup: Option = match &self.popup { + Some(ptype) => Some(ptype.clone()), _ => None, }; - match &self.input_mode { - InputMode::Explorer => self.handle_input_event_mode_explorer(ev), - InputMode::Popup(_) => { + match &self.popup { + None => self.handle_input_event_mode_explorer(ev), + Some(_) => { if let Some(popup) = popup { self.handle_input_event_mode_popup(ev, popup); } @@ -103,7 +103,7 @@ impl FileTransferActivity { KeyCode::Esc => { // Handle quit event // Create quit prompt dialog - self.input_mode = self.create_disconnect_popup(); + self.popup = self.create_disconnect_popup(); } KeyCode::Tab => self.switch_input_field(), // switch tab KeyCode::Right => self.tab = FileExplorerTab::Remote, // switch to right tab @@ -162,7 +162,7 @@ impl FileTransferActivity { FsEntry::File(file) => file.name.clone(), }; // Show delete prompt - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( format!("Delete file \"{}\"", file_name), FileTransferActivity::callback_delete_fsentry, FileTransferActivity::callback_nothing_to_do, @@ -176,18 +176,18 @@ impl FileTransferActivity { } 'b' | 'B' => { // Choose file sorting type - self.input_mode = InputMode::Popup(PopupType::FileSortingDialog); + self.popup = Some(Popup::FileSortingDialog); } 'c' | 'C' => { // Copy - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert destination name"), FileTransferActivity::callback_copy, )); } 'd' | 'D' => { // Make directory - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert directory name"), FileTransferActivity::callback_mkdir, )); @@ -201,7 +201,7 @@ impl FileTransferActivity { FsEntry::File(file) => file.name.clone(), }; // Show delete prompt - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( format!("Delete file \"{}\"", file_name), FileTransferActivity::callback_delete_fsentry, FileTransferActivity::callback_nothing_to_do, @@ -211,18 +211,18 @@ impl FileTransferActivity { 'g' | 'G' => { // Goto // Show input popup - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Change working directory"), FileTransferActivity::callback_change_directory, )); } 'h' | 'H' => { // Show help - self.input_mode = InputMode::Popup(PopupType::Help); + self.popup = Some(Popup::Help); } 'i' | 'I' => { // Show file info - self.input_mode = InputMode::Popup(PopupType::FileInfo); + self.popup = Some(Popup::FileInfo); } 'l' | 'L' => { // Reload file entries @@ -231,7 +231,7 @@ impl FileTransferActivity { } 'n' | 'N' => { // New file - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("New file"), Self::callback_new_file, )); @@ -265,11 +265,11 @@ impl FileTransferActivity { } 'q' | 'Q' => { // Create quit prompt dialog - self.input_mode = self.create_quit_popup(); + self.popup = self.create_quit_popup(); } 'r' | 'R' => { // Rename - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert new name"), FileTransferActivity::callback_rename, )); @@ -277,7 +277,7 @@ impl FileTransferActivity { 's' | 'S' => { // Save as... // Ask for input - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Save as..."), FileTransferActivity::callback_save_as, )); @@ -322,7 +322,7 @@ impl FileTransferActivity { KeyCode::Esc => { // Handle quit event // Create quit prompt dialog - self.input_mode = self.create_disconnect_popup(); + self.popup = self.create_disconnect_popup(); } KeyCode::Tab => self.switch_input_field(), // switch tab KeyCode::Left => self.tab = FileExplorerTab::Local, // switch to local tab @@ -381,7 +381,7 @@ impl FileTransferActivity { FsEntry::File(file) => file.name.clone(), }; // Show delete prompt - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( format!("Delete file \"{}\"", file_name), FileTransferActivity::callback_delete_fsentry, FileTransferActivity::callback_nothing_to_do, @@ -395,18 +395,18 @@ impl FileTransferActivity { } 'b' | 'B' => { // Choose file sorting type - self.input_mode = InputMode::Popup(PopupType::FileSortingDialog); + self.popup = Some(Popup::FileSortingDialog); } 'c' | 'C' => { // Copy - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert destination name"), FileTransferActivity::callback_copy, )); } 'd' | 'D' => { // Make directory - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert directory name"), FileTransferActivity::callback_mkdir, )); @@ -420,7 +420,7 @@ impl FileTransferActivity { FsEntry::File(file) => file.name.clone(), }; // Show delete prompt - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( format!("Delete file \"{}\"", file_name), FileTransferActivity::callback_delete_fsentry, FileTransferActivity::callback_nothing_to_do, @@ -430,18 +430,18 @@ impl FileTransferActivity { 'g' | 'G' => { // Goto // Show input popup - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Change working directory"), FileTransferActivity::callback_change_directory, )); } 'h' | 'H' => { // Show help - self.input_mode = InputMode::Popup(PopupType::Help); + self.popup = Some(Popup::Help); } 'i' | 'I' => { // Show file info - self.input_mode = InputMode::Popup(PopupType::FileInfo); + self.popup = Some(Popup::FileInfo); } 'l' | 'L' => { // Reload file entries @@ -449,7 +449,7 @@ impl FileTransferActivity { } 'n' | 'N' => { // New file - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("New file"), Self::callback_new_file, )); @@ -476,17 +476,17 @@ impl FileTransferActivity { Err(err) => self.log_and_alert(LogLevel::Error, err), } // Put input mode back to normal - self.input_mode = InputMode::Explorer; + self.popup = None; } } } 'q' | 'Q' => { // Create quit prompt dialog - self.input_mode = self.create_quit_popup(); + self.popup = self.create_quit_popup(); } 'r' | 'R' => { // Rename - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Insert new name"), FileTransferActivity::callback_rename, )); @@ -494,7 +494,7 @@ impl FileTransferActivity { 's' | 'S' => { // Save as... // Ask for input - self.input_mode = InputMode::Popup(PopupType::Input( + self.popup = Some(Popup::Input( String::from("Save as..."), FileTransferActivity::callback_save_as, )); @@ -539,7 +539,7 @@ impl FileTransferActivity { KeyCode::Esc => { // Handle quit event // Create quit prompt dialog - self.input_mode = self.create_disconnect_popup(); + self.popup = self.create_disconnect_popup(); } KeyCode::Tab => self.switch_input_field(), // switch tab KeyCode::Down => { @@ -578,7 +578,7 @@ impl FileTransferActivity { KeyCode::Char(ch) => match ch { 'q' | 'Q' => { // Create quit prompt dialog - self.input_mode = self.create_quit_popup(); + self.popup = self.create_quit_popup(); } _ => { /* Nothing to do */ } }, @@ -590,17 +590,17 @@ impl FileTransferActivity { /// ### handle_input_event_mode_explorer /// /// Input event handler for popup mode. Handler is then based on Popup type - fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: PopupType) { + fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, popup: Popup) { match popup { - PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), - PopupType::FileInfo => self.handle_input_event_mode_popup_fileinfo(ev), - PopupType::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev), - PopupType::FileSortingDialog => self.handle_input_event_mode_popup_file_sorting(ev), - PopupType::Help => self.handle_input_event_mode_popup_help(ev), - PopupType::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb), - PopupType::Progress(_) => self.handle_input_event_mode_popup_progress(ev), - PopupType::Wait(_) => self.handle_input_event_mode_popup_wait(ev), - PopupType::YesNo(_, yes_cb, no_cb) => { + Popup::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), + Popup::FileInfo => self.handle_input_event_mode_popup_fileinfo(ev), + Popup::Fatal(_) => self.handle_input_event_mode_popup_fatal(ev), + Popup::FileSortingDialog => self.handle_input_event_mode_popup_file_sorting(ev), + Popup::Help => self.handle_input_event_mode_popup_help(ev), + Popup::Input(_, cb) => self.handle_input_event_mode_popup_input(ev, cb), + Popup::Progress(_) => self.handle_input_event_mode_popup_progress(ev), + Popup::Wait(_) => self.handle_input_event_mode_popup_wait(ev), + Popup::YesNo(_, yes_cb, no_cb) => { self.handle_input_event_mode_popup_yesno(ev, yes_cb, no_cb) } } @@ -614,7 +614,7 @@ impl FileTransferActivity { if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set input mode back to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; } } } @@ -627,7 +627,7 @@ impl FileTransferActivity { if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set input mode back to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; } } } @@ -654,7 +654,7 @@ impl FileTransferActivity { match key.code { KeyCode::Esc | KeyCode::Enter => { // Exit - self.input_mode = InputMode::Explorer; + self.popup = None; } KeyCode::Right => { // Update sorting mode @@ -691,7 +691,7 @@ impl FileTransferActivity { if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set input mode back to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; } } } @@ -708,7 +708,7 @@ impl FileTransferActivity { // Clear current input text self.input_txt.clear(); // Set mode back to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; } KeyCode::Enter => { // Submit @@ -716,7 +716,7 @@ impl FileTransferActivity { // Clear current input text self.input_txt.clear(); // Set mode back to explorer BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? - self.input_mode = InputMode::Explorer; + self.popup = None; // Call cb cb(self, input_text); } @@ -765,7 +765,7 @@ impl FileTransferActivity { match key.code { KeyCode::Enter => { // @! Set input mode to Explorer BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? - self.input_mode = InputMode::Explorer; + self.popup = None; // Check if user selected yes or not match self.choice_opt { DialogYesNoOption::No => no_cb(self), diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index fe6c33b..49a7c19 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -31,7 +31,7 @@ extern crate users; // Local use super::{ Context, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputField, - InputMode, LogLevel, LogRecord, PopupType, + LogLevel, LogRecord, Popup, }; use crate::fs::explorer::{FileExplorer, FileSorting}; use crate::utils::fmt::{align_text_center, fmt_time}; @@ -101,36 +101,36 @@ impl FileTransferActivity { &mut log_state, ); // Draw popup - if let InputMode::Popup(popup) = &self.input_mode { + if let Some(popup) = &self.popup { // Calculate popup size let (width, height): (u16, u16) = match popup { - PopupType::Alert(_, _) => (50, 10), - PopupType::Fatal(_) => (50, 10), - PopupType::FileInfo => (50, 50), - PopupType::FileSortingDialog => (50, 10), - PopupType::Help => (50, 80), - PopupType::Input(_, _) => (40, 10), - PopupType::Progress(_) => (40, 10), - PopupType::Wait(_) => (50, 10), - PopupType::YesNo(_, _, _) => (30, 10), + Popup::Alert(_, _) => (50, 10), + Popup::Fatal(_) => (50, 10), + Popup::FileInfo => (50, 50), + Popup::FileSortingDialog => (50, 10), + Popup::Help => (50, 80), + Popup::Input(_, _) => (40, 10), + Popup::Progress(_) => (40, 10), + Popup::Wait(_) => (50, 10), + Popup::YesNo(_, _, _) => (30, 10), }; let popup_area: Rect = self.draw_popup_area(f.size(), width, height); f.render_widget(Clear, popup_area); //this clears out the background match popup { - PopupType::Alert(color, txt) => f.render_widget( + Popup::Alert(color, txt) => f.render_widget( self.draw_popup_alert(*color, txt.clone(), popup_area.width), popup_area, ), - PopupType::Fatal(txt) => f.render_widget( + Popup::Fatal(txt) => f.render_widget( self.draw_popup_fatal(txt.clone(), popup_area.width), popup_area, ), - PopupType::FileInfo => f.render_widget(self.draw_popup_fileinfo(), popup_area), - PopupType::FileSortingDialog => { + Popup::FileInfo => f.render_widget(self.draw_popup_fileinfo(), popup_area), + Popup::FileSortingDialog => { f.render_widget(self.draw_popup_file_sorting_dialog(), popup_area) } - PopupType::Help => f.render_widget(self.draw_popup_help(), popup_area), - PopupType::Input(txt, _) => { + Popup::Help => f.render_widget(self.draw_popup_help(), popup_area), + Popup::Input(txt, _) => { f.render_widget(self.draw_popup_input(txt.clone()), popup_area); // Set cursor f.set_cursor( @@ -138,14 +138,14 @@ impl FileTransferActivity { popup_area.y + 1, ) } - PopupType::Progress(txt) => { + Popup::Progress(txt) => { f.render_widget(self.draw_popup_progress(txt.clone()), popup_area) } - PopupType::Wait(txt) => f.render_widget( + Popup::Wait(txt) => f.render_widget( self.draw_popup_wait(txt.clone(), popup_area.width), popup_area, ), - PopupType::YesNo(txt, _, _) => { + Popup::YesNo(txt, _, _) => { f.render_widget(self.draw_popup_yesno(txt.clone()), popup_area) } } diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 5dee089..642083c 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -20,10 +20,7 @@ */ // Locals -use super::{ - Color, ConfigClient, FileTransferActivity, InputField, InputMode, LogLevel, LogRecord, - PopupType, -}; +use super::{Color, ConfigClient, FileTransferActivity, InputField, LogLevel, LogRecord, Popup}; use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSorting, GroupDirs}; use crate::system::environment; use crate::system::sshkey_storage::SshKeyStorage; @@ -59,14 +56,14 @@ impl FileTransferActivity { LogLevel::Warn => Color::Yellow, }; self.log(level, msg.as_str()); - self.input_mode = InputMode::Popup(PopupType::Alert(color, msg)); + self.popup = Some(Popup::Alert(color, msg)); } /// ### create_quit_popup /// /// Create quit popup input mode (since must be shared between different input handlers) - pub(super) fn create_disconnect_popup(&mut self) -> InputMode { - InputMode::Popup(PopupType::YesNo( + pub(super) fn create_disconnect_popup(&mut self) -> Option { + Some(Popup::YesNo( String::from("Are you sure you want to disconnect?"), FileTransferActivity::disconnect, FileTransferActivity::callback_nothing_to_do, @@ -76,8 +73,8 @@ impl FileTransferActivity { /// ### create_quit_popup /// /// Create quit popup input mode (since must be shared between different input handlers) - pub(super) fn create_quit_popup(&mut self) -> InputMode { - InputMode::Popup(PopupType::YesNo( + pub(super) fn create_quit_popup(&mut self) -> Option { + Some(Popup::YesNo( String::from("Are you sure you want to quit?"), FileTransferActivity::disconnect_and_quit, FileTransferActivity::callback_nothing_to_do, diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index c2029da..646d0d6 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -89,11 +89,11 @@ enum DialogYesNoOption { No, } -/// ## PopupType +/// ## Popup /// -/// PopupType describes the type of popup +/// Popup describes the type of popup #[derive(Clone)] -enum PopupType { +enum Popup { Alert(Color, String), // Block color; Block text Fatal(String), // Must quit after being hidden FileInfo, // Show info about current file @@ -105,16 +105,6 @@ enum PopupType { YesNo(String, DialogCallback, DialogCallback), // Yes, no callback } -/// ## InputMode -/// -/// InputMode describes the current input mode -/// Each input mode handle the input events in a different way -#[derive(Clone)] -enum InputMode { - Explorer, - Popup(PopupType), -} - /// ## FileExplorerTab /// /// File explorer tab @@ -241,7 +231,7 @@ pub struct FileTransferActivity { log_index: usize, // Current log index entry selected log_records: VecDeque, // Log records log_size: usize, // Log records size (max) - input_mode: InputMode, // Current input mode + popup: Option, // Current input mode input_field: InputField, // Current selected input mode input_txt: String, // Input text choice_opt: DialogYesNoOption, // Dialog popup selected option @@ -277,7 +267,7 @@ impl FileTransferActivity { log_index: 0, log_records: VecDeque::with_capacity(256), // 256 events is enough I guess log_size: 256, // Must match with capacity - input_mode: InputMode::Explorer, + popup: None, input_field: InputField::Explorer, input_txt: String::new(), choice_opt: DialogYesNoOption::Yes, @@ -324,11 +314,10 @@ impl Activity for FileTransferActivity { if self.context.is_none() { return; } - let is_explorer_mode: bool = matches!(self.input_mode, InputMode::Explorer); - // Check if connected - if !self.client.is_connected() && is_explorer_mode { + // Check if connected (popup must be None, otherwise would try reconnecting in loop in case of error) + if !self.client.is_connected() && self.popup.is_none() { // Set init state to connecting popup - self.input_mode = InputMode::Popup(PopupType::Wait(format!( + self.popup = Some(Popup::Wait(format!( "Connecting to {}:{}...", self.params.address, self.params.port ))); diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index 381538e..633a07f 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -30,7 +30,7 @@ extern crate crossterm; extern crate tempfile; // Locals -use super::{FileTransferActivity, InputMode, LogLevel, PopupType}; +use super::{FileTransferActivity, LogLevel, Popup}; use crate::fs::{FsEntry, FsFile}; use crate::utils::fmt::fmt_millis; @@ -68,12 +68,12 @@ impl FileTransferActivity { ); } // Set state to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; self.reload_remote_dir(); } Err(err) => { // Set popup fatal error - self.input_mode = InputMode::Popup(PopupType::Fatal(format!("{}", err))); + self.popup = Some(Popup::Fatal(format!("{}", err))); } } } @@ -83,7 +83,7 @@ impl FileTransferActivity { /// disconnect from remote pub(super) fn disconnect(&mut self) { // Show popup disconnecting - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Disconnecting from remote..."), )); @@ -129,7 +129,7 @@ impl FileTransferActivity { FsEntry::Directory(dir) => dir.name.clone(), FsEntry::File(file) => file.name.clone(), }; - self.input_mode = InputMode::Popup(PopupType::Wait(format!("Uploading \"{}\"", file_name))); + self.popup = Some(Popup::Wait(format!("Uploading \"{}\"", file_name))); // Draw self.draw(); // Get remote path @@ -211,9 +211,9 @@ impl FileTransferActivity { } else { // @! Successful // Eventually, Reset input mode to explorer (if input mode is wait or progress) - if let InputMode::Popup(ptype) = &self.input_mode { - if matches!(ptype, PopupType::Wait(_) | PopupType::Progress(_)) { - self.input_mode = InputMode::Explorer + if let Some(ptype) = &self.popup { + if matches!(ptype, Popup::Wait(_) | Popup::Progress(_)) { + self.popup = None } } } @@ -235,8 +235,7 @@ impl FileTransferActivity { FsEntry::Directory(dir) => dir.name.clone(), FsEntry::File(file) => file.name.clone(), }; - self.input_mode = - InputMode::Popup(PopupType::Wait(format!("Downloading \"{}\"...", file_name))); + self.popup = Some(Popup::Wait(format!("Downloading \"{}\"...", file_name))); // Draw self.draw(); // Match entry @@ -352,7 +351,7 @@ impl FileTransferActivity { self.transfer.aborted = false; } else { // Eventually, Reset input mode to explorer - self.input_mode = InputMode::Explorer; + self.popup = None; } } @@ -381,10 +380,7 @@ impl FileTransferActivity { // Write remote file let mut total_bytes_written: usize = 0; // Set input state to popup progress - self.input_mode = InputMode::Popup(PopupType::Progress(format!( - "Uploading \"{}\"", - local.name - ))); + self.popup = Some(Popup::Progress(format!("Uploading \"{}\"", local.name))); // Reset transfer states self.transfer.reset(); let mut last_progress_val: f64 = 0.0; @@ -484,7 +480,7 @@ impl FileTransferActivity { match self.client.recv_file(remote) { Ok(mut rhnd) => { // Set popup progress - self.input_mode = InputMode::Popup(PopupType::Progress(format!( + self.popup = Some(Popup::Progress(format!( "Downloading \"{}\"...", remote.name, ))); From 6dd4cfaa3c623ee8f6adca0ad6e84bf9aa43a0c3 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 11:03:44 +0100 Subject: [PATCH 49/64] InputMode as Option in AuthActivity --- src/ui/activities/auth_activity/bookmarks.rs | 19 +++--- src/ui/activities/auth_activity/input.rs | 68 ++++++++++---------- src/ui/activities/auth_activity/layout.rs | 21 +++--- src/ui/activities/auth_activity/mod.rs | 25 +++---- 4 files changed, 61 insertions(+), 72 deletions(-) diff --git a/src/ui/activities/auth_activity/bookmarks.rs b/src/ui/activities/auth_activity/bookmarks.rs index 7526d72..e0fa090 100644 --- a/src/ui/activities/auth_activity/bookmarks.rs +++ b/src/ui/activities/auth_activity/bookmarks.rs @@ -27,7 +27,7 @@ extern crate dirs; // Locals -use super::{AuthActivity, Color, DialogYesNoOption, InputMode, PopupType}; +use super::{AuthActivity, Color, DialogYesNoOption, Popup}; use crate::system::bookmarks_client::BookmarksClient; use crate::system::environment; @@ -89,7 +89,7 @@ impl AuthActivity { let port: u16 = match self.port.parse::() { Ok(val) => { if val > 65535 { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port must be in range 0-65535"), )); @@ -98,7 +98,7 @@ impl AuthActivity { val as u16 } Err(_) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port is not a number"), )); @@ -174,7 +174,7 @@ impl AuthActivity { let port: u16 = match self.port.parse::() { Ok(val) => { if val > 65535 { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port must be in range 0-65535"), )); @@ -183,7 +183,7 @@ impl AuthActivity { val as u16 } Err(_) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port is not a number"), )); @@ -208,7 +208,7 @@ impl AuthActivity { fn write_bookmarks(&mut self) { if let Some(bookmarks_cli) = self.bookmarks_client.as_ref() { if let Err(err) = bookmarks_cli.write_bookmarks() { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, format!("Could not write bookmarks: {}", err), )); @@ -225,12 +225,13 @@ impl AuthActivity { Ok(path) => { // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. if let Some(path) = path { - let (bookmarks_file, key_file): (PathBuf, PathBuf) = environment::get_bookmarks_paths(path.as_path()); + let (bookmarks_file, key_file): (PathBuf, PathBuf) = + environment::get_bookmarks_paths(path.as_path()); // Initialize client match BookmarksClient::new(bookmarks_file.as_path(), key_file.as_path(), 16) { Ok(cli) => self.bookmarks_client = Some(cli), Err(err) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, format!( "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", @@ -244,7 +245,7 @@ impl AuthActivity { } } Err(err) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, format!("Could not initialize configuration directory: {}", err), )) diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index 38b638e..7c93abe 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -25,7 +25,7 @@ use super::{ AuthActivity, DialogCallback, DialogYesNoOption, FileTransferProtocol, InputEvent, InputField, - InputForm, InputMode, PopupType, + InputForm, Popup, }; use crossterm::event::{KeyCode, KeyModifiers}; @@ -36,13 +36,13 @@ impl AuthActivity { /// /// Handle input event, based on current input mode pub(super) fn handle_input_event(&mut self, ev: &InputEvent) { - let popup: Option = match &self.input_mode { - InputMode::Popup(ptype) => Some(ptype.clone()), + let popup: Option = match &self.popup { + Some(ptype) => Some(ptype.clone()), _ => None, }; - match self.input_mode { - InputMode::Form => self.handle_input_event_mode_form(ev), - InputMode::Popup(_) => { + match &self.popup { + None => self.handle_input_event_mode_form(ev), + Some(_) => { if let Some(ptype) = popup { self.handle_input_event_mode_popup(ev, ptype) } @@ -69,7 +69,7 @@ impl AuthActivity { match key.code { KeyCode::Esc => { // Show quit dialog - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to quit termscp?"), AuthActivity::callback_quit, AuthActivity::callback_nothing_to_do, @@ -81,10 +81,8 @@ impl AuthActivity { // Check form // Check address if self.address.is_empty() { - self.input_mode = InputMode::Popup(PopupType::Alert( - Color::Red, - String::from("Invalid address"), - )); + self.popup = + Some(Popup::Alert(Color::Red, String::from("Invalid address"))); return; } // Check port @@ -92,7 +90,7 @@ impl AuthActivity { match self.port.parse::() { Ok(val) => { if val > 65535 { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port must be in range 0-65535"), )); @@ -100,7 +98,7 @@ impl AuthActivity { } } Err(_) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, String::from("Specified port is not a number"), )); @@ -157,7 +155,7 @@ impl AuthActivity { match ch { 'H' | 'h' => { // Show help - self.input_mode = InputMode::Popup(PopupType::Help); + self.popup = Some(Popup::Help); } 'C' | 'c' => { // Show setup @@ -167,7 +165,7 @@ impl AuthActivity { // Default choice option to no self.choice_opt = DialogYesNoOption::No; // Save bookmark as... - self.input_mode = InputMode::Popup(PopupType::SaveBookmark); + self.popup = Some(Popup::SaveBookmark); } _ => { /* Nothing to do */ } } @@ -225,7 +223,7 @@ impl AuthActivity { match key.code { KeyCode::Esc => { // Show quit dialog - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to quit termscp?"), AuthActivity::callback_quit, AuthActivity::callback_nothing_to_do, @@ -257,7 +255,7 @@ impl AuthActivity { } KeyCode::Delete => { // Ask if user wants to delete bookmark - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to delete the selected bookmark?"), AuthActivity::callback_del_bookmark, AuthActivity::callback_nothing_to_do, @@ -278,7 +276,7 @@ impl AuthActivity { } 'E' | 'e' => { // Ask if user wants to delete bookmark; NOTE: same as - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to delete the selected bookmark?"), AuthActivity::callback_del_bookmark, AuthActivity::callback_nothing_to_do, @@ -286,13 +284,13 @@ impl AuthActivity { } 'H' | 'h' => { // Show help - self.input_mode = InputMode::Popup(PopupType::Help); + self.popup = Some(Popup::Help); } 'S' | 's' => { // Default choice option to no self.choice_opt = DialogYesNoOption::No; // Save bookmark as... - self.input_mode = InputMode::Popup(PopupType::SaveBookmark); + self.popup = Some(Popup::SaveBookmark); } _ => { /* Nothing to do */ } }, @@ -309,7 +307,7 @@ impl AuthActivity { match key.code { KeyCode::Esc => { // Show quit dialog - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to quit termscp?"), AuthActivity::callback_quit, AuthActivity::callback_nothing_to_do, @@ -341,7 +339,7 @@ impl AuthActivity { } KeyCode::Delete => { // Ask if user wants to delete bookmark - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to delete the selected host?"), AuthActivity::callback_del_bookmark, AuthActivity::callback_nothing_to_do, @@ -362,7 +360,7 @@ impl AuthActivity { } 'E' | 'e' => { // Ask if user wants to delete bookmark; NOTE: same as - self.input_mode = InputMode::Popup(PopupType::YesNo( + self.popup = Some(Popup::YesNo( String::from("Are you sure you want to delete the selected host?"), AuthActivity::callback_del_bookmark, AuthActivity::callback_nothing_to_do, @@ -370,13 +368,13 @@ impl AuthActivity { } 'H' | 'h' => { // Show help - self.input_mode = InputMode::Popup(PopupType::Help); + self.popup = Some(Popup::Help); } 'S' | 's' => { // Default choice option to no self.choice_opt = DialogYesNoOption::No; // Save bookmark as... - self.input_mode = InputMode::Popup(PopupType::SaveBookmark); + self.popup = Some(Popup::SaveBookmark); } _ => { /* Nothing to do */ } }, @@ -388,12 +386,12 @@ impl AuthActivity { /// ### handle_input_event_mode_text /// /// Handler for input event when in popup mode - fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, ptype: PopupType) { + fn handle_input_event_mode_popup(&mut self, ev: &InputEvent, ptype: Popup) { match ptype { - PopupType::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), - PopupType::Help => self.handle_input_event_mode_popup_help(ev), - PopupType::SaveBookmark => self.handle_input_event_mode_popup_save_bookmark(ev), - PopupType::YesNo(_, yes_cb, no_cb) => { + Popup::Alert(_, _) => self.handle_input_event_mode_popup_alert(ev), + Popup::Help => self.handle_input_event_mode_popup_help(ev), + Popup::SaveBookmark => self.handle_input_event_mode_popup_save_bookmark(ev), + Popup::YesNo(_, yes_cb, no_cb) => { self.handle_input_event_mode_popup_yesno(ev, yes_cb, no_cb) } } @@ -406,7 +404,7 @@ impl AuthActivity { // Only enter should be allowed here if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { - self.input_mode = InputMode::Form; // Hide popup + self.popup = None; // Hide popup } } } @@ -419,7 +417,7 @@ impl AuthActivity { if let InputEvent::Key(key) = ev { if matches!(key.code, KeyCode::Esc | KeyCode::Enter) { // Set input mode back to form - self.input_mode = InputMode::Form; + self.popup = None; } } } @@ -436,7 +434,7 @@ impl AuthActivity { // Clear current input text self.input_txt.clear(); // Set mode back to form - self.input_mode = InputMode::Form; + self.popup = None; // Reset choice option to yes self.choice_opt = DialogYesNoOption::Yes; } @@ -446,7 +444,7 @@ impl AuthActivity { // Clear current input text self.input_txt.clear(); // Set mode back to form BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? - self.input_mode = InputMode::Form; + self.popup = None; // Call cb self.callback_save_bookmark(input_text); // Reset choice option to yes @@ -477,7 +475,7 @@ impl AuthActivity { match key.code { KeyCode::Enter => { // @! Set input mode to Form BEFORE CALLBACKS!!! Callback can then overwrite this, clever uh? - self.input_mode = InputMode::Form; + self.popup = None; // Check if user selected yes or not match self.choice_opt { DialogYesNoOption::No => no_cb(self), diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 8907945..52a45ed 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -25,8 +25,7 @@ // Locals use super::{ - AuthActivity, Context, DialogYesNoOption, FileTransferProtocol, InputField, InputForm, - InputMode, PopupType, + AuthActivity, Context, DialogYesNoOption, FileTransferProtocol, InputField, InputForm, Popup, }; use crate::utils::fmt::align_text_center; // Ext @@ -123,23 +122,23 @@ impl AuthActivity { f.render_stateful_widget(tab, bookmark_chunks[1], &mut recents_state); } // Draw popup - if let InputMode::Popup(popup) = &self.input_mode { + if let Some(popup) = &self.popup { // Calculate popup size let (width, height): (u16, u16) = match popup { - PopupType::Alert(_, _) => (50, 10), - PopupType::Help => (50, 70), - PopupType::SaveBookmark => (20, 20), - PopupType::YesNo(_, _, _) => (30, 10), + Popup::Alert(_, _) => (50, 10), + Popup::Help => (50, 70), + Popup::SaveBookmark => (20, 20), + Popup::YesNo(_, _, _) => (30, 10), }; let popup_area: Rect = self.draw_popup_area(f.size(), width, height); f.render_widget(Clear, popup_area); //this clears out the background match popup { - PopupType::Alert(color, txt) => f.render_widget( + Popup::Alert(color, txt) => f.render_widget( self.draw_popup_alert(*color, txt.clone(), popup_area.width), popup_area, ), - PopupType::Help => f.render_widget(self.draw_popup_help(), popup_area), - PopupType::SaveBookmark => { + Popup::Help => f.render_widget(self.draw_popup_help(), popup_area), + Popup::SaveBookmark => { let popup_chunks = Layout::default() .direction(Direction::Vertical) .constraints( @@ -160,7 +159,7 @@ impl AuthActivity { popup_chunks[0].y + 1, ) } - PopupType::YesNo(txt, _, _) => { + Popup::YesNo(txt, _, _) => { f.render_widget(self.draw_popup_yesno(txt.clone()), popup_area) } } diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index 376be4e..d4960a2 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -71,26 +71,17 @@ enum DialogYesNoOption { No, } -/// ### PopupType +/// ### Popup /// -/// PopupType describes the type of the popup displayed +/// Popup describes the type of the popup displayed #[derive(Clone)] -enum PopupType { +enum Popup { Alert(Color, String), // Show a message displaying text with the provided color Help, // Help page SaveBookmark, YesNo(String, DialogCallback, DialogCallback), // Yes, no callback } -/// ### InputMode -/// -/// InputMode describes the current input mode -/// Each input mode handle the input events in a different way -enum InputMode { - Form, - Popup(PopupType), -} - #[derive(std::cmp::PartialEq)] /// ### InputForm /// @@ -117,7 +108,7 @@ pub struct AuthActivity { bookmarks_client: Option, config_client: Option, selected_field: InputField, // Selected field in AuthCredentials Form - input_mode: InputMode, + popup: Option, input_form: InputForm, password_placeholder: String, redraw: bool, // Should ui actually be redrawned? @@ -151,7 +142,7 @@ impl AuthActivity { bookmarks_client: None, config_client: None, selected_field: InputField::Address, - input_mode: InputMode::Form, + popup: None, input_form: InputForm::AuthCredentials, password_placeholder: String::new(), redraw: true, // True at startup @@ -181,7 +172,7 @@ impl AuthActivity { self.config_client = Some(cli); } Err(err) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, format!("Could not initialize user configuration: {}", err), )) @@ -190,7 +181,7 @@ impl AuthActivity { } } Err(err) => { - self.input_mode = InputMode::Popup(PopupType::Alert( + self.popup = Some(Popup::Alert( Color::Red, format!("Could not initialize configuration directory: {}", err), )) @@ -212,7 +203,7 @@ impl Activity for AuthActivity { self.context.as_mut().unwrap().clear_screen(); // Put raw mode on enabled let _ = enable_raw_mode(); - self.input_mode = InputMode::Form; + self.popup = None; // Init bookmarks client if self.bookmarks_client.is_none() { self.init_bookmarks_client(); From e20a78acefcbd876305371f88b2b41490fb2b245 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 11:05:01 +0100 Subject: [PATCH 50/64] Don't collapse bookmarks tabs --- src/ui/activities/auth_activity/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 52a45ed..339da5e 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -397,7 +397,7 @@ impl AuthActivity { List::new(hosts) .block( Block::default() - .borders(Borders::TOP | Borders::BOTTOM | Borders::RIGHT) + .borders(Borders::ALL) .border_style(match self.input_form { InputForm::Recents => Style::default().fg(Color::LightBlue), _ => Style::default(), From 68cd77a9b3ae4ede06161e622d07cf26041a46af Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 12:01:20 +0100 Subject: [PATCH 51/64] Added `utils::parser::parse_datetime` --- src/utils/parser.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 72b447f..a502024 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -181,6 +181,21 @@ pub fn parse_lstime(tm: &str, fmt_year: &str, fmt_hours: &str) -> Result Result { + match NaiveDateTime::parse_from_str(tm, fmt) { + Ok(dt) => { + let sys_time: SystemTime = SystemTime::UNIX_EPOCH; + Ok(sys_time + .checked_add(Duration::from_secs(dt.timestamp() as u64)) + .unwrap_or(SystemTime::UNIX_EPOCH)) + } + Err(err) => Err(err), + } +} + #[cfg(test)] mod tests { @@ -319,4 +334,19 @@ mod tests { assert!(parse_lstime("Feb 31 2018", "%b %d %Y", "%b %d %H:%M").is_err()); assert!(parse_lstime("Feb 15 25:32", "%b %d %Y", "%b %d %H:%M").is_err()); } + + #[test] + fn test_utils_parse_datetime() { + assert_eq!( + parse_datetime("04-08-14 03:09PM", "%d-%m-%y %I:%M%p") + .ok() + .unwrap() + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + // Not enough argument for datetime + assert!(parse_datetime("04-08-14", "%d-%m-%y").is_err()); + } } From c141c6c44d666b9198fc29fa18285dfe55c28f20 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 15:08:42 +0100 Subject: [PATCH 52/64] Added `LIST` command parser for Windows server (DOS-like syntax) --- CHANGELOG.md | 5 + src/filetransfer/ftp_transfer.rs | 167 +++++++++++++++++++++++++------ 2 files changed, 143 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcf8e54..84b95f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ FIXME: Released on - Windows: `C:\Users\Alice\AppData\Roaming\termscp\.ssh\` - Enhancements: - Replaced `sha256` sum with last modification time check, to verify if a file has been changed in the text editor + - **FTP** + - Added `LIST` command parser for Windows server (DOS-like syntax) - Default protocol changed to default protocol in configuration when providing address as CLI argument - Explorers: - Hidden files are now not shown by default; use `A` to show hidden files. @@ -44,6 +46,9 @@ FIXME: Released on - `A`: Toggle hidden files - `B`: Sort files by (name, size, creation time, modify time) - `N`: New file +- Bugfix: + - SCP client didn't show file types for files + - FTP client didn't show file types for files - Dependencies: - added `bitflags 1.2.1` - removed `data-encoding` diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index d699a9a..5f36768 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -30,7 +30,7 @@ extern crate regex; use super::{FileTransfer, FileTransferError, FileTransferErrorType}; use crate::fs::{FsDirectory, FsEntry, FsFile}; -use crate::utils::parser::parse_lstime; +use crate::utils::parser::{parse_datetime, parse_lstime}; // Includes use ftp4::native_tls::TlsConnector; @@ -60,6 +60,25 @@ impl FtpFileTransfer { /// /// Parse a line of LIST command output and instantiates an FsEntry from it fn parse_list_line(&self, path: &Path, line: &str) -> Result { + // Try to parse using UNIX syntax + match self.parse_unix_list_line(path, line) { + Ok(entry) => Ok(entry), + Err(_) => match self.parse_dos_list_line(path, line) { + // If UNIX parsing fails, try DOS + Ok(entry) => Ok(entry), + Err(_) => Err(()), + }, + } + } + + /// ### parse_unix_list_line + /// + /// Try to parse a "LIST" output command line in UNIX format. + /// Returns error if syntax is not UNIX compliant. + /// UNIX syntax has the following syntax: + /// {FILE_TYPE}{UNIX_PEX} {HARD_LINKS} {USER} {GROUP} {SIZE} {DATE} {FILENAME} + /// -rw-r--r-- 1 cvisintin staff 4968 27 Dic 10:46 CHANGELOG.md + fn parse_unix_list_line(&self, path: &Path, line: &str) -> Result { // Prepare list regex // NOTE: about this damn regex lazy_static! { @@ -210,6 +229,96 @@ impl FtpFileTransfer { None => Err(()), } } + + /// ### parse_dos_list_line + /// + /// Try to parse a "LIST" output command line in DOS format. + /// Returns error if syntax is not DOS compliant. + /// DOS syntax has the following syntax: + /// {DATE} {TIME} { | SIZE} {FILENAME} + /// 10-19-20 03:19PM pub + /// 04-08-14 03:09PM 403 readme.txt + fn parse_dos_list_line(&self, path: &Path, line: &str) -> Result { + // Prepare list regex + // NOTE: you won't find this regex on the internet. It seems I'm the only person in the world who needs this + lazy_static! { + static ref DOS_RE: Regex = Regex::new( + r#"^(\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}\s*[AP]M)\s+()?([\d,]*)\s+(.+)$"# + ) + .unwrap(); + } + // Apply regex to result + match DOS_RE.captures(line) { + // String matches regex + Some(metadata) => { + // NOTE: metadata fmt: (regex, date_time, is_dir?, file_size?, file_name) + // Expected 4 + 1 (5) values: + 1 cause regex is repeated at 0 + if metadata.len() < 5 { + return Err(()); + } + // Parse date time + let time: SystemTime = + match parse_datetime(metadata.get(1).unwrap().as_str(), "%d-%m-%y %I:%M%p") { + Ok(t) => t, + Err(_) => SystemTime::UNIX_EPOCH, // Don't return error + }; + // Get if is a directory + let is_dir: bool = metadata.get(2).is_some(); + // Get file size + let file_size: usize = match is_dir { + true => 0, // If is directory, filesize is 0 + false => match metadata.get(3) { + // If is file, parse arg 3 + Some(val) => match val.as_str().parse::() { + Ok(sz) => sz, + Err(_) => 0, + }, + None => 0, // Should not happen + }, + }; + // Get file name + let file_name: String = String::from(metadata.get(4).unwrap().as_str()); + // Get absolute path + let mut abs_path: PathBuf = PathBuf::from(path); + abs_path.push(file_name.as_str()); + // Get extension + let extension: Option = match abs_path.as_path().extension() { + None => None, + Some(s) => Some(String::from(s.to_string_lossy())), + }; + // Return entry + Ok(match is_dir { + true => FsEntry::Directory(FsDirectory { + name: file_name, + abs_path, + last_change_time: time, + last_access_time: time, + creation_time: time, + readonly: false, + symlink: None, + user: None, + group: None, + unix_pex: None, + }), + false => FsEntry::File(FsFile { + name: file_name, + abs_path, + last_change_time: time, + last_access_time: time, + creation_time: time, + size: file_size, + ftype: extension, + readonly: false, + symlink: None, + user: None, + group: None, + unix_pex: None, + }), + }) + } + None => Err(()), // Invalid syntax + } + } } impl FileTransfer for FtpFileTransfer { @@ -835,9 +944,32 @@ mod tests { .is_err()); } - /* NOTE: they don't work #[test] - fn test_filetransfer_ftp_list_dir() { + fn test_filetransfer_ftp_list_dir_dos_syntax() { + let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); + // Connect + assert!(ftp + .connect( + String::from("test.rebex.net"), + 21, + Some(String::from("demo")), + Some(String::from("password")) + ) + .is_ok()); + // Pwd + assert_eq!(ftp.pwd().ok().unwrap(), PathBuf::from("/")); + // List dir + println!("{:?}", ftp.list_dir(PathBuf::from("/").as_path())); + let files: Vec = ftp.list_dir(PathBuf::from("/").as_path()).ok().unwrap(); + // There should be at least 1 file + assert!(files.len() > 0); + // Disconnect + assert!(ftp.disconnect().is_ok()); + } + + + #[test] + fn test_filetransfer_ftp_list_dir_unix_syntax() { let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); // Connect assert!(ftp.connect(String::from("speedtest.tele2.net"), 21, None, None).is_ok()); @@ -846,36 +978,13 @@ mod tests { // List dir println!("{:?}", ftp.list_dir(PathBuf::from("/").as_path())); let files: Vec = ftp.list_dir(PathBuf::from("/").as_path()).ok().unwrap(); - // There should be 19 files - assert_eq!(files.len(), 19); - // Verify first entry (1000GB.zip) - let first: &FsEntry = files.get(0).unwrap(); - if let FsEntry::File(f) = first { - assert_eq!(f.name, String::from("1000GB.zip")); - assert_eq!(f.abs_path, PathBuf::from("/1000GB.zip")); - assert_eq!(f.size, 1073741824000); - assert_eq!(*f.ftype.as_ref().unwrap(), String::from("zip")); - assert_eq!(f.unix_pex.unwrap(), (6, 4, 4)); - assert_eq!(f.creation_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(), Duration::from_secs(1455840000)); - assert_eq!(f.last_access_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(), Duration::from_secs(1455840000)); - assert_eq!(f.last_change_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(), Duration::from_secs(1455840000)); - } else { - panic!("First should be a file, but it a directory"); - } - // Verify last entry (directory upload) - let last: &FsEntry = files.get(18).unwrap(); - if let FsEntry::Directory(d) = last { - assert_eq!(d.name, String::from("upload")); - assert_eq!(d.abs_path, PathBuf::from("/upload")); - assert_eq!(d.readonly, false); - assert_eq!(d.unix_pex.unwrap(), (7, 5, 5)); - } else { - panic!("Last should be a directory, but is a file"); - } + // There should be at least 1 file + assert!(files.len() > 0); // Disconnect assert!(ftp.disconnect().is_ok()); } + /* NOTE: they don't work #[test] fn test_filetransfer_ftp_recv() { let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); From 6975beaf308b0d2f2995a2a94af36cb381aefd38 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 15:08:57 +0100 Subject: [PATCH 53/64] Fixed file extension not found in SCP/FTP --- src/filetransfer/ftp_transfer.rs | 3 ++- src/filetransfer/scp_transfer.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 5f36768..38327a3 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -190,11 +190,12 @@ impl FtpFileTransfer { return Err(()); } let mut abs_path: PathBuf = PathBuf::from(path); + abs_path.push(file_name.as_str()); + // get extension let extension: Option = match abs_path.as_path().extension() { None => None, Some(s) => Some(String::from(s.to_string_lossy())), }; - abs_path.push(file_name.as_str()); // Return // Push to entries Ok(match is_dir { diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index 3eae73e..b960f8a 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -189,11 +189,12 @@ impl ScpFileTransfer { return Err(()); } let mut abs_path: PathBuf = PathBuf::from(path); + abs_path.push(file_name.as_str()); + // Get extension let extension: Option = match abs_path.as_path().extension() { None => None, Some(s) => Some(String::from(s.to_string_lossy())), }; - abs_path.push(file_name.as_str()); // Return // Push to entries Ok(match is_dir { From 32ae5cc1824a3a8313b5404d8ee31972c123dd5e Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 19:28:41 +0100 Subject: [PATCH 54/64] Removed test for macos --- src/filetransfer/ftp_transfer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 38327a3..56b2a1a 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -970,6 +970,7 @@ mod tests { #[test] + #[cfg(not(target_os = "macos"))] fn test_filetransfer_ftp_list_dir_unix_syntax() { let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); // Connect From 06a23737760a1dd559d7a7f502aee19dad5ad28f Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Sun, 27 Dec 2020 20:42:52 +0100 Subject: [PATCH 55/64] parse dos line test --- src/filetransfer/ftp_transfer.rs | 96 +++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 56b2a1a..3fecf55 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -719,7 +719,7 @@ mod tests { } #[test] - fn test_filetransfer_ftp_parse_list_line() { + fn test_filetransfer_ftp_parse_list_line_unix() { let ftp: FtpFileTransfer = FtpFileTransfer::new(false); // Simple file let fs_entry: FsEntry = ftp @@ -850,6 +850,95 @@ mod tests { .is_err()); } + #[test] + fn test_filetransfer_ftp_parse_list_line_dos() { + let ftp: FtpFileTransfer = FtpFileTransfer::new(false); + // Simple file + let fs_entry: FsEntry = ftp + .parse_list_line( + PathBuf::from("/tmp").as_path(), + "04-08-14 03:09PM 8192 omar.txt", + ) + .ok() + .unwrap(); + if let FsEntry::File(file) = fs_entry { + assert_eq!(file.abs_path, PathBuf::from("/tmp/omar.txt")); + assert_eq!(file.name, String::from("omar.txt")); + assert_eq!(file.size, 8192); + assert!(file.symlink.is_none()); + assert_eq!(file.user, None); + assert_eq!(file.group, None); + assert_eq!(file.unix_pex, None); + assert_eq!( + file.last_access_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + assert_eq!( + file.last_change_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + assert_eq!( + file.creation_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + } else { + panic!("Expected file, got directory"); + } + // Directory + let fs_entry: FsEntry = ftp + .parse_list_line( + PathBuf::from("/tmp").as_path(), + "04-08-14 03:09PM docs", + ) + .ok() + .unwrap(); + if let FsEntry::Directory(dir) = fs_entry { + assert_eq!(dir.abs_path, PathBuf::from("/tmp/docs")); + assert_eq!(dir.name, String::from("docs")); + assert!(dir.symlink.is_none()); + assert_eq!(dir.user, None); + assert_eq!(dir.group, None); + assert_eq!(dir.unix_pex, None); + assert_eq!( + dir.last_access_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + assert_eq!( + dir.last_change_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + assert_eq!( + dir.creation_time + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + .unwrap(), + Duration::from_secs(1407164940) + ); + assert_eq!(dir.readonly, false); + } else { + panic!("Expected directory, got directory"); + } + // Error + assert!(ftp + .parse_list_line(PathBuf::from("/").as_path(), "04-08-14 omar.txt") + .is_err()); + } + #[test] fn test_filetransfer_ftp_connect_unsecure_anonymous() { let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); @@ -968,13 +1057,14 @@ mod tests { assert!(ftp.disconnect().is_ok()); } - #[test] #[cfg(not(target_os = "macos"))] fn test_filetransfer_ftp_list_dir_unix_syntax() { let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false); // Connect - assert!(ftp.connect(String::from("speedtest.tele2.net"), 21, None, None).is_ok()); + assert!(ftp + .connect(String::from("speedtest.tele2.net"), 21, None, None) + .is_ok()); // Pwd assert_eq!(ftp.pwd().ok().unwrap(), PathBuf::from("/")); // List dir From 120dc8ecb4fbba303874e9ff4674522578753d77 Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Mon, 28 Dec 2020 22:45:28 +0100 Subject: [PATCH 56/64] Fixed buffer sizes for transfers --- src/filetransfer/scp_transfer.rs | 4 ++-- src/filetransfer/sftp_transfer.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index b960f8a..755dc42 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -772,7 +772,7 @@ impl FileTransfer for ScpFileTransfer { (mtime, atime) }; match session.scp_send(file_name, mode, local.size as u64, Some(times)) { - Ok(channel) => Ok(Box::new(BufWriter::with_capacity(8192, channel))), + Ok(channel) => Ok(Box::new(BufWriter::with_capacity(65536, channel))), Err(err) => Err(FileTransferError::new_ex( FileTransferErrorType::ProtocolError, format!("{}", err), @@ -795,7 +795,7 @@ impl FileTransfer for ScpFileTransfer { // Set blocking to true session.set_blocking(true); match session.scp_recv(file.abs_path.as_path()) { - Ok(reader) => Ok(Box::new(BufReader::with_capacity(8192, reader.0))), + Ok(reader) => Ok(Box::new(BufReader::with_capacity(65536, reader.0))), Err(err) => Err(FileTransferError::new_ex( FileTransferErrorType::ProtocolError, format!("{}", err), diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index f17f75f..3208a82 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -578,7 +578,7 @@ impl FileTransfer for SftpFileTransfer { }; // Open remote file match sftp.open(remote_path.as_path()) { - Ok(file) => Ok(Box::new(BufReader::with_capacity(8192, file))), + Ok(file) => Ok(Box::new(BufReader::with_capacity(65536, file))), Err(err) => Err(FileTransferError::new_ex( FileTransferErrorType::NoSuchFileOrDirectory, format!("{}", err), From daa3b3e549faadd3577ba0ddfa32fa1bba59b83d Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Mon, 28 Dec 2020 22:54:28 +0100 Subject: [PATCH 57/64] Fixed `0 B/S` transfer rate displayed after completing download in less than 1 second --- CHANGELOG.md | 1 + src/ui/activities/filetransfer_activity/mod.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b95f5..e1fb776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ FIXME: Released on - Bugfix: - SCP client didn't show file types for files - FTP client didn't show file types for files + - Fixed `0 B/S` transfer rate displayed after completing download in less than 1 second - Dependencies: - added `bitflags 1.2.1` - removed `data-encoding` diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index 646d0d6..00e6d0e 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -203,7 +203,11 @@ impl TransferStates { // bytes_written : elapsed_secs = x : 1 let elapsed_secs: u64 = self.started.elapsed().as_secs(); match elapsed_secs { - 0 => 0, // NOTE: would divide by 0 :D + 0 => match self.bytes_written == self.bytes_total { + // NOTE: would divide by 0 :D + true => self.bytes_total as u64, // Download completed in less than 1 second + false => 0, // 0 B/S + }, _ => self.bytes_written as u64 / elapsed_secs, } } From 49790b4704d89c5a3c274766720e3cb6fc3a2f05 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 2 Jan 2021 13:04:49 +0100 Subject: [PATCH 58/64] Updated references to veeso --- CONTRIBUTING.md | 2 +- Cargo.toml | 4 ++-- README.md | 16 ++++++++-------- dist/build/x86_64/Dockerfile | 2 +- dist/build/x86_64_archlinux/Dockerfile | 2 +- dist/pkgs/arch/.SRCINFO | 4 ++-- dist/pkgs/arch/PKGBUILD | 4 ++-- src/main.rs | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afb35d2..003289b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in At the moment, these kind of contributions are more appreciated and should be preferred: -- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/ChristianVisintin/termscp/issues) +- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/veeso/termscp/issues) - New file transfers: for further details see [Implementing File Transfer](#implementing-file-transfers) - Code optimizations: any optimization to the code is welcome diff --git a/Cargo.toml b/Cargo.toml index b0d41c4..31a3e75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ license = "GPL-3.0" keywords = ["scp-client", "sftp-client", "ftp-client", "winscp", "command-line-utility"] categories = ["command-line-utilities"] description = "TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal." -homepage = "https://github.com/ChristianVisintin/termscp" -repository = "https://github.com/ChristianVisintin/termscp" +homepage = "https://github.com/veeso/termscp" +repository = "https://github.com/veeso/termscp" documentation = "https://docs.rs/termscp" readme = "README.md" diff --git a/README.md b/README.md index 64eb8d9..2b74714 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # TermSCP -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/ChristianVisintin/termscp.svg)](https://github.com/ChristianVisintin/termscp) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/veeso/termscp.svg)](https://github.com/veeso/termscp) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) -[![Build](https://github.com/ChristianVisintin/termscp/workflows/Linux/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/MacOS/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![Build](https://github.com/ChristianVisintin/termscp/workflows/Windows/badge.svg)](https://github.com/ChristianVisintin/termscp/actions) [![codecov](https://codecov.io/gh/ChristianVisintin/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/ChristianVisintin/termscp) +[![Build](https://github.com/veeso/termscp/workflows/Linux/badge.svg)](https://github.com/veeso/termscp/actions) [![Build](https://github.com/veeso/termscp/workflows/MacOS/badge.svg)](https://github.com/veeso/termscp/actions) [![Build](https://github.com/veeso/termscp/workflows/Windows/badge.svg)](https://github.com/veeso/termscp/actions) [![codecov](https://codecov.io/gh/veeso/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/veeso/termscp) ~ Basically, WinSCP on a terminal ~ Developed by Christian Visintin @@ -85,8 +85,8 @@ cargo install termscp ### Deb package ๐Ÿ“ฆ -Get `deb` package from [HERE](https://github.com/ChristianVisintin/termscp/releases/latest/download/termscp_0.2.0_amd64.deb) -or run `wget https://github.com/ChristianVisintin/termscp/releases/latest/download/termscp_0.2.0_amd64.deb` +Get `deb` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp_0.2.0_amd64.deb) +or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp_0.2.0_amd64.deb` then install through dpkg: @@ -98,8 +98,8 @@ gdebi termscp_*.deb ### RPM package ๐Ÿ“ฆ -Get `rpm` package from [HERE](https://github.com/ChristianVisintin/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm) -or run `wget https://github.com/ChristianVisintin/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm` +Get `rpm` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm) +or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm` then install through rpm: @@ -125,7 +125,7 @@ Start PowerShell as administrator and run choco install termscp ``` -Alternatively you can download the ZIP file from [HERE](https://github.com/ChristianVisintin/termscp/releases/latest/download/termscp.0.2.0.nupkg) +Alternatively you can download the ZIP file from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp.0.2.0.nupkg) and then with PowerShell started with administrator previleges, run: @@ -140,7 +140,7 @@ You can install TermSCP on MacOS using [brew](https://brew.sh/) From your terminal run ```sh -brew tap ChristianVisintin/termscp +brew tap veeso/termscp brew install termscp ``` diff --git a/dist/build/x86_64/Dockerfile b/dist/build/x86_64/Dockerfile index 1341258..d365023 100644 --- a/dist/build/x86_64/Dockerfile +++ b/dist/build/x86_64/Dockerfile @@ -6,7 +6,7 @@ RUN rustup target add x86_64-unknown-linux-gnu # Install dependencies RUN apt update && apt install -y rpm # Clone repository -RUN git clone https://github.com/ChristianVisintin/termscp.git +RUN git clone https://github.com/veeso/termscp.git # Set workdir to termscp WORKDIR /usr/src/termscp/ # Install cargo RPM/Deb diff --git a/dist/build/x86_64_archlinux/Dockerfile b/dist/build/x86_64_archlinux/Dockerfile index 9fb4d60..5ad39c3 100644 --- a/dist/build/x86_64_archlinux/Dockerfile +++ b/dist/build/x86_64_archlinux/Dockerfile @@ -18,7 +18,7 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && chmod +x /tmp/rust.sh && \ /tmp/rust.sh -y # Clone repository -RUN git clone https://github.com/ChristianVisintin/termscp.git +RUN git clone https://github.com/veeso/termscp.git # Set workdir to termscp WORKDIR /usr/src/termscp/ # Install cargo arxch diff --git a/dist/pkgs/arch/.SRCINFO b/dist/pkgs/arch/.SRCINFO index 04d1627..b5426e0 100644 --- a/dist/pkgs/arch/.SRCINFO +++ b/dist/pkgs/arch/.SRCINFO @@ -2,12 +2,12 @@ pkgbase = termscp-bin pkgdesc = TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal. pkgver = 0.2.0 pkgrel = 1 - url = https://github.com/ChristianVisintin/termscp + url = https://github.com/veeso/termscp arch = x86_64 license = GPL-3.0 provides = termscp options = strip - source = https://github.com/ChristianVisintin/termscp/releases/download/v0.2.0/termscp-0.2.0-x86_64.tar.gz + source = https://github.com/veeso/termscp/releases/download/v0.2.0/termscp-0.2.0-x86_64.tar.gz sha256sums = b40f5223e74514c4a9855831da7b5c4a79d415822ec2840ccae98278a2176d01 pkgname = termscp-bin diff --git a/dist/pkgs/arch/PKGBUILD b/dist/pkgs/arch/PKGBUILD index 599a03b..e99b323 100644 --- a/dist/pkgs/arch/PKGBUILD +++ b/dist/pkgs/arch/PKGBUILD @@ -3,12 +3,12 @@ pkgname=termscp pkgver=0.2.0 pkgrel=1 pkgdesc="TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal." -url="https://github.com/ChristianVisintin/termscp" +url="https://github.com/veeso/termscp" license=("GPL-3.0") arch=("x86_64") provides=("termscp") options=("strip") -source=("https://github.com/ChristianVisintin/termscp/releases/download/v$pkgver/termscp-$pkgver-x86_64.tar.gz") +source=("https://github.com/veeso/termscp/releases/download/v$pkgver/termscp-$pkgver-x86_64.tar.gz") sha256sums=("b40f5223e74514c4a9855831da7b5c4a79d415822ec2840ccae98278a2176d01") package() { diff --git a/src/main.rs b/src/main.rs index 048c233..0b94184 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,7 @@ use filetransfer::FileTransferProtocol; fn print_usage(opts: Options) { let brief = String::from("Usage: termscp [options]... [protocol://user@address:port]"); print!("{}", opts.usage(&brief)); - println!("\nPlease, report issues to "); + println!("\nPlease, report issues to "); } fn main() { From fa5468be4abe791787bf5330cb8098d28db14df5 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 9 Jan 2021 14:29:30 +0100 Subject: [PATCH 59/64] Fixed time check tests --- src/filetransfer/ftp_transfer.rs | 22 +++++++--------------- src/utils/parser.rs | 31 +++++++++++++++++-------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 3fecf55..5c94875 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -705,6 +705,7 @@ impl FileTransfer for FtpFileTransfer { mod tests { use super::*; + use crate::utils::fmt::fmt_time; use std::time::Duration; #[test] @@ -778,25 +779,16 @@ mod tests { assert_eq!(file.group, Some(9)); assert_eq!(file.unix_pex.unwrap(), (7, 5, 5)); assert_eq!( - file.last_access_time - .duration_since(SystemTime::UNIX_EPOCH) - .ok() - .unwrap(), - Duration::from_secs(1604593920) + fmt_time(file.last_access_time, "%m %d %M").as_str(), + "11 05 32" ); assert_eq!( - file.last_change_time - .duration_since(SystemTime::UNIX_EPOCH) - .ok() - .unwrap(), - Duration::from_secs(1604593920) + fmt_time(file.last_change_time, "%m %d %M").as_str(), + "11 05 32" ); assert_eq!( - file.creation_time - .duration_since(SystemTime::UNIX_EPOCH) - .ok() - .unwrap(), - Duration::from_secs(1604593920) + fmt_time(file.creation_time, "%m %d %M").as_str(), + "11 05 32" ); } else { panic!("Expected file, got directory"); diff --git a/src/utils/parser.rs b/src/utils/parser.rs index a502024..5f7f776 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -200,6 +200,7 @@ pub fn parse_datetime(tm: &str, fmt: &str) -> Result { mod tests { use super::*; + use crate::utils::fmt::fmt_time; #[test] fn test_utils_parse_remote_opt() { @@ -294,22 +295,24 @@ mod tests { fn test_utils_parse_lstime() { // Good cases assert_eq!( - parse_lstime("Nov 5 16:32", "%b %d %Y", "%b %d %H:%M") - .ok() - .unwrap() - .duration_since(SystemTime::UNIX_EPOCH) - .ok() - .unwrap(), - Duration::from_secs(1604593920) + fmt_time( + parse_lstime("Nov 5 16:32", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap(), + "%m %d %M" + ) + .as_str(), + "11 05 32" ); assert_eq!( - parse_lstime("Dec 2 21:32", "%b %d %Y", "%b %d %H:%M") - .ok() - .unwrap() - .duration_since(SystemTime::UNIX_EPOCH) - .ok() - .unwrap(), - Duration::from_secs(1606944720) + fmt_time( + parse_lstime("Dec 2 21:32", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap(), + "%m %d %M" + ) + .as_str(), + "12 02 32" ); assert_eq!( parse_lstime("Nov 5 2018", "%b %d %Y", "%b %d %H:%M") From f981602221c68b0e086113ac6e82ec445a77e9a8 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 9 Jan 2021 15:05:49 +0100 Subject: [PATCH 60/64] Definetely fixed FTP issues --- CHANGELOG.md | 2 + Cargo.lock | 123 +++++++++++++++++++++++++-------------------------- Cargo.toml | 2 +- README.md | 2 +- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fb776..66eba20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,10 +49,12 @@ FIXME: Released on - Bugfix: - SCP client didn't show file types for files - FTP client didn't show file types for files + - FTP file transfer not working properly with `STOR` and `RETR`. - Fixed `0 B/S` transfer rate displayed after completing download in less than 1 second - Dependencies: - added `bitflags 1.2.1` - removed `data-encoding` + - updated `ftp` to `4.0.2` - updated `rand` to `0.8.0` - removed `ring` - updated `textwrap` to `0.13.1` diff --git a/Cargo.lock b/Cargo.lock index 05aeb57..3e30123 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "bytesize" @@ -354,9 +354,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "ftp4" -version = "4.0.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6318bd155755b6e07ccb7bf8e5b1b7cb221c74fff7c6440692ef38eb2ec1d42c" +checksum = "7e03634a7a0e74618f9adf1e088495caa54ea07e72d449813e6439ce8ac9906f" dependencies = [ "chrono", "lazy_static", @@ -403,24 +403,24 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -460,9 +460,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libssh2-sys" @@ -560,9 +560,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "mio" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33bc887064ef1fd66020c9adfc45bb9f33d75a42096c81e7c56c65b75dd1a8b" +checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" dependencies = [ "libc", "log", @@ -583,9 +583,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcc7939b5edc4e4f86b1b4a04bb1498afaaf871b1a6691838ed06fcb48d3a3f" +checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" dependencies = [ "lazy_static", "libc", @@ -635,12 +635,12 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.30" +version = "0.10.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" +checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" dependencies = [ "bitflags", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "foreign-types", "lazy_static", "libc", @@ -655,9 +655,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.58" +version = "0.9.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" dependencies = [ "autocfg", "cc", @@ -684,7 +684,7 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api 0.4.2", - "parking_lot_core 0.8.1", + "parking_lot_core 0.8.2", ] [[package]] @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c6d9b8427445284a09c55be860a15855ab580a417ccad9da88f5a06787ced0" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ "cfg-if 1.0.0", "instant", @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -751,7 +751,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -760,13 +760,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +checksum = "c24fcd450d3fa2b592732565aa4f17a27a61c65ece4726353e000939b0edee34" dependencies = [ "libc", "rand_chacha 0.3.0", - "rand_core 0.6.0", + "rand_core 0.6.1", "rand_hc 0.3.0", ] @@ -787,7 +787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.0", + "rand_core 0.6.1", ] [[package]] @@ -796,16 +796,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", ] [[package]] name = "rand_core" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ - "getrandom 0.2.0", + "getrandom 0.2.1", ] [[package]] @@ -823,7 +823,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.0", + "rand_core 0.6.1", ] [[package]] @@ -838,16 +838,16 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "redox_syscall", "rust-argon2", ] [[package]] name = "regex" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ "aho-corasick", "memchr", @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "remove_dir_all" @@ -966,9 +966,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" dependencies = [ "libc", "mio", @@ -977,18 +977,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "smawk" @@ -998,13 +998,12 @@ checksum = "e1bc737c97d093feb72e67f4926d9b22d717ce8580cd25f0ce86d74e859c466d" [[package]] name = "socket2" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", "winapi", ] @@ -1022,9 +1021,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.53" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ "proc-macro2", "quote", @@ -1061,7 +1060,7 @@ dependencies = [ "hostname", "lazy_static", "magic-crypt", - "rand 0.8.0", + "rand 0.8.1", "regex", "rpassword", "serde", @@ -1077,9 +1076,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aca9e798437265144ddacce09343df0b3413a0aef54b1e212e640e472118b80" +checksum = "3cdcf6b66102d38821c33eea2bf1e8b7bd738072171cbf8a0683fbb46fcb8b0b" dependencies = [ "smawk", "unicode-width", @@ -1087,9 +1086,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" dependencies = [ "lazy_static", ] @@ -1174,9 +1173,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "version_check" @@ -1271,9 +1270,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35495e7faf4c657051a8e9725d9c37ac57879e915be3ed55bb401af84382035" +checksum = "d595b2e146f36183d6a590b8d41568e2bc84c922267f43baf61c956330eeb436" dependencies = [ "wasm-bindgen", "web-sys", diff --git a/Cargo.toml b/Cargo.toml index 31a3e75..2a2fd9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ content_inspector = "0.2.4" crossterm = "0.18.2" dirs = "3.0.1" edit = "0.1.2" -ftp4 = { version = "^4.0.1", features = ["secure"] } +ftp4 = { version = "^4.0.2", features = ["secure"] } getopts = "0.2.21" hostname = "0.3.1" lazy_static = "1.4.0" diff --git a/README.md b/README.md index 2b74714..226d544 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ The developer documentation can be found on Rust Docs at Date: Sat, 9 Jan 2021 15:28:20 +0100 Subject: [PATCH 61/64] config gif --- README.md | 4 ++++ assets/images/config.gif | Bin 0 -> 705780 bytes 2 files changed, 4 insertions(+) create mode 100644 assets/images/config.gif diff --git a/README.md b/README.md index 226d544..5f946d6 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,10 @@ TermSCP is powered by these aweseome projects: ![Bookmarks](assets/images/bookmarks.gif) +> Setup + +![Setup](assets/images/config.gif) + > Text editor ![TextEditor](assets/images/text-editor.gif) diff --git a/assets/images/config.gif b/assets/images/config.gif new file mode 100644 index 0000000000000000000000000000000000000000..c2b9b34b377d3e232e73ac28bd252789e65dc28f GIT binary patch literal 705780 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

6z-rMFPj~zWD}e49hznn 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

Wa;p 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 z

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�(?_DJ!fh-c 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 Ar~m)} literal 0 HcmV?d00001 From c54a9ef5c939b54b167e8fa55ec6b831f9b625d2 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 9 Jan 2021 20:35:55 +0100 Subject: [PATCH 62/64] termscp 0.3.0 ready --- CHANGELOG.md | 2 +- README.md | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66eba20..2e53daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ ## 0.3.0 -FIXME: Released on + Released on 10/01/2021 > The SSH Key Storage Update diff --git a/README.md b/README.md index 5f946d6..6c83ac3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # TermSCP -[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/veeso/termscp.svg)](https://github.com/veeso/termscp) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.2.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Stars](https://img.shields.io/github/stars/veeso/termscp.svg)](https://github.com/veeso/termscp) [![Downloads](https://img.shields.io/crates/d/termscp.svg)](https://crates.io/crates/termscp) [![Crates.io](https://img.shields.io/badge/crates.io-v0.3.0-orange.svg)](https://crates.io/crates/termscp) [![Docs](https://docs.rs/termscp/badge.svg)](https://docs.rs/termscp) [![Build](https://github.com/veeso/termscp/workflows/Linux/badge.svg)](https://github.com/veeso/termscp/actions) [![Build](https://github.com/veeso/termscp/workflows/MacOS/badge.svg)](https://github.com/veeso/termscp/actions) [![Build](https://github.com/veeso/termscp/workflows/Windows/badge.svg)](https://github.com/veeso/termscp/actions) [![codecov](https://codecov.io/gh/veeso/termscp/branch/main/graph/badge.svg?token=au67l7nQah)](https://codecov.io/gh/veeso/termscp) ~ Basically, WinSCP on a terminal ~ Developed by Christian Visintin -Current version: 0.2.0 (21/12/2020) +Current version: 0.3.0 (10/01/2021) --- @@ -85,8 +85,8 @@ cargo install termscp ### Deb package ๐Ÿ“ฆ -Get `deb` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp_0.2.0_amd64.deb) -or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp_0.2.0_amd64.deb` +Get `deb` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp_0.3.0_amd64.deb) +or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp_0.3.0_amd64.deb` then install through dpkg: @@ -98,8 +98,8 @@ gdebi termscp_*.deb ### RPM package ๐Ÿ“ฆ -Get `rpm` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm) -or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp-0.2.0-1.x86_64.rpm` +Get `rpm` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp-0.3.0-1.x86_64.rpm) +or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp-0.3.0-1.x86_64.rpm` then install through rpm: @@ -125,7 +125,7 @@ Start PowerShell as administrator and run choco install termscp ``` -Alternatively you can download the ZIP file from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp.0.2.0.nupkg) +Alternatively you can download the ZIP file from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp.0.3.0.nupkg) and then with PowerShell started with administrator previleges, run: @@ -319,15 +319,13 @@ The developer documentation can be found on Rust Docs at Date: Sat, 9 Jan 2021 20:45:06 +0100 Subject: [PATCH 63/64] Updated copyright --- LICENSE | 4 ++-- src/activity_manager.rs | 2 +- src/bookmarks/mod.rs | 2 +- src/bookmarks/serializer.rs | 2 +- src/config/mod.rs | 2 +- src/config/serializer.rs | 2 +- src/filetransfer/ftp_transfer.rs | 2 +- src/filetransfer/mod.rs | 2 +- src/filetransfer/scp_transfer.rs | 2 +- src/filetransfer/sftp_transfer.rs | 2 +- src/fs/explorer/builder.rs | 2 +- src/fs/explorer/mod.rs | 2 +- src/fs/mod.rs | 2 +- src/host/mod.rs | 2 +- src/lib.rs | 2 +- src/main.rs | 2 +- src/system/bookmarks_client.rs | 2 +- src/system/config_client.rs | 2 +- src/system/environment.rs | 2 +- src/system/mod.rs | 2 +- src/system/sshkey_storage.rs | 2 +- src/ui/activities/auth_activity/bookmarks.rs | 2 +- src/ui/activities/auth_activity/callbacks.rs | 2 +- src/ui/activities/auth_activity/input.rs | 2 +- src/ui/activities/auth_activity/layout.rs | 2 +- src/ui/activities/auth_activity/mod.rs | 2 +- src/ui/activities/filetransfer_activity/callbacks.rs | 2 +- src/ui/activities/filetransfer_activity/input.rs | 2 +- src/ui/activities/filetransfer_activity/layout.rs | 2 +- src/ui/activities/filetransfer_activity/misc.rs | 2 +- src/ui/activities/filetransfer_activity/mod.rs | 2 +- src/ui/activities/filetransfer_activity/session.rs | 2 +- src/ui/activities/mod.rs | 2 +- src/ui/activities/setup_activity/callbacks.rs | 2 +- src/ui/activities/setup_activity/config.rs | 2 +- src/ui/activities/setup_activity/input.rs | 2 +- src/ui/activities/setup_activity/layout.rs | 2 +- src/ui/activities/setup_activity/misc.rs | 2 +- src/ui/activities/setup_activity/mod.rs | 2 +- src/ui/context.rs | 2 +- src/ui/input.rs | 2 +- src/ui/mod.rs | 2 +- src/utils/crypto.rs | 2 +- src/utils/fmt.rs | 2 +- src/utils/mod.rs | 2 +- src/utils/parser.rs | 2 +- src/utils/random.rs | 2 +- 47 files changed, 48 insertions(+), 48 deletions(-) diff --git a/LICENSE b/LICENSE index e075f67..c3dd646 100644 --- a/LICENSE +++ b/LICENSE @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. TermSCP - Copyright (C) 2020 Christian Visintin + Copyright (C) 2020-2021 Christian Visintin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - TermSCP Copyright (C) 2020 Christian Visintin + TermSCP Copyright (C) 2020-2021 Christian Visintin This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/src/activity_manager.rs b/src/activity_manager.rs index f8c49d7..d36b4c9 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/bookmarks/mod.rs b/src/bookmarks/mod.rs index 7015322..331d412 100644 --- a/src/bookmarks/mod.rs +++ b/src/bookmarks/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/bookmarks/serializer.rs b/src/bookmarks/serializer.rs index ded9561..4835f26 100644 --- a/src/bookmarks/serializer.rs +++ b/src/bookmarks/serializer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/config/mod.rs b/src/config/mod.rs index 7e41f34..6178a51 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/config/serializer.rs b/src/config/serializer.rs index e4c7fc0..e2d62a3 100644 --- a/src/config/serializer.rs +++ b/src/config/serializer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/ftp_transfer.rs b/src/filetransfer/ftp_transfer.rs index 5c94875..7fa03b5 100644 --- a/src/filetransfer/ftp_transfer.rs +++ b/src/filetransfer/ftp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/mod.rs b/src/filetransfer/mod.rs index 0c04f7d..92d5af5 100644 --- a/src/filetransfer/mod.rs +++ b/src/filetransfer/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/scp_transfer.rs b/src/filetransfer/scp_transfer.rs index 755dc42..5cd2351 100644 --- a/src/filetransfer/scp_transfer.rs +++ b/src/filetransfer/scp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/filetransfer/sftp_transfer.rs b/src/filetransfer/sftp_transfer.rs index 3208a82..9e2622b 100644 --- a/src/filetransfer/sftp_transfer.rs +++ b/src/filetransfer/sftp_transfer.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/explorer/builder.rs b/src/fs/explorer/builder.rs index 4c2d1c9..2e16dcc 100644 --- a/src/fs/explorer/builder.rs +++ b/src/fs/explorer/builder.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/explorer/mod.rs b/src/fs/explorer/mod.rs index 3d4e735..2d1a3e0 100644 --- a/src/fs/explorer/mod.rs +++ b/src/fs/explorer/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 04468ce..ea718a9 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/host/mod.rs b/src/host/mod.rs index 59e45c5..2411991 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/lib.rs b/src/lib.rs index a779075..d65280e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/main.rs b/src/main.rs index 0b94184..f7f8a9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/bookmarks_client.rs b/src/system/bookmarks_client.rs index 95c9829..7d98028 100644 --- a/src/system/bookmarks_client.rs +++ b/src/system/bookmarks_client.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/config_client.rs b/src/system/config_client.rs index 0a1eb19..9463269 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/environment.rs b/src/system/environment.rs index 8a5ef34..29798b3 100644 --- a/src/system/environment.rs +++ b/src/system/environment.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/mod.rs b/src/system/mod.rs index 089987a..b31a84c 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index 016e688..20eb8b2 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/bookmarks.rs b/src/ui/activities/auth_activity/bookmarks.rs index e0fa090..f035b9d 100644 --- a/src/ui/activities/auth_activity/bookmarks.rs +++ b/src/ui/activities/auth_activity/bookmarks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/callbacks.rs b/src/ui/activities/auth_activity/callbacks.rs index 5fe802d..645f6ca 100644 --- a/src/ui/activities/auth_activity/callbacks.rs +++ b/src/ui/activities/auth_activity/callbacks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/input.rs b/src/ui/activities/auth_activity/input.rs index 7c93abe..6f9fb33 100644 --- a/src/ui/activities/auth_activity/input.rs +++ b/src/ui/activities/auth_activity/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/layout.rs b/src/ui/activities/auth_activity/layout.rs index 339da5e..7368bc3 100644 --- a/src/ui/activities/auth_activity/layout.rs +++ b/src/ui/activities/auth_activity/layout.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/auth_activity/mod.rs b/src/ui/activities/auth_activity/mod.rs index d4960a2..f1fa96c 100644 --- a/src/ui/activities/auth_activity/mod.rs +++ b/src/ui/activities/auth_activity/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index 4d6e525..702082c 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 9df1256..23ecc83 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index 49a7c19..4cf3600 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/misc.rs b/src/ui/activities/filetransfer_activity/misc.rs index 642083c..3c0c286 100644 --- a/src/ui/activities/filetransfer_activity/misc.rs +++ b/src/ui/activities/filetransfer_activity/misc.rs @@ -1,6 +1,6 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index 00e6d0e..e6b9aeb 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index 633a07f..c3e19f2 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/mod.rs b/src/ui/activities/mod.rs index dbc95bb..dc188ab 100644 --- a/src/ui/activities/mod.rs +++ b/src/ui/activities/mod.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/callbacks.rs b/src/ui/activities/setup_activity/callbacks.rs index 85410fd..98205ce 100644 --- a/src/ui/activities/setup_activity/callbacks.rs +++ b/src/ui/activities/setup_activity/callbacks.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/config.rs b/src/ui/activities/setup_activity/config.rs index 7a8f63c..7867c79 100644 --- a/src/ui/activities/setup_activity/config.rs +++ b/src/ui/activities/setup_activity/config.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/input.rs b/src/ui/activities/setup_activity/input.rs index 5819710..38ab98d 100644 --- a/src/ui/activities/setup_activity/input.rs +++ b/src/ui/activities/setup_activity/input.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/layout.rs b/src/ui/activities/setup_activity/layout.rs index cee5655..45ef475 100644 --- a/src/ui/activities/setup_activity/layout.rs +++ b/src/ui/activities/setup_activity/layout.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/misc.rs b/src/ui/activities/setup_activity/misc.rs index 4903c60..695c015 100644 --- a/src/ui/activities/setup_activity/misc.rs +++ b/src/ui/activities/setup_activity/misc.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/activities/setup_activity/mod.rs b/src/ui/activities/setup_activity/mod.rs index b7f783c..724d06c 100644 --- a/src/ui/activities/setup_activity/mod.rs +++ b/src/ui/activities/setup_activity/mod.rs @@ -5,7 +5,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/context.rs b/src/ui/context.rs index f92e6a0..df382f5 100644 --- a/src/ui/context.rs +++ b/src/ui/context.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/input.rs b/src/ui/input.rs index 1aed160..bb7931b 100644 --- a/src/ui/input.rs +++ b/src/ui/input.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/ui/mod.rs b/src/ui/mod.rs index e4e4bd4..31da84e 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/crypto.rs b/src/utils/crypto.rs index cf5ace9..68faa45 100644 --- a/src/utils/crypto.rs +++ b/src/utils/crypto.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/fmt.rs b/src/utils/fmt.rs index 7af3f49..939ee02 100644 --- a/src/utils/fmt.rs +++ b/src/utils/fmt.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5d20a9a..cb298e1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 5f7f776..271f4aa 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * diff --git a/src/utils/random.rs b/src/utils/random.rs index 0c17c11..335f0ae 100644 --- a/src/utils/random.rs +++ b/src/utils/random.rs @@ -4,7 +4,7 @@ /* * -* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com +* Copyright (C) 2020-2021Christian Visintin - christian.visintin1997@gmail.com * * This file is part of "TermSCP" * From 2b543263344eb4596a7e058ffc271d47cc942ccb Mon Sep 17 00:00:00 2001 From: veeso Date: Sun, 10 Jan 2021 17:30:20 +0100 Subject: [PATCH 64/64] 0.3.0 ready --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6c83ac3..be09693 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ It happens quite often to me, when using SCP at work to forget the path of a fil - Compatible with Windows, Linux, BSD and MacOS - Written in Rust - Easy to extend with new file transfers protocols +- Developed keeping an eye on performance ---