@@ -547,4 +547,123 @@ impl NetworkManager {
547547 _ => "Unknown" ,
548548 }
549549 }
550+
551+ pub async fn forget ( & self , ssid : & str ) -> zbus:: Result < ( ) > {
552+ use std:: collections:: HashMap ;
553+ use zvariant:: { OwnedObjectPath , Value } ;
554+
555+ let nm = NMProxy :: new ( & self . conn ) . await ?;
556+
557+ // 1) Disconnect any Wi-Fi device currently connected to this SSID
558+ let devices = nm. get_devices ( ) . await ?;
559+ for dev_path in & devices {
560+ let dev = NMDeviceProxy :: builder ( & self . conn )
561+ . path ( dev_path. clone ( ) ) ?
562+ . build ( )
563+ . await ?;
564+ if dev. device_type ( ) . await ? != 2 {
565+ continue ;
566+ }
567+
568+ let wifi = NMWirelessProxy :: builder ( & self . conn )
569+ . path ( dev_path. clone ( ) ) ?
570+ . build ( )
571+ . await ?;
572+ if let Ok ( ap_path) = wifi. active_access_point ( ) . await
573+ && ap_path. as_str ( ) != "/"
574+ {
575+ let ap = NMAccessPointProxy :: builder ( & self . conn )
576+ . path ( ap_path. clone ( ) ) ?
577+ . build ( )
578+ . await ?;
579+ if let Ok ( bytes) = ap. ssid ( ) . await
580+ && std:: str:: from_utf8 ( & bytes) . ok ( ) == Some ( ssid)
581+ {
582+ let dev_proxy: zbus:: Proxy < ' _ > = zbus:: proxy:: Builder :: new ( & self . conn )
583+ . destination ( "org.freedesktop.NetworkManager" ) ?
584+ . path ( dev_path. clone ( ) ) ?
585+ . interface ( "org.freedesktop.NetworkManager.Device" ) ?
586+ . build ( )
587+ . await ?;
588+ let _ = dev_proxy. call_method ( "Disconnect" , & ( ) ) . await ;
589+
590+ for _ in 0 ..10 {
591+ if dev. state ( ) . await ? == 30 {
592+ break ;
593+ }
594+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 200 ) ) . await ;
595+ }
596+ }
597+ }
598+ }
599+
600+ // 2) Delete any saved profiles for this SSID
601+ let settings: zbus:: Proxy < ' _ > = zbus:: proxy:: Builder :: new ( & self . conn )
602+ . destination ( "org.freedesktop.NetworkManager" ) ?
603+ . path ( "/org/freedesktop/NetworkManager/Settings" ) ?
604+ . interface ( "org.freedesktop.NetworkManager.Settings" ) ?
605+ . build ( )
606+ . await ?;
607+
608+ let list_reply = settings. call_method ( "ListConnections" , & ( ) ) . await ?;
609+ let conns: Vec < OwnedObjectPath > = list_reply. body ( ) . deserialize ( ) ?;
610+
611+ let mut deleted_any = false ;
612+
613+ for cpath in conns {
614+ let cproxy: zbus:: Proxy < ' _ > = zbus:: proxy:: Builder :: new ( & self . conn )
615+ . destination ( "org.freedesktop.NetworkManager" ) ?
616+ . path ( cpath. clone ( ) ) ?
617+ . interface ( "org.freedesktop.NetworkManager.Settings.Connection" ) ?
618+ . build ( )
619+ . await ?;
620+
621+ if let Ok ( id) = cproxy. get_property :: < String > ( "Id" ) . await
622+ && id == ssid
623+ {
624+ let _ = cproxy. call_method ( "Delete" , & ( ) ) . await ;
625+ deleted_any = true ;
626+ continue ;
627+ }
628+
629+ if let Ok ( msg) = cproxy. call_method ( "GetSettings" , & ( ) ) . await {
630+ let body = msg. body ( ) ;
631+ let settings_map: HashMap < String , HashMap < String , Value > > = body. deserialize ( ) ?;
632+
633+ if let Some ( conn_sec) = settings_map. get ( "connection" )
634+ && let Some ( Value :: Str ( id) ) = conn_sec. get ( "id" )
635+ && id. as_str ( ) == ssid
636+ {
637+ let _ = cproxy. call_method ( "Delete" , & ( ) ) . await ;
638+ deleted_any = true ;
639+ continue ;
640+ }
641+
642+ if let Some ( wifi_sec) = settings_map. get ( "802-11-wireless" )
643+ && let Some ( Value :: Array ( arr) ) = wifi_sec. get ( "ssid" )
644+ {
645+ let mut raw = Vec :: new ( ) ;
646+ for v in arr. iter ( ) {
647+ if let Ok ( b) = u8:: try_from ( v. clone ( ) ) {
648+ raw. push ( b) ;
649+ }
650+ }
651+ if std:: str:: from_utf8 ( & raw ) . ok ( ) == Some ( ssid) {
652+ let _ = cproxy. call_method ( "Delete" , & ( ) ) . await ;
653+ deleted_any = true ;
654+ continue ;
655+ }
656+ }
657+ }
658+ }
659+
660+ if deleted_any {
661+ println ! ( "Forgot and disconnected '{ssid}'" ) ;
662+ Ok ( ( ) )
663+ } else {
664+ Err ( zbus:: Error :: Failure ( format ! (
665+ "No saved connection for {ssid}"
666+ ) ) )
667+ }
668+ }
550669}
0 commit comments