pub(crate) use _scproxy::module_def;
#[pymodule]
mod _scproxy {
use crate::vm::{
Py, PyResult, VirtualMachine,
builtins::{PyDict, PyDictRef, PyStr},
convert::ToPyObject,
};
use system_configuration::core_foundation::{
array::CFArray,
base::{CFType, FromVoid, TCFType},
dictionary::CFDictionary,
number::CFNumber,
string::{CFString, CFStringRef},
};
use system_configuration::sys::{
dynamic_store_copy_specific::SCDynamicStoreCopyProxies, schema_definitions::*,
};
fn proxy_dict() -> Option<CFDictionary<CFString, CFType>> {
let proxy_dict = unsafe { SCDynamicStoreCopyProxies(core::ptr::null()) };
if proxy_dict.is_null() {
None
} else {
Some(unsafe { CFDictionary::wrap_under_create_rule(proxy_dict) })
}
}
#[pyfunction]
fn _get_proxy_settings(vm: &VirtualMachine) -> PyResult<Option<PyDictRef>> {
let Some(proxy_dict) = proxy_dict() else {
return Ok(None);
};
let result = vm.ctx.new_dict();
let v = 0
!= proxy_dict
.find(unsafe { kSCPropNetProxiesExcludeSimpleHostnames })
.and_then(|v| v.downcast::<CFNumber>())
.and_then(|v| v.to_i32())
.unwrap_or(0);
result.set_item("exclude_simple", vm.ctx.new_bool(v).into(), vm)?;
if let Some(an_array) = proxy_dict
.find(unsafe { kSCPropNetProxiesExceptionsList })
.and_then(|v| v.downcast::<CFArray>())
{
let v = an_array
.into_iter()
.map(|s| {
unsafe { CFType::from_void(*s) }
.downcast::<CFString>()
.map(|s| PyStr::from(s.to_string()))
.to_pyobject(vm)
})
.collect();
result.set_item("exceptions", vm.ctx.new_tuple(v).into(), vm)?;
}
Ok(Some(result))
}
#[pyfunction]
fn _get_proxies(vm: &VirtualMachine) -> PyResult<Option<PyDictRef>> {
let Some(proxy_dict) = proxy_dict() else {
return Ok(None);
};
let result = vm.ctx.new_dict();
let set_proxy = |result: &Py<PyDict>,
proto: &str,
enabled_key: CFStringRef,
host_key: CFStringRef,
port_key: CFStringRef|
-> PyResult<()> {
let enabled = 0
!= proxy_dict
.find(enabled_key)
.and_then(|v| v.downcast::<CFNumber>())
.and_then(|v| v.to_i32())
.unwrap_or(0);
if enabled
&& let Some(host) = proxy_dict
.find(host_key)
.and_then(|v| v.downcast::<CFString>())
{
let h = alloc::borrow::Cow::<str>::from(&host);
let v = if let Some(port) = proxy_dict
.find(port_key)
.and_then(|v| v.downcast::<CFNumber>())
.and_then(|v| v.to_i32())
{
format!("http://{h}:{port}")
} else {
format!("http://{h}")
};
result.set_item(proto, vm.new_pyobj(v), vm)?;
}
Ok(())
};
unsafe {
set_proxy(
&result,
"http",
kSCPropNetProxiesHTTPEnable,
kSCPropNetProxiesHTTPProxy,
kSCPropNetProxiesHTTPPort,
)?;
set_proxy(
&result,
"https",
kSCPropNetProxiesHTTPSEnable,
kSCPropNetProxiesHTTPSProxy,
kSCPropNetProxiesHTTPSPort,
)?;
set_proxy(
&result,
"ftp",
kSCPropNetProxiesFTPEnable,
kSCPropNetProxiesFTPProxy,
kSCPropNetProxiesFTPPort,
)?;
set_proxy(
&result,
"gopher",
kSCPropNetProxiesGopherEnable,
kSCPropNetProxiesGopherProxy,
kSCPropNetProxiesGopherPort,
)?;
}
Ok(Some(result))
}
}