Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b38504240 |
3 changed files with 2 additions and 78 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -54,7 +54,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "breadcrumbs"
|
name = "breadcrumbs"
|
||||||
version = "2.1.1"
|
version = "2.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "breadcrumbs"
|
name = "breadcrumbs"
|
||||||
version = "2.1.1"
|
version = "2.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Profile-aware Wi-Fi state machine with Tailscale handling and self-healing watch daemon"
|
description = "Profile-aware Wi-Fi state machine with Tailscale handling and self-healing watch daemon"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
76
src/main.rs
76
src/main.rs
|
|
@ -99,20 +99,6 @@ enum Cmd {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
show_passwords: bool,
|
show_passwords: bool,
|
||||||
},
|
},
|
||||||
/// Connect to a specific saved network by SSID, bypassing profile routing
|
|
||||||
Join { ssid: String },
|
|
||||||
/// List saved network SSIDs
|
|
||||||
Networks {
|
|
||||||
/// Emit a JSON array instead of one-per-line
|
|
||||||
#[arg(long)]
|
|
||||||
json: bool,
|
|
||||||
},
|
|
||||||
/// Scan for visible networks and list them with signal strength
|
|
||||||
ScanList {
|
|
||||||
/// Emit JSON instead of human-readable output
|
|
||||||
#[arg(long)]
|
|
||||||
json: bool,
|
|
||||||
},
|
|
||||||
/// Open the config file in $EDITOR
|
/// Open the config file in $EDITOR
|
||||||
Edit,
|
Edit,
|
||||||
/// Quick connectivity / Tailscale diagnostics
|
/// Quick connectivity / Tailscale diagnostics
|
||||||
|
|
@ -206,9 +192,6 @@ fn real_main(cli: Cli) -> Result<i32, String> {
|
||||||
at,
|
at,
|
||||||
} => cmd_add(&mut cfg, ssid, password, hidden, to, at),
|
} => cmd_add(&mut cfg, ssid, password, hidden, to, at),
|
||||||
Cmd::Forget { ssid } => cmd_forget(&mut cfg, &ssid),
|
Cmd::Forget { ssid } => cmd_forget(&mut cfg, &ssid),
|
||||||
Cmd::Join { ssid } => cmd_join(&be, &cfg, &ssid),
|
|
||||||
Cmd::Networks { json } => cmd_networks(&cfg, json),
|
|
||||||
Cmd::ScanList { json } => cmd_scan_list(&cfg, json),
|
|
||||||
Cmd::Scan { to } => cmd_scan(&mut cfg, to),
|
Cmd::Scan { to } => cmd_scan(&mut cfg, to),
|
||||||
Cmd::List { show_passwords } => cmd_list(&cfg, show_passwords),
|
Cmd::List { show_passwords } => cmd_list(&cfg, show_passwords),
|
||||||
Cmd::Edit => cmd_edit(),
|
Cmd::Edit => cmd_edit(),
|
||||||
|
|
@ -531,65 +514,6 @@ fn cmd_add(
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmd_join(be: &dyn Backend, cfg: &Config, ssid: &str) -> Result<i32, String> {
|
|
||||||
let net = cfg
|
|
||||||
.network(ssid)
|
|
||||||
.ok_or_else(|| format!("no saved network '{ssid}' — add it first with `breadcrumbs add {ssid}`"))?;
|
|
||||||
let iface = be
|
|
||||||
.wifi_interface()
|
|
||||||
.ok_or_else(|| "no Wi-Fi adapter found".to_string())?;
|
|
||||||
be.radio_on();
|
|
||||||
match nm::connect_verbose(&iface, net, cfg.settings.nmcli_wait, &cfg.settings.dns) {
|
|
||||||
Ok(()) => {
|
|
||||||
println!("{C_GREEN}connected{C_RESET} {C_BOLD}{ssid}{C_RESET}");
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{C_RED}connect failed{C_RESET}: {e}");
|
|
||||||
Ok(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_scan_list(cfg: &Config, json: bool) -> Result<i32, String> {
|
|
||||||
let iface = nm::wifi_interface().ok_or("no Wi-Fi adapter found")?;
|
|
||||||
let entries = nm::scan_list(&iface);
|
|
||||||
let saved: std::collections::HashSet<&str> =
|
|
||||||
cfg.networks.iter().map(|n| n.ssid.as_str()).collect();
|
|
||||||
if json {
|
|
||||||
let v: Vec<serde_json::Value> = entries
|
|
||||||
.iter()
|
|
||||||
.map(|e| {
|
|
||||||
serde_json::json!({
|
|
||||||
"ssid": e.ssid,
|
|
||||||
"signal": e.signal,
|
|
||||||
"security": e.security,
|
|
||||||
"saved": saved.contains(e.ssid.as_str()),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
println!("{}", serde_json::to_string(&v).unwrap_or_else(|_| "[]".into()));
|
|
||||||
} else {
|
|
||||||
for e in &entries {
|
|
||||||
let mark = if saved.contains(e.ssid.as_str()) { "*" } else { " " };
|
|
||||||
println!("{mark} {:>3}% {} {}", e.signal, e.ssid, e.security);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_networks(cfg: &Config, json: bool) -> Result<i32, String> {
|
|
||||||
let ssids: Vec<&str> = cfg.networks.iter().map(|n| n.ssid.as_str()).collect();
|
|
||||||
if json {
|
|
||||||
println!("{}", serde_json::to_string(&ssids).unwrap_or_else(|_| "[]".into()));
|
|
||||||
} else {
|
|
||||||
for ssid in &ssids {
|
|
||||||
println!("{ssid}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_forget(cfg: &mut Config, ssid: &str) -> Result<i32, String> {
|
fn cmd_forget(cfg: &mut Config, ssid: &str) -> Result<i32, String> {
|
||||||
let before = cfg.networks.len();
|
let before = cfg.networks.len();
|
||||||
cfg.networks.retain(|n| n.ssid != ssid);
|
cfg.networks.retain(|n| n.ssid != ssid);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue