tauri_plugin_network_manager/
desktop.rs

1use std::collections::HashMap;
2use std::process::Command;
3use std::sync::mpsc;
4use tauri::{plugin::PluginApi, AppHandle, Runtime};
5use zbus::names::InterfaceName;
6use zbus::zvariant::Value;
7
8use crate::error::Result;
9use crate::models::*;
10
11impl<R: Runtime> VSKNetworkManager<'static, R> {
12    /// Get WiFi icon based on signal strength
13    fn get_wifi_icon(strength: u8) -> String {
14        match strength {
15            0..=25 => "network-wireless-signal-weak-symbolic".to_string(),
16            26..=50 => "network-wireless-signal-ok-symbolic".to_string(),
17            51..=75 => "network-wireless-signal-good-symbolic".to_string(),
18            76..=100 => "network-wireless-signal-excellent-symbolic".to_string(),
19            _ => "network-wireless-signal-none-symbolic".to_string(),
20        }
21    }
22
23    fn get_wired_icon(is_connected: bool) -> String {
24        if is_connected {
25            "network-wired-symbolic".to_string()
26        } else {
27            "network-offline-symbolic".to_string()
28        }
29    }
30
31    /// Create a new VSKNetworkManager instance
32    pub async fn new(app: AppHandle<R>) -> Result<Self> {
33        let connection = zbus::blocking::Connection::system()?;
34        let proxy = zbus::blocking::fdo::PropertiesProxy::builder(&connection)
35            .destination("org.freedesktop.NetworkManager")?
36            .path("/org/freedesktop/NetworkManager")?
37            .build()?;
38
39        Ok(Self {
40            connection,
41            proxy,
42            app,
43        })
44    }
45
46    fn has_internet_connectivity() -> bool {
47        Command::new("ping")
48            .arg("-c")
49            .arg("1")
50            .arg("8.8.8.8")
51            .output()
52            .map(|output| output.status.success())
53            .unwrap_or(false)
54    }
55
56    pub fn get_current_network_state(&self) -> Result<NetworkInfo> {
57        // Get active connections
58        let active_connections_variant = self.proxy.get(
59            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
60            "ActiveConnections",
61        )?;
62
63        // If no active connections, return default
64        match active_connections_variant.downcast_ref() {
65            Some(Value::Array(arr)) if !arr.is_empty() => {
66                // Get the first active connection path
67                match arr[0] {
68                    zbus::zvariant::Value::ObjectPath(ref path) => {
69                        // Get devices for this connection
70                        // Crear un proxy de propiedades para obtener las propiedades
71                        let properties_proxy =
72                            zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
73                                .destination("org.freedesktop.NetworkManager")?
74                                .path(path)?
75                                .build()?;
76
77                        let devices_variant = properties_proxy.get(
78                            InterfaceName::from_static_str_unchecked(
79                                "org.freedesktop.NetworkManager.Connection.Active",
80                            ),
81                            "Devices",
82                        )?;
83
84                        // Get the first device (if available)
85                        let device_path = match devices_variant.downcast_ref() {
86                            Some(Value::Array(device_arr)) if !device_arr.is_empty() => {
87                                match device_arr[0] {
88                                    zbus::zvariant::Value::ObjectPath(ref dev_path) => {
89                                        dev_path.clone()
90                                    }
91                                    _ => return Ok(NetworkInfo::default()),
92                                }
93                            }
94                            _ => return Ok(NetworkInfo::default()),
95                        };
96
97                        // Retrieve connection details
98                        // Crear un proxy de propiedades para el dispositivo
99                        let device_properties_proxy =
100                            zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
101                                .destination("org.freedesktop.NetworkManager")?
102                                .path(&device_path)?
103                                .build()?;
104
105                        let connection_type = device_properties_proxy.get(
106                            InterfaceName::from_static_str_unchecked(
107                                "org.freedesktop.NetworkManager.Device",
108                            ),
109                            "DeviceType",
110                        )?;
111
112                        let state_variant = properties_proxy.get(
113                            InterfaceName::from_static_str_unchecked(
114                                "org.freedesktop.NetworkManager.Connection.Active",
115                            ),
116                            "State",
117                        )?;
118
119                        let is_connected = match state_variant.downcast_ref() {
120                            Some(zbus::zvariant::Value::U32(state)) => *state == 2, // 2 = ACTIVATED
121                            _ => false,
122                        };
123
124                        // Determine connection type
125                        let connection_type_str = match connection_type.downcast_ref() {
126                            Some(zbus::zvariant::Value::U32(device_type)) => match device_type {
127                                1 => "Ethernet".to_string(),
128                                2 => "WiFi".to_string(),
129                                _ => "Unknown".to_string(),
130                            },
131                            _ => "Unknown".to_string(),
132                        };
133
134                        // Default network info
135                        let mut network_info = NetworkInfo {
136                            name: "Unknown".to_string(),
137                            ssid: "Unknown".to_string(),
138                            connection_type: connection_type_str.clone(),
139                            icon: "network-offline-symbolic".to_string(),
140                            ip_address: "0.0.0.0".to_string(),
141                            mac_address: "00:00:00:00:00:00".to_string(),
142                            signal_strength: 0,
143                            security_type: WiFiSecurityType::None,
144                            is_connected: is_connected && Self::has_internet_connectivity(),
145                        };
146
147                        let hw_address_variant = device_properties_proxy.get(
148                            InterfaceName::from_static_str_unchecked(
149                                "org.freedesktop.NetworkManager.Device",
150                            ),
151                            "HwAddress",
152                        )?;
153
154                        network_info.mac_address = match hw_address_variant.downcast_ref() {
155                            Some(zbus::zvariant::Value::Str(s)) => s.to_string(),
156                            _ => "00:00:00:00:00:00".to_string(),
157                        };
158
159                        // For WiFi networks, get additional details
160                        if connection_type_str == "WiFi" {
161                            // Get active access point
162                            // Crear un proxy de propiedades para el dispositivo inalámbrico
163                            let wireless_properties_proxy =
164                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
165                                    .destination("org.freedesktop.NetworkManager")?
166                                    .path(&device_path)?
167                                    .build()?;
168
169                            let active_ap_path = wireless_properties_proxy.get(
170                                InterfaceName::from_static_str_unchecked(
171                                    "org.freedesktop.NetworkManager.Device.Wireless",
172                                ),
173                                "ActiveAccessPoint",
174                            )?;
175
176                            if let Some(zbus::zvariant::Value::ObjectPath(ap_path)) =
177                                active_ap_path.downcast_ref()
178                            {
179                                let _ap_proxy = zbus::blocking::Proxy::new(
180                                    &self.connection,
181                                    "org.freedesktop.NetworkManager",
182                                    ap_path,
183                                    "org.freedesktop.NetworkManager.AccessPoint",
184                                )?;
185
186                                // Get SSID
187                                // Crear un proxy de propiedades para el punto de acceso
188                                let ap_properties_proxy =
189                                    zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
190                                        .destination("org.freedesktop.NetworkManager")?
191                                        .path(ap_path)?
192                                        .build()?;
193
194                                let ssid_variant = ap_properties_proxy.get(
195                                    InterfaceName::from_static_str_unchecked(
196                                        "org.freedesktop.NetworkManager.AccessPoint",
197                                    ),
198                                    "Ssid",
199                                )?;
200
201                                network_info.ssid = match ssid_variant.downcast_ref() {
202                                    Some(zbus::zvariant::Value::Array(ssid_bytes)) => {
203                                        // Convertir el array de bytes a una cadena UTF-8
204                                        let bytes: Vec<u8> = ssid_bytes
205                                            .iter()
206                                            .filter_map(|v| {
207                                                if let zbus::zvariant::Value::U8(b) = v {
208                                                    Some(*b)
209                                                } else {
210                                                    None
211                                                }
212                                            })
213                                            .collect();
214
215                                        String::from_utf8_lossy(&bytes).to_string()
216                                    }
217                                    _ => "Unknown".to_string(),
218                                };
219                                network_info.name = network_info.ssid.clone();
220
221                                // Get signal strength
222                                let strength_variant = ap_properties_proxy.get(
223                                    InterfaceName::from_static_str_unchecked(
224                                        "org.freedesktop.NetworkManager.AccessPoint",
225                                    ),
226                                    "Strength",
227                                )?;
228
229                                network_info.signal_strength = match strength_variant.downcast_ref()
230                                {
231                                    Some(zbus::zvariant::Value::U8(s)) => *s,
232                                    _ => 0,
233                                };
234
235                                // Update icon based on signal strength
236                                network_info.icon =
237                                    Self::get_wifi_icon(network_info.signal_strength);
238
239                                // Determine security type
240                                let wpa_flags_variant = ap_properties_proxy.get(
241                                    InterfaceName::from_static_str_unchecked(
242                                        "org.freedesktop.NetworkManager.AccessPoint",
243                                    ),
244                                    "WpaFlags",
245                                )?;
246
247                                network_info.security_type = match wpa_flags_variant.downcast_ref()
248                                {
249                                    Some(zbus::zvariant::Value::U32(flags)) => {
250                                        if *flags == 0 {
251                                            WiFiSecurityType::None
252                                        } else {
253                                            WiFiSecurityType::WpaPsk
254                                        }
255                                    }
256                                    _ => WiFiSecurityType::None,
257                                };
258                            }
259                        } else {
260                            // This is a wired connection
261                            network_info.icon = Self::get_wired_icon(network_info.is_connected);
262                        }
263                        // Get IP configuration
264                        let ip4_config_path = device_properties_proxy.get(
265                            InterfaceName::from_static_str_unchecked(
266                                "org.freedesktop.NetworkManager.Device",
267                            ),
268                            "Ip4Config",
269                        )?;
270
271                        // Retrieve IP address if available
272                        if let Some(zbus::zvariant::Value::ObjectPath(config_path)) =
273                            ip4_config_path.downcast_ref()
274                        {
275                            // Crear un proxy de propiedades para la configuración IP
276                            let ip_config_properties_proxy =
277                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
278                                    .destination("org.freedesktop.NetworkManager")?
279                                    .path(config_path)?
280                                    .build()?;
281
282                            let addresses_variant = ip_config_properties_proxy.get(
283                                InterfaceName::from_static_str_unchecked(
284                                    "org.freedesktop.NetworkManager.IP4Config",
285                                ),
286                                "Addresses",
287                            )?;
288
289                            if let Some(Value::Array(addr_arr)) = addresses_variant.downcast_ref() {
290                                if let Some(Value::Array(ip_tuple)) = addr_arr.first() {
291                                    if ip_tuple.len() >= 1 {
292                                        if let Value::U32(ip_int) = &ip_tuple[0] {
293                                            use std::net::Ipv4Addr;
294                                            network_info.ip_address =
295                                                Ipv4Addr::from((*ip_int).to_be()).to_string();
296                                        }
297                                    }
298                                }
299                            }
300                        }
301
302                        Ok(network_info)
303                    }
304                    _ => Ok(NetworkInfo::default()),
305                }
306            }
307            _ => Ok(NetworkInfo::default()),
308        }
309    }
310
311    /// List available WiFi networks
312    pub fn list_wifi_networks(&self) -> Result<Vec<NetworkInfo>> {
313        // Get all devices
314        let devices_variant = self.proxy.get(
315            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
316            "Devices",
317        )?;
318
319        let mut networks = Vec::new();
320        let current_network = self.get_current_network_state()?;
321
322        if let Some(zbus::zvariant::Value::Array(devices)) = devices_variant.downcast_ref() {
323            // Iterate over devices in the array
324            let device_values = devices.get();
325            for device in device_values {
326                if let zbus::zvariant::Value::ObjectPath(ref device_path) = device {
327                    // Create a device proxy
328                    let device_props =
329                        zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
330                            .destination("org.freedesktop.NetworkManager")?
331                            .path(device_path)?
332                            .build()?;
333
334                    // Check if this is a wireless device
335                    let device_type_variant = device_props.get(
336                        InterfaceName::from_static_str_unchecked(
337                            "org.freedesktop.NetworkManager.Device",
338                        ),
339                        "DeviceType",
340                    )?;
341
342                    // DeviceType 2 is WiFi
343                    if let Some(zbus::zvariant::Value::U32(device_type)) =
344                        device_type_variant.downcast_ref()
345                    {
346                        if device_type == &2u32 {
347                            // This is a WiFi device, get its access points
348                            let wireless_props =
349                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
350                                    .destination("org.freedesktop.NetworkManager")?
351                                    .path(device_path)?
352                                    .build()?;
353
354                            let access_points_variant = wireless_props.get(
355                                InterfaceName::from_static_str_unchecked(
356                                    "org.freedesktop.NetworkManager.Device.Wireless",
357                                ),
358                                "AccessPoints",
359                            )?;
360
361                            if let Some(zbus::zvariant::Value::Array(aps)) =
362                                access_points_variant.downcast_ref()
363                            {
364                                // Iterate over access points
365                                let ap_values = aps.get();
366                                for ap in ap_values {
367                                    if let zbus::zvariant::Value::ObjectPath(ref ap_path) = ap {
368                                        let ap_props =
369                                            zbus::blocking::fdo::PropertiesProxy::builder(
370                                                &self.connection,
371                                            )
372                                            .destination("org.freedesktop.NetworkManager")?
373                                            .path(ap_path)?
374                                            .build()?;
375
376                                        // Get SSID
377                                        let ssid_variant = ap_props.get(
378                                            InterfaceName::from_static_str_unchecked(
379                                                "org.freedesktop.NetworkManager.AccessPoint",
380                                            ),
381                                            "Ssid",
382                                        )?;
383
384                                        let ssid = match ssid_variant.downcast_ref() {
385                                            Some(zbus::zvariant::Value::Array(ssid_bytes)) => {
386                                                // Convertir el array de bytes a una cadena UTF-8
387                                                let bytes: Vec<u8> = ssid_bytes
388                                                    .iter()
389                                                    .filter_map(|v| {
390                                                        if let zbus::zvariant::Value::U8(b) = v {
391                                                            Some(*b)
392                                                        } else {
393                                                            None
394                                                        }
395                                                    })
396                                                    .collect();
397
398                                                String::from_utf8_lossy(&bytes).to_string()
399                                            }
400                                            _ => "Unknown".to_string(),
401                                        };
402
403                                        // Get signal strength
404                                        let strength_variant = ap_props.get(
405                                            InterfaceName::from_static_str_unchecked(
406                                                "org.freedesktop.NetworkManager.AccessPoint",
407                                            ),
408                                            "Strength",
409                                        )?;
410
411                                        let strength = match strength_variant.downcast_ref() {
412                                            Some(zbus::zvariant::Value::U8(s)) => *s,
413                                            _ => 0,
414                                        };
415
416                                        // Get security flags
417                                        let _flags_variant = ap_props.get(
418                                            InterfaceName::from_static_str_unchecked(
419                                                "org.freedesktop.NetworkManager.AccessPoint",
420                                            ),
421                                            "Flags",
422                                        )?;
423
424                                        let wpa_flags_variant = ap_props.get(
425                                            InterfaceName::from_static_str_unchecked(
426                                                "org.freedesktop.NetworkManager.AccessPoint",
427                                            ),
428                                            "WpaFlags",
429                                        )?;
430
431                                        let security_type = match wpa_flags_variant.downcast_ref() {
432                                            Some(zbus::zvariant::Value::U32(flags)) => {
433                                                if *flags == 0 {
434                                                    WiFiSecurityType::None
435                                                } else {
436                                                    WiFiSecurityType::WpaPsk
437                                                }
438                                            }
439                                            _ => WiFiSecurityType::None,
440                                        };
441
442                                        // Get hardware address (MAC)
443                                        let hw_address_variant = device_props.get(
444                                            InterfaceName::from_static_str_unchecked(
445                                                "org.freedesktop.NetworkManager.Device",
446                                            ),
447                                            "HwAddress",
448                                        )?;
449
450                                        let mac_address = match hw_address_variant.downcast_ref() {
451                                            Some(zbus::zvariant::Value::Str(s)) => s.to_string(),
452                                            _ => "00:00:00:00:00:00".to_string(),
453                                        };
454
455                                        // Check if this is the currently connected network
456                                        let is_connected = current_network.ssid == ssid;
457
458                                        // Create network info
459                                        let network_info = NetworkInfo {
460                                            name: ssid.clone(),
461                                            ssid,
462                                            connection_type: "wifi".to_string(),
463                                            icon: Self::get_wifi_icon(strength),
464                                            ip_address: if is_connected {
465                                                current_network.ip_address.clone()
466                                            } else {
467                                                "0.0.0.0".to_string()
468                                            },
469                                            mac_address,
470                                            signal_strength: strength,
471                                            security_type,
472                                            is_connected,
473                                        };
474
475                                        // Add to list if not already present
476                                        if !networks
477                                            .iter()
478                                            .any(|n: &NetworkInfo| n.ssid == network_info.ssid)
479                                        {
480                                            networks.push(network_info);
481                                        }
482                                    }
483                                }
484                            }
485                        }
486                    }
487                }
488            }
489        }
490
491        // Sort networks by signal strength (descending)
492        networks.sort_by(|a, b| b.signal_strength.cmp(&a.signal_strength));
493
494        Ok(networks)
495    }
496
497    /// Connect to a WiFi network
498    pub async fn connect_to_wifi(&self, config: WiFiConnectionConfig) -> Result<()> {
499        // Create connection settings
500        let mut connection_settings = HashMap::new();
501        let mut wifi_settings = HashMap::new();
502        let mut security_settings = HashMap::new();
503
504        // Set connection name and type
505        let mut connection = HashMap::new();
506        connection.insert("id".to_string(), Value::from(config.ssid.clone()));
507        connection.insert("type".to_string(), Value::from("802-11-wireless"));
508        connection_settings.insert("connection".to_string(), connection);
509
510        // Set WiFi settings
511        wifi_settings.insert("ssid".to_string(), Value::from(config.ssid.clone()));
512        wifi_settings.insert("mode".to_string(), Value::from("infrastructure"));
513
514        // Set security settings based on security type
515        match config.security_type {
516            WiFiSecurityType::None => {
517                // No security settings needed
518            }
519            WiFiSecurityType::Wep => {
520                security_settings.insert("key-mgmt".to_string(), Value::from("none"));
521                if let Some(password) = config.password {
522                    security_settings.insert("wep-key0".to_string(), Value::from(password));
523                }
524            }
525            WiFiSecurityType::WpaPsk => {
526                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-psk"));
527                if let Some(password) = config.password {
528                    security_settings.insert("psk".to_string(), Value::from(password));
529                }
530            }
531            WiFiSecurityType::WpaEap => {
532                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-eap"));
533                if let Some(password) = config.password {
534                    security_settings.insert("password".to_string(), Value::from(password));
535                }
536                if let Some(username) = config.username {
537                    security_settings.insert("identity".to_string(), Value::from(username));
538                }
539            }
540            WiFiSecurityType::Wpa2Psk => {
541                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-psk"));
542                security_settings.insert("proto".to_string(), Value::from("rsn"));
543                if let Some(password) = config.password {
544                    security_settings.insert("psk".to_string(), Value::from(password));
545                }
546            }
547            WiFiSecurityType::Wpa3Psk => {
548                security_settings.insert("key-mgmt".to_string(), Value::from("sae"));
549                if let Some(password) = config.password {
550                    security_settings.insert("psk".to_string(), Value::from(password));
551                }
552            }
553        }
554
555        connection_settings.insert("802-11-wireless".to_string(), wifi_settings);
556        connection_settings.insert("802-11-wireless-security".to_string(), security_settings);
557
558        // Crear un proxy para NetworkManager
559        let nm_proxy = zbus::blocking::Proxy::new(
560            &self.connection,
561            "org.freedesktop.NetworkManager",
562            "/org/freedesktop/NetworkManager",
563            "org.freedesktop.NetworkManager",
564        )?;
565
566        // Llamar al método AddAndActivateConnection
567        let _result: (
568            zbus::zvariant::OwnedObjectPath,
569            zbus::zvariant::OwnedObjectPath,
570        ) = nm_proxy.call("AddAndActivateConnection", &(connection_settings, "/", "/"))?;
571
572        Ok(())
573    }
574
575    /// Toggle network state
576    pub fn toggle_network_state(&self, enabled: bool) -> Result<bool> {
577        let nm_proxy = zbus::blocking::Proxy::new(
578            &self.connection,
579            "org.freedesktop.NetworkManager",
580            "/org/freedesktop/NetworkManager",
581            "org.freedesktop.NetworkManager",
582        )?;
583
584        let state = if enabled { "on" } else { "off" };
585        let _output = Command::new("nmcli")
586            .arg("networking")
587            .arg(state)
588            .output()?;
589
590        let current_state: bool = nm_proxy.get_property("NetworkingEnabled")?;
591        Ok(current_state)
592    }
593
594    /// Listen for network changes
595    pub fn listen_network_changes(&self) -> Result<mpsc::Receiver<NetworkInfo>> {
596        let (tx, rx) = mpsc::channel();
597        let connection_clone = self.connection.clone();
598        let app_handle = self.app.clone();
599
600        // Crear un hilo para escuchar los cambios de red
601        std::thread::spawn(move || {
602            match zbus::blocking::Connection::system() {
603                Ok(conn) => {
604                    // Proxy para el objeto raíz, interfaz DBus.Properties
605                    if let Ok(proxy) = zbus::blocking::Proxy::new(
606                        &conn,
607                        "org.freedesktop.NetworkManager",
608                        "/org/freedesktop/NetworkManager",
609                        "org.freedesktop.NetworkManager",
610                    ) {
611                        if let Ok(mut signal) = proxy.receive_signal("StateChanged") {
612                            while let Some(_msg) = signal.next() {
613                                let network_manager = VSKNetworkManager {
614                                    connection: connection_clone.clone(),
615                                    proxy: zbus::blocking::fdo::PropertiesProxy::builder(
616                                        &connection_clone,
617                                    )
618                                    .destination("org.freedesktop.NetworkManager")
619                                    .unwrap()
620                                    .path("/org/freedesktop/NetworkManager")
621                                    .unwrap()
622                                    .build()
623                                    .unwrap(),
624                                    app: app_handle.clone(),
625                                };
626
627                                if let Ok(network_info) =
628                                    network_manager.get_current_network_state()
629                                {
630                                    if tx.send(network_info).is_err() {
631                                        break;
632                                    }
633                                }
634                            }
635                        }
636                    }
637                }
638                Err(e) => {
639                    eprintln!(
640                        "Error al conectar con D-Bus para escuchar cambios de red: {:?}",
641                        e
642                    );
643                }
644            }
645        });
646
647        Ok(rx)
648    }
649
650    /// Disconnect from the current WiFi network
651    pub async fn disconnect_from_wifi(&self) -> Result<()> {
652        // Obtener el estado actual de la red para identificar la conexión activa
653        let _current_state = self.get_current_network_state()?;
654
655        // Crear un proxy para NetworkManager
656        let nm_proxy = zbus::blocking::Proxy::new(
657            &self.connection,
658            "org.freedesktop.NetworkManager",
659            "/org/freedesktop/NetworkManager",
660            "org.freedesktop.NetworkManager",
661        )?;
662
663        // Obtener las conexiones activas
664        let active_connections_variant: zbus::zvariant::OwnedValue = self.proxy.get(
665            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
666            "ActiveConnections",
667        )?;
668
669        // Convertir el valor a un vector de ObjectPath
670        let active_connections = match active_connections_variant.downcast_ref() {
671            Some(zbus::zvariant::Value::Array(arr)) => arr
672                .iter()
673                .filter_map(|v| match v {
674                    zbus::zvariant::Value::ObjectPath(path) => {
675                        Some(zbus::zvariant::OwnedObjectPath::from(path.to_owned()))
676                    }
677                    _ => None,
678                })
679                .collect::<Vec<zbus::zvariant::OwnedObjectPath>>(),
680            _ => Vec::new(),
681        };
682
683        if !active_connections.is_empty() {
684            nm_proxy.call::<_, _, ()>("DeactivateConnection", &(active_connections[0].as_str()))?;
685            Ok(())
686        } else {
687            Ok(())
688        }
689    }
690
691    /// Get the list of saved WiFi networks
692    pub fn get_saved_wifi_networks(&self) -> Result<Vec<NetworkInfo>> {
693        // Crear un proxy para el servicio de configuración de NetworkManager
694        let settings_proxy = zbus::blocking::Proxy::new(
695            &self.connection,
696            "org.freedesktop.NetworkManager",
697            "/org/freedesktop/NetworkManager/Settings",
698            "org.freedesktop.NetworkManager.Settings",
699        )?;
700
701        // Obtener todas las conexiones guardadas
702        let connections: Vec<zbus::zvariant::OwnedObjectPath> =
703            settings_proxy.call("ListConnections", &())?;
704        let mut saved_networks = Vec::new();
705
706        // Procesar cada conexión guardada
707        for conn_path in connections {
708            // Crear un proxy para cada conexión
709            let conn_proxy = zbus::blocking::Proxy::new(
710                &self.connection,
711                "org.freedesktop.NetworkManager",
712                conn_path.as_str(),
713                "org.freedesktop.NetworkManager.Settings.Connection",
714            )?;
715
716            // Obtener la configuración de la conexión como un HashMap
717            let settings: std::collections::HashMap<String, zbus::zvariant::OwnedValue> =
718                conn_proxy.call("GetSettings", &())?;
719
720            // Verificar si es una conexión WiFi
721            if let Some(connection) = settings.get("connection") {
722                let connection_value = connection.to_owned();
723                let connection_dict =
724                    match <zbus::zvariant::Value<'_> as Clone>::clone(&connection_value)
725                        .downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>(
726                    ) {
727                        Some(dict) => dict,
728                        None => continue,
729                    };
730
731                // Verificar el tipo de conexión
732                if let Some(conn_type) = connection_dict.get("type") {
733                    let conn_type_value = conn_type.to_owned();
734                    let conn_type_str =
735                        match <zbus::zvariant::Value<'_> as Clone>::clone(&conn_type_value)
736                            .downcast::<String>()
737                        {
738                            Some(s) => s,
739                            None => continue,
740                        };
741
742                    // Si es una conexión WiFi, extraer la información
743                    if conn_type_str == "802-11-wireless" {
744                        let mut network_info = NetworkInfo::default();
745                        network_info.connection_type = "wifi".to_string();
746
747                        // Obtener el nombre de la conexión
748                        if let Some(id) = connection_dict.get("id") {
749                            let id_value = id.to_owned();
750                            if let Some(name) =
751                                <zbus::zvariant::Value<'_> as Clone>::clone(&id_value)
752                                    .downcast::<String>()
753                            {
754                                network_info.name = name;
755                            }
756                        }
757
758                        // Obtener el SSID
759                        if let Some(wireless) = settings.get("802-11-wireless") {
760                            let wireless_value = wireless.to_owned();
761                            let wireless_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&wireless_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
762                                Some(dict) => dict,
763                                None => continue,
764                            };
765
766                            if let Some(ssid) = wireless_dict.get("ssid") {
767                                let ssid_value = ssid.to_owned();
768                                if let Some(ssid_bytes) =
769                                    <zbus::zvariant::Value<'_> as Clone>::clone(&ssid_value)
770                                        .downcast::<Vec<u8>>()
771                                {
772                                    if let Ok(ssid_str) = String::from_utf8(ssid_bytes) {
773                                        network_info.ssid = ssid_str;
774                                    }
775                                }
776                            }
777                        }
778
779                        // Determinar el tipo de seguridad
780                        if let Some(security) = settings.get("802-11-wireless-security") {
781                            let security_value = security.to_owned();
782                            let security_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&security_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
783                                Some(dict) => dict,
784                                None => {
785                                    network_info.security_type = WiFiSecurityType::None;
786                                    saved_networks.push(network_info);
787                                    continue;
788                                },
789                            };
790
791                            if let Some(key_mgmt) = security_dict.get("key-mgmt") {
792                                let key_mgmt_value = key_mgmt.to_owned();
793                                if let Some(key_mgmt_str) =
794                                    <zbus::zvariant::Value<'_> as Clone>::clone(&key_mgmt_value)
795                                        .downcast::<String>()
796                                {
797                                    match key_mgmt_str.as_str() {
798                                        "none" => {
799                                            network_info.security_type = WiFiSecurityType::None
800                                        }
801                                        "wpa-psk" => {
802                                            network_info.security_type = WiFiSecurityType::WpaPsk
803                                        }
804                                        "wpa-eap" => {
805                                            network_info.security_type = WiFiSecurityType::WpaEap
806                                        }
807                                        _ => network_info.security_type = WiFiSecurityType::None,
808                                    }
809                                }
810                            }
811                        } else {
812                            network_info.security_type = WiFiSecurityType::None;
813                        }
814
815                        // Agregar a la lista de redes guardadas
816                        saved_networks.push(network_info);
817                    }
818                }
819            }
820        }
821
822        Ok(saved_networks)
823    }
824
825    /// Delete a saved WiFi connection by SSID
826    pub fn delete_wifi_connection(&self, ssid: &str) -> Result<bool> {
827        // Crear un proxy para el servicio de configuración de NetworkManager
828        let settings_proxy = zbus::blocking::Proxy::new(
829            &self.connection,
830            "org.freedesktop.NetworkManager",
831            "/org/freedesktop/NetworkManager/Settings",
832            "org.freedesktop.NetworkManager.Settings",
833        )?;
834
835        // Obtener todas las conexiones guardadas
836        let connections: Vec<zbus::zvariant::OwnedObjectPath> =
837            settings_proxy.call("ListConnections", &())?;
838
839        // Procesar cada conexión guardada
840        for conn_path in connections {
841            // Crear un proxy para cada conexión
842            let conn_proxy = zbus::blocking::Proxy::new(
843                &self.connection,
844                "org.freedesktop.NetworkManager",
845                conn_path.as_str(),
846                "org.freedesktop.NetworkManager.Settings.Connection",
847            )?;
848
849            // Obtener la configuración de la conexión como un HashMap
850            let settings: std::collections::HashMap<String, zbus::zvariant::OwnedValue> =
851                conn_proxy.call("GetSettings", &())?;
852
853            // Verificar si es una conexión WiFi
854            if let Some(connection) = settings.get("connection") {
855                let connection_value = connection.to_owned();
856                let connection_dict =
857                    match <zbus::zvariant::Value<'_> as Clone>::clone(&connection_value)
858                        .downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>(
859                    ) {
860                        Some(dict) => dict,
861                        None => continue,
862                    };
863
864                // Verificar el tipo de conexión
865                if let Some(conn_type) = connection_dict.get("type") {
866                    let conn_type_value = conn_type.to_owned();
867                    let conn_type_str =
868                        match <zbus::zvariant::Value<'_> as Clone>::clone(&conn_type_value)
869                            .downcast::<String>()
870                        {
871                            Some(s) => s,
872                            None => continue,
873                        };
874
875                    // Si es una conexión WiFi, verificar el SSID
876                    if conn_type_str == "802-11-wireless" {
877                        if let Some(wireless) = settings.get("802-11-wireless") {
878                            let wireless_value = wireless.to_owned();
879                            let wireless_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&wireless_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
880                                Some(dict) => dict,
881                                None => continue,
882                            };
883
884                            if let Some(ssid_value) = wireless_dict.get("ssid") {
885                                let ssid_owned = ssid_value.to_owned();
886                                if let Some(ssid_bytes) =
887                                    <zbus::zvariant::Value<'_> as Clone>::clone(&ssid_owned)
888                                        .downcast::<Vec<u8>>()
889                                {
890                                    if let Ok(conn_ssid_str) = String::from_utf8(ssid_bytes) {
891                                        // Si el SSID coincide, eliminar la conexión
892                                        if conn_ssid_str == ssid {
893                                            conn_proxy.call::<_, _, ()>("Delete", &())?;
894                                            return Ok(true);
895                                        }
896                                    }
897                                }
898                            }
899                        }
900                    }
901                }
902            }
903        }
904
905        // No se encontró ninguna conexión con el SSID especificado
906        Ok(false)
907    }
908}
909
910/// Initialize the network manager plugin
911pub async fn init(
912    app: &AppHandle<tauri::Wry>,
913    _api: PluginApi<tauri::Wry, ()>,
914) -> Result<VSKNetworkManager<'static, tauri::Wry>> {
915    Ok(VSKNetworkManager::new(app.clone()).await?)
916}