/** * Mounts an image on the device. * * @param client The connected mobile_image_mounter client. * @param image_path The absolute path of the image to mount. The image must * be present before calling this function. * @param image_signature Pointer to a buffer holding the images' signature * @param signature_length Length of the signature image_signature points to * @param image_type Type of image to mount * @param result Pointer to a plist that will receive the result of the * operation. * * @note This function may return MOBILE_IMAGE_MOUNTER_E_SUCCESS even if the * operation has failed. Check the resulting plist for further information. * Note that there is no unmounting function. The mount persists until the * device is rebooted. * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if on ore more parameters are * invalid, or another error code otherwise. */ mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *image_signature, uint16_t signature_length, const char *image_type, plist_t *result) { if (!client || !image_path || !image_signature || (signature_length == 0) || !image_type || !result) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; } mobile_image_mounter_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "Command", plist_new_string("MountImage")); plist_dict_insert_item(dict, "ImagePath", plist_new_string(image_path)); plist_dict_insert_item(dict, "ImageSignature", plist_new_data(image_signature, signature_length)); plist_dict_insert_item(dict, "ImageType", plist_new_string(image_type)); mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error sending XML plist to device!", __func__); goto leave_unlock; } res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, result)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error receiving response from device!", __func__); } leave_unlock: mobile_image_mounter_unlock(client); return res; }
dl_status dl_start(dl_t self) { // Assume usbmuxd supports proto_version 1. If not then we'd need to // send a binary listen request, check for failure, then retry this: plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "ClientVersionString", plist_new_string( "device_listener")); plist_dict_insert_item(dict, "MessageType", plist_new_string("Listen")); plist_dict_insert_item(dict, "ProgName", plist_new_string("libusbmuxd")); char *xml = NULL; uint32_t xml_length = 0; plist_to_xml(dict, &xml, &xml_length); plist_free(dict); size_t length = 16 + xml_length; char *packet = (char *)calloc(length, sizeof(char)); if (!packet) { return DL_ERROR; } char *tail = packet; tail = dl_sprintf_uint32(tail, length); tail = dl_sprintf_uint32(tail, 1); // version: 1 tail = dl_sprintf_uint32(tail, TYPE_PLIST); // type: plist tail = dl_sprintf_uint32(tail, 1); // tag: 1 tail = stpncpy(tail, xml, xml_length); free(xml); dl_status ret = self->send_packet(self, packet, length); free(packet); return ret; }
/** * Uninstall an application from the device. * * @param client The connected installation proxy client * @param appid ApplicationIdentifier of the app to uninstall * @param client_options The client options to use, as PLIST_DICT, or NULL. * Currently there are no known client options, so pass NULL here. * @param status_cb Callback function for progress and status information. If * NULL is passed, this function will run synchronously. * @param user_data Callback data passed to status_cb. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occured. * * @note If a callback function is given (async mode), this function returns * INSTPROXY_E_SUCCESS immediately if the status updater thread has been * created successfully; any error occuring during the operation has to be * handled inside the specified callback function. */ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) { if (!client || !client->parent || !appid) { return INSTPROXY_E_INVALID_ARG; } if (client->status_updater) { return INSTPROXY_E_OP_IN_PROGRESS; } instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid)); plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); instproxy_lock(client); res = instproxy_send_command(client, "Uninstall", client_options, appid, NULL); instproxy_unlock(client); plist_free(dict); if (res != INSTPROXY_E_SUCCESS) { debug_info("could not send plist, error %d", res); return res; } return instproxy_create_status_updater(client, status_cb, "Uninstall", user_data); }
/** * Sets the icon state of the connected device. * * @param client The connected sbservices client to use. * @param newstate A plist containing the new iconstate. * * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or newstate is NULL, or an SBSERVICES_E_* error code otherwise. */ sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) { if (!client || !client->parent || !newstate) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("setIconState")); plist_dict_insert_item(dict, "iconState", plist_copy(newstate)); sbs_lock(client); res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); } /* NO RESPONSE */ if (dict) { plist_free(dict); } sbs_unlock(client); return res; }
/** Sends a notification to the device's Notification Proxy. * * notification messages seen so far: * com.apple.itunes-mobdev.syncWillStart * com.apple.itunes-mobdev.syncDidStart * * @param client The client to send to * @param notification The notification message to send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_plist_send(client, dict); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); res = np_plist_send(client, dict); plist_free(dict); if (res != NP_E_SUCCESS) { log_debug_msg("%s: Error sending XML plist to device!\n", __func__); } np_unlock(client); return res; }
void fixup_tss(plist_t tss) { plist_t node; plist_t node2; node = plist_dict_get_item(tss, "RestoreLogo"); if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { node2 = plist_dict_get_item(tss, "AppleLogo"); if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { plist_dict_remove_item(tss, "RestoreLogo"); plist_dict_insert_item(tss, "RestoreLogo", plist_copy(node2)); } } node = plist_dict_get_item(tss, "RestoreDeviceTree"); if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { node2 = plist_dict_get_item(tss, "DeviceTree"); if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { plist_dict_remove_item(tss, "RestoreDeviceTree"); plist_dict_insert_item(tss, "RestoreDeviceTree", plist_copy(node2)); } } node = plist_dict_get_item(tss, "RestoreKernelCache"); if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { node2 = plist_dict_get_item(tss, "KernelCache"); if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { plist_dict_remove_item(tss, "RestoreKernelCache"); plist_dict_insert_item(tss, "RestoreKernelCache", plist_copy(node2)); } } }
/** * Sends a notification to the device's notification_proxy. * * @param client The client to send to * @param notification The notification message to send * * @return NP_E_SUCCESS on success, or an error returned by np_plist_send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { debug_info("Error sending XML plist to device!"); } np_unlock(client); return res; }
/** * Request a backup from the connected device. * * @param client The connected MobileBackup client to use. * @param backup_manifest The backup manifest, a plist_t of type PLIST_DICT * containing the backup state of the last backup. For a first-time backup * set this parameter to NULL. * @param base_path The base path on the device to use for the backup * operation, usually "/". * @param proto_version A string denoting the version of the backup protocol * to use. Latest known version is "1.6" * * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if * one of the parameters is invalid, MOBILEBACKUP_E_PLIST_ERROR if * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR * if a communication error occurs, MOBILEBACKUP_E_REPLY_NOT_OK */ mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) { if (!client || !client->parent || !base_path || !proto_version) return MOBILEBACKUP_E_INVALID_ARG; if (backup_manifest && (plist_get_node_type(backup_manifest) != PLIST_DICT)) return MOBILEBACKUP_E_PLIST_ERROR; mobilebackup_error_t err; /* construct request plist */ plist_t dict = plist_new_dict(); if (backup_manifest) plist_dict_insert_item(dict, "BackupManifestKey", plist_copy(backup_manifest)); plist_dict_insert_item(dict, "BackupComputerBasePathKey", plist_new_string(base_path)); plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); plist_dict_insert_item(dict, "BackupProtocolVersion", plist_new_string(proto_version)); /* send request */ err = mobilebackup_send_message(client, NULL, dict); plist_free(dict); dict = NULL; if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send backup request message (%d)!", err); goto leave; } /* now receive and hopefully get a BackupMessageBackupReplyOK */ err = mobilebackup_receive_message(client, "BackupMessageBackupReplyOK", &dict); if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not receive BackupReplyOK message (%d)!", err); goto leave; } plist_t node = plist_dict_get_item(dict, "BackupProtocolVersion"); if (node) { char *str = NULL; plist_get_string_val(node, &str); if (str) { if (strcmp(str, proto_version) != 0) { err = MOBILEBACKUP_E_BAD_VERSION; } free(str); } } if (err != MOBILEBACKUP_E_SUCCESS) goto leave; /* BackupMessageBackupReplyOK received, send it back */ err = mobilebackup_send_message(client, NULL, dict); if (err != MOBILEBACKUP_E_SUCCESS) { debug_info("ERROR: Could not send BackupReplyOK ACK (%d)", err); } leave: if (dict) plist_free(dict); return err; }
/** * Sends a notification to the device's notification_proxy. * * @param client The client to send to * @param notification The notification message to send * * @return NP_E_SUCCESS on success, or an error returned by np_plist_send */ np_error_t np_post_notification(np_client_t client, const char *notification) { if (!client || !notification) { return NP_E_INVALID_ARG; } np_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("PostNotification")); plist_dict_insert_item(dict,"Name", plist_new_string(notification)); np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); dict = plist_new_dict(); plist_dict_insert_item(dict,"Command", plist_new_string("Shutdown")); res = np_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != NP_E_SUCCESS) { debug_info("Error sending XML plist to device!"); } // try to read an answer, we just ignore errors here dict = NULL; property_list_service_receive_plist(client->parent, &dict); if (dict) { #ifndef STRIP_DEBUG_CODE char *cmd_value = NULL; plist_t cmd_value_node = plist_dict_get_item(dict, "Command"); if (plist_get_node_type(cmd_value_node) == PLIST_STRING) { plist_get_string_val(cmd_value_node, &cmd_value); } if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) { // this is the expected answer } else { debug_plist(dict); } if (cmd_value) { free(cmd_value); } #endif plist_free(dict); } np_unlock(client); return res; }
static int notify_device_remove(struct mux_client *client, uint32_t device_id) { int res = -1; if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Detached")); plist_dict_insert_item(dict, "DeviceID", plist_new_uint(device_id)); res = send_plist_pkt(client, 0, dict); plist_free(dict); } else { /* binary packet */ res = send_pkt(client, 0, MESSAGE_DEVICE_REMOVE, &device_id, sizeof(uint32_t)); } return res; }
static int send_device_list(struct mux_client *client, uint32_t tag) { int res = -1; plist_t dict = plist_new_dict(); plist_t devices = plist_new_array(); struct device_info *devs = NULL; struct device_info *dev; int i; int count = device_get_list(0, &devs); dev = devs; for (i = 0; devs && i < count; i++) { plist_t device = create_device_attached_plist(dev++); if (device) { plist_array_append_item(devices, device); } } if (devs) free(devs); plist_dict_insert_item(dict, "DeviceList", devices); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; }
static int send_result(struct mux_client *client, uint32_t tag, uint32_t result) { int res = -1; if (client->proto_version == 1) { /* XML plist packet */ plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Result")); plist_dict_insert_item(dict, "Number", plist_new_uint(result)); res = send_plist_pkt(client, tag, dict); plist_free(dict); } else { /* binary packet */ res = send_pkt(client, tag, MESSAGE_RESULT, &result, sizeof(uint32_t)); } return res; }
/** * Get the home screen wallpaper as PNG data. * * @param client The connected sbservices client to use. * @param pngdata Pointer that will point to a newly allocated buffer * containing the PNG data upon successful return. It is up to the caller * to free the memory. * @param pngsize Pointer to a uint64_t that will be set to the size of the * buffer pngdata points to upon successful return. * * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when * client or pngdata are invalid, or an SBSERVICES_E_* error * code otherwise. */ sbservices_error_t sbservices_get_home_screen_wallpaper_pngdata(sbservices_client_t client, char **pngdata, uint64_t *pngsize) { if (!client || !client->parent || !pngdata) return SBSERVICES_E_INVALID_ARG; sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "command", plist_new_string("getHomeScreenWallpaperPNGData")); sbs_lock(client); res = sbservices_error(property_list_service_send_binary_plist(client->parent, dict)); if (res != SBSERVICES_E_SUCCESS) { debug_info("could not send plist, error %d", res); goto leave_unlock; } plist_free(dict); dict = NULL; res = sbservices_error(property_list_service_receive_plist(client->parent, &dict)); if (res == SBSERVICES_E_SUCCESS) { plist_t node = plist_dict_get_item(dict, "pngData"); if (node) { plist_get_data_val(node, pngdata, pngsize); } } leave_unlock: if (dict) { plist_free(dict); } sbs_unlock(client); return res; }
/** * Hangs up the connection to the mobile_image_mounter service. * This functions has to be called before freeing up a mobile_image_mounter * instance. If not, errors appear in the device's syslog. * * @param client The client to hang up * * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success, * MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is invalid, * or another error code otherwise. */ mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) { if (!client) { return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG; } mobile_image_mounter_lock(client); plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "Command", plist_new_string("Hangup")); mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict)); plist_free(dict); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error sending XML plist to device!", __func__); goto leave_unlock; } dict = NULL; res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &dict)); if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { debug_info("%s: Error receiving response from device!", __func__); } if (dict) { debug_plist(dict); plist_free(dict); } leave_unlock: mobile_image_mounter_unlock(client); return res; }
/** * Sends a backup message plist. * * @param client The connected MobileBackup client to use. * @param message The message to send. This will be inserted into the request * plist as value for MessageName. If this parameter is NULL, * the plist passed in the options parameter will be sent directly. * @param options Additional options as PLIST_DICT to add to the request. * The MessageName key with the value passed in the message parameter * will be inserted into this plist before sending it. This parameter * can be NULL if message is not NULL. */ mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, const char *message, plist_t options) { if (!client || !client->parent || (!message && !options)) return MOBILEBACKUP2_E_INVALID_ARG; if (options && (plist_get_node_type(options) != PLIST_DICT)) { return MOBILEBACKUP2_E_INVALID_ARG; } mobilebackup2_error_t err; if (message) { plist_t dict = NULL; if (options) { dict = plist_copy(options); } else { dict = plist_new_dict(); } plist_dict_insert_item(dict, "MessageName", plist_new_string(message)); /* send it as DLMessageProcessMessage */ err = mobilebackup2_error(device_link_service_send_process_message(client->parent, dict)); plist_free(dict); } else { err = mobilebackup2_error(device_link_service_send_process_message(client->parent, options)); } if (err != MOBILEBACKUP2_E_SUCCESS) { debug_info("ERROR: Could not send message '%s' (%d)!", message, err); } return err; }
/** * Adds a label key with the passed value to a plist dict node. * * @param plist The plist to add the key to * @param label The value for the label key * */ static void plist_dict_add_label(plist_t plist, const char *label) { if (plist && label) { if (plist_get_node_type(plist) == PLIST_DICT) plist_dict_insert_item(plist, "Label", plist_new_string(label)); } }
void plist_dict_merge(plist_t *target, plist_t source) { if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT)) return; char* key = NULL; plist_dict_iter it = NULL; plist_t subnode = NULL; plist_dict_new_iter(source, &it); if (!it) return; do { plist_dict_next_item(source, it, &key, &subnode); if (!key) break; if (plist_dict_get_item(*target, key) != NULL) plist_dict_remove_item(*target, key); plist_dict_insert_item(*target, key, plist_copy(subnode)); free(key); key = NULL; } while (1); free(it); }
/** * Sends the Goodbye request to restored signaling the end of communication. * * @param client The restore client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request */ restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return RESTORE_E_PLIST_ERROR; } if (restored_check_result(dict) == RESULT_SUCCESS) { debug_info("success"); ret = RESTORE_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
/** * Requests device to reboot. * * @param client The restored client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL */ restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Reboot")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (RESTORE_E_SUCCESS != ret) return ret; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; if (!dict) return RESTORE_E_PLIST_ERROR; plist_free(dict); dict = NULL; return ret; }
/** * Puts the device into deep sleep mode and disconnects from host. * * @param client The diagnostics_relay client * * @return DIAGNOSTICS_RELAY_E_SUCCESS on success, * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL, * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the * request */ diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Request", plist_new_string("Sleep")); ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; ret = diagnostics_relay_receive(client, &dict); if (!dict) { return DIAGNOSTICS_RELAY_E_PLIST_ERROR; } int check = diagnostics_relay_check_result(dict); if (check == RESULT_SUCCESS) { ret = DIAGNOSTICS_RELAY_E_SUCCESS; } else if (check == RESULT_UNKNOWN_REQUEST) { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST; } else { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; } plist_free(dict); return ret; }
/** * Query the type of the service daemon. Depending on whether the device is * queried in normal mode or restore mode, different types will be returned. * * @param client The restored client * @param type The type returned by the service daemon. Pass NULL to ignore. * @param version The restore protocol version. Pass NULL to ignore. * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL */ restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; ret = RESTORE_E_UNKNOWN_ERROR; plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && (plist_get_node_type(type_node) == PLIST_STRING)) { char* typestr = NULL; /* save our device information info */ client->info = dict; plist_get_string_val(type_node, &typestr); debug_info("success with type %s", typestr); /* return the type if requested */ if (type) { *type = typestr; } else { free(typestr); } /* fetch the restore protocol version */ if (version) { plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion"); if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { plist_get_uint_val(version_node, version); debug_info("restored protocol version %llu", *version); } else { return RESTORE_E_UNKNOWN_ERROR; } } ret = RESTORE_E_SUCCESS; } else { debug_info("hmm. QueryType response does not contain a type?!"); debug_plist(dict); plist_free(dict); } return ret; }
/** * Send a request to the connected mobilebackup2 service. * * @param client * @param request The request to send to the backup service. * Currently, this is one of "Backup", "Restore", "Info", or "List". * @param target_identifier UDID of the target device. * @param source_identifier UDID of backup data? * @param options Additional options in a plist of type PLIST_DICT. * * @return MOBILEBACKUP2_E_SUCCESS if the request was successfully sent, * or a MOBILEBACKUP2_E_* error value otherwise. */ mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, const char *request, const char *target_identifier, const char *source_identifier, plist_t options) { if (!client || !client->parent || !request || !target_identifier) return MOBILEBACKUP2_E_INVALID_ARG; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "TargetIdentifier", plist_new_string(target_identifier)); if (source_identifier) { plist_dict_insert_item(dict, "SourceIdentifier", plist_new_string(source_identifier)); } if (options) { plist_dict_insert_item(dict, "Options", plist_copy(options)); } mobilebackup2_error_t err = mobilebackup2_send_message(client, request, dict); plist_free(dict); return err; }
/** * Performs the mobilebackup2 protocol version exchange. * * @param client The MobileBackup client to use. * @param local_versions An array of supported versions to send to the remote. * @param count The number of items in local_versions. * @param remote_version Holds the protocol version of the remote on success. * * @return MOBILEBACKUP2_E_SUCCESS on success, or a MOBILEBACKUP2_E_* error * code otherwise. */ mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) { int i; if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; plist_t dict = plist_new_dict(); plist_t array = plist_new_array(); for (i = 0; i < count; i++) { plist_array_append_item(array, plist_new_real(local_versions[i])); } plist_dict_insert_item(dict, "SupportedProtocolVersions", array); mobilebackup2_error_t err = mobilebackup2_send_message(client, "Hello", dict); plist_free(dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; dict = NULL; err = internal_mobilebackup2_receive_message(client, "Response", &dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; /* check if we received an error */ plist_t node = plist_dict_get_item(dict, "ErrorCode"); if (!node || (plist_get_node_type(node) != PLIST_UINT)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } uint64_t val = 0; plist_get_uint_val(node, &val); if (val != 0) { if (val == 1) { err = MOBILEBACKUP2_E_NO_COMMON_VERSION; } else { err = MOBILEBACKUP2_E_REPLY_NOT_OK; } goto leave; } /* retrieve the protocol version of the device */ node = plist_dict_get_item(dict, "ProtocolVersion"); if (!node || (plist_get_node_type(node) != PLIST_REAL)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } *remote_version = 0.0; plist_get_real_val(node, remote_version); leave: if (dict) plist_free(dict); return err; }
diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, const char* name, const char* _class, plist_t* result) { if (!client || (name == NULL && _class == NULL) || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); if (name) plist_dict_insert_item(dict,"EntryName", plist_new_string(name)); if (_class) plist_dict_insert_item(dict,"EntryClass", plist_new_string(_class)); plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry")); ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; ret = diagnostics_relay_receive(client, &dict); if (!dict) { return DIAGNOSTICS_RELAY_E_PLIST_ERROR; } int check = diagnostics_relay_check_result(dict); if (check == RESULT_SUCCESS) { ret = DIAGNOSTICS_RELAY_E_SUCCESS; } else if (check == RESULT_UNKNOWN_REQUEST) { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST; } else { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; } if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { plist_free(dict); return ret; } plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); if (value_node) { *result = plist_copy(value_node); } plist_free(dict); return ret; }
static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, int flags) { if (!client) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"Request", plist_new_string(name)); if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) { plist_dict_insert_item(dict, "WaitForDisconnect", plist_new_bool(1)); } if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) { plist_dict_insert_item(dict, "DisplayPass", plist_new_bool(1)); } if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) { plist_dict_insert_item(dict, "DisplayFail", plist_new_bool(1)); } ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; ret = diagnostics_relay_receive(client, &dict); if (!dict) { return DIAGNOSTICS_RELAY_E_PLIST_ERROR; } int check = diagnostics_relay_check_result(dict); if (check == RESULT_SUCCESS) { ret = DIAGNOSTICS_RELAY_E_SUCCESS; } else if (check == RESULT_UNKNOWN_REQUEST) { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST; } else { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; } plist_free(dict); return ret; }
/** * Send a command to the connected house_arrest service. * Calls house_arrest_send_request() internally. * * @param client The house_arrest client to use. * @param command The command to send. Currently, only VendContainer and * VendDocuments are known. * @param appid The application identifier to pass along with the . * * @note If this function returns HOUSE_ARREST_E_SUCCESS it does not mean * that the command was successful. To check for success or failure you * need to call house_arrest_get_result(). * @see house_arrest_get_result * * @return HOUSE_ARREST_E_SUCCESS if the command was successfully sent, * HOUSE_ARREST_E_INVALID_ARG if client, command, or appid is invalid, * HOUSE_ARREST_E_INVALID_MODE if the client is not in the correct mode, * or HOUSE_ARREST_E_CONN_FAILED if a connection error occured. */ house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid) { if (!client || !client->parent || !command || !appid) return HOUSE_ARREST_E_INVALID_ARG; if (client->mode != HOUSE_ARREST_CLIENT_MODE_NORMAL) return HOUSE_ARREST_E_INVALID_MODE; house_arrest_error_t res = HOUSE_ARREST_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "Command", plist_new_string(command)); plist_dict_insert_item(dict, "Identifier", plist_new_string(appid)); res = house_arrest_send_request(client, dict); plist_free(dict); return res; }
static plist_t create_device_attached_plist(struct device_info *dev) { plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("Attached")); plist_dict_insert_item(dict, "DeviceID", plist_new_uint(dev->id)); plist_t props = plist_new_dict(); // TODO: get current usb speed plist_dict_insert_item(props, "ConnectionSpeed", plist_new_uint(480000000)); plist_dict_insert_item(props, "ConnectionType", plist_new_string("USB")); plist_dict_insert_item(props, "DeviceID", plist_new_uint(dev->id)); plist_dict_insert_item(props, "LocationID", plist_new_uint(dev->location)); plist_dict_insert_item(props, "ProductID", plist_new_uint(dev->pid)); plist_dict_insert_item(props, "SerialNumber", plist_new_string(dev->serial)); plist_dict_insert_item(dict, "Properties", props); return dict; }
/** * Queries a value from the device specified by a key. * * @param client An initialized restored client. * @param key The key name to request * @param value A plist node representing the result value node * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found */ restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) { if (!client || !key) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; /* setup request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); if (key) { plist_dict_insert_item(dict,"QueryKey", plist_new_string(key)); } plist_dict_insert_item(dict,"Request", plist_new_string("QueryValue")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (ret != RESTORE_E_SUCCESS) return ret; /* Now get device's answer */ ret = restored_receive(client, &dict); if (ret != RESTORE_E_SUCCESS) return ret; plist_t value_node = plist_dict_get_item(dict, key); if (value_node) { debug_info("has a value"); *value = plist_copy(value_node); } else { ret = RESTORE_E_PLIST_ERROR; } plist_free(dict); return ret; }
diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist_t keys, plist_t* result) { if (!client || plist_get_node_type(keys) != PLIST_ARRAY || result == NULL) return DIAGNOSTICS_RELAY_E_INVALID_ARG; diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict,"MobileGestaltKeys", plist_copy(keys)); plist_dict_insert_item(dict,"Request", plist_new_string("MobileGestalt")); ret = diagnostics_relay_send(client, dict); plist_free(dict); dict = NULL; ret = diagnostics_relay_receive(client, &dict); if (!dict) { return DIAGNOSTICS_RELAY_E_PLIST_ERROR; } int check = diagnostics_relay_check_result(dict); if (check == RESULT_SUCCESS) { ret = DIAGNOSTICS_RELAY_E_SUCCESS; } else if (check == RESULT_UNKNOWN_REQUEST) { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST; } else { ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; } if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { plist_free(dict); return ret; } plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); if (value_node) { *result = plist_copy(value_node); } plist_free(dict); return ret; }
/** * Get a screen shot from the connected device. * * @param client The connection screenshotr service client. * @param imgdata Pointer that will point to a newly allocated buffer * containing TIFF image data upon successful return. It is up to the * caller to free the memory. * @param imgsize Pointer to a uint64_t that will be set to the size of the * buffer imgdata points to upon successful return. * * @return SCREENSHOTR_E_SUCCESS on success, SCREENSHOTR_E_INVALID_ARG if * one or more parameters are invalid, or another error code if an * error occured. */ screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) { if (!client || !client->parent || !imgdata) return SCREENSHOTR_E_INVALID_ARG; screenshotr_error_t res = SCREENSHOTR_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "MessageType", plist_new_string("ScreenShotRequest")); res = screenshotr_error(device_link_service_send_process_message(client->parent, dict)); plist_free(dict); if (res != SCREENSHOTR_E_SUCCESS) { debug_info("could not send plist, error %d", res); return res; } dict = NULL; res = screenshotr_error(device_link_service_receive_process_message(client->parent, &dict)); if (res != SCREENSHOTR_E_SUCCESS) { debug_info("could not get screenshot data, error %d", res); goto leave; } if (!dict) { debug_info("did not receive screenshot data!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } plist_t node = plist_dict_get_item(dict, "MessageType"); char *strval = NULL; plist_get_string_val(node, &strval); if (!strval || strcmp(strval, "ScreenShotReply")) { debug_info("invalid screenshot data received!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } node = plist_dict_get_item(dict, "ScreenShotData"); if (!node || plist_get_node_type(node) != PLIST_DATA) { debug_info("no PNG data received!"); res = SCREENSHOTR_E_PLIST_ERROR; goto leave; } plist_get_data_val(node, imgdata, imgsize); res = SCREENSHOTR_E_SUCCESS; leave: if (dict) plist_free(dict); return res; }