diff --git a/Cargo.lock b/Cargo.lock index ab28626..4f89671 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3145,6 +3145,7 @@ dependencies = [ "tracing-error", "tracing-subscriber", "vergen-gix", + "windows-sys 0.61.2", "xml", ] @@ -3198,6 +3199,12 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.52.0" @@ -3216,6 +3223,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/config/config.json5 b/config/config.json5 index 2eecb94..11e6d5b 100644 --- a/config/config.json5 +++ b/config/config.json5 @@ -213,4 +213,8 @@ "": "Suspend" }, }, + "network_server": "SERVER", + "network_share": "SHARE", + "network_user": "USER", + "network_pass": "PASS" } diff --git a/core/src/config.rs b/core/src/config.rs index 0cb107b..002c7ec 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -54,6 +54,14 @@ pub struct Config { pub keybindings: KeyBindings, #[serde(default)] pub styles: Styles, + #[serde(default)] + pub network_server: String, + #[serde(default)] + pub network_share: String, + #[serde(default)] + pub network_user: String, + #[serde(default)] + pub network_pass: String, } pub static PROJECT_NAME: &str = "DEJA-VU"; @@ -76,16 +84,14 @@ impl Config { let config_dir = get_config_dir(); let mut builder = config::Config::builder() .set_default("app_title", default_config.app_title.as_str())? - .set_default( - "clone_app_path", - String::from("C:\\Program Files\\Some Clone Tool\\app.exe"), - )? - .set_default( - "conemu_path", - String::from("C:\\Program Files\\ConEmu\\ConEmu64.exe"), - )? + .set_default("clone_app_path", default_config.app_title.as_str())? + .set_default("conemu_path", default_config.app_title.as_str())? .set_default("config_dir", config_dir.to_str().unwrap())? - .set_default("data_dir", data_dir.to_str().unwrap())?; + .set_default("data_dir", data_dir.to_str().unwrap())? + .set_default("network_server", default_config.app_title.as_str())? + .set_default("network_share", default_config.app_title.as_str())? + .set_default("network_user", default_config.app_title.as_str())? + .set_default("network_pass", default_config.app_title.as_str())?; let config_files = [ ("config.json5", config::FileFormat::Json5), diff --git a/win_installer/Cargo.toml b/win_installer/Cargo.toml index d7bcc76..e801d4d 100644 --- a/win_installer/Cargo.toml +++ b/win_installer/Cargo.toml @@ -41,6 +41,7 @@ tracing = "0.1.41" tracing-error = "0.2.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] } tempfile = "3.23.0" +windows-sys = { version = "0.61.1", features = ["Win32_NetworkManagement_WNet"] } xml = "1.1.0" [build-dependencies] diff --git a/win_installer/src/app.rs b/win_installer/src/app.rs index 71c249d..ad3f845 100644 --- a/win_installer/src/app.rs +++ b/win_installer/src/app.rs @@ -67,9 +67,10 @@ pub struct App { impl App { pub fn new(tick_rate: f64, frame_rate: f64) -> Result { let (action_tx, action_rx) = mpsc::unbounded_channel(); + let config = Config::new()?; let disk_list_arc = Arc::new(Mutex::new(Vec::new())); let tasks = Tasks::new(action_tx.clone(), disk_list_arc.clone()); - let state = State::new(disk_list_arc); + let state = State::new(config.clone(), disk_list_arc); let wim_sources = Arc::clone(&state.wim_sources); Ok(Self { // TUI @@ -83,7 +84,7 @@ impl App { Box::new(Footer::new()), Box::new(popup::Popup::new()), ], - config: Config::new()?, + config, frame_rate, last_tick_key_events: Vec::new(), should_quit: false, @@ -284,7 +285,7 @@ impl App { } Action::FindWimNetwork => { self.state.reset_network(); - // TODO: Actually scan network! + self.state.scan_wim_network(); } Action::NextScreen => { let next_mode = self.next_mode(); diff --git a/win_installer/src/main.rs b/win_installer/src/main.rs index ab05a63..8d21810 100644 --- a/win_installer/src/main.rs +++ b/win_installer/src/main.rs @@ -20,6 +20,7 @@ use crate::app::App; mod app; mod components; +mod net; mod state; mod wim; diff --git a/win_installer/src/net.rs b/win_installer/src/net.rs new file mode 100644 index 0000000..ea24c0c --- /dev/null +++ b/win_installer/src/net.rs @@ -0,0 +1,68 @@ +// This file is part of Deja-Vu. +// +// Deja-Vu 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. +// +// Deja-Vu 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 Deja-Vu. If not, see . +// + +//#![windows_subsystem = "windows"] +use std::ffi::CString; + +use windows_sys::Win32::Foundation::NO_ERROR; +use windows_sys::Win32::NetworkManagement::WNet; + +fn to_cstr(s: &str) -> CString { + CString::new(s).unwrap() +} + +pub fn connect_network_share( + server: &str, + share: &str, + username: &str, + password: &str, +) -> Result<(), u32> { + let remote_name = to_cstr(&format!("\\\\{server}\\{share}")); + + // init resources + let mut resources = WNet::NETRESOURCEA { + dwDisplayType: WNet::RESOURCEDISPLAYTYPE_SHAREADMIN, + dwScope: WNet::RESOURCE_GLOBALNET, + dwType: WNet::RESOURCETYPE_DISK, + dwUsage: WNet::RESOURCEUSAGE_ALL, + lpComment: std::ptr::null_mut(), + lpLocalName: std::ptr::null_mut(), // PUT a volume here if you want to mount as a windows volume + lpProvider: std::ptr::null_mut(), + lpRemoteName: remote_name.as_c_str().as_ptr() as *mut u8, + }; + + let username = to_cstr(username); + let password = to_cstr(password); + + // mount + let result = unsafe { + let username_ptr = username.as_ptr(); + let password_ptr = password.as_ptr(); + WNet::WNetAddConnection2A( + &mut resources as *mut WNet::NETRESOURCEA, + password_ptr as *const u8, + username_ptr as *const u8, + //WNet::CONNECT_INTERACTIVE, // Interactive will show a system dialog in case credentials are wrong to retry with the password. Put 0 if you don't want it + 0, + ) + }; + + if result == NO_ERROR { + Ok(()) + } else { + Err(result) + } +} diff --git a/win_installer/src/state.rs b/win_installer/src/state.rs index 1f56254..1fa47f9 100644 --- a/win_installer/src/state.rs +++ b/win_installer/src/state.rs @@ -38,6 +38,7 @@ use crate::{ #[derive(Debug, Default)] pub struct State { + pub config: Config, pub disk_index_dest: Option, pub disk_list: Arc>>, pub driver: Option, @@ -49,11 +50,12 @@ pub struct State { } impl State { - pub fn new(disk_list: Arc>>) -> Self { - let wim_sources = WimSources::new(); + pub fn new(config: Config, disk_list: Arc>>) -> Self { + let wim_sources = Arc::new(Mutex::new(WimSources::new())); State { + config, disk_list, - wim_sources: Arc::new(Mutex::new(wim_sources)), + wim_sources, ..Default::default() } } @@ -85,6 +87,16 @@ impl State { }); } + pub fn scan_wim_network(&mut self) { + let config = self.config.clone(); + let disk_list_arc = self.disk_list.clone(); + let wim_sources_arc = self.wim_sources.clone(); + tokio::task::spawn(async move { + scan_network_share(config, disk_list_arc, wim_sources_arc); + }); + } +} + pub fn scan_local_drives( disk_list_arc: Arc>>, wim_sources_arc: Arc>, @@ -119,4 +131,24 @@ pub fn scan_local_drives( } }); } + +pub fn scan_network_share( + config: Config, + disk_list_arc: Arc>>, + wim_sources_arc: Arc>, +) { + let result = connect_network_share( + &config.network_server, + &config.network_share, + &config.network_user, + &config.network_pass, + ); + + // Connect to share + if result.is_err() { + return; + } + + // Scan share + let _ = 14; }