ReSet/src/components/wifi/wifi_options.rs

391 lines
16 KiB
Rust

use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use adw::glib::Object;
use adw::prelude::{ActionRowExt, ComboRowExt, PreferencesGroupExt};
use adw::subclass::prelude::ObjectSubclassIsExt;
use adw::{gio, glib};
use dbus::arg::PropMap;
use dbus::{Error, Path};
use glib::{clone, PropertySet};
use gtk::prelude::{ButtonExt, EditableExt, WidgetExt};
use IpProtocol::{IPv4, IPv6};
use ReSet_Lib::network::connection::{Connection, DNSMethod4, DNSMethod6, Enum, TypeSettings};
use crate::components::wifi::utils::IpProtocol;
use crate::components::wifi::wifi_address_entry::WifiAddressEntry;
use crate::components::wifi::wifi_options_impl;
use crate::components::wifi::wifi_route_entry::WifiRouteEntry;
glib::wrapper! {
pub struct WifiOptions(ObjectSubclass<wifi_options_impl::WifiOptions>)
@extends adw::NavigationPage, gtk::Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
unsafe impl Send for WifiOptions {}
unsafe impl Sync for WifiOptions {}
impl WifiOptions {
pub fn new(connection: Connection, access_point: Path<'static>) -> Arc<Self> {
let wifi_option: Arc<WifiOptions> = Arc::new(Object::builder().build());
wifi_option.imp().connection.set(connection);
wifi_option.initialize_ui();
setup_callbacks(&wifi_option, access_point);
wifi_option
}
pub fn initialize_ui(&self) {
let self_imp = self.imp();
let ip4_address_length;
let ip4_route_length;
let ip6_address_length;
let ip6_route_length;
{
let conn = self_imp.connection.borrow();
ip4_address_length = conn.ipv4.address_data.len();
ip4_route_length = conn.ipv4.route_data.len();
ip6_address_length = conn.ipv4.address_data.len();
ip6_route_length = conn.ipv4.route_data.len();
// General
self_imp
.reset_wifi_auto_connect
.set_active(conn.settings.autoconnect);
self_imp
.reset_wifi_metered
.set_active(conn.settings.metered != -1);
match &conn.device {
TypeSettings::WIFI(wifi) => {
self_imp.reset_wifi_link_speed.set_visible(false);
self_imp.reset_wifi_ip4_addr.set_visible(false);
self_imp.reset_wifi_ip6_addr.set_visible(false);
self_imp.reset_wifi_dns.set_visible(false);
self_imp.reset_wifi_gateway.set_visible(false);
self_imp.reset_wifi_last_used.set_visible(true);
self_imp.reset_wifi_mac.set_subtitle(&wifi.cloned_mac_address);
self_imp
.reset_wifi_name
.set_subtitle(&String::from_utf8(wifi.ssid.clone()).unwrap_or_default());
}
TypeSettings::ETHERNET(ethernet) => {
self_imp.reset_wifi_link_speed.set_visible(true);
self_imp.reset_wifi_ip4_addr.set_visible(true);
self_imp.reset_wifi_ip6_addr.set_visible(true);
self_imp.reset_wifi_dns.set_visible(true);
self_imp.reset_wifi_gateway.set_visible(true);
self_imp.reset_wifi_last_used.set_visible(false);
self_imp
.reset_wifi_mac
.set_subtitle(&ethernet.cloned_mac_address);
self_imp
.reset_wifi_link_speed
.set_subtitle(&ethernet.speed.to_string());
}
TypeSettings::VPN(_vpn) => {}
TypeSettings::None => {}
};
// IPv4
self_imp
.reset_ip4_method
.set_selected(conn.ipv4.dns_method.to_i32() as u32);
self.set_ip4_visibility(conn.ipv4.dns_method.to_i32() as u32);
let ipv4_dns: Vec<String> = conn
.ipv4
.dns
.iter()
.map(|addr| {
addr.iter()
.map(|octet| octet.to_string())
.collect::<Vec<String>>()
.join(".")
})
.collect();
self_imp.reset_ip4_dns.set_text(&ipv4_dns.join(", "));
self_imp.reset_ip4_gateway.set_text(&conn.ipv4.gateway);
// IPv6
self_imp
.reset_ip6_method
.set_selected(conn.ipv6.dns_method.to_i32() as u32);
self.set_ip6_visibility(conn.ipv6.dns_method.to_i32() as u32);
let ipv6_dns: Vec<String> = conn
.ipv6
.dns
.iter()
.map(|addr| {
addr.iter()
.map(|octet| octet.to_string())
.collect::<Vec<String>>()
.join(":")
})
.collect();
self_imp.reset_ip6_dns.set_text(&ipv6_dns.join(", "));
self_imp.reset_ip6_gateway.set_text(&conn.ipv6.gateway);
// Security
if let TypeSettings::WIFI(wifi) = &conn.device {
match wifi.security_settings.key_management.as_str() {
"none" => {
self_imp.reset_wifi_security_dropdown.set_selected(0);
self_imp.reset_wifi_password.set_visible(false);
self_imp.reset_wifi_password.set_text("");
}
"wpa-psk" => {
self_imp.reset_wifi_security_dropdown.set_selected(1);
self_imp.reset_wifi_password.set_visible(true);
self_imp
.reset_wifi_password
.set_text(&wifi.security_settings.psk);
}
_ => {}
}
}
}
// IPv4
for i in 0..ip4_address_length {
let address = &WifiAddressEntry::new(Some(i), self_imp.connection.clone(), IPv4);
self_imp.reset_ip4_address_group.add(address);
}
let address = &WifiAddressEntry::new(None, self_imp.connection.clone(), IPv4);
self_imp.reset_ip4_address_group.add(address);
for i in 0..ip4_route_length {
let route = &WifiRouteEntry::new(Some(i), self_imp.connection.clone(), IPv4);
self_imp.reset_ip4_routes_group.add(route)
}
let route = &WifiRouteEntry::new(None, self_imp.connection.clone(), IPv4);
self_imp.reset_ip4_routes_group.add(route);
// IPv6
for i in 0..ip6_address_length {
let address = &WifiAddressEntry::new(Some(i), self_imp.connection.clone(), IPv6);
self_imp.reset_ip6_address_group.add(address);
}
let address = &WifiAddressEntry::new(None, self_imp.connection.clone(), IPv6);
self_imp.reset_ip6_address_group.add(address);
for i in 0..ip6_route_length {
let route = &WifiRouteEntry::new(Some(i), self_imp.connection.clone(), IPv6);
self_imp.reset_ip6_routes_group.add(route);
}
let route = &WifiRouteEntry::new(None, self_imp.connection.clone(), IPv6);
self_imp.reset_ip6_routes_group.add(route);
// Security
}
pub fn set_ip4_visibility(&self, method: u32) {
let self_imp = self.imp();
match method {
0 => {
// auto
self_imp.reset_ip4_address_group.set_visible(false);
self_imp.reset_ip4_routes_group.set_visible(true);
self_imp.reset_ip4_gateway.set_visible(false);
}
1 => {
// manual
self_imp.reset_ip4_address_group.set_visible(true);
self_imp.reset_ip4_routes_group.set_visible(true);
self_imp.reset_ip4_gateway.set_visible(true);
}
_ => {
self_imp.reset_ip4_address_group.set_visible(false);
self_imp.reset_ip4_routes_group.set_visible(false);
self_imp.reset_ip4_gateway.set_visible(false);
}
}
}
pub fn set_ip6_visibility(&self, method: u32) {
let self_imp = self.imp();
match method {
0 | 1 => {
// auto, dhcp
self_imp.reset_ip6_address_group.set_visible(false);
self_imp.reset_ip6_routes_group.set_visible(true);
self_imp.reset_ip6_gateway.set_visible(false);
}
2 => {
// manual
self_imp.reset_ip6_address_group.set_visible(true);
self_imp.reset_ip6_routes_group.set_visible(true);
self_imp.reset_ip6_gateway.set_visible(true);
}
_ => {
self_imp.reset_ip6_address_group.set_visible(false);
self_imp.reset_ip6_routes_group.set_visible(false);
self_imp.reset_ip6_gateway.set_visible(false);
}
}
}
}
fn setup_callbacks(wifi_options: &Arc<WifiOptions>, path: Path<'static>) {
let imp = wifi_options.imp();
// General
imp.reset_wifi_auto_connect
.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.autoconnect = x.is_active();
}));
imp.reset_wifi_metered
.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.metered = if x.is_active() { 1 } else { 2 };
}));
imp.wifi_options_apply_button
.connect_clicked(clone!(@weak imp => move |_| {
let prop = imp.connection.borrow().convert_to_propmap();
set_connection_settings(path.clone(), prop);
}));
// IPv4
let wifi_options_ip4 = wifi_options.clone();
imp.reset_ip4_method
.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
let mut conn = imp.connection.borrow_mut();
conn.ipv4.dns_method = DNSMethod4::from_i32(selected as i32);
wifi_options_ip4.set_ip4_visibility(selected);
}));
imp.reset_ip4_dns
.connect_changed(clone!(@weak imp => move |entry| {
let dns_input = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv4.dns.clear();
if dns_input.is_empty() {
imp.reset_ip4_dns.remove_css_class("error");
return;
}
for dns_entry in dns_input.as_str().split(',').map(|s| s.trim()) {
if let Ok(addr) = Ipv4Addr::from_str(dns_entry) {
imp.reset_ip4_dns.remove_css_class("error");
conn.ipv4.dns.push(addr.octets().to_vec());
} else {
imp.reset_ip4_dns.add_css_class("error");
}
}
}));
imp.reset_ip4_address_add_button
.connect_clicked(clone!(@weak imp => move |_| {
let address = &WifiAddressEntry::new(None, imp.connection.clone(), IpProtocol::IPv4);
imp.reset_ip4_address_group.add(address);
}));
imp.reset_ip4_gateway
.connect_changed(clone!(@weak imp => move |entry| {
let gateway_input = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv4.gateway.clear();
if gateway_input.is_empty() {
imp.reset_ip4_gateway.remove_css_class("error");
return;
}
if Ipv4Addr::from_str(gateway_input.as_str()).is_ok() {
imp.reset_ip4_gateway.remove_css_class("error");
conn.ipv4.gateway = gateway_input.to_string();
} else {
imp.reset_ip4_gateway.add_css_class("error");
}
}));
// IPv6
let wifi_options_ip6 = wifi_options.clone();
imp.reset_ip6_method
.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
let mut conn = imp.connection.borrow_mut();
conn.ipv6.dns_method = DNSMethod6::from_i32(selected as i32);
wifi_options_ip6.set_ip6_visibility(selected);
}));
imp.reset_ip6_dns
.connect_changed(clone!(@weak imp => move |entry| {
let dns_input = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv6.dns.clear();
if dns_input.is_empty() {
imp.reset_ip6_dns.remove_css_class("error");
return;
}
for dns_entry in dns_input.as_str().split(',').map(|s| s.trim()) {
if let Ok(addr) = Ipv6Addr::from_str(dns_entry) {
imp.reset_ip6_dns.remove_css_class("error");
conn.ipv6.dns.push(addr.octets().to_vec());
} else {
imp.reset_ip6_dns.add_css_class("error");
}
}
}));
imp.reset_ip6_address_add_button
.connect_clicked(clone!(@weak imp => move |_| {
let address = &WifiAddressEntry::new(None, imp.connection.clone(), IpProtocol::IPv4);
imp.reset_ip6_address_group.add(address);
}));
imp.reset_ip6_gateway
.connect_changed(clone!(@weak imp => move |entry| {
let gateway_input = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv6.gateway.clear();
if gateway_input.is_empty() {
imp.reset_ip6_gateway.remove_css_class("error");
return;
}
if Ipv6Addr::from_str(gateway_input.as_str()).is_ok() {
imp.reset_ip6_gateway.remove_css_class("error");
conn.ipv6.gateway = gateway_input.to_string();
} else {
imp.reset_ip6_gateway.add_css_class("error");
}
}));
// Security
imp.reset_wifi_security_dropdown
.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
let mut conn = imp.connection.borrow_mut();
match (selected, &mut conn.device) {
(0 , TypeSettings::WIFI(wifi)) => { // None
imp.reset_wifi_password.set_visible(false);
wifi.security_settings.key_management = String::from("none");
wifi.security_settings.authentication_algorithm = String::from("open");
},
(1 , TypeSettings::WIFI(wifi)) => { // WPA/WPA2 Personal
imp.reset_wifi_password.set_visible(true);
wifi.security_settings.key_management = String::from("wpa-psk");
wifi.security_settings.authentication_algorithm = String::from("");
},
(_, _) => {}
}
}));
imp.reset_wifi_password
.connect_changed(clone!(@weak imp => move |entry| {
let password_input = entry.text();
let mut conn = imp.connection.borrow_mut();
if let TypeSettings::WIFI(wifi) = &mut conn.device {
wifi.security_settings.psk = password_input.to_string();
}
}));
}
fn set_connection_settings(path: Path<'static>, prop: PropMap) {
gio::spawn_blocking(move || {
let conn = dbus::blocking::Connection::new_session().unwrap();
let proxy = conn.with_proxy(
"org.Xetibo.ReSetDaemon",
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let _: Result<(bool,), Error> = proxy.method_call(
"org.Xetibo.ReSetWireless",
"SetConnectionSettings",
(path, prop),
);
});
}