1use super::{error, warn, Result};
2use serde::Serialize;
3use std::collections::HashMap;
4use std::fmt::Display;
5use std::str::FromStr;
6use tokio::net::UnixDatagram;
7
8#[derive(Serialize, Debug, Clone)]
9pub struct ScanResult {
11 pub mac: String,
12 pub frequency: String,
13 pub signal: isize,
14 pub flags: String,
15 pub name: String,
16}
17
18impl ScanResult {
19 pub fn vec_from_str(response: &str) -> Result<Vec<ScanResult>> {
20 let mut results = Vec::new();
21 let split = response.split('\n').skip(1);
22 for line in split {
23 let mut line_split = line.split_whitespace();
24 if let (Some(mac), Some(frequency), Some(signal), Some(flags)) = (
25 line_split.next(),
26 line_split.next(),
27 line_split.next(),
28 line_split.next(),
29 ) {
30 let mut name: Option<String> = None;
31 for text in line_split {
32 match &mut name {
33 Some(started) => {
34 started.push(' ');
35 started.push_str(text);
36 }
37 None => {
38 name = Some(text.to_string());
39 }
40 }
41 }
42 if let Some(name) = name {
43 if let Ok(signal) = isize::from_str(signal) {
44 let scan_result = ScanResult {
45 mac: mac.to_string(),
46 frequency: frequency.to_string(),
47 signal,
48 flags: flags.to_string(),
49 name,
50 };
51 results.push(scan_result);
52 } else {
53 warn!("Invalid string for signal: {signal}");
54 }
55 }
56 }
57 }
58 Ok(results)
59 }
60}
61
62#[derive(Serialize, Debug, Clone)]
63pub struct NetworkResult {
65 pub network_id: usize,
66 pub ssid: String,
67 pub flags: String,
68}
69
70impl NetworkResult {
71 pub async fn vec_from_str(
72 response: &str,
73 socket: &mut UnixDatagram,
74 ) -> Result<Vec<NetworkResult>> {
75 let mut buffer = [0; 256];
76 let mut results = Vec::new();
77 let split = response.split('\n').skip(1);
78 for line in split {
79 let mut line_split = line.split_whitespace();
80 if let Some(network_id) = line_split.next() {
81 let cmd = format!("GET_NETWORK {network_id} ssid");
82 let bytes = cmd.into_bytes();
83 socket.send(&bytes).await?;
84 let n = socket.recv(&mut buffer).await?;
85 let ssid = std::str::from_utf8(&buffer[..n])?.trim_matches('\"');
86 if let Ok(network_id) = usize::from_str(network_id) {
87 if let Some(flags) = line_split.last() {
88 results.push(NetworkResult {
89 flags: flags.into(),
90 ssid: ssid.into(),
91 network_id,
92 })
93 }
94 } else {
95 warn!("Invalid network_id: {network_id}")
96 }
97 }
98 }
99 Ok(results)
100 }
101}
102
103pub type Status = HashMap<String, String>;
105
106pub(crate) fn parse_status(response: &str) -> Result<Status> {
107 use config::{Config, File, FileFormat};
108 let config = Config::builder()
109 .add_source(File::from_str(response, FileFormat::Ini))
110 .build()
111 .map_err(|e| error::Error::ParsingWifiStatus {
112 e,
113 s: response.into(),
114 })?;
115 Ok(config.try_deserialize::<HashMap<String, String>>().unwrap())
116}
117
118#[derive(Debug)]
119pub enum KeyMgmt {
123 None,
124 WpaPsk,
125 WpaEap,
126 IEEE8021X,
127}
128
129impl Display for KeyMgmt {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 let str = match self {
132 KeyMgmt::None => "NONE".to_string(),
133 KeyMgmt::WpaPsk => "WPA-PSK".to_string(),
134 KeyMgmt::WpaEap => "WPA-EAP".to_string(),
135 KeyMgmt::IEEE8021X => "IEEE8021X".to_string(),
136 };
137 write!(f, "{}", str)
138 }
139}