diff --git a/idevice/src/plist_macro.rs b/idevice/src/plist_macro.rs index c117179..3453b43 100644 --- a/idevice/src/plist_macro.rs +++ b/idevice/src/plist_macro.rs @@ -52,6 +52,23 @@ /// ``` #[macro_export] macro_rules! plist { + // Force: dictionary out + (dict { $($tt:tt)+ }) => {{ + let mut object = plist::Dictionary::new(); + $crate::plist_internal!(@object object () ($($tt)+) ($($tt)+)); + object + }}; + + // Force: value out (explicit, though default already does this) + (value { $($tt:tt)+ }) => { + $crate::plist_internal!({ $($tt)+ }) + }; + + // Force: raw vec of plist::Value out + (array [ $($tt:tt)+ ]) => { + $crate::plist_internal!(@array [] $($tt)+) + }; + // Hide distracting implementation details from the generated rustdoc. ($($plist:tt)+) => { $crate::plist_internal!($($plist)+) diff --git a/idevice/src/services/core_device/app_service.rs b/idevice/src/services/core_device/app_service.rs index d4a2952..eedd185 100644 --- a/idevice/src/services/core_device/app_service.rs +++ b/idevice/src/services/core_device/app_service.rs @@ -143,12 +143,13 @@ impl AppServiceClient { internal_apps: bool, default_apps: bool, ) -> Result, IdeviceError> { - let mut options = plist::Dictionary::new(); - options.insert("includeAppClips".into(), app_clips.into()); - options.insert("includeRemovableApps".into(), removable_apps.into()); - options.insert("includeHiddenApps".into(), hidden_apps.into()); - options.insert("includeInternalApps".into(), internal_apps.into()); - options.insert("includeDefaultApps".into(), default_apps.into()); + let options = crate::plist!(dict { + "includeAppClips": app_clips, + "includeRemovableApps": removable_apps, + "includeHiddenApps": hidden_apps, + "includeInternalApps": internal_apps, + "includeDefaultApps": default_apps, + }); let res = self .inner .invoke("com.apple.coredevice.feature.listapps", Some(options)) diff --git a/idevice/src/services/dvt/process_control.rs b/idevice/src/services/dvt/process_control.rs index c1f6edb..f31d046 100644 --- a/idevice/src/services/dvt/process_control.rs +++ b/idevice/src/services/dvt/process_control.rs @@ -98,9 +98,10 @@ impl<'a, R: ReadWrite> ProcessControlClient<'a, R> { "launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:" .into(), ); - let mut options = Dictionary::new(); - options.insert("StartSuspendedKey".into(), start_suspended.into()); - options.insert("KillExisting".into(), kill_existing.into()); + let options = crate::plist!(dict { + "StartSuspendedKey": start_suspended, + "KillExisting": kill_existing + }); let env_vars = match env_vars { Some(e) => e, diff --git a/idevice/src/services/heartbeat.rs b/idevice/src/services/heartbeat.rs index 745abaf..f198d48 100644 --- a/idevice/src/services/heartbeat.rs +++ b/idevice/src/services/heartbeat.rs @@ -90,11 +90,10 @@ impl HeartbeatClient { /// # Errors /// Returns `IdeviceError` if the message fails to send pub async fn send_polo(&mut self) -> Result<(), IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "Polo".into()); - self.idevice - .send_plist(plist::Value::Dictionary(req.clone())) - .await?; + let req = crate::plist!({ + "Command": "Polo" + }); + self.idevice.send_plist(req).await?; Ok(()) } } diff --git a/idevice/src/services/installation_proxy.rs b/idevice/src/services/installation_proxy.rs index 9cf28fb..325d210 100644 --- a/idevice/src/services/installation_proxy.rs +++ b/idevice/src/services/installation_proxy.rs @@ -70,22 +70,15 @@ impl InstallationProxyClient { bundle_identifiers: Option>, ) -> Result, IdeviceError> { let application_type = application_type.unwrap_or("Any"); - let mut options = plist::Dictionary::new(); - if let Some(ids) = bundle_identifiers { - let ids = ids - .into_iter() - .map(plist::Value::String) - .collect::>(); - options.insert("BundleIDs".into(), ids.into()); - } - options.insert("ApplicationType".into(), application_type.into()); - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "Lookup".into()); - req.insert("ClientOptions".into(), plist::Value::Dictionary(options)); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "Lookup", + "ClientOptions": { + "ApplicationType": application_type, + "BundleIDs":? bundle_identifiers, + } + }); + self.idevice.send_plist(req).await?; let mut res = self.idevice.read_plist().await?; match res.remove("LookupResult") { @@ -155,14 +148,13 @@ impl InstallationProxyClient { let package_path = package_path.into(); let options = options.unwrap_or(plist::Value::Dictionary(Dictionary::new())); - let mut command = Dictionary::new(); - command.insert("Command".into(), "Install".into()); - command.insert("ClientOptions".into(), options); - command.insert("PackagePath".into(), package_path.into()); + let command = crate::plist!({ + "Command": "Install", + "ClientOptions": options, + "PackagePath": package_path, + }); - self.idevice - .send_plist(plist::Value::Dictionary(command)) - .await?; + self.idevice.send_plist(command).await?; self.watch_completion(callback, state).await } @@ -220,14 +212,13 @@ impl InstallationProxyClient { let package_path = package_path.into(); let options = options.unwrap_or(plist::Value::Dictionary(Dictionary::new())); - let mut command = Dictionary::new(); - command.insert("Command".into(), "Upgrade".into()); - command.insert("ClientOptions".into(), options); - command.insert("PackagePath".into(), package_path.into()); + let command = crate::plist!({ + "Command": "Upgrade", + "ClientOptions": options, + "PackagePath": package_path, + }); - self.idevice - .send_plist(plist::Value::Dictionary(command)) - .await?; + self.idevice.send_plist(command).await?; self.watch_completion(callback, state).await } @@ -285,14 +276,13 @@ impl InstallationProxyClient { let bundle_id = bundle_id.into(); let options = options.unwrap_or(plist::Value::Dictionary(Dictionary::new())); - let mut command = Dictionary::new(); - command.insert("Command".into(), "Uninstall".into()); - command.insert("ApplicationIdentifier".into(), bundle_id.into()); - command.insert("ClientOptions".into(), options); + let command = crate::plist!({ + "Command": "Uninstall", + "ApplicationIdentifier": bundle_id, + "ClientOptions": options, + }); - self.idevice - .send_plist(plist::Value::Dictionary(command)) - .await?; + self.idevice.send_plist(command).await?; self.watch_completion(callback, state).await } @@ -317,14 +307,13 @@ impl InstallationProxyClient { ) -> Result { let options = options.unwrap_or(plist::Value::Dictionary(Dictionary::new())); - let mut command = Dictionary::new(); - command.insert("Command".into(), "CheckCapabilitiesMatch".into()); - command.insert("ClientOptions".into(), options); - command.insert("Capabilities".into(), capabilities.into()); + let command = crate::plist!({ + "Command": "CheckCapabilitiesMatch", + "ClientOptions": options, + "Capabilities": capabilities + }); - self.idevice - .send_plist(plist::Value::Dictionary(command)) - .await?; + self.idevice.send_plist(command).await?; let mut res = self.idevice.read_plist().await?; if let Some(caps) = res.remove("LookupResult").and_then(|x| x.as_boolean()) { @@ -355,13 +344,12 @@ impl InstallationProxyClient { ) -> Result, IdeviceError> { let options = options.unwrap_or(plist::Value::Dictionary(Dictionary::new())); - let mut command = Dictionary::new(); - command.insert("Command".into(), "Browse".into()); - command.insert("ClientOptions".into(), options); + let command = crate::plist!({ + "Command": "Browse", + "ClientOptions": options, + }); - self.idevice - .send_plist(plist::Value::Dictionary(command)) - .await?; + self.idevice.send_plist(command).await?; let mut values = Vec::new(); loop { diff --git a/idevice/src/services/lockdown.rs b/idevice/src/services/lockdown.rs index 3ef2133..7c07972 100644 --- a/idevice/src/services/lockdown.rs +++ b/idevice/src/services/lockdown.rs @@ -93,20 +93,13 @@ impl LockdownClient { key: Option<&str>, domain: Option<&str>, ) -> Result { - let mut request = plist::Dictionary::new(); - request.insert("Label".into(), self.idevice.label.clone().into()); - request.insert("Request".into(), "GetValue".into()); - - if let Some(key) = key { - request.insert("Key".into(), key.into()); - } - if let Some(domain) = domain { - request.insert("Domain".into(), domain.into()); - } - - self.idevice - .send_plist(plist::Value::Dictionary(request)) - .await?; + let request = crate::plist!({ + "Label": self.idevice.label.clone(), + "Request": "GetValue", + "Key":? key, + "Domain":? domain + }); + self.idevice.send_plist(request).await?; let message: plist::Dictionary = self.idevice.read_plist().await?; match message.get("Value") { Some(m) => Ok(m.to_owned()), @@ -138,19 +131,15 @@ impl LockdownClient { ) -> Result<(), IdeviceError> { let key = key.into(); - let mut req = plist::Dictionary::new(); - req.insert("Label".into(), self.idevice.label.clone().into()); - req.insert("Request".into(), "SetValue".into()); - req.insert("Key".into(), key.into()); - req.insert("Value".into(), value); + let req = crate::plist!({ + "Label": self.idevice.label.clone(), + "Request": "SetValue", + "Key": key, + "Value": value, + "Domain":? domain + }); - if let Some(domain) = domain { - req.insert("Domain".into(), domain.into()); - } - - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + self.idevice.send_plist(req).await?; self.idevice.read_plist().await?; Ok(()) @@ -177,28 +166,14 @@ impl LockdownClient { return Err(IdeviceError::NoEstablishedConnection); } - let mut request = plist::Dictionary::new(); - request.insert( - "Label".to_string(), - plist::Value::String(self.idevice.label.clone()), - ); + let request = crate::plist!({ + "Label": self.idevice.label.clone(), + "Request": "StartSession", + "HostID": pairing_file.host_id.clone(), + "SystemBUID": pairing_file.system_buid.clone() - request.insert( - "Request".to_string(), - plist::Value::String("StartSession".to_string()), - ); - request.insert( - "HostID".to_string(), - plist::Value::String(pairing_file.host_id.clone()), - ); - request.insert( - "SystemBUID".to_string(), - plist::Value::String(pairing_file.system_buid.clone()), - ); - - self.idevice - .send_plist(plist::Value::Dictionary(request)) - .await?; + }); + self.idevice.send_plist(request).await?; let response = self.idevice.read_plist().await?; match response.get("EnableSessionSSL") { @@ -236,12 +211,11 @@ impl LockdownClient { identifier: impl Into, ) -> Result<(u16, bool), IdeviceError> { let identifier = identifier.into(); - let mut req = plist::Dictionary::new(); - req.insert("Request".into(), "StartService".into()); - req.insert("Service".into(), identifier.into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Request": "StartService", + "Service": identifier, + }); + self.idevice.send_plist(req).await?; let response = self.idevice.read_plist().await?; let ssl = match response.get("EnableServiceSSL") { @@ -307,37 +281,29 @@ impl LockdownClient { }; let ca = crate::ca::generate_certificates(&pub_key, None).unwrap(); - let mut pair_record = plist::Dictionary::new(); - pair_record.insert("DevicePublicKey".into(), plist::Value::Data(pub_key)); - pair_record.insert("DeviceCertificate".into(), plist::Value::Data(ca.dev_cert)); - pair_record.insert( - "HostCertificate".into(), - plist::Value::Data(ca.host_cert.clone()), - ); - pair_record.insert("HostID".into(), host_id.into()); - pair_record.insert("RootCertificate".into(), plist::Value::Data(ca.host_cert)); - pair_record.insert( - "RootPrivateKey".into(), - plist::Value::Data(ca.private_key.clone()), - ); - pair_record.insert("WiFiMACAddress".into(), wifi_mac.into()); - pair_record.insert("SystemBUID".into(), system_buid.into()); + let mut pair_record = crate::plist!(dict { + "DevicePublicKey": pub_key, + "DeviceCertificate": ca.dev_cert, + "HostCertificate": ca.host_cert.clone(), + "HostID": host_id, + "RootCertificate": ca.host_cert, + "RootPrivateKey": ca.private_key.clone(), + "WiFiMACAddress": wifi_mac, + "SystemBUID": system_buid, + }); - let mut options = plist::Dictionary::new(); - options.insert("ExtendedPairingErrors".into(), true.into()); - - let mut req = plist::Dictionary::new(); - req.insert("Label".into(), self.idevice.label.clone().into()); - req.insert("Request".into(), "Pair".into()); - req.insert( - "PairRecord".into(), - plist::Value::Dictionary(pair_record.clone()), - ); - req.insert("ProtocolVersion".into(), "2".into()); - req.insert("PairingOptions".into(), plist::Value::Dictionary(options)); + let req = crate::plist!({ + "Label": self.idevice.label.clone(), + "Request": "Pair", + "PairRecord": pair_record.clone(), + "ProtocolVersion": "2", + "PairingOptions": { + "ExtendedPairingErrors": true + } + }); loop { - self.idevice.send_plist(req.clone().into()).await?; + self.idevice.send_plist(req.clone()).await?; match self.idevice.read_plist().await { Ok(escrow) => { pair_record.insert("HostPrivateKey".into(), plist::Value::Data(ca.private_key)); diff --git a/idevice/src/services/mobile_image_mounter.rs b/idevice/src/services/mobile_image_mounter.rs index d0735bd..432acef 100644 --- a/idevice/src/services/mobile_image_mounter.rs +++ b/idevice/src/services/mobile_image_mounter.rs @@ -55,11 +55,10 @@ impl ImageMounter { /// # Errors /// Returns `IdeviceError` if communication fails or response is malformed pub async fn copy_devices(&mut self) -> Result, IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "CopyDevices".into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "CopyDevices" + }); + self.idevice.send_plist(req).await?; let mut res = self.idevice.read_plist().await?; match res.remove("EntryList") { @@ -83,12 +82,11 @@ impl ImageMounter { image_type: impl Into<&str>, ) -> Result, IdeviceError> { let image_type = image_type.into(); - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "LookupImage".into()); - req.insert("ImageType".into(), image_type.into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "LookupImage", + "ImageType": image_type + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("ImageSignature") { @@ -152,14 +150,13 @@ impl ImageMounter { } }; - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "ReceiveBytes".into()); - req.insert("ImageType".into(), image_type.into()); - req.insert("ImageSize".into(), image_size.into()); - req.insert("ImageSignature".into(), plist::Value::Data(signature)); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "ReceiveBytes", + "ImageType": image_type, + "ImageSize": image_size, + "ImageSignature": signature, + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("Status") { @@ -210,19 +207,14 @@ impl ImageMounter { ) -> Result<(), IdeviceError> { let image_type = image_type.into(); - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "MountImage".into()); - req.insert("ImageType".into(), image_type.into()); - req.insert("ImageSignature".into(), plist::Value::Data(signature)); - if let Some(trust_cache) = trust_cache { - req.insert("ImageTrustCache".into(), plist::Value::Data(trust_cache)); - } - if let Some(info_plist) = info_plist { - req.insert("ImageInfoPlist".into(), info_plist); - } - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "MountImage", + "ImageType": image_type, + "ImageSignature": signature, + "ImageTrustCache":? trust_cache, + "ImageInfoPlist":? info_plist, + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; @@ -253,12 +245,11 @@ impl ImageMounter { mount_path: impl Into, ) -> Result<(), IdeviceError> { let mount_path = mount_path.into(); - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "UnmountImage".into()); - req.insert("MountPath".into(), mount_path.into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "UnmountImage", + "MountPath": mount_path, + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("Status") { @@ -288,14 +279,13 @@ impl ImageMounter { ) -> Result, IdeviceError> { let image_type = image_type.into(); - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "QueryPersonalizationManifest".into()); - req.insert("PersonalizedImageType".into(), image_type.clone().into()); - req.insert("ImageType".into(), image_type.into()); - req.insert("ImageSignature".into(), plist::Value::Data(signature)); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "QueryPersonalizationManifest", + "PersonalizedImageType": image_type.clone(), + "ImageType": image_type, + "ImageSignature": signature + }); + self.idevice.send_plist(req).await?; let mut res = self.idevice.read_plist().await?; match res.remove("ImageSignature") { @@ -312,11 +302,10 @@ impl ImageMounter { /// # Errors /// Returns `IdeviceError` if query fails pub async fn query_developer_mode_status(&mut self) -> Result { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "QueryDeveloperModeStatus".into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "QueryDeveloperModeStatus" + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("DeveloperModeStatus") { @@ -339,14 +328,11 @@ impl ImageMounter { &mut self, personalized_image_type: Option<&str>, ) -> Result, IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "QueryNonce".into()); - if let Some(image_type) = personalized_image_type { - req.insert("PersonalizedImageType".into(), image_type.into()); - } - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "QueryNonce", + "PersonalizedImageType":? personalized_image_type, + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("PersonalizationNonce") { @@ -369,14 +355,11 @@ impl ImageMounter { &mut self, image_type: Option<&str>, ) -> Result { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "QueryPersonalizationIdentifiers".into()); - if let Some(image_type) = image_type { - req.insert("PersonalizedImageType".into(), image_type.into()); - } - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "QueryPersonalizationIdentifiers", + "PersonalizedImageType":? image_type, + }); + self.idevice.send_plist(req).await?; let res = self.idevice.read_plist().await?; match res.get("PersonalizationIdentifiers") { @@ -390,11 +373,10 @@ impl ImageMounter { /// # Errors /// Returns `IdeviceError` if operation fails pub async fn roll_personalization_nonce(&mut self) -> Result<(), IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "RollPersonalizationNonce".into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "RollPersonalizationNonce" + }); + self.idevice.send_plist(req).await?; Ok(()) } @@ -404,11 +386,10 @@ impl ImageMounter { /// # Errors /// Returns `IdeviceError` if operation fails pub async fn roll_cryptex_nonce(&mut self) -> Result<(), IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("Command".into(), "RollCryptexNonce".into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "Command": "RollCryptexNonce" + }); + self.idevice.send_plist(req).await?; Ok(()) } @@ -669,11 +650,12 @@ impl ImageMounter { } }; - let mut parameters = plist::Dictionary::new(); - parameters.insert("ApProductionMode".into(), true.into()); - parameters.insert("ApSecurityDomain".into(), 1.into()); - parameters.insert("ApSecurityMode".into(), true.into()); - parameters.insert("ApSupportsImg4".into(), true.into()); + let parameters = crate::plist!(dict { + "ApProductionMode": true, + "ApSecurityMode": 1, + "ApSecurityMode": true, + "ApSupportsImg4": true + }); for (key, manifest_item) in manifest { println!("{key}, {manifest_item:?}"); diff --git a/idevice/src/services/mobilebackup2.rs b/idevice/src/services/mobilebackup2.rs index 6fb47c3..b186710 100644 --- a/idevice/src/services/mobilebackup2.rs +++ b/idevice/src/services/mobilebackup2.rs @@ -185,31 +185,14 @@ impl RestoreOptions { } pub fn to_plist(&self) -> Dictionary { - let mut opts = Dictionary::new(); - opts.insert( - "RestoreShouldReboot".into(), - plist::Value::Boolean(self.reboot), - ); - opts.insert( - "RestoreDontCopyBackup".into(), - plist::Value::Boolean(!self.copy), - ); - opts.insert( - "RestorePreserveSettings".into(), - plist::Value::Boolean(self.preserve_settings), - ); - opts.insert( - "RestoreSystemFiles".into(), - plist::Value::Boolean(self.system_files), - ); - opts.insert( - "RemoveItemsNotRestored".into(), - plist::Value::Boolean(self.remove_items_not_restored), - ); - if let Some(pw) = &self.password { - opts.insert("Password".into(), plist::Value::String(pw.clone())); - } - opts + crate::plist!(dict { + "RestoreShouldReboot": self.reboot, + "RestoreDontCopyBackup": !self.copy, + "RestorePreserveSettings": self.preserve_settings, + "RestoreSystemFiles": self.system_files, + "RemoveItemsNotRestored": self.remove_items_not_restored, + "Password":? self.password.clone() + }) } } @@ -297,12 +280,11 @@ impl MobileBackup2Client { debug!("Starting mobilebackup2 version exchange"); // Send supported protocol versions (matching libimobiledevice) - let mut hello_dict = Dictionary::new(); - let versions = vec![plist::Value::Real(2.0), plist::Value::Real(2.1)]; - hello_dict.insert( - "SupportedProtocolVersions".into(), - plist::Value::Array(versions), - ); + let hello_dict = crate::plist!(dict { + "SupportedProtocolVersions": [ + 2.0, 2.1 + ] + }); self.send_device_link_message("Hello", Some(hello_dict)) .await?; @@ -349,25 +331,15 @@ impl MobileBackup2Client { message_name: &str, options: Option, ) -> Result<(), IdeviceError> { - // Create DLMessageProcessMessage array format - let mut message_array = Vec::new(); - message_array.push(plist::Value::String("DLMessageProcessMessage".into())); - // Create the actual message dictionary - let mut message_dict = Dictionary::new(); - message_dict.insert("MessageName".into(), message_name.into()); - - if let Some(opts) = options { - for (key, value) in opts { - message_dict.insert(key, value); - } - } - - message_array.push(plist::Value::Dictionary(message_dict)); + let message_dict = crate::plist!(dict { + "MessageName": message_name, + :, options: Option, ) -> Result<(), IdeviceError> { - let mut dict = Dictionary::new(); - if let Some(t) = target_identifier { - dict.insert("TargetIdentifier".into(), t.into()); - } - if let Some(s) = source_identifier { - dict.insert("SourceIdentifier".into(), s.into()); - } - if let Some(opts) = options { - dict.insert("Options".into(), plist::Value::Dictionary(opts)); + let dict = crate::plist!(dict { + "TargetIdentifier":? target_identifier, + "SourceIdentifier":? source_identifier, + "Options":? options, // Special cases like Unback/EnableCloudBackup are handled by caller if needed - } + }); self.send_device_link_message(request, Some(dict)).await } @@ -1090,17 +1057,10 @@ impl MobileBackup2Client { .ok_or(IdeviceError::InvalidHostID)?; self.assert_backup_exists(backup_root, source)?; - let mut dict = Dictionary::new(); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.unwrap().to_string()), - ); - if let Some(src) = source_identifier { - dict.insert( - "SourceIdentifier".into(), - plist::Value::String(src.to_string()), - ); - } + let dict = crate::plist!(dict { + "TargetIdentifier": target_udid.unwrap(), + "SourceIdentifier":? source_identifier, + }); self.send_device_link_message("Info", Some(dict)).await?; match self.process_restore_dl_loop(backup_root).await? { @@ -1121,16 +1081,11 @@ impl MobileBackup2Client { .ok_or(IdeviceError::InvalidHostID)?; self.assert_backup_exists(backup_root, source)?; - let mut dict = Dictionary::new(); - dict.insert("MessageName".into(), plist::Value::String("List".into())); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.unwrap().to_string()), - ); - dict.insert( - "SourceIdentifier".into(), - plist::Value::String(source.to_string()), - ); + let dict = crate::plist!(dict { + "MessageName": "List", + "TargetIdentifier": target_udid.unwrap(), + "SourceIdentifier": source, + }); self.send_device_link_message("List", Some(dict)).await?; match self.process_restore_dl_loop(backup_root).await? { @@ -1151,20 +1106,12 @@ impl MobileBackup2Client { .or(target_udid) .ok_or(IdeviceError::InvalidHostID)?; self.assert_backup_exists(backup_root, source)?; - - let mut dict = Dictionary::new(); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.unwrap().to_string()), - ); - dict.insert("MessageName".into(), plist::Value::String("Unback".into())); - dict.insert( - "SourceIdentifier".into(), - plist::Value::String(source.to_string()), - ); - if let Some(pw) = password { - dict.insert("Password".into(), plist::Value::String(pw.to_string())); - } + let dict = crate::plist!(dict { + "TargetIdentifier": target_udid.unwrap(), + "MessageName": "Unback", + "SourceIdentifier": source, + "Password":? password + }); self.send_device_link_message("Unback", Some(dict)).await?; let _ = self.process_restore_dl_loop(backup_root).await?; Ok(()) @@ -1184,28 +1131,14 @@ impl MobileBackup2Client { .or(target_udid) .ok_or(IdeviceError::InvalidHostID)?; self.assert_backup_exists(backup_root, source)?; - - let mut dict = Dictionary::new(); - dict.insert("MessageName".into(), plist::Value::String("Extract".into())); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.unwrap().to_string()), - ); - dict.insert( - "DomainName".into(), - plist::Value::String(domain_name.to_string()), - ); - dict.insert( - "RelativePath".into(), - plist::Value::String(relative_path.to_string()), - ); - dict.insert( - "SourceIdentifier".into(), - plist::Value::String(source.to_string()), - ); - if let Some(pw) = password { - dict.insert("Password".into(), plist::Value::String(pw.to_string())); - } + let dict = crate::plist!(dict { + "MessageName": "Extract", + "TargetIdentifier": target_udid.unwrap(), + "DomainName": domain_name, + "RelativePath": relative_path, + "SourceIdentifier": source, + "Password":? password, + }); self.send_device_link_message("Extract", Some(dict)).await?; let _ = self.process_restore_dl_loop(backup_root).await?; Ok(()) @@ -1219,21 +1152,12 @@ impl MobileBackup2Client { new: Option<&str>, ) -> Result<(), IdeviceError> { let target_udid = self.idevice.udid(); - let mut dict = Dictionary::new(); - dict.insert( - "MessageName".into(), - plist::Value::String("ChangePassword".into()), - ); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()), - ); - if let Some(o) = old { - dict.insert("OldPassword".into(), plist::Value::String(o.to_string())); - } - if let Some(n) = new { - dict.insert("NewPassword".into(), plist::Value::String(n.to_string())); - } + let dict = crate::plist!(dict { + "MessageName": "ChangePassword", + "TargetIdentifier": target_udid.ok_or(IdeviceError::InvalidHostID)?, + "OldPassword":? old, + "NewPassword":? new + }); self.send_device_link_message("ChangePassword", Some(dict)) .await?; let _ = self.process_restore_dl_loop(backup_root).await?; @@ -1243,15 +1167,10 @@ impl MobileBackup2Client { /// Erase device via mobilebackup2 pub async fn erase_device_from_path(&mut self, backup_root: &Path) -> Result<(), IdeviceError> { let target_udid = self.idevice.udid(); - let mut dict = Dictionary::new(); - dict.insert( - "MessageName".into(), - plist::Value::String("EraseDevice".into()), - ); - dict.insert( - "TargetIdentifier".into(), - plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()), - ); + let dict = crate::plist!(dict { + "MessageName": "EraseDevice", + "TargetIdentifier": target_udid.ok_or(IdeviceError::InvalidHostID)? + }); self.send_device_link_message("EraseDevice", Some(dict)) .await?; let _ = self.process_restore_dl_loop(backup_root).await?; @@ -1291,10 +1210,10 @@ impl MobileBackup2Client { /// Returns `IdeviceError` if disconnection fails pub async fn disconnect(&mut self) -> Result<(), IdeviceError> { // Send DLMessageDisconnect array per DeviceLink protocol - let arr = vec![ - plist::Value::String("DLMessageDisconnect".into()), - plist::Value::String("___EmptyParameterString___".into()), - ]; + let arr = crate::plist!(array [ + "DLMessageDisconnect", + "___EmptyParameterString___" + ]); self.send_dl_array(arr).await?; debug!("Disconnected from backup service"); Ok(()) diff --git a/idevice/src/services/os_trace_relay.rs b/idevice/src/services/os_trace_relay.rs index 793f80a..9fb07d3 100644 --- a/idevice/src/services/os_trace_relay.rs +++ b/idevice/src/services/os_trace_relay.rs @@ -4,7 +4,6 @@ //! https://github.com/doronz88/pymobiledevice3/blob/master/pymobiledevice3/services/os_trace.py use chrono::{DateTime, NaiveDateTime}; -use plist::Dictionary; use tokio::io::AsyncWriteExt; use crate::{Idevice, IdeviceError, IdeviceService, obf}; @@ -70,15 +69,14 @@ impl OsTraceRelayClient { Some(p) => p as i64, None => -1, }; - let mut req = Dictionary::new(); - req.insert("Request".into(), "StartActivity".into()); - req.insert("Pid".into(), Into::into(pid)); - req.insert("MessageFilter".into(), Into::into(65_535)); - req.insert("StreamFlags".into(), Into::into(60)); + let req = crate::plist!({ + "Request": "StartActivity", + "Pid": pid, + "MessageFilter": 65_535, + "StreamFlags": 60 + }); - self.idevice - .send_bplist(plist::Value::Dictionary(req)) - .await?; + self.idevice.send_bplist(req).await?; // Read a single byte self.idevice.read_raw(1).await?; @@ -100,12 +98,11 @@ impl OsTraceRelayClient { /// Get the list of available PIDs pub async fn get_pid_list(&mut self) -> Result, IdeviceError> { - let mut req = Dictionary::new(); - req.insert("Request".into(), "PidList".into()); + let req = crate::plist!({ + "Request": "PidList" + }); - self.idevice - .send_bplist(plist::Value::Dictionary(req)) - .await?; + self.idevice.send_bplist(req).await?; // Read a single byte self.idevice.read_raw(1).await?; @@ -133,24 +130,14 @@ impl OsTraceRelayClient { age_limit: Option, start_time: Option, ) -> Result<(), IdeviceError> { - let mut req = Dictionary::new(); - req.insert("Request".into(), "CreateArchive".into()); + let req = crate::plist!({ + "Request": "CreateArchive", + "SizeLimit":? size_limit, + "AgeLimit":? age_limit, + "StartTime":? start_time, + }); - if let Some(size) = size_limit { - req.insert("SizeLimit".into(), size.into()); - } - - if let Some(age) = age_limit { - req.insert("AgeLimit".into(), age.into()); - } - - if let Some(time) = start_time { - req.insert("StartTime".into(), time.into()); - } - - self.idevice - .send_bplist(plist::Value::Dictionary(req)) - .await?; + self.idevice.send_bplist(req).await?; // Read a single byte if self.idevice.read_raw(1).await?[0] != 1 { diff --git a/idevice/src/services/restore_service.rs b/idevice/src/services/restore_service.rs index b2f4590..1f3dd73 100644 --- a/idevice/src/services/restore_service.rs +++ b/idevice/src/services/restore_service.rs @@ -35,12 +35,11 @@ impl RestoreServiceClient { /// Enter recovery pub async fn enter_recovery(&mut self) -> Result<(), IdeviceError> { - let mut req = Dictionary::new(); - req.insert("command".into(), "recovery".into()); + let req = crate::plist!({ + "command": "recovery" + }); - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { @@ -69,12 +68,10 @@ impl RestoreServiceClient { /// Reboot pub async fn reboot(&mut self) -> Result<(), IdeviceError> { - let mut req = Dictionary::new(); - req.insert("command".into(), "reboot".into()); - - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + let req = crate::plist!({ + "command": "reboot" + }); + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { @@ -103,12 +100,10 @@ impl RestoreServiceClient { /// Get preflightinfo pub async fn get_preflightinfo(&mut self) -> Result { - let mut req = Dictionary::new(); - req.insert("command".into(), "getpreflightinfo".into()); - - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + let req = crate::plist!({ + "command": "getpreflightinfo" + }); + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { @@ -133,12 +128,10 @@ impl RestoreServiceClient { /// Get nonces /// Doesn't seem to work pub async fn get_nonces(&mut self) -> Result { - let mut req = Dictionary::new(); - req.insert("command".into(), "getnonces".into()); - - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + let req = crate::plist!({ + "command": "getnonces" + }); + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { @@ -163,12 +156,10 @@ impl RestoreServiceClient { /// Get app parameters /// Doesn't seem to work pub async fn get_app_parameters(&mut self) -> Result { - let mut req = Dictionary::new(); - req.insert("command".into(), "getappparameters".into()); - - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + let req = crate::plist!({ + "command": "getappparameters" + }); + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { @@ -195,13 +186,11 @@ impl RestoreServiceClient { pub async fn restore_lang(&mut self, language: impl Into) -> Result<(), IdeviceError> { let language = language.into(); - let mut req = Dictionary::new(); - req.insert("command".into(), "restorelang".into()); - req.insert("argument".into(), language.into()); - - self.stream - .send_object(plist::Value::Dictionary(req), true) - .await?; + let req = crate::plist!({ + "command": "restorelang", + "argument": language, + }); + self.stream.send_object(req, true).await?; let res = self.stream.recv().await?; let mut res = match res { diff --git a/idevice/src/services/springboardservices.rs b/idevice/src/services/springboardservices.rs index f115f30..e8edfec 100644 --- a/idevice/src/services/springboardservices.rs +++ b/idevice/src/services/springboardservices.rs @@ -57,12 +57,11 @@ impl SpringBoardServicesClient { &mut self, bundle_identifier: String, ) -> Result, IdeviceError> { - let mut req = plist::Dictionary::new(); - req.insert("command".into(), "getIconPNGData".into()); - req.insert("bundleId".into(), bundle_identifier.into()); - self.idevice - .send_plist(plist::Value::Dictionary(req)) - .await?; + let req = crate::plist!({ + "command": "getIconPNGData", + "bundleId": bundle_identifier, + }); + self.idevice.send_plist(req).await?; let mut res = self.idevice.read_plist().await?; match res.remove("pngData") {