diff options
| -rw-r--r-- | include/libimobiledevice/mobilebackup.h | 4 | ||||
| -rw-r--r-- | src/mobilebackup.c | 150 | 
2 files changed, 154 insertions, 0 deletions
| diff --git a/include/libimobiledevice/mobilebackup.h b/include/libimobiledevice/mobilebackup.h index e51d4c1..e29dbf4 100644 --- a/include/libimobiledevice/mobilebackup.h +++ b/include/libimobiledevice/mobilebackup.h @@ -35,6 +35,7 @@ extern "C" {  #define MOBILEBACKUP_E_PLIST_ERROR           -2  #define MOBILEBACKUP_E_MUX_ERROR             -3  #define MOBILEBACKUP_E_BAD_VERSION           -4 +#define MOBILEBACKUP_E_REPLY_NOT_OK          -5  #define MOBILEBACKUP_E_UNKNOWN_ERROR       -256 @@ -47,6 +48,9 @@ mobilebackup_error_t mobilebackup_client_new(idevice_t device, uint16_t port, mo  mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client);  mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t *plist);  mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist); +mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version); +mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client); +mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason);  #ifdef __cplusplus  } diff --git a/src/mobilebackup.c b/src/mobilebackup.c index 91b9e73..d4f36d6 100644 --- a/src/mobilebackup.c +++ b/src/mobilebackup.c @@ -129,3 +129,153 @@ mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t pli  	return mobilebackup_error(device_link_service_send(client->parent, plist));  } +/** + * 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 it as DLMessageProcessMessage */ +	err = mobilebackup_error(device_link_service_send_process_message(client->parent, 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_error(device_link_service_receive_process_message(client->parent, &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, "BackupMessageTypeKey"); +	if (!node) { +		debug_info("ERROR: BackupMessageTypeKey not found in BackupReplyOK message!"); +		err = MOBILEBACKUP_E_PLIST_ERROR; +		goto leave; +	} + +	char *str = NULL; +	plist_get_string_val(node, &str); +	if (!str || (strcmp(str, "BackupMessageBackupReplyOK") != 0)) { +		debug_info("ERROR: BackupMessageTypeKey value does not match 'BackupMessageBackupReplyOK'"); +		err = MOBILEBACKUP_E_REPLY_NOT_OK; +		if (str) +			free(str); +		goto leave; +	} +	free(str); +	str = NULL; + +	node = plist_dict_get_item(dict, "BackupProtocolVersion"); +	if (node) { +		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_error(device_link_service_send_process_message(client->parent, 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 confirmation to the device that a backup file has been received. + * + * @param client The connected MobileBackup client to use. + *  + * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if + *    client is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication error + *    occurs. + */ +mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) +{ +	if (!client || !client->parent) +		return MOBILEBACKUP_E_INVALID_ARG; + +	mobilebackup_error_t err; + +	/* construct ACK plist */ +	plist_t dict = plist_new_dict(); +	plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("kBackupMessageBackupFileReceived")); + +	/* send it as DLMessageProcessMessage */ +	err = mobilebackup_error(device_link_service_send_process_message(client->parent, dict)); +	plist_free(dict); + +	return err; +} + +/** + * Sends a backup error message to the device. + * + * @param client The connected MobileBackup client to use. + * @param reason A string describing the reason for the error message. + *  + * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if + *    one of the parameters is invalid, or MOBILEBACKUP_E_MUX_ERROR if a + *    communication error occurs. + */ +mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) +{ +	if (!client || !client->parent || !reason) +		return MOBILEBACKUP_E_INVALID_ARG; + +	mobilebackup_error_t err; + +	/* construct error plist */ +	plist_t dict = plist_new_dict(); +	plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageError")); +	plist_dict_insert_item(dict, "BackupErrorReasonKey", plist_new_string(reason)); + +	/* send it as DLMessageProcessMessage */ +	err = mobilebackup_error(device_link_service_send_process_message(client->parent, dict)); +	plist_free(dict); + +	return err; +} | 
