use std::{
collections::HashMap,
fmt,
net::{Ipv4Addr, Ipv6Addr},
sync::Arc,
};
use zvariant::{OwnedObjectPath, OwnedValue};
use crate::models::{FromSetting, IpAddress, IpRoute, Property};
pub(crate) type RawSettings = HashMap<String, HashMap<String, OwnedValue>>;
#[non_exhaustive]
#[derive(Clone)]
pub struct SavedConnection {
pub path: OwnedObjectPath,
pub uuid: String,
pub id: String,
pub connection_type: String,
pub interface_name: Option<String>,
pub autoconnect: bool,
pub autoconnect_priority: i32,
pub timestamp_unix: u64,
pub permissions: Vec<String>,
pub unsaved: bool,
pub filename: Option<String>,
pub summary: SettingsSummary,
pub ipv4: Option<IpSettings<Ipv4Addr>>,
pub ipv6: Option<IpSettings<Ipv6Addr>>,
pub(crate) settings: Arc<RawSettings>,
}
impl SavedConnection {
#[must_use]
pub fn get_property<T: FromSetting>(&self, property: Property<T>) -> Option<T> {
self.settings
.get(property.section())?
.get(property.key())
.and_then(T::from_setting)
}
#[must_use]
pub fn sections(&self) -> Vec<&str> {
let mut sections: Vec<&str> = self.settings.keys().map(String::as_str).collect();
sections.sort_unstable();
sections
}
#[must_use]
pub fn has_section(&self, section: &str) -> bool {
self.settings.contains_key(section)
}
}
impl fmt::Debug for SavedConnection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SavedConnection")
.field("path", &self.path)
.field("uuid", &self.uuid)
.field("id", &self.id)
.field("connection_type", &self.connection_type)
.field("interface_name", &self.interface_name)
.field("autoconnect", &self.autoconnect)
.field("autoconnect_priority", &self.autoconnect_priority)
.field("timestamp_unix", &self.timestamp_unix)
.field("permissions", &self.permissions)
.field("unsaved", &self.unsaved)
.field("filename", &self.filename)
.field("summary", &self.summary)
.field("ipv4", &self.ipv4)
.field("ipv6", &self.ipv6)
.field("sections", &self.sections())
.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct SavedConnectionBrief {
pub path: OwnedObjectPath,
pub uuid: String,
pub id: String,
pub connection_type: String,
}
#[non_exhaustive]
#[derive(Debug, Default, Clone)]
pub struct SettingsPatch {
pub autoconnect: Option<bool>,
pub autoconnect_priority: Option<i32>,
pub id: Option<String>,
pub interface_name: Option<Option<String>>,
pub raw_overlay: Option<HashMap<String, HashMap<String, OwnedValue>>>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct VpnSecretFlags(pub u32);
impl VpnSecretFlags {
pub const AGENT_OWNED: u32 = 0x1;
#[must_use]
pub fn agent_owned(self) -> bool {
self.0 & Self::AGENT_OWNED != 0
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WifiKeyMgmt {
None,
Wep,
WpaPsk,
WpaEap,
Sae,
Owe,
OweTransitionMode,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WifiSecuritySummary {
pub key_mgmt: WifiKeyMgmt,
pub has_psk_field: bool,
pub psk_agent_owned: bool,
pub eap_methods: Vec<String>,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum SettingsSummary {
Wifi {
ssid: String,
mode: Option<String>,
security: Option<WifiSecuritySummary>,
band: Option<String>,
channel: Option<u32>,
bssid: Option<String>,
hidden: bool,
mac_randomization: Option<String>,
},
Ethernet {
mac_address: Option<String>,
auto_negotiate: Option<bool>,
speed_mbps: Option<u32>,
mtu: Option<u32>,
},
Vpn {
service_type: String,
user_name: Option<String>,
password_flags: VpnSecretFlags,
data_keys: Vec<String>,
persistent: bool,
},
WireGuard {
listen_port: Option<u16>,
mtu: Option<u32>,
fwmark: Option<u32>,
peer_count: usize,
first_peer_endpoint: Option<String>,
},
Gsm {
apn: Option<String>,
user_name: Option<String>,
password_flags: u32,
pin_flags: u32,
},
Cdma {
number: Option<String>,
user_name: Option<String>,
password_flags: u32,
},
Bluetooth {
bdaddr: String,
bt_type: String,
},
Other {
sections: Vec<String>,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IpSettings<A> {
pub method: IpMethod,
pub addresses: Vec<IpAddress<A>>,
pub gateway: Option<A>,
pub dns: Vec<A>,
pub dns_search: Vec<String>,
pub routes: Vec<IpRoute<A>>,
pub never_default: bool,
pub ignore_auto_dns: bool,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IpMethod {
Auto,
Dhcp,
Manual,
Disabled,
LinkLocal,
Shared,
Ignore,
Other(String),
}
impl From<String> for IpMethod {
fn from(value: String) -> Self {
match value.as_str() {
"auto" => Self::Auto,
"dhcp" => Self::Dhcp,
"manual" => Self::Manual,
"disabled" => Self::Disabled,
"link-local" => Self::LinkLocal,
"shared" => Self::Shared,
"ignore" => Self::Ignore,
_ => Self::Other(value),
}
}
}