/** * Sends changed entities of the currently set data class to the device * * @param client The mobilesync client * @param entities The changed entity records as a PLIST_DICT * @param is_last_record A flag indicating if this submission is the last one * @param actions Additional actions for the device created with mobilesync_actions_new() * or NULL if no actions should be passed * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid, * @retval MOBILESYNC_E_WRONG_DIRECTION if the current sync direction does * not permit this call */ mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions) { if (!client || !client->data_class || !entities) { return MOBILESYNC_E_INVALID_ARG; } if (plist_get_node_type(entities) != PLIST_DICT) { return MOBILESYNC_E_INVALID_ARG; } if (client->direction != MOBILESYNC_SYNC_DIR_COMPUTER_TO_DEVICE) { return MOBILESYNC_E_WRONG_DIRECTION; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; msg = create_process_changes_message(client->data_class, entities, (is_last_record > 0 ? 0 : 1), actions); err = mobilesync_send(client, msg); if (msg) { plist_free(msg); msg = NULL; } return err; }
/** * Cancels a running synchronization session with a device at any time. * * @param client The mobilesync client * @param reason The reason to supply to the device for cancelling * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) { if (!client || !client->data_class || !reason) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageCancelSession")); plist_array_append_item(msg, plist_new_string(client->data_class)); plist_array_append_item(msg, plist_new_string(reason)); err = mobilesync_send(client, msg); plist_free(msg); msg = NULL; free(client->data_class); client->data_class = NULL; client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
static void mobilesync_disconnect(mobilesync_client_t client) { if (!client) return; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); mobilesync_send(client, array); plist_free(array); array = NULL; }
/** * Acknowledges to the device that the changes have been merged on the computer * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } plist_t msg = NULL; mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageAcknowledgeChangesFromDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); plist_free(msg); return err; }
static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, const char *operation) { if (!client || !client->data_class || !operation) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string(operation)); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); if (msg) { plist_free(msg); msg = NULL; } return err; }
/** * Requests the device to delete all records of the current data class * * @note The operation must be called after starting synchronization. * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid form */ mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; plist_t response_type_node = NULL; char *response_type = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageClearAllRecordsOnDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(response_type, "SDMessageCancelSession")) { char *reason = NULL; err = MOBILESYNC_E_CANCELLED; plist_get_string_val(plist_array_get_item(msg, 2), &reason); debug_info("Device cancelled: %s", reason); free(reason); goto out; } if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords")) { err = MOBILESYNC_E_PLIST_ERROR; } out: if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } return err; }
/** * Finish a synchronization session of a data class on the device. * A session must have previously been started using mobilesync_start(). * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid * form */ mobilesync_error_t mobilesync_finish(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; plist_t response_type_node = NULL; char *response_type = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageFinishSessionOnDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(response_type, "SDMessageDeviceFinishedSession")) { err = MOBILESYNC_E_SUCCESS; } out: if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } free(client->data_class); client->data_class = NULL; client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
/** * Requests starting synchronization of a data class with the device * * @param client The mobilesync client * @param data_class The data class identifier to sync * @param anchors The anchors required to exchange with the device. The anchors * allow the device to tell if the synchronization information on the computer * and device are consistent to determine what sync type is required. * @param computer_data_class_version The version of the data class storage on the computer * @param sync_type A pointer to store the sync type reported by the device_anchor * @param device_data_class_version The version of the data class storage on the device * @param error_description A pointer to store an error message if reported by the device * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid form * @retval MOBILESYNC_E_SYNC_REFUSED if the device refused to sync * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * sync request */ mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) { if (!client || client->data_class || !data_class || !anchors || !anchors->computer_anchor) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; char *response_type = NULL; char *sync_type_str = NULL; plist_t msg = NULL; plist_t response_type_node = NULL; *error_description = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageSyncDataClassWithDevice")); plist_array_append_item(msg, plist_new_string(data_class)); if (anchors->device_anchor) { plist_array_append_item(msg, plist_new_string(anchors->device_anchor)); } else { plist_array_append_item(msg, plist_new_string("---")); } plist_array_append_item(msg, plist_new_string(anchors->computer_anchor)); plist_array_append_item(msg, plist_new_uint(computer_data_class_version)); plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } // did the device refuse to sync with the computer? if (!strcmp(response_type, "SDMessageRefuseToSyncDataClassWithComputer")) { err = MOBILESYNC_E_SYNC_REFUSED; plist_get_string_val(plist_array_get_item(msg, 2), error_description); debug_info("Device refused sync: %s", error_description); goto out; } // did the device cancel the session? if (!strcmp(response_type, "SDMessageCancelSession")) { err = MOBILESYNC_E_CANCELLED; plist_get_string_val(plist_array_get_item(msg, 2), error_description); debug_info("Device cancelled: %s", error_description); goto out; } if (sync_type != NULL) { plist_t sync_type_node = plist_array_get_item(msg, 4); if (!sync_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(sync_type_node, &sync_type_str); if (!sync_type_str) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(sync_type_str, "SDSyncTypeFast")) { *sync_type = MOBILESYNC_SYNC_TYPE_FAST; } else if (!strcmp(sync_type_str, "SDSyncTypeSlow")) { *sync_type = MOBILESYNC_SYNC_TYPE_SLOW; } else if (!strcmp(sync_type_str, "SDSyncTypeReset")) { *sync_type = MOBILESYNC_SYNC_TYPE_RESET; } else { err = MOBILESYNC_E_PLIST_ERROR; goto out; } } if (device_data_class_version != NULL) { plist_t device_data_class_version_node = plist_array_get_item(msg, 5); if (!device_data_class_version_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_uint_val(device_data_class_version_node, device_data_class_version); } err = MOBILESYNC_E_SUCCESS; out: if (sync_type_str) { free(sync_type_str); sync_type_str = NULL; } if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } client->data_class = strdup(data_class); client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, mobilesync_client_t * client) { if (!device || dst_port == 0 || !client || *client) return MOBILESYNC_E_INVALID_ARG; mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; /* Attempt connection */ iphone_connection_t connection = NULL; if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { return ret; } mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); client_loc->connection = connection; /* perform handshake */ plist_t array = NULL; /* first receive version */ ret = mobilesync_recv(client_loc, &array); plist_t msg_node = plist_find_node_by_string(array, "DLMessageVersionExchange"); plist_t ver_1 = plist_get_next_sibling(msg_node); plist_t ver_2 = plist_get_next_sibling(ver_1); plist_type ver_1_type = plist_get_node_type(ver_1); plist_type ver_2_type = plist_get_node_type(ver_2); if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) { uint64_t ver_1_val = 0; uint64_t ver_2_val = 0; plist_get_uint_val(ver_1, &ver_1_val); plist_get_uint_val(ver_2, &ver_2_val); plist_free(array); array = NULL; if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1 && ver_2_val == MSYNC_VERSION_INT2) { array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); plist_array_append_item(array, plist_new_string("DLVersionsOk")); ret = mobilesync_send(client_loc, array); plist_free(array); array = NULL; ret = mobilesync_recv(client_loc, &array); plist_t rep_node = plist_find_node_by_string(array, "DLMessageDeviceReady"); if (rep_node) { ret = MOBILESYNC_E_SUCCESS; *client = client_loc; } else { ret = MOBILESYNC_E_BAD_VERSION; } plist_free(array); array = NULL; } } if (MOBILESYNC_E_SUCCESS != ret) mobilesync_client_free(client_loc); return ret; }