diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 740113a..afe3b2c 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -38,7 +38,27 @@ AppContext::AppContext(QObject *parent) : QObject{parent} void AppContext::cachePairedDevices() { +#ifndef __APPLE__ m_pairingFileCache = core->get_pairing_files(); +#else + QMap maybeStalePairingFiles = + SettingsManager::sharedInstance()->getAllIdeviceDefaultPairingFiles(); + + for (const QString &mac : maybeStalePairingFiles.keys()) { + const QString path = maybeStalePairingFiles.value(mac); + qDebug() << "Using pairing file" << path << "for MAC:" << mac + << "cached from settings"; + m_pairingFileCache[mac] = QVariant(path); + } + QMap fresh = core->get_pairing_files(); + for (const QString &mac : fresh.keys()) { + const QString path = fresh.value(mac).toString(); + qDebug() << "Using fresh pairing file" << path << "for MAC:" << mac + << "from backend"; + m_pairingFileCache[mac] = QVariant(path); + } + +#endif } void AppContext::addDevice(iDescriptor::Uniq uniq, @@ -361,22 +381,11 @@ void AppContext::tryToConnectToNetworkDevice(const NetworkDevice &device) qDebug() << "No pairing file cached for device with MAC:" << device.macAddress << "Emitting noPairingFileForWirelessDevice event"; - emitNoPairingFileForWirelessDevice(device.macAddress); + emit noPairingFileForWirelessDevice(device.macAddress); return; } - core->init_wireless_device(device.address, - LOCKDOWN_PATH + QString("/") + pairing_file, - device.macAddress); -} - -void AppContext::emitNoPairingFileForWirelessDevice(const QString &udid) -{ - emit noPairingFileForWirelessDevice(udid); -} - -void AppContext::emitInitStarted(const QString &macAddress) -{ - emit initStarted(macAddress); + core->init_wireless_device(device.address, pairing_file, device.macAddress); + emit initStarted(device.macAddress); } void AppContext::handlePairing(iDescriptor::Uniq uniq, bool timeout) diff --git a/src/appcontext.h b/src/appcontext.h index 0ab92c9..b4f993a 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -57,8 +57,6 @@ public: const DeviceSelection &getCurrentDeviceSelection() const; const iDescriptorDevice * getDeviceByMacAddress(const QString &macAddress) const; - void emitNoPairingFileForWirelessDevice(const QString &udid); - void emitInitStarted(const QString &macAddress); private: QMap> m_devices; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4ce27b3..866bb68 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -411,29 +411,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) return; } - qDebug() << "Trying to add network device with MAC:" - << device.macAddress; - - QString pairing_file = - AppContext::sharedInstance()->getCachedPairingFile( - device.macAddress); - - if (pairing_file.isEmpty()) { - qDebug() << "No pairing file cached for device with MAC:" - << device.macAddress - << "Emitting noPairingFileForWirelessDevice event"; - AppContext::sharedInstance() - ->emitNoPairingFileForWirelessDevice(device.macAddress); - return; - } - - qDebug() << "Found cached pairing file for device with MAC:" - << device.macAddress << "IP:" << device.address - << "Initializing wireless connection"; - AppContext::sharedInstance()->core->init_wireless_device( - device.address, LOCKDOWN_PATH + QString("/") + pairing_file, - device.macAddress); - AppContext::sharedInstance()->emitInitStarted(device.macAddress); + AppContext::sharedInstance()->tryToConnectToNetworkDevice(device); }); } diff --git a/src/networkdevicestoconnectwidget.cpp b/src/networkdevicestoconnectwidget.cpp index ef8855f..ca7507a 100644 --- a/src/networkdevicestoconnectwidget.cpp +++ b/src/networkdevicestoconnectwidget.cpp @@ -165,9 +165,15 @@ NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent) updateDeviceList(); + // in case the backend fails to find pairing file connect(AppContext::sharedInstance()->core, &CXX::Core::no_pairing_file, this, &NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice); + + connect(AppContext::sharedInstance(), + &AppContext::noPairingFileForWirelessDevice, this, + &NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice); + connect(AppContext::sharedInstance()->core, &CXX::Core::init_failed, this, &NetworkDevicesToConnectWidget::onDeviceInitFailed); connect(AppContext::sharedInstance(), &AppContext::initStarted, this, diff --git a/src/rust/include/idescriptor_rust.h b/src/rust/include/idescriptor_rust.h deleted file mode 100644 index 216c15b..0000000 --- a/src/rust/include/idescriptor_rust.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int kind; // 1 = connected, 2 = disconnected, 3 = pairing pending, 4 = - // pairing failed - char *udid; -} IdeviceEvent; - -typedef void (*IdeviceEventCallback)(const IdeviceEvent *event); - -void idevice_event_subscribe(IdeviceEventCallback cb); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/src/rust/src/hause_arrest.rs b/src/rust/src/hause_arrest.rs index e52b452..e9d592d 100644 --- a/src/rust/src/hause_arrest.rs +++ b/src/rust/src/hause_arrest.rs @@ -1,14 +1,12 @@ use crate::{APP_DEVICE_STATE, RUNTIME, VIDEO_STREAMS, afc, run_sync, utils}; use cxx_qt::{CxxQtType, Threading}; use cxx_qt_lib::{QByteArray, QMap, QMapPair_QString_QVariant, QString}; -use idevice::{ - afc::{AfcClient, opcode::AfcFopenMode}, -}; +use idevice::afc::{AfcClient, opcode::AfcFopenMode}; use std::pin::Pin; use std::sync::Arc; use tokio::{ - io::{AsyncReadExt}, + io::AsyncReadExt, net::TcpListener, sync::{Mutex, oneshot}, }; @@ -239,11 +237,11 @@ impl qobject::HauseArrest { fn start_video_stream(&self, file_path: &QString) -> QString { let afc_opt = self.rust().afc_handle.clone(); - - let Some(afc) = afc_opt else { - eprintln!("HouseArrest: AfcClient not initialized"); - return QString::default(); - }; + + let Some(afc) = afc_opt else { + eprintln!("HouseArrest: AfcClient not initialized"); + return QString::default(); + }; let udid_str = self.udid.to_string(); let path_str = file_path.to_string(); diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 84ce3dc..1566db8 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -18,8 +18,8 @@ use std::future::Future; use std::sync::mpsc; use std::thread; use tokio::runtime::{Builder, Runtime}; -use tokio::task::JoinHandle; use tokio::sync::oneshot; +use tokio::task::JoinHandle; use core::pin::Pin; use cxx_qt::Threading; @@ -27,16 +27,14 @@ use cxx_qt_lib::{QMap, QMapPair_QString_QVariant, QString, QVariant}; use crate::qobject::Core; use once_cell::sync::Lazy; -use plist::{Value}; -mod afc_services; -mod image_loader; -mod service_manager; -mod screenshot; -mod utils; -mod hause_arrest; +use plist::Value; mod afc; +mod afc_services; +mod hause_arrest; mod io_manager; - +mod screenshot; +mod service_manager; +mod utils; const POSSIBLE_ROOT: &str = "../../../../"; const APP_LABEL: &str = "iDescriptor"; @@ -80,7 +78,6 @@ static RUNTIME: Lazy = Lazy::new(|| { static VIDEO_STREAMS: Lazy>>> = Lazy::new(|| std::sync::Mutex::new(HashMap::new())); - pub fn run_sync(fut: F) -> R where F: Future + Send + 'static, @@ -145,7 +142,7 @@ mod qobject { pub struct RCore; impl qobject::Core { - fn init(self: Pin<&mut Self>) { + fn init(self: Pin<&mut Self>) { self.listen(); } @@ -396,8 +393,11 @@ impl qobject::Core { emit_connected(qt_thread.clone(), udid).await; }); } + /* DISCONNECTED */ Ok(UsbmuxdListenEvent::Disconnected(device_id)) => { if let Some(udid) = device_map.remove(&device_id) { + clean_device_from_app_state(&udid).await; + let qt_thread = qt_t.clone(); qt_thread .queue(move |Core_qobj| { @@ -506,8 +506,9 @@ impl qobject::Core { fn get_pairing_files(self: Pin<&mut Self>) -> QMap { let mut map = QMap::::default(); - let paths = - match std::fs::read_dir(get_lockdown_path()) { + #[cfg(not(target_os = "macos"))] + { + let paths = match std::fs::read_dir(utils::get_lockdown_path()) { Ok(iter) => iter .filter_map(|entry| { let entry = entry.ok()?; @@ -518,49 +519,75 @@ impl qobject::Core { Err(_) => Vec::new(), }; - paths.into_iter().for_each(|path| { - if let Ok(pf) = PairingFile::read_from_file(&path) { - if let Some(fname) = path.file_name().and_then(|s| s.to_str()) { + paths.into_iter().for_each(|path| { + if let Ok(pf) = PairingFile::read_from_file(&path) { + let abs = path.canonicalize().unwrap_or(path); + let abs_str = abs.to_string_lossy().to_string(); + map.insert( QString::from(pf.wifi_mac_address), - QVariant::from(&QString::from(fname)), + QVariant::from(&QString::from(abs_str)), ); } + }); + } + + #[cfg(target_os = "macos")] + { + let entries: Vec<(String, String)> = run_sync(async { + let mut out = Vec::new(); + + if let Ok(mut uc) = UsbmuxdConnection::default().await { + if let Ok(devs) = uc.get_devices().await { + for dev in devs { + if let Ok(pair_rec) = uc.get_pair_record(&dev.udid).await { + out.push(( + pair_rec.wifi_mac_address.clone(), + format!("{}.plist", dev.udid), + )); + } + } + } + } + + out + }); + + let base = utils::get_lockdown_path(); + + // turn $UDID.plist into /var/db/lockdown/UDID.plist + for (wifi_mac, file_name) in entries { + let full_path = base.join(&file_name); + let full_path_str = full_path.to_string_lossy().into_owned(); + + map.insert( + QString::from(wifi_mac), + QVariant::from(&QString::from(full_path_str)), + ); } - }); + } map } fn remove_device(self: Pin<&mut Self>, udid: &QString) { let udid_str = udid.to_string(); RUNTIME.spawn(async move { - let mut state = APP_DEVICE_STATE.lock().await; - if let Some(svc) = state.remove(&udid_str) { - let streams = svc.video_streams.lock().await; - for (_path, flag) in streams.iter() { - flag.store(true, Ordering::Relaxed); - } - println!("Removed device with UDID {}", udid_str); - } else { - eprintln!( - "Attempted to remove non-existent device with UDID {}", - udid_str - ); - } + clean_device_from_app_state(&udid_str).await; }); } } -fn get_lockdown_path() -> String { - #[cfg(target_os = "linux")] - return "/var/lib/lockdown".to_string(); - - #[cfg(target_os = "macos")] - return "/var/db/lockdown".to_string(); - - #[cfg(target_os = "windows")] - return std::env::var("PROGRAMDATA").unwrap_or_else(|_| "C:\\ProgramData".to_string()) - + "/Apple/Lockdown"; +async fn clean_device_from_app_state(udid: &str) { + let mut state = APP_DEVICE_STATE.lock().await; + if let Some(svc) = state.remove(udid) { + let streams = svc.video_streams.lock().await; + for (_path, flag) in streams.iter() { + flag.store(true, Ordering::Relaxed); + } + println!("Removed device with UDID {}", udid); + } else { + eprintln!("Attempted to remove non-existent device with UDID {}", udid); + } } //FIXME: dont spawn hb if init fails @@ -603,9 +630,7 @@ async fn init_idescriptor_device< } eprintln!("init_idescriptor_device: Lockdown session started."); - eprintln!( - "init_idescriptor_device: Attempting to get default values from Lockdown." - ); + eprintln!("init_idescriptor_device: Attempting to get default values from Lockdown."); let mut def_vals = match lc.get_value(None, None).await { Ok(v) => v, Err(e) => { @@ -627,9 +652,7 @@ async fn init_idescriptor_device< } if is_wireless { - eprintln!( - "init_idescriptor_device: Attempting to connect to HeartbeatClient." - ); + eprintln!("init_idescriptor_device: Attempting to connect to HeartbeatClient."); hb = match heartbeat::HeartbeatClient::connect(&provider_for_hb).await { Ok(h) => Some(h), Err(e) => { @@ -660,7 +683,7 @@ async fn init_idescriptor_device< eprintln!("heartbeat: get_marco failed (fail count: {fails}): {e:?}"); if fails >= 3 { eprintln!("heartbeat: too many failures for giving up"); - APP_DEVICE_STATE.lock().await.remove(&udid_for_hb); + clean_device_from_app_state(&udid_for_hb).await; let udid_for_event = udid_for_hb.clone(); let _ = qt_thread_for_hb.queue(move |Core_qobj| { @@ -682,7 +705,7 @@ async fn init_idescriptor_device< eprintln!("heartbeat: send_polo failed (fail count: {fails}): {e:?}"); if fails >= 3 { eprintln!("heartbeat: too many failures for , giving up"); - APP_DEVICE_STATE.lock().await.remove(&udid_for_hb); + clean_device_from_app_state(&udid_for_hb).await; let udid_for_event = udid_for_hb.clone(); let _ = qt_thread_for_hb.queue(move |Core_qobj| { @@ -699,11 +722,9 @@ async fn init_idescriptor_device< } eprintln!("heartbeat: Polo sent successfully."); interval += 5; - // tokio::time::sleep(std::time::Duration::from_secs(interval + 5)).await; } - eprintln!("heartbeat: heartbeat task for ended."); - // loop exits → task ends + eprintln!("heartbeat: heartbeat task ended."); })); } @@ -729,9 +750,7 @@ async fn init_idescriptor_device< } }; - eprintln!( - "init_idescriptor_device: Attempting to connect to AFC client." - ); + eprintln!("init_idescriptor_device: Attempting to connect to AFC client."); let mut afc_client = match AfcClient::connect(&provider).await { Ok(c) => c, Err(e) => { @@ -741,9 +760,7 @@ async fn init_idescriptor_device< }; eprintln!("init_idescriptor_device: Connected to AfcClient."); - eprintln!( - "init_idescriptor_device: Attempting to connect to DiagnosticsRelayClient." - ); + eprintln!("init_idescriptor_device: Attempting to connect to DiagnosticsRelayClient."); let mut diag_relay = match DiagnosticsRelayClient::connect(&provider).await { Ok(c) => c, Err(e) => { @@ -754,7 +771,7 @@ async fn init_idescriptor_device< eprintln!("init_idescriptor_device: Connected to DiagnosticsRelayClient."); // afc_client.set_timeout(Some(5000)).await; - let afc2 = match AfcClient::new_afc2(&provider).await { + let afc2 = match AfcClient::new_afc2(&provider).await { Ok(c) => Some(Arc::new(Mutex::new(c))), Err(e) => { eprintln!("AfcClient::new_afc2 failed: {e:?}"); @@ -829,9 +846,7 @@ async fn init_idescriptor_device< let mut buf = Vec::new(); if def_vals.to_writer_xml(&mut buf).is_err() { - eprintln!( - "init_idescriptor_device: Failed to serialize default values to XML." - ); + eprintln!("init_idescriptor_device: Failed to serialize default values to XML."); return None; } let info = String::from_utf8(buf).ok()?; diff --git a/src/rust/src/service_manager.rs b/src/rust/src/service_manager.rs index fb21f7b..cfd1bff 100644 --- a/src/rust/src/service_manager.rs +++ b/src/rust/src/service_manager.rs @@ -1,25 +1,23 @@ +use crate::{APP_DEVICE_STATE, RUNTIME, utils}; use cxx_qt::Threading; -use cxx_qt_lib::{ - QByteArray, QList, QMap, QMapPair_QString_QVariant, QString, QVariant, -}; -use idevice::{ - IdeviceService, RsdService, amfi, dvt::{ - location_simulation::LocationSimulationClient, remote_server::RemoteServerClient - }, installation_proxy::InstallationProxyClient, mobile_image_mounter::ImageMounter, provider::IdeviceProvider, rsd::RsdHandshake, simulate_location::LocationSimulationService, springboardservices::SpringBoardServicesClient, -}; +use cxx_qt_lib::{QByteArray, QList, QMap, QMapPair_QString_QVariant, QString, QVariant}; use idevice::afc::opcode::AfcFopenMode; use idevice::services::core_device_proxy::CoreDeviceProxy; -use crate::{APP_DEVICE_STATE, RUNTIME, utils}; -use plist::{ Value}; - -use serde_json; -use std::{ - io::{Read}, - pin::Pin, - time::Duration, +use idevice::{ + IdeviceService, RsdService, amfi, + dvt::{location_simulation::LocationSimulationClient, remote_server::RemoteServerClient}, + installation_proxy::InstallationProxyClient, + mobile_image_mounter::ImageMounter, + provider::IdeviceProvider, + rsd::RsdHandshake, + simulate_location::LocationSimulationService, + springboardservices::SpringBoardServicesClient, }; -use plist_macro::plist; +use plist::Value; +use plist_macro::plist; +use serde_json; +use std::{io::Read, pin::Pin, time::Duration}; #[cxx_qt::bridge(namespace = "CXX")] mod qobject { @@ -64,7 +62,6 @@ mod qobject { #[qinvokable] fn set_location(&self, latitude: &QString, longitude: &QString) -> i32; - #[qinvokable] fn fetch_app_icon(&self, bundle_id: QString); @@ -72,7 +69,10 @@ mod qobject { fn cable_info_retrieved(self: Pin<&mut ServiceManager>, info: QString); #[qsignal] - fn mobilegestalt_info_retrieved(self: Pin<&mut ServiceManager>, info: QMap_QString_QVariant); + fn mobilegestalt_info_retrieved( + self: Pin<&mut ServiceManager>, + info: QMap_QString_QVariant, + ); #[qsignal] fn dev_image_mounted(self: Pin<&mut ServiceManager>, success: bool); @@ -81,24 +81,35 @@ mod qobject { fn developer_mode_option_revealed(self: Pin<&mut ServiceManager>, success: bool); #[qsignal] - fn mounted_image_retrieved(self: Pin<&mut ServiceManager>, sig: QByteArray, sig_length: u64); + fn mounted_image_retrieved( + self: Pin<&mut ServiceManager>, + sig: QByteArray, + sig_length: u64, + ); #[qsignal] fn installed_apps_retrieved(self: Pin<&mut ServiceManager>, apps: &QMap_QString_QVariant); #[qsignal] - fn app_icon_loaded(self: Pin<&mut ServiceManager>, bundle_id: QString, icon_data: QByteArray); - + fn app_icon_loaded( + self: Pin<&mut ServiceManager>, + bundle_id: QString, + icon_data: QByteArray, + ); #[qsignal] fn battery_info_updated(self: Pin<&mut ServiceManager>, info: &QString); - #[qinvokable] fn fetch_disk_usage(&self, skip_gallery_usage: bool); #[qsignal] - fn disk_usage_retrieved(self: Pin<&mut ServiceManager>, success: bool, apps_usage: u64, gallery_usage: u64); + fn disk_usage_retrieved( + self: Pin<&mut ServiceManager>, + success: bool, + apps_usage: u64, + gallery_usage: u64, + ); } impl cxx_qt::Threading for ServiceManager {} @@ -130,28 +141,29 @@ impl cxx_qt::Constructor<(QString, u32)> for qobject::ServiceManager { RServiceManager { udid: args.0, ios_version: args.1, - } + } } - fn initialize(self: Pin<&mut Self>, _arguments: Self::InitializeArguments) { - let udid_for_log = self.get_udid().to_string(); - println!("ServiceServiceManager::ServiceManager::initialize called for UDID: {udid_for_log}"); - self.start_update_battery_info_interval(); - } + fn initialize(self: Pin<&mut Self>, _arguments: Self::InitializeArguments) { + let udid_for_log = self.get_udid().to_string(); + println!( + "ServiceServiceManager::ServiceManager::initialize called for UDID: {udid_for_log}" + ); + self.start_update_battery_info_interval(); + } } impl qobject::ServiceManager { - - pub fn start_update_battery_info_interval(self: Pin<&mut Self>) { - let qt_thread = self.qt_thread(); + pub fn start_update_battery_info_interval(self: Pin<&mut Self>) { + let qt_thread = self.qt_thread(); let udid = self.get_udid().to_string(); println!("Starting battery info update interval for device {udid}"); - RUNTIME.spawn(async move { - let mut interval = tokio::time::interval(Duration::from_secs(30)); - - loop { - interval.tick().await; - + RUNTIME.spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(30)); + + loop { + interval.tick().await; + let maybe_device = APP_DEVICE_STATE.lock().await.get(udid.as_str()).cloned(); let device = match maybe_device { @@ -162,21 +174,27 @@ impl qobject::ServiceManager { } }; - println!("start_update_battery_info_interval: Fetching battery info for device {udid}"); + println!( + "start_update_battery_info_interval: Fetching battery info for device {udid}" + ); - utils::get_battery_info(&mut *device.diag.lock().await).await.map(|info| { - let mut buf = Vec::new(); - if Value::Dictionary(info).to_writer_xml(&mut buf).is_ok() { - if let Ok(s) = String::from_utf8(buf) { - qt_thread.queue(move |t| { - t.battery_info_updated(&QString::from(s)); - }).ok(); + utils::get_battery_info(&mut *device.diag.lock().await) + .await + .map(|info| { + let mut buf = Vec::new(); + if Value::Dictionary(info).to_writer_xml(&mut buf).is_ok() { + if let Ok(s) = String::from_utf8(buf) { + qt_thread + .queue(move |t| { + t.battery_info_updated(&QString::from(s)); + }) + .ok(); + } } - } - }); - } - }); - } + }); + } + }); + } fn get_udid(&self) -> &QString { use cxx_qt::CxxQtType; @@ -638,7 +656,6 @@ impl qobject::ServiceManager { }); } - fn fetch_app_icon(&self, bundle_id: QString) { let udid = self.get_udid().to_string(); let qt_t = self.qt_thread(); @@ -684,11 +701,10 @@ impl qobject::ServiceManager { }); } - fn set_location(&self, latitude: &QString, longitude: &QString) -> i32 { let udid = self.get_udid().to_string(); let ios_version = self.get_ios_version(); - + /* FIXME: use RUNTIME.spawn in the future */ @@ -866,16 +882,15 @@ async fn set_device_location_rsd( longitude: f64, ) -> Result<(), idevice::IdeviceError> { let rsd_port = proxy.handshake.server_rsd_port; - let adapter = proxy.create_software_tunnel()?; - let mut adapter = adapter.to_async_handle(); - let stream = adapter.connect(rsd_port).await?; - - let mut handshake = RsdHandshake::new(stream).await?; - - let mut remote_server = - RemoteServerClient::connect_rsd(&mut adapter, &mut handshake).await?; - remote_server.read_message(0).await?; - - let mut location_client = LocationSimulationClient::new(&mut remote_server).await?; - location_client.set(latitude, longitude).await + let adapter = proxy.create_software_tunnel()?; + let mut adapter = adapter.to_async_handle(); + let stream = adapter.connect(rsd_port).await?; + + let mut handshake = RsdHandshake::new(stream).await?; + + let mut remote_server = RemoteServerClient::connect_rsd(&mut adapter, &mut handshake).await?; + remote_server.read_message(0).await?; + + let mut location_client = LocationSimulationClient::new(&mut remote_server).await?; + location_client.set(latitude, longitude).await } diff --git a/src/rust/src/utils.rs b/src/rust/src/utils.rs index a630754..47ca076 100644 --- a/src/rust/src/utils.rs +++ b/src/rust/src/utils.rs @@ -8,6 +8,7 @@ use idevice::{ use plist::Dictionary as PlistDictionary; use plist_macro::plist; use rusqlite::Connection; +use std::path::PathBuf; pub async fn get_battery_info(diag: &mut DiagnosticsRelayClient) -> Option { match diag.ioregistry(None, None, Some("IOPMPowerSource")).await { @@ -118,3 +119,30 @@ pub fn query_gallery_usage(db_bytes: &mut Vec) -> Result PathBuf { + if let Ok(val) = std::env::var("USBMUXD_PAIRING_FILES_LOCATION") { + if !val.is_empty() { + eprintln!("Pulling pairing files from USBMUXD_PAIRING_FILES_LOCATION: {val}"); + return PathBuf::from(val); + } + } + + #[cfg(target_os = "linux")] + { + PathBuf::from("/var/lib/lockdown") + } + + #[cfg(target_os = "macos")] + { + PathBuf::from("/var/db/lockdown") + } + + #[cfg(target_os = "windows")] + { + let base = std::env::var_os("PROGRAMDATA") + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from(r"C:\ProgramData")); + base.join("Apple").join("Lockdown") + } +}