From 5ac0f4272b4985627ae27693b28c93eea37a4d3b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 16 Mar 2010 02:18:16 +0100 Subject: mobilebackup: new functions added --- include/libimobiledevice/mobilebackup.h | 4 + src/mobilebackup.c | 150 ++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) 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; +} -- cgit v1.1-32-gdbae