diff --git a/src/activity_manager.rs b/src/activity_manager.rs index cb04f2a..fae07fd 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -4,7 +4,7 @@ // Deps // Namespaces -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::Duration; use remotefs_ssh::SshKeyStorage as SshKeyStorageTrait; @@ -34,12 +34,11 @@ pub enum NextActivity { pub struct ActivityManager { context: Option, ticks: Duration, - local_dir: PathBuf, } impl ActivityManager { /// Initializes a new Activity Manager - pub fn new(local_dir: &Path, ticks: Duration) -> Result { + pub fn new(ticks: Duration) -> Result { // Prepare Context // Initialize configuration client let (config_client, error_config): (ConfigClient, Option) = @@ -59,7 +58,6 @@ impl ActivityManager { let ctx: Context = Context::new(bookmarks_client, config_client, theme_provider, error); Ok(ActivityManager { context: Some(ctx), - local_dir: local_dir.to_path_buf(), ticks, }) } @@ -243,8 +241,19 @@ impl ActivityManager { return None; } }; + + // get local path: + // - if set in file transfer params, get it from there + // - otherwise is env current dir + // - otherwise is / + let local_wrkdir = ft_params + .local_path + .clone() + .or(std::env::current_dir().ok()) + .unwrap_or(PathBuf::from("/")); + // Prepare activity - let host: Localhost = match Localhost::new(self.local_dir.clone()) { + let host: Localhost = match Localhost::new(local_wrkdir) { Ok(host) => host, Err(err) => { // Set error in context diff --git a/src/config/bookmarks.rs b/src/config/bookmarks.rs index 711598d..117c152 100644 --- a/src/config/bookmarks.rs +++ b/src/config/bookmarks.rs @@ -38,8 +38,11 @@ pub struct Bookmark { pub username: Option, /// Password is optional; base64, aes-128 encrypted password pub password: Option, - /// Remote folder to connect to - pub directory: Option, + /// Remote folder to connect to (serde rename for legacy reasons) + #[serde(rename = "directory")] + pub remote_path: Option, + /// local folder to open at startup + pub local_path: Option, /// S3 params; optional. When used other fields are empty for sure pub s3: Option, /// SMB params; optional. Extra params required for SMB protocol @@ -71,7 +74,8 @@ pub struct SmbParams { impl From for Bookmark { fn from(params: FileTransferParams) -> Self { let protocol = params.protocol; - let directory = params.entry_directory; + let remote_path = params.remote_path; + let local_path = params.local_path; // Create generic or others match params.params { ProtocolParams::Generic(params) => Self { @@ -80,7 +84,8 @@ impl From for Bookmark { port: Some(params.port), username: params.username, password: params.password, - directory, + remote_path, + local_path, s3: None, smb: None, }, @@ -90,7 +95,8 @@ impl From for Bookmark { port: None, username: None, password: None, - directory, + remote_path, + local_path, s3: Some(S3Params::from(params)), smb: None, }, @@ -104,7 +110,8 @@ impl From for Bookmark { port: None, username: params.username, password: params.password, - directory, + remote_path, + local_path, s3: None, }, } @@ -155,7 +162,8 @@ impl From for FileTransferParams { Self::new(bookmark.protocol, ProtocolParams::Smb(params)) } } - .entry_directory(bookmark.directory) // Set entry directory + .remote_path(bookmark.remote_path) // Set entry remote_path + .local_path(bookmark.local_path) // Set entry local path } } @@ -246,7 +254,8 @@ mod tests { protocol: FileTransferProtocol::Sftp, username: Some(String::from("root")), password: Some(String::from("password")), - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: None, }; @@ -256,7 +265,8 @@ mod tests { protocol: FileTransferProtocol::Scp, username: Some(String::from("admin")), password: Some(String::from("password")), - directory: Some(PathBuf::from("/home")), + remote_path: Some(PathBuf::from("/home")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: None, }; @@ -273,9 +283,13 @@ mod tests { assert_eq!(bookmark.username.as_deref().unwrap(), "root"); assert_eq!(bookmark.password.as_deref().unwrap(), "password"); assert_eq!( - bookmark.directory.as_deref().unwrap(), + bookmark.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); + assert_eq!( + bookmark.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); let bookmark: &Bookmark = hosts .recents .get(&String::from("ISO20201218T181432")) @@ -286,9 +300,13 @@ mod tests { assert_eq!(bookmark.username.as_deref().unwrap(), "admin"); assert_eq!(bookmark.password.as_deref().unwrap(), "password"); assert_eq!( - bookmark.directory.as_deref().unwrap(), + bookmark.remote_path.as_deref().unwrap(), std::path::Path::new("/home") ); + assert_eq!( + bookmark.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); } #[test] @@ -300,7 +318,8 @@ mod tests { password: Some(String::from("omar")), }); let params: FileTransferParams = FileTransferParams::new(FileTransferProtocol::Scp, params) - .entry_directory(Some(PathBuf::from("/home"))); + .remote_path(Some(PathBuf::from("/home"))) + .local_path(Some(PathBuf::from("/tmp"))); let bookmark = Bookmark::from(params); assert_eq!(bookmark.protocol, FileTransferProtocol::Scp); assert_eq!(bookmark.address.as_deref().unwrap(), "127.0.0.1"); @@ -308,9 +327,13 @@ mod tests { assert_eq!(bookmark.username.as_deref().unwrap(), "root"); assert_eq!(bookmark.password.as_deref().unwrap(), "omar"); assert_eq!( - bookmark.directory.as_deref().unwrap(), + bookmark.remote_path.as_deref().unwrap(), std::path::Path::new("/home") ); + assert_eq!( + bookmark.local_path.as_deref().unwrap(), + std::path::Path::new("/tmp") + ); assert!(bookmark.s3.is_none()); } @@ -345,16 +368,21 @@ mod tests { protocol: FileTransferProtocol::Sftp, username: Some(String::from("root")), password: Some(String::from("password")), - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: None, }; let params = FileTransferParams::from(bookmark); assert_eq!(params.protocol, FileTransferProtocol::Sftp); assert_eq!( - params.entry_directory.as_deref().unwrap(), + params.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); + assert_eq!( + params.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); let gparams = params.params.generic_params().unwrap(); assert_eq!(gparams.address.as_str(), "192.168.1.1"); assert_eq!(gparams.port, 22); @@ -370,7 +398,8 @@ mod tests { port: None, username: None, password: None, - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: Some(S3Params { bucket: String::from("veeso"), region: Some(String::from("eu-west-1")), @@ -385,9 +414,13 @@ mod tests { let params = FileTransferParams::from(bookmark); assert_eq!(params.protocol, FileTransferProtocol::AwsS3); assert_eq!( - params.entry_directory.as_deref().unwrap(), + params.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); + assert_eq!( + params.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); let gparams = params.params.s3_params().unwrap(); assert_eq!(gparams.bucket_name.as_str(), "veeso"); assert_eq!(gparams.region.as_deref().unwrap(), "eu-west-1"); @@ -407,7 +440,8 @@ mod tests { port: Some(445), username: Some("foo".to_string()), password: Some("bar".to_string()), - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: Some(SmbParams { share: "test".to_string(), @@ -418,9 +452,13 @@ mod tests { let params = FileTransferParams::from(bookmark); assert_eq!(params.protocol, FileTransferProtocol::Smb); assert_eq!( - params.entry_directory.as_deref().unwrap(), + params.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); + assert_eq!( + params.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); let smb_params = params.params.smb_params().unwrap(); assert_eq!(smb_params.address.as_str(), "localhost"); assert_eq!(smb_params.port, 445); @@ -439,7 +477,8 @@ mod tests { port: Some(445), username: None, password: None, - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: Some(SmbParams { share: "test".to_string(), @@ -450,9 +489,13 @@ mod tests { let params = FileTransferParams::from(bookmark); assert_eq!(params.protocol, FileTransferProtocol::Smb); assert_eq!( - params.entry_directory.as_deref().unwrap(), + params.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); + assert_eq!( + params.local_path.as_deref().unwrap(), + std::path::Path::new("/usr") + ); let smb_params = params.params.smb_params().unwrap(); assert_eq!(smb_params.address.as_str(), "localhost"); assert_eq!(smb_params.share.as_str(), "test"); diff --git a/src/config/serialization.rs b/src/config/serialization.rs index 20a648b..fe6ff01 100644 --- a/src/config/serialization.rs +++ b/src/config/serialization.rs @@ -380,7 +380,7 @@ mod tests { assert_eq!(host.username.as_deref().unwrap(), "cvisintin"); assert_eq!(host.password.as_deref().unwrap(), "mysecret"); assert_eq!( - host.directory.as_deref().unwrap(), + host.remote_path.as_deref().unwrap(), std::path::Path::new("/tmp") ); let host: &Bookmark = hosts.bookmarks.get("aws-server-prod1").unwrap(); @@ -441,7 +441,8 @@ mod tests { protocol: FileTransferProtocol::Sftp, username: Some(String::from("root")), password: None, - directory: None, + remote_path: None, + local_path: None, s3: None, smb: None, }, @@ -454,7 +455,8 @@ mod tests { protocol: FileTransferProtocol::Sftp, username: Some(String::from("cvisintin")), password: Some(String::from("password")), - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: None, }, @@ -467,7 +469,8 @@ mod tests { protocol: FileTransferProtocol::AwsS3, username: None, password: None, - directory: None, + remote_path: None, + local_path: None, s3: Some(S3Params { bucket: "veeso".to_string(), region: Some("eu-west-1".to_string()), @@ -492,7 +495,8 @@ mod tests { protocol: FileTransferProtocol::Smb, username: None, password: None, - directory: None, + remote_path: None, + local_path: None, s3: None, smb: smb_params, }, @@ -506,7 +510,8 @@ mod tests { protocol: FileTransferProtocol::Scp, username: Some(String::from("omar")), password: Some(String::from("aaa")), - directory: Some(PathBuf::from("/tmp")), + remote_path: Some(PathBuf::from("/tmp")), + local_path: Some(PathBuf::from("/usr")), s3: None, smb: None, }, @@ -547,7 +552,7 @@ mod tests { let file_content: &str = r#" [bookmarks] raspberrypi2 = { address = "192.168.1.31", port = 22, protocol = "SFTP", username = "root", password = "mypassword" } - msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP", username = "cvisintin", password = "mysecret", directory = "/tmp" } + msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP", username = "cvisintin", password = "mysecret", directory = "/tmp", local_path = "/usr" } aws-server-prod1 = { address = "51.23.67.12", port = 21, protocol = "FTPS", username = "aws001" } [bookmarks.my-bucket] diff --git a/src/filetransfer/params.rs b/src/filetransfer/params.rs index 76234c6..7471ef2 100644 --- a/src/filetransfer/params.rs +++ b/src/filetransfer/params.rs @@ -11,7 +11,8 @@ use super::FileTransferProtocol; pub struct FileTransferParams { pub protocol: FileTransferProtocol, pub params: ProtocolParams, - pub entry_directory: Option, + pub remote_path: Option, + pub local_path: Option, } /// Container for protocol params @@ -64,13 +65,20 @@ impl FileTransferParams { Self { protocol, params, - entry_directory: None, + remote_path: None, + local_path: None, } } - /// Set entry directory - pub fn entry_directory>(mut self, dir: Option

) -> Self { - self.entry_directory = dir.map(|x| x.as_ref().to_path_buf()); + /// Set remote directory + pub fn remote_path>(mut self, dir: Option

) -> Self { + self.remote_path = dir.map(|x| x.as_ref().to_path_buf()); + self + } + + /// Set local directory + pub fn local_path>(mut self, dir: Option

) -> Self { + self.local_path = dir.map(|x| x.as_ref().to_path_buf()); self } @@ -325,16 +333,15 @@ mod test { fn test_filetransfer_params() { let params: FileTransferParams = FileTransferParams::new(FileTransferProtocol::Scp, ProtocolParams::default()) - .entry_directory(Some(&Path::new("/tmp"))); + .remote_path(Some(&Path::new("/tmp"))) + .local_path(Some(&Path::new("/usr"))); assert_eq!( params.params.generic_params().unwrap().address.as_str(), "localhost" ); assert_eq!(params.protocol, FileTransferProtocol::Scp); - assert_eq!( - params.entry_directory.as_deref().unwrap(), - Path::new("/tmp") - ); + assert_eq!(params.remote_path.as_deref().unwrap(), Path::new("/tmp")); + assert_eq!(params.local_path.as_deref().unwrap(), Path::new("/usr")); } #[test] diff --git a/src/main.rs b/src/main.rs index 435dffc..9b39251 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,9 +14,9 @@ extern crate log; extern crate magic_crypt; // External libs -use std::path::PathBuf; +use std::env; +use std::path::{Path, PathBuf}; use std::time::Duration; -use std::{env, path::Path}; // Include mod activity_manager; @@ -172,13 +172,8 @@ fn run_install_update() -> i32 { } fn run_activity(activity: NextActivity, ticks: Duration, remote: Remote) -> i32 { - // Get working directory - let wrkdir: PathBuf = match env::current_dir() { - Ok(dir) => dir, - Err(_) => PathBuf::from("/"), - }; // Create activity manager (and context too) - let mut manager: ActivityManager = match ActivityManager::new(wrkdir.as_path(), ticks) { + let mut manager: ActivityManager = match ActivityManager::new(ticks) { Ok(m) => m, Err(err) => { eprintln!("Could not start activity manager: {err}"); diff --git a/src/ui/activities/auth/bookmarks.rs b/src/ui/activities/auth/bookmarks.rs index 60520e4..7cb7e19 100644 --- a/src/ui/activities/auth/bookmarks.rs +++ b/src/ui/activities/auth/bookmarks.rs @@ -150,7 +150,13 @@ impl AuthActivity { self.mount_protocol(bookmark.protocol); self.mount_remote_directory( bookmark - .entry_directory + .remote_path + .map(|x| x.to_string_lossy().to_string()) + .unwrap_or_default(), + ); + self.mount_local_directory( + bookmark + .local_path .map(|x| x.to_string_lossy().to_string()) .unwrap_or_default(), ); diff --git a/src/ui/activities/auth/components/form.rs b/src/ui/activities/auth/components/form.rs index 6013230..d5590d5 100644 --- a/src/ui/activities/auth/components/form.rs +++ b/src/ui/activities/auth/components/form.rs @@ -8,13 +8,12 @@ use tuirealm::event::{Key, KeyEvent, KeyModifiers}; use tuirealm::props::{Alignment, BorderType, Borders, Color, InputType, Style}; use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue}; +use super::{FileTransferProtocol, FormMsg, Msg, UiMsg}; use crate::ui::activities::auth::{ RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP, RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB, }; -use super::{FileTransferProtocol, FormMsg, Msg, UiMsg}; - // -- protocol #[derive(MockComponent)] @@ -118,7 +117,7 @@ impl InputRemoteDirectory { ) .foreground(color) .placeholder("/home/foo", Style::default().fg(Color::Rgb(128, 128, 128))) - .title("Default remote directory", Alignment::Left) + .title("Default remote working directory", Alignment::Left) .input_type(InputType::Text) .value(remote_dir), } @@ -136,6 +135,42 @@ impl Component for InputRemoteDirectory { } } +// -- remote directory + +#[derive(MockComponent)] +pub struct InputLocalDirectory { + component: Input, +} + +impl InputLocalDirectory { + pub fn new(local_dir: &str, color: Color) -> Self { + Self { + component: Input::default() + .borders( + Borders::default() + .color(color) + .modifiers(BorderType::Rounded), + ) + .foreground(color) + .placeholder("/home/foo", Style::default().fg(Color::Rgb(128, 128, 128))) + .title("Default local working directory", Alignment::Left) + .input_type(InputType::Text) + .value(local_dir), + } + } +} + +impl Component for InputLocalDirectory { + fn on(&mut self, ev: Event) -> Option { + handle_input_ev( + self, + ev, + Msg::Ui(UiMsg::LocalDirectoryBlurDown), + Msg::Ui(UiMsg::LocalDirectoryBlurUp), + ) + } +} + // -- address #[derive(MockComponent)] diff --git a/src/ui/activities/auth/components/mod.rs b/src/ui/activities/auth/components/mod.rs index ec227db..313ae64 100644 --- a/src/ui/activities/auth/components/mod.rs +++ b/src/ui/activities/auth/components/mod.rs @@ -16,9 +16,10 @@ pub use bookmarks::{ #[cfg(unix)] pub use form::InputSmbWorkgroup; pub use form::{ - InputAddress, InputPassword, InputPort, InputRemoteDirectory, InputS3AccessKey, InputS3Bucket, - InputS3Endpoint, InputS3Profile, InputS3Region, InputS3SecretAccessKey, InputS3SecurityToken, - InputS3SessionToken, InputSmbShare, InputUsername, ProtocolRadio, RadioS3NewPathStyle, + InputAddress, InputLocalDirectory, InputPassword, InputPort, InputRemoteDirectory, + InputS3AccessKey, InputS3Bucket, InputS3Endpoint, InputS3Profile, InputS3Region, + InputS3SecretAccessKey, InputS3SecurityToken, InputS3SessionToken, InputSmbShare, + InputUsername, ProtocolRadio, RadioS3NewPathStyle, }; pub use popup::{ ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup, diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index ff40ae8..e54d706 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -59,7 +59,8 @@ impl AuthActivity { Ok(FileTransferParams { protocol, params: ProtocolParams::Generic(params), - entry_directory: self.get_input_remote_directory(), + local_path: self.get_input_local_directory(), + remote_path: self.get_input_remote_directory(), }) } @@ -72,7 +73,8 @@ impl AuthActivity { Ok(FileTransferParams { protocol: FileTransferProtocol::AwsS3, params: ProtocolParams::AwsS3(params), - entry_directory: self.get_input_remote_directory(), + local_path: self.get_input_local_directory(), + remote_path: self.get_input_remote_directory(), }) } @@ -91,7 +93,8 @@ impl AuthActivity { Ok(FileTransferParams { protocol: FileTransferProtocol::Smb, params: ProtocolParams::Smb(params), - entry_directory: self.get_input_remote_directory(), + local_path: self.get_input_local_directory(), + remote_path: self.get_input_remote_directory(), }) } diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index 600ef47..82227a6 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -46,6 +46,7 @@ pub enum Id { InfoPopup, InstallUpdatePopup, Keybindings, + LocalDirectory, NewVersionChangelog, NewVersionDisclaimer, Password, @@ -108,6 +109,8 @@ pub enum UiMsg { CloseKeybindingsPopup, CloseQuitPopup, CloseSaveBookmark, + LocalDirectoryBlurDown, + LocalDirectoryBlurUp, ParamsFormBlur, PasswordBlurDown, PasswordBlurUp, diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index c680695..10dfda3 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -158,6 +158,12 @@ impl AuthActivity { assert!(self.app.umount(&Id::BookmarkName).is_ok()); assert!(self.app.umount(&Id::BookmarkSavePassword).is_ok()); } + UiMsg::LocalDirectoryBlurDown => { + assert!(self.app.active(&Id::Protocol).is_ok()); + } + UiMsg::LocalDirectoryBlurUp => { + assert!(self.app.active(&Id::RemoteDirectory).is_ok()); + } UiMsg::ParamsFormBlur => { assert!(self.app.active(&Id::BookmarksList).is_ok()); } @@ -201,13 +207,13 @@ impl AuthActivity { .is_ok()); } UiMsg::ProtocolBlurUp => { - assert!(self.app.active(&Id::RemoteDirectory).is_ok()); + assert!(self.app.active(&Id::LocalDirectory).is_ok()); } UiMsg::RececentsListBlur => { assert!(self.app.active(&Id::BookmarksList).is_ok()); } UiMsg::RemoteDirectoryBlurDown => { - assert!(self.app.active(&Id::Protocol).is_ok()); + assert!(self.app.active(&Id::LocalDirectory).is_ok()); } UiMsg::RemoteDirectoryBlurUp => { assert!(self diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index b185755..a9c8dc6 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -43,6 +43,7 @@ impl AuthActivity { // Auth form self.mount_protocol(default_protocol); self.mount_remote_directory(""); + self.mount_local_directory(""); self.mount_address(""); self.mount_port(Self::get_default_port_for_protocol(default_protocol)); self.mount_username(""); @@ -582,14 +583,14 @@ impl AuthActivity { .is_ok()); } - pub(super) fn mount_remote_directory>(&mut self, entry_directory: S) { + pub(super) fn mount_remote_directory>(&mut self, remote_path: S) { let protocol_color = self.theme().auth_protocol; assert!(self .app .remount( Id::RemoteDirectory, Box::new(components::InputRemoteDirectory::new( - entry_directory.as_ref(), + remote_path.as_ref(), protocol_color )), vec![] @@ -597,6 +598,21 @@ impl AuthActivity { .is_ok()); } + pub(super) fn mount_local_directory>(&mut self, local_path: S) { + let color = self.theme().auth_username; + assert!(self + .app + .remount( + Id::LocalDirectory, + Box::new(components::InputLocalDirectory::new( + local_path.as_ref(), + color + )), + vec![] + ) + .is_ok()); + } + pub(super) fn mount_address(&mut self, address: &str) { let addr_color = self.theme().auth_address; assert!(self @@ -853,6 +869,15 @@ impl AuthActivity { } } + pub(super) fn get_input_local_directory(&self) -> Option { + match self.app.state(&Id::LocalDirectory) { + Ok(State::One(StateValue::String(x))) if !x.is_empty() => { + Some(PathBuf::from(x.as_str())) + } + _ => None, + } + } + pub(super) fn get_input_addr(&self) -> String { match self.app.state(&Id::Address) { Ok(State::One(StateValue::String(x))) => x, @@ -1053,6 +1078,12 @@ impl AuthActivity { Some(&Id::RemoteDirectory) => { [Id::Port, Id::Username, Id::Password, Id::RemoteDirectory] } + Some(&Id::LocalDirectory) => [ + Id::Username, + Id::Password, + Id::RemoteDirectory, + Id::LocalDirectory, + ], _ => [Id::Address, Id::Port, Id::Username, Id::Password], } } @@ -1093,6 +1124,12 @@ impl AuthActivity { Id::S3NewPathStyle, Id::RemoteDirectory, ], + Some(&Id::LocalDirectory) => [ + Id::S3SessionToken, + Id::S3NewPathStyle, + Id::RemoteDirectory, + Id::LocalDirectory, + ], _ => [Id::S3Bucket, Id::S3Region, Id::S3Endpoint, Id::S3Profile], } } @@ -1111,6 +1148,12 @@ impl AuthActivity { Id::SmbWorkgroup, Id::RemoteDirectory, ], + Some(&Id::LocalDirectory) => [ + Id::Password, + Id::SmbWorkgroup, + Id::RemoteDirectory, + Id::LocalDirectory, + ], _ => [Id::Address, Id::Port, Id::SmbShare, Id::Username], } } @@ -1127,6 +1170,12 @@ impl AuthActivity { Id::Password, Id::RemoteDirectory, ], + Some(&Id::LocalDirectory) => [ + Id::Username, + Id::Password, + Id::RemoteDirectory, + Id::LocalDirectory, + ], _ => [Id::Address, Id::SmbShare, Id::Username, Id::Password], } } diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index 6b4c07a..29800c2 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -220,7 +220,7 @@ pub struct FileTransferActivity { cache: Option, /// Fs watcher fswatcher: Option, - /// conncted once + /// connected once connected: bool, } diff --git a/src/ui/activities/filetransfer/session.rs b/src/ui/activities/filetransfer/session.rs index 853a555..5ffc13a 100644 --- a/src/ui/activities/filetransfer/session.rs +++ b/src/ui/activities/filetransfer/session.rs @@ -53,7 +53,7 @@ impl FileTransferActivity { /// Connect to remote pub(super) fn connect(&mut self) { let ft_params = self.context().ft_params().unwrap().clone(); - let entry_dir: Option = ft_params.entry_directory; + let entry_dir: Option = ft_params.remote_path; // Connect to remote match self.client.connect() { Ok(Welcome { banner, .. }) => { @@ -71,11 +71,11 @@ impl FileTransferActivity { } // Try to change directory to entry directory let mut remote_chdir: Option = None; - if let Some(entry_directory) = &entry_dir { - remote_chdir = Some(entry_directory.clone()); + if let Some(remote_path) = &entry_dir { + remote_chdir = Some(remote_path.clone()); } - if let Some(entry_directory) = remote_chdir { - self.remote_changedir(entry_directory.as_path(), false); + if let Some(remote_path) = remote_chdir { + self.remote_changedir(remote_path.as_path(), false); } // Set state to explorer self.umount_wait(); diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 410f8ed..079e6e3 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -218,7 +218,7 @@ fn parse_generic_remote_opt( }, }; // Get workdir - let entry_directory: Option = + let remote_path: Option = groups.get(4).map(|group| PathBuf::from(group.as_str())); let params: ProtocolParams = ProtocolParams::Generic( GenericProtocolParams::default() @@ -226,7 +226,7 @@ fn parse_generic_remote_opt( .port(port) .username(username), ); - Ok(FileTransferParams::new(protocol, params).entry_directory(entry_directory)) + Ok(FileTransferParams::new(protocol, params).remote_path(remote_path)) } None => Err(String::from("Bad remote host syntax!")), } @@ -245,13 +245,13 @@ fn parse_s3_remote_opt(s: &str) -> Result { .map(|x| x.as_str().to_string()) .unwrap_or_default(); let profile: Option = groups.get(3).map(|x| x.as_str().to_string()); - let entry_directory: Option = + let remote_path: Option = groups.get(4).map(|group| PathBuf::from(group.as_str())); Ok(FileTransferParams::new( FileTransferProtocol::AwsS3, ProtocolParams::AwsS3(AwsS3Params::new(bucket, Some(region), profile)), ) - .entry_directory(entry_directory)) + .remote_path(remote_path)) } None => Err(String::from("Bad remote host syntax!")), } @@ -282,14 +282,14 @@ fn parse_smb_remote_opts(s: &str) -> Result { Some(group) => group.as_str().to_string(), None => return Err(String::from("Missing address")), }; - let entry_directory: Option = + let remote_path: Option = groups.get(5).map(|group| PathBuf::from(group.as_str())); Ok(FileTransferParams::new( FileTransferProtocol::Smb, ProtocolParams::Smb(SmbParams::new(address, share).port(port).username(username)), ) - .entry_directory(entry_directory)) + .remote_path(remote_path)) } None => Err(String::from("Bad remote host syntax!")), } @@ -308,14 +308,14 @@ fn parse_smb_remote_opts(s: &str) -> Result { Some(group) => group.as_str().to_string(), None => return Err(String::from("Missing address")), }; - let entry_directory: Option = + let remote_path: Option = groups.get(4).map(|group| PathBuf::from(group.as_str())); Ok(FileTransferParams::new( FileTransferProtocol::Smb, ProtocolParams::Smb(SmbParams::new(address, share).username(username)), ) - .entry_directory(entry_directory)) + .remote_path(remote_path)) } None => Err(String::from("Bad remote host syntax!")), } @@ -441,7 +441,7 @@ mod tests { params.username.as_deref().unwrap().to_string(), String::from("root") ); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // User + port let result: FileTransferParams = parse_remote_opt(&String::from("root@172.26.104.1:8022")) .ok() @@ -454,7 +454,7 @@ mod tests { String::from("root") ); assert_eq!(result.protocol, FileTransferProtocol::Sftp); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // Port only let result: FileTransferParams = parse_remote_opt(&String::from("172.26.104.1:4022")) .ok() @@ -464,7 +464,7 @@ mod tests { assert_eq!(params.address, String::from("172.26.104.1")); assert_eq!(params.port, 4022); assert!(params.username.is_none()); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // Protocol let result: FileTransferParams = parse_remote_opt(&String::from("ftp://172.26.104.1")) .ok() @@ -474,7 +474,7 @@ mod tests { assert_eq!(params.address, String::from("172.26.104.1")); assert_eq!(params.port, 21); // Fallback to ftp default assert!(params.username.is_none()); // Doesn't fall back - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // Protocol let result: FileTransferParams = parse_remote_opt(&String::from("sftp://172.26.104.1")) .ok() @@ -484,7 +484,7 @@ mod tests { assert_eq!(params.address, String::from("172.26.104.1")); assert_eq!(params.port, 22); // Fallback to sftp default assert!(params.username.is_none()); // Doesn't fall back - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); let result: FileTransferParams = parse_remote_opt(&String::from("scp://172.26.104.1")) .ok() .unwrap(); @@ -493,7 +493,7 @@ mod tests { assert_eq!(params.address, String::from("172.26.104.1")); assert_eq!(params.port, 22); // Fallback to scp default assert!(params.username.is_none()); // Doesn't fall back - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // Protocol + user let result: FileTransferParams = parse_remote_opt(&String::from("ftps://anon@172.26.104.1")) @@ -507,7 +507,7 @@ mod tests { params.username.as_deref().unwrap().to_string(), String::from("anon") ); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); // Path let result: FileTransferParams = parse_remote_opt(&String::from("root@172.26.104.1:8022:/var")) @@ -521,7 +521,7 @@ mod tests { params.username.as_deref().unwrap().to_string(), String::from("root") ); - assert_eq!(result.entry_directory.unwrap(), PathBuf::from("/var")); + assert_eq!(result.remote_path.unwrap(), PathBuf::from("/var")); // Port only let result: FileTransferParams = parse_remote_opt(&String::from("172.26.104.1:home")) .ok() @@ -531,7 +531,7 @@ mod tests { assert_eq!(params.address, String::from("172.26.104.1")); assert_eq!(params.port, 22); assert!(params.username.is_none()); - assert_eq!(result.entry_directory.unwrap(), PathBuf::from("home")); + assert_eq!(result.remote_path.unwrap(), PathBuf::from("home")); // All together now let result: FileTransferParams = parse_remote_opt(&String::from("ftp://anon@172.26.104.1:8021:/tmp")) @@ -545,7 +545,7 @@ mod tests { params.username.as_deref().unwrap().to_string(), String::from("anon") ); - assert_eq!(result.entry_directory.unwrap(), PathBuf::from("/tmp")); + assert_eq!(result.remote_path.unwrap(), PathBuf::from("/tmp")); // bad syntax // Bad protocol assert!(parse_remote_opt(&String::from("omar://172.26.104.1")).is_err()); @@ -562,7 +562,7 @@ mod tests { .unwrap(); let params = result.params.s3_params().unwrap(); assert_eq!(result.protocol, FileTransferProtocol::AwsS3); - assert_eq!(result.entry_directory, None); + assert_eq!(result.remote_path, None); assert_eq!(params.bucket_name.as_str(), "mybucket"); assert_eq!(params.region.as_deref().unwrap(), "eu-central-1"); assert_eq!(params.profile, None); @@ -573,7 +573,7 @@ mod tests { .unwrap(); let params = result.params.s3_params().unwrap(); assert_eq!(result.protocol, FileTransferProtocol::AwsS3); - assert_eq!(result.entry_directory, None); + assert_eq!(result.remote_path, None); assert_eq!(params.bucket_name.as_str(), "mybucket"); assert_eq!(params.region.as_deref().unwrap(), "eu-central-1"); assert_eq!(params.profile.as_deref(), Some("default")); @@ -584,7 +584,7 @@ mod tests { .unwrap(); let params = result.params.s3_params().unwrap(); assert_eq!(result.protocol, FileTransferProtocol::AwsS3); - assert_eq!(result.entry_directory, Some(PathBuf::from("/foobar"))); + assert_eq!(result.remote_path, Some(PathBuf::from("/foobar"))); assert_eq!(params.bucket_name.as_str(), "mybucket"); assert_eq!(params.region.as_deref().unwrap(), "eu-central-1"); assert_eq!(params.profile, None); @@ -595,7 +595,7 @@ mod tests { .unwrap(); let params = result.params.s3_params().unwrap(); assert_eq!(result.protocol, FileTransferProtocol::AwsS3); - assert_eq!(result.entry_directory, Some(PathBuf::from("/foobar"))); + assert_eq!(result.remote_path, Some(PathBuf::from("/foobar"))); assert_eq!(params.bucket_name.as_str(), "mybucket"); assert_eq!(params.region.as_deref().unwrap(), "eu-central-1"); assert_eq!(params.profile.as_deref(), Some("default")); @@ -615,7 +615,7 @@ mod tests { assert!(params.username.is_some()); assert!(params.password.is_none()); assert!(params.workgroup.is_none()); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); } #[test] @@ -633,7 +633,7 @@ mod tests { assert!(params.workgroup.is_none()); assert_eq!(params.share.as_str(), "myshare"); assert_eq!( - result.entry_directory.as_deref().unwrap(), + result.remote_path.as_deref().unwrap(), std::path::Path::new("/dir/subdir") ); } @@ -648,7 +648,7 @@ mod tests { assert_eq!(params.address.as_str(), "myserver"); assert_eq!(params.share.as_str(), "myshare"); - assert!(result.entry_directory.is_none()); + assert!(result.remote_path.is_none()); } #[test] @@ -663,7 +663,7 @@ mod tests { assert_eq!(params.share.as_str(), "myshare"); assert_eq!(params.username.as_deref().unwrap(), "omar"); assert_eq!( - result.entry_directory.as_deref().unwrap(), + result.remote_path.as_deref().unwrap(), std::path::Path::new("\\path") ); } diff --git a/src/utils/ssh.rs b/src/utils/ssh.rs index 7da56c7..b8b4775 100644 --- a/src/utils/ssh.rs +++ b/src/utils/ssh.rs @@ -15,7 +15,8 @@ pub fn parse_ssh2_config(path: &str) -> Result { #[cfg(test)] mod test { - use crate::utils::{ssh::parse_ssh2_config, test_helpers}; + use crate::utils::ssh::parse_ssh2_config; + use crate::utils::test_helpers; #[test] fn should_parse_ssh2_config() {