pub(crate) use _scproxy::module_def; #[pymodule] mod _scproxy { // straight-forward port of Modules/_scproxy.c 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> { // Py_BEGIN_ALLOW_THREADS let proxy_dict = unsafe { SCDynamicStoreCopyProxies(core::ptr::null()) }; // Py_END_ALLOW_THREADS if proxy_dict.is_null() { None } else { Some(unsafe { CFDictionary::wrap_under_create_rule(proxy_dict) }) } } #[pyfunction] fn _get_proxy_settings(vm: &VirtualMachine) -> PyResult> { 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::()) .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::()) { let v = an_array .into_iter() .map(|s| { unsafe { CFType::from_void(*s) } .downcast::() .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> { let Some(proxy_dict) = proxy_dict() else { return Ok(None); }; let result = vm.ctx.new_dict(); let set_proxy = |result: &Py, 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::()) .and_then(|v| v.to_i32()) .unwrap_or(0); if enabled && let Some(host) = proxy_dict .find(host_key) .and_then(|v| v.downcast::()) { let h = alloc::borrow::Cow::::from(&host); let v = if let Some(port) = proxy_dict .find(port_key) .and_then(|v| v.downcast::()) .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)) } }