use crate::{Error, Result, Sysproxy};
use std::{process::Command, str::from_utf8};
const CMD_KEY: &str = "org.gnome.system.proxy";
impl Sysproxy {
pub fn get_system_proxy() -> Result<Sysproxy> {
let enable = Sysproxy::get_enable()?;
let mut socks = get_proxy("socks")?;
let https = get_proxy("https")?;
let http = get_proxy("http")?;
if socks.host.len() == 0 {
if http.host.len() > 0 {
socks.host = http.host;
socks.port = http.port;
}
if https.host.len() > 0 {
socks.host = https.host;
socks.port = https.port;
}
}
socks.enable = enable;
socks.bypass = Sysproxy::get_bypass().unwrap_or("".into());
Ok(socks)
}
pub fn set_system_proxy(&self) -> Result<()> {
self.set_enable()?;
if self.enable {
self.set_socks()?;
self.set_https()?;
self.set_http()?;
self.set_bypass()?;
}
Ok(())
}
pub fn get_enable() -> Result<bool> {
let mode = gsettings().args(["get", CMD_KEY, "mode"]).output()?;
let mode = from_utf8(&mode.stdout).or(Err(Error::ParseStr))?.trim();
Ok(mode == "'manual'")
}
pub fn get_bypass() -> Result<String> {
let bypass = gsettings()
.args(["get", CMD_KEY, "ignore-hosts"])
.output()?;
let bypass = from_utf8(&bypass.stdout).or(Err(Error::ParseStr))?.trim();
let bypass = bypass.strip_prefix('[').unwrap_or(bypass);
let bypass = bypass.strip_suffix(']').unwrap_or(bypass);
let bypass = bypass
.split(',')
.map(|h| strip_str(h.trim()))
.collect::<Vec<&str>>()
.join(",");
Ok(bypass)
}
pub fn get_http() -> Result<Sysproxy> {
get_proxy("http")
}
pub fn get_https() -> Result<Sysproxy> {
get_proxy("https")
}
pub fn get_socks() -> Result<Sysproxy> {
get_proxy("socks")
}
pub fn set_enable(&self) -> Result<()> {
let mode = if self.enable { "'manual'" } else { "'none'" };
gsettings().args(["set", CMD_KEY, "mode", mode]).status()?;
Ok(())
}
pub fn set_bypass(&self) -> Result<()> {
let bypass = self
.bypass
.split(',')
.map(|h| {
let mut host = String::from(h.trim());
if !host.starts_with('\'') && !host.starts_with('"') {
host = String::from("'") + &host;
}
if !host.ends_with('\'') && !host.ends_with('"') {
host = host + "'";
}
host
})
.collect::<Vec<String>>()
.join(", ");
let bypass = format!("[{bypass}]");
gsettings()
.args(["set", CMD_KEY, "ignore-hosts", bypass.as_str()])
.status()?;
Ok(())
}
pub fn set_http(&self) -> Result<()> {
set_proxy(self, "http")
}
pub fn set_https(&self) -> Result<()> {
set_proxy(self, "https")
}
pub fn set_socks(&self) -> Result<()> {
set_proxy(self, "socks")
}
}
fn gsettings() -> Command {
Command::new("gsettings")
}
fn set_proxy(proxy: &Sysproxy, service: &str) -> Result<()> {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();
let host = format!("'{}'", proxy.host);
let host = host.as_str();
let port = format!("{}", proxy.port);
let port = port.as_str();
gsettings().args(["set", schema, "host", host]).status()?;
gsettings().args(["set", schema, "port", port]).status()?;
Ok(())
}
fn get_proxy(service: &str) -> Result<Sysproxy> {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();
let host = gsettings().args(["get", schema, "host"]).output()?;
let host = from_utf8(&host.stdout).or(Err(Error::ParseStr))?.trim();
let host = strip_str(host);
let port = gsettings().args(["get", schema, "port"]).output()?;
let port = from_utf8(&port.stdout).or(Err(Error::ParseStr))?.trim();
let port = port.parse().unwrap_or(80u16);
Ok(Sysproxy {
enable: false,
host: String::from(host),
port,
bypass: "".into(),
})
}
fn strip_str<'a>(text: &'a str) -> &'a str {
text.strip_prefix('\'')
.unwrap_or(text)
.strip_suffix('\'')
.unwrap_or(text)
}