diff --git a/Cargo.lock b/Cargo.lock
index 26a8e325..4cc087ec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,21 +2,6 @@
# It is not intended for manual editing.
version = 4
-[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler2"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
-
[[package]]
name = "async-broadcast"
version = "0.7.2"
@@ -160,21 +145,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-[[package]]
-name = "backtrace"
-version = "0.3.75"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-targets 0.52.6",
-]
-
[[package]]
name = "bitflags"
version = "2.9.4"
@@ -723,12 +693,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
[[package]]
name = "gio"
version = "0.21.2"
@@ -970,17 +934,6 @@ dependencies = [
"hashbrown",
]
-[[package]]
-name = "io-uring"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
-dependencies = [
- "bitflags",
- "cfg-if",
- "libc",
-]
-
[[package]]
name = "ipnetwork"
version = "0.21.1"
@@ -1049,15 +1002,6 @@ dependencies = [
"autocfg",
]
-[[package]]
-name = "miniz_oxide"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
-dependencies = [
- "adler2",
-]
-
[[package]]
name = "mio"
version = "1.0.4"
@@ -1154,15 +1098,6 @@ dependencies = [
"zbus",
]
-[[package]]
-name = "object"
-version = "0.36.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
-dependencies = [
- "memchr",
-]
-
[[package]]
name = "once_cell"
version = "1.21.3"
@@ -1229,7 +1164,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
- "windows-targets 0.52.6",
+ "windows-targets",
]
[[package]]
@@ -1382,12 +1317,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "rustc-demangle"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
-
[[package]]
name = "rustc_version"
version = "0.4.1"
@@ -1430,9 +1359,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
@@ -1440,18 +1369,18 @@ dependencies = [
[[package]]
name = "serde_core"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.226"
+version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -1611,18 +1540,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "2.0.16"
+version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "2.0.16"
+version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
@@ -1631,29 +1560,26 @@ dependencies = [
[[package]]
name = "tokio"
-version = "1.47.1"
+version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
+checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
- "backtrace",
"bytes",
- "io-uring",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "slab",
"socket2",
"tokio-macros",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.0",
]
[[package]]
name = "tokio-macros"
-version = "2.5.0"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
@@ -1781,6 +1707,7 @@ checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
dependencies = [
"getrandom 0.3.3",
"js-sys",
+ "serde",
"wasm-bindgen",
]
@@ -2013,12 +1940,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-[[package]]
-name = "windows-link"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
-
[[package]]
name = "windows-link"
version = "0.2.0"
@@ -2031,16 +1952,7 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.3",
+ "windows-targets",
]
[[package]]
@@ -2049,7 +1961,7 @@ version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
dependencies = [
- "windows-link 0.2.0",
+ "windows-link",
]
[[package]]
@@ -2058,31 +1970,14 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
-dependencies = [
- "windows-link 0.1.3",
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
@@ -2091,96 +1986,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
-
[[package]]
name = "winnow"
version = "0.5.40"
@@ -2233,9 +2080,9 @@ dependencies = [
[[package]]
name = "zbus"
-version = "5.11.0"
+version = "5.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7"
+checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91"
dependencies = [
"async-broadcast",
"async-executor",
@@ -2257,7 +2104,8 @@ dependencies = [
"serde_repr",
"tracing",
"uds_windows",
- "windows-sys 0.60.2",
+ "uuid",
+ "windows-sys 0.61.0",
"winnow 0.7.13",
"zbus_macros",
"zbus_names",
@@ -2266,9 +2114,9 @@ dependencies = [
[[package]]
name = "zbus_macros"
-version = "5.11.0"
+version = "5.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
+checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -2293,9 +2141,9 @@ dependencies = [
[[package]]
name = "zvariant"
-version = "5.7.0"
+version = "5.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db"
+checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c"
dependencies = [
"endi",
"enumflags2",
@@ -2307,9 +2155,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
-version = "5.7.0"
+version = "5.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e"
+checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006"
dependencies = [
"proc-macro-crate",
"proc-macro2",
diff --git a/README.md b/README.md
index a2f73cea..edcaef6c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,11 @@

-# nmrs
-#### Wayland-native frontend for NetworkManager. Provides a GTK4 UI and a D-Bus proxy core, built in Rust.
-
+# nmrs 🦀
+
+
Wayland-native frontend for NetworkManager. Provides a GTK4 UI and a D-Bus proxy core, built in Rust.
+
+
+
+
#
diff --git a/nmrs-core/src/dbus.rs b/nmrs-core/src/dbus.rs
index 591dab28..89054d10 100644
--- a/nmrs-core/src/dbus.rs
+++ b/nmrs-core/src/dbus.rs
@@ -249,9 +249,10 @@ impl NetworkManager {
);
let nm = NMProxy::new(&self.conn).await?;
- let devices = nm.get_devices().await?;
+ let devices = nm.get_devices().await?;
let mut wifi_device: Option = None;
+
for dp in devices {
let dev = NMDeviceProxy::builder(&self.conn)
.path(dp.clone())?
@@ -259,9 +260,11 @@ impl NetworkManager {
.await?;
if dev.device_type().await? == 2 {
wifi_device = Some(dp.clone());
+ eprintln!(" Found WiFi device: {dp}");
break;
}
}
+
let wifi_device =
wifi_device.ok_or(zbus::Error::Failure("no Wi-Fi device found".into()))?;
@@ -271,32 +274,50 @@ impl NetworkManager {
.await?;
if let Some(active) = self.current_ssid().await {
+ eprintln!("Currently connected to: {active}");
if active == ssid {
eprintln!("Already connected to {active}, skipping connect()");
return Ok(());
} else {
- eprintln!("Currently connected to {active}, disconnecting before reconnecting...");
+ eprintln!("Disconnecting from {active}.");
if let Ok(conns) = nm.active_connections().await {
for conn_path in conns {
+ eprintln!("Deactivating connection: {conn_path}");
let _ = nm.deactivate_connection(conn_path).await;
}
}
- for _ in 0..10 {
+ for i in 0..10 {
let d = NMDeviceProxy::builder(&self.conn)
.path(wifi_device.clone())?
.build()
.await?;
- if DeviceState::from(d.state().await?) == DeviceState::Disconnected {
+ let state = DeviceState::from(d.state().await?);
+ eprintln!("Loop {i}: Device state = {state:?}");
+
+ if state == DeviceState::Disconnected
+ || state == DeviceState::Unavailable
+ || state == DeviceState::Deactivating
+ {
+ eprintln!("Device disconneced or deactivating");
break;
}
- tokio::time::sleep(std::time::Duration::from_millis(300)).await;
+
+ Delay::new(Duration::from_millis(300)).await;
}
+
+ eprintln!("Disconnect complete");
}
+ } else {
+ eprintln!("Not currently connected to any network");
}
- let _ = wifi.request_scan(HashMap::new()).await;
- tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+ match wifi.request_scan(HashMap::new()).await {
+ Ok(_) => eprintln!("Scan requested successfully"),
+ Err(e) => eprintln!("Scan request FAILED: {e}"),
+ }
+ Delay::new(Duration::from_secs(3)).await;
+ eprintln!("Scan wait complete");
let mut ap_path: Option = None;
for ap in wifi.get_all_access_points().await? {
@@ -306,30 +327,40 @@ impl NetworkManager {
.await?;
let ssid_bytes = apx.ssid().await?;
let ap_ssid = std::str::from_utf8(&ssid_bytes).unwrap_or("");
+ eprintln!("Found AP: '{ap_ssid}'");
if ap_ssid == ssid {
ap_path = Some(ap.clone());
+ eprintln!("Matched target SSID");
break;
}
}
+ if ap_path.is_none() {
+ eprintln!("Could not find AP for '{ssid}'");
+ }
+
let settings = build_wifi_connection(ssid, &creds);
- if matches!(creds, crate::models::WifiSecurity::Open) {
- println!("Connecting to open network '{ssid}'");
- nm.add_and_activate_connection(
- settings,
- wifi_device.clone(),
- ObjectPath::from_str_unchecked("/").into(),
- )
- .await?;
- } else {
- let specific_object =
- ap_path.unwrap_or_else(|| ObjectPath::from_str_unchecked("/").into());
- nm.add_and_activate_connection(settings, wifi_device.clone(), specific_object)
- .await?;
+ let specific_object = ap_path.unwrap_or_else(|| ObjectPath::from_str_unchecked("/").into());
+
+ match nm
+ .add_and_activate_connection(settings, wifi_device.clone(), specific_object)
+ .await
+ {
+ Ok(_) => eprintln!("add_and_activate_connection() succeeded"),
+ Err(e) => {
+ eprintln!("add_and_activate_connection() failed: {e}");
+ return Err(e);
+ }
}
- println!("Connection request for '{ssid}' submitted successfully");
+ let dev_proxy = NMDeviceProxy::builder(&self.conn)
+ .path(wifi_device.clone())?
+ .build()
+ .await?;
+ eprintln!("Dev state after connect(): {:?}", dev_proxy.state().await?);
+ eprintln!("---Connection request for '{ssid}' submitted successfully---");
+
Ok(())
}
@@ -547,4 +578,121 @@ impl NetworkManager {
_ => "Unknown",
}
}
+
+ pub async fn forget(&self, ssid: &str) -> zbus::Result<()> {
+ use std::collections::HashMap;
+ use zvariant::{OwnedObjectPath, Value};
+
+ let nm = NMProxy::new(&self.conn).await?;
+
+ let devices = nm.get_devices().await?;
+ for dev_path in &devices {
+ let dev = NMDeviceProxy::builder(&self.conn)
+ .path(dev_path.clone())?
+ .build()
+ .await?;
+ if dev.device_type().await? != 2 {
+ continue;
+ }
+
+ let wifi = NMWirelessProxy::builder(&self.conn)
+ .path(dev_path.clone())?
+ .build()
+ .await?;
+ if let Ok(ap_path) = wifi.active_access_point().await
+ && ap_path.as_str() != "/"
+ {
+ let ap = NMAccessPointProxy::builder(&self.conn)
+ .path(ap_path.clone())?
+ .build()
+ .await?;
+ if let Ok(bytes) = ap.ssid().await
+ && std::str::from_utf8(&bytes).ok() == Some(ssid)
+ {
+ let dev_proxy: zbus::Proxy<'_> = zbus::proxy::Builder::new(&self.conn)
+ .destination("org.freedesktop.NetworkManager")?
+ .path(dev_path.clone())?
+ .interface("org.freedesktop.NetworkManager.Device")?
+ .build()
+ .await?;
+ let _ = dev_proxy.call_method("Disconnect", &()).await;
+
+ for _ in 0..10 {
+ if dev.state().await? == 30 {
+ break;
+ }
+ tokio::time::sleep(std::time::Duration::from_millis(200)).await;
+ }
+ }
+ }
+ }
+
+ let settings: zbus::Proxy<'_> = zbus::proxy::Builder::new(&self.conn)
+ .destination("org.freedesktop.NetworkManager")?
+ .path("/org/freedesktop/NetworkManager/Settings")?
+ .interface("org.freedesktop.NetworkManager.Settings")?
+ .build()
+ .await?;
+
+ let list_reply = settings.call_method("ListConnections", &()).await?;
+ let conns: Vec = list_reply.body().deserialize()?;
+
+ let mut deleted_any = false;
+
+ for cpath in conns {
+ let cproxy: zbus::Proxy<'_> = zbus::proxy::Builder::new(&self.conn)
+ .destination("org.freedesktop.NetworkManager")?
+ .path(cpath.clone())?
+ .interface("org.freedesktop.NetworkManager.Settings.Connection")?
+ .build()
+ .await?;
+
+ if let Ok(id) = cproxy.get_property::("Id").await
+ && id == ssid
+ {
+ let _ = cproxy.call_method("Delete", &()).await;
+ deleted_any = true;
+ continue;
+ }
+
+ if let Ok(msg) = cproxy.call_method("GetSettings", &()).await {
+ let body = msg.body();
+ let settings_map: HashMap> = body.deserialize()?;
+
+ if let Some(conn_sec) = settings_map.get("connection")
+ && let Some(Value::Str(id)) = conn_sec.get("id")
+ && id.as_str() == ssid
+ {
+ let _ = cproxy.call_method("Delete", &()).await;
+ deleted_any = true;
+ continue;
+ }
+
+ if let Some(wifi_sec) = settings_map.get("802-11-wireless")
+ && let Some(Value::Array(arr)) = wifi_sec.get("ssid")
+ {
+ let mut raw = Vec::new();
+ for v in arr.iter() {
+ if let Ok(b) = u8::try_from(v.clone()) {
+ raw.push(b);
+ }
+ }
+ if std::str::from_utf8(&raw).ok() == Some(ssid) {
+ let _ = cproxy.call_method("Delete", &()).await;
+ deleted_any = true;
+ continue;
+ }
+ }
+ }
+ }
+
+ if deleted_any {
+ eprintln!("Forgot and disconnected '{ssid}'");
+ Ok(())
+ } else {
+ Err(zbus::Error::Failure(format!(
+ "No saved connection for {ssid}"
+ )))
+ }
+ }
}
diff --git a/nmrs-core/src/models.rs b/nmrs-core/src/models.rs
index 85f7bd01..0fa0dc7d 100644
--- a/nmrs-core/src/models.rs
+++ b/nmrs-core/src/models.rs
@@ -13,6 +13,7 @@ pub struct Network {
pub is_eap: bool,
}
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkInfo {
pub ssid: String,
pub bssid: String,
@@ -80,6 +81,8 @@ pub enum DeviceState {
Prepare,
Config,
Activated,
+ Deactivating,
+ Failed,
Other(u32),
}
@@ -114,6 +117,8 @@ impl From for DeviceState {
40 => DeviceState::Prepare,
50 => DeviceState::Config,
100 => DeviceState::Activated,
+ 110 => DeviceState::Deactivating,
+ 120 => DeviceState::Failed,
v => DeviceState::Other(v),
}
}
@@ -140,6 +145,8 @@ impl Display for DeviceState {
DeviceState::Prepare => write!(f, "Preparing"),
DeviceState::Config => write!(f, "Configuring"),
DeviceState::Activated => write!(f, "Activated"),
+ DeviceState::Deactivating => write!(f, "Deactivating"),
+ DeviceState::Failed => write!(f, "Failed"),
DeviceState::Other(v) => write!(f, "Other({v})"),
}
}
diff --git a/nmrs-core/src/wifi_builders.rs b/nmrs-core/src/wifi_builders.rs
index 1b112814..29eb2360 100644
--- a/nmrs-core/src/wifi_builders.rs
+++ b/nmrs-core/src/wifi_builders.rs
@@ -117,23 +117,36 @@ pub fn build_wifi_connection(
s_conn.insert("type", Value::from("802-11-wireless"));
s_conn.insert("id", Value::from(ssid.to_string()));
s_conn.insert("uuid", Value::from(uuid::Uuid::new_v4().to_string()));
+ s_conn.insert("autoconnect", Value::from(true));
+ s_conn.insert("interface-name", Value::from("wlan0"));
conn.insert("connection", s_conn);
let mut s_wifi = HashMap::new();
s_wifi.insert("ssid", Value::from(ssid.as_bytes().to_vec()));
s_wifi.insert("mode", Value::from("infrastructure"));
- conn.insert("802-11-wireless", s_wifi);
match security {
models::WifiSecurity::Open => {}
models::WifiSecurity::WpaPsk { psk } => {
+ s_wifi.insert("security", Value::from("802-11-wireless-security"));
let mut s_sec = HashMap::new();
s_sec.insert("key-mgmt", Value::from("wpa-psk"));
+ s_sec.insert("auth-alg", Value::from("open"));
s_sec.insert("psk", Value::from(psk.to_string()));
conn.insert("802-11-wireless-security", s_sec);
}
_ => {}
}
+ conn.insert("802-11-wireless", s_wifi);
+
+ let mut ipv4 = HashMap::new();
+ ipv4.insert("method", Value::from("auto"));
+ conn.insert("ipv4", ipv4);
+
+ let mut ipv6 = HashMap::new();
+ ipv6.insert("method", Value::from("auto"));
+ conn.insert("ipv6", ipv6);
+
conn
}
diff --git a/nmrs-ui/src/style.css b/nmrs-ui/src/style.css
index 349ae0bd..cd68114d 100644
--- a/nmrs-ui/src/style.css
+++ b/nmrs-ui/src/style.css
@@ -168,3 +168,19 @@ label.network-poor { color: #ef4444; }
.wifi-open {
color: white;
}
+
+.loading-spinner {
+ margin-top: 12px;
+ margin-bottom: 12px;
+ opacity: 0.6;
+}
+
+.forget-button {
+ font-size: 0.85em;
+ opacity: 0.7;
+ padding: 2px 6px;
+ border-radius: 6px;
+}
+.forget-button:hover {
+ opacity: 1;
+}
diff --git a/nmrs-ui/src/ui/connect.rs b/nmrs-ui/src/ui/connect.rs
index 781faf1b..afcfaacb 100644
--- a/nmrs-ui/src/ui/connect.rs
+++ b/nmrs-ui/src/ui/connect.rs
@@ -78,11 +78,16 @@ fn draw_connect_modal(parent: &ApplicationWindow, ssid: &str, is_eap: bool) {
.unwrap_or_default();
let ssid = ssid_owned.clone();
- println!("User entered username={username}, password={pwd}");
+ eprintln!("User entered username={username}, password={pwd}");
glib::MainContext::default().spawn_local(async move {
+ eprintln!("---in spawned task here--");
+ eprintln!("Creating NetworkManager");
+
match NetworkManager::new().await {
Ok(nm) => {
+ println!("NetworkManager created successfully");
+
let creds = if is_eap {
WifiSecurity::WpaEap {
opts: EapOptions {
@@ -100,12 +105,16 @@ fn draw_connect_modal(parent: &ApplicationWindow, ssid: &str, is_eap: bool) {
WifiSecurity::WpaPsk { psk: pwd }
};
- if let Err(err) = nm.connect(&ssid, creds).await {
- eprintln!("Failed to connect: {err}");
+ println!("Calling nm.connect() for '{ssid}'");
+ match nm.connect(&ssid, creds).await {
+ Ok(_) => println!("nm.connect() succeeded!"),
+ Err(err) => eprintln!("nm.connect() failed: {err}"),
}
}
- Err(err) => eprintln!("Failed to init NetworkManager: {err}"),
+ Err(err) => eprintln!("Failed to create NetworkManager: {err}"),
}
+
+ println!("---finsihed spawned task---");
});
dialog_rc.close();
diff --git a/nmrs-ui/src/ui/header.rs b/nmrs-ui/src/ui/header.rs
index b06829fc..fb0cce28 100644
--- a/nmrs-ui/src/ui/header.rs
+++ b/nmrs-ui/src/ui/header.rs
@@ -37,6 +37,7 @@ pub fn build_header(
let wifi_switch = Switch::new();
wifi_switch.set_valign(gtk::Align::Center);
header.pack_end(&wifi_switch);
+ wifi_switch.set_size_request(24, 24);
header.pack_end(&status);
@@ -48,6 +49,7 @@ pub fn build_header(
let stack_clone = stack.clone();
glib::MainContext::default().spawn_local(async move {
+ stack_clone.set_visible_child_name("loading");
clear_children(&list_container_clone);
match NetworkManager::new().await {
@@ -56,12 +58,15 @@ pub fn build_header(
wifi_switch_clone.set_active(enabled);
if enabled {
- status_clone.set_text("");
+ status_clone.set_text("Scanning...");
+ let _ = nm.scan_networks().await;
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
match nm.list_networks().await {
Ok(nets) => {
let list: ListBox =
networks::networks_view(&nets, &pw, &stack_clone);
list_container_clone.append(&list);
+ stack_clone.set_visible_child_name("networks");
}
Err(err) => {
status_clone
@@ -117,6 +122,7 @@ pub fn build_header(
let list: ListBox =
networks::networks_view(&nets, &pw, &stack_inner);
list_container_clone.append(&list);
+ stack_inner.set_visible_child_name("networks");
}
Err(err) => {
status_clone
diff --git a/nmrs-ui/src/ui/mod.rs b/nmrs-ui/src/ui/mod.rs
index 6a2ace72..0085e247 100644
--- a/nmrs-ui/src/ui/mod.rs
+++ b/nmrs-ui/src/ui/mod.rs
@@ -5,7 +5,8 @@ pub mod networks;
use gtk::prelude::*;
use gtk::{
- Application, ApplicationWindow, Box as GtkBox, Label, Orientation, ScrolledWindow, Stack,
+ Application, ApplicationWindow, Box as GtkBox, Label, Orientation, ScrolledWindow, Spinner,
+ Stack,
};
pub fn build_ui(app: &Application) {
@@ -18,8 +19,19 @@ pub fn build_ui(app: &Application) {
let list_container = GtkBox::new(Orientation::Vertical, 0);
let stack = Stack::new();
+
+ let spinner = Spinner::new();
+ spinner.set_halign(gtk::Align::Center);
+ spinner.set_valign(gtk::Align::Center);
+ spinner.set_property("width-request", 24i32);
+ spinner.set_property("height-request", 24i32);
+ spinner.add_css_class("loading-spinner");
+ spinner.start();
+
+ stack.add_named(&spinner, Some("loading"));
+ stack.set_visible_child_name("loading");
+
stack.add_named(&list_container, Some("networks"));
- stack.set_visible_child_name("networks");
let header = header::build_header(&status, &list_container, &win, &stack);
vbox.append(&header);
diff --git a/nmrs-ui/src/ui/network_page.rs b/nmrs-ui/src/ui/network_page.rs
index 36a927f3..f235510b 100644
--- a/nmrs-ui/src/ui/network_page.rs
+++ b/nmrs-ui/src/ui/network_page.rs
@@ -1,9 +1,10 @@
use glib::clone;
use gtk::prelude::*;
use gtk::{Align, Box, Button, Image, Label, Orientation};
+use nmrs_core::NetworkManager;
use nmrs_core::models::NetworkInfo;
-pub fn network_page(info: &NetworkInfo, stack: >k::Stack) -> Box {
+pub fn network_page(info: NetworkInfo, stack: >k::Stack) -> Box {
let container = Box::new(Orientation::Vertical, 12);
container.add_css_class("network-page");
@@ -27,8 +28,36 @@ pub fn network_page(info: &NetworkInfo, stack: >k::Stack) -> Box {
icon.set_pixel_size(24);
let title = Label::new(Some(&info.ssid));
title.add_css_class("network-title");
+
+ let spacer = Box::new(Orientation::Horizontal, 0);
+ spacer.set_hexpand(true);
+
+ let forget_btn = Button::with_label("Forget");
+ forget_btn.add_css_class("forget-button");
+ forget_btn.set_halign(Align::End);
+ forget_btn.set_valign(Align::Center);
+ forget_btn.set_cursor_from_name(Some("pointer"));
+
+ forget_btn.connect_clicked(clone!(
+ #[strong]
+ info,
+ #[weak]
+ stack,
+ move |_| {
+ let ssid = info.ssid.clone();
+ glib::MainContext::default().spawn_local(async move {
+ if let Ok(nm) = NetworkManager::new().await {
+ let _ = nm.forget(&ssid).await;
+ stack.set_visible_child_name("networks");
+ }
+ });
+ }
+ ));
+
header.append(&icon);
header.append(&title);
+ header.append(&spacer);
+ header.append(&forget_btn);
container.append(&header);
// Basic info section
diff --git a/nmrs-ui/src/ui/networks.rs b/nmrs-ui/src/ui/networks.rs
index 3b6efbc3..6dafc822 100644
--- a/nmrs-ui/src/ui/networks.rs
+++ b/nmrs-ui/src/ui/networks.rs
@@ -74,7 +74,7 @@ pub fn networks_view(
if let Ok(nm) = NetworkManager::new().await
&& let Ok(details) = nm.show_details(&net_data).await
{
- let container = network_page(&details, &stack);
+ let container = network_page(details, &stack);
if let Some(old) = stack.child_by_name("details") {
stack.remove(&old);