summaryrefslogtreecommitdiffstats
path: root/src/mobilebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mobilebackup.c')
-rw-r--r--src/mobilebackup.c227
1 files changed, 57 insertions, 170 deletions
diff --git a/src/mobilebackup.c b/src/mobilebackup.c
index fcff60d..36986a4 100644
--- a/src/mobilebackup.c
+++ b/src/mobilebackup.c
@@ -1,36 +1,41 @@
1/* 1/*
2 * mobilebackup.c 2 * mobilebackup.c
3 * Contains functions for the built-in MobileBackup client. 3 * Contains functions for the built-in MobileBackup client.
4 * 4 *
5 * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
5 * Copyright (c) 2009 Martin Szulecki All Rights Reserved. 6 * Copyright (c) 2009 Martin Szulecki All Rights Reserved.
6 * 7 *
7 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version. 11 * version 2.1 of the License, or (at your option) any later version.
11 * 12 *
12 * This library is distributed in the hope that it will be useful, 13 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
16 * 17 *
17 * You should have received a copy of the GNU Lesser General Public 18 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software 19 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 21 */
21 22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
22#include <plist/plist.h> 26#include <plist/plist.h>
23#include <string.h> 27#include <string.h>
24#include <stdlib.h> 28#include <stdlib.h>
29#include <stdio.h>
25 30
26#include "mobilebackup.h" 31#include "mobilebackup.h"
27#include "device_link_service.h" 32#include "device_link_service.h"
28#include "debug.h" 33#include "common/debug.h"
29 34
30#define MBACKUP_VERSION_INT1 100 35#define MBACKUP_VERSION_INT1 100
31#define MBACKUP_VERSION_INT2 0 36#define MBACKUP_VERSION_INT2 0
32 37
33#define IS_FLAG_SET(x, y) ((x & y) == y) 38#define IS_FLAG_SET(x, y) (((x) & (y)) == (y))
34 39
35/** 40/**
36 * Convert an device_link_service_error_t value to an mobilebackup_error_t value. 41 * Convert an device_link_service_error_t value to an mobilebackup_error_t value.
@@ -52,6 +57,10 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err)
52 return MOBILEBACKUP_E_PLIST_ERROR; 57 return MOBILEBACKUP_E_PLIST_ERROR;
53 case DEVICE_LINK_SERVICE_E_MUX_ERROR: 58 case DEVICE_LINK_SERVICE_E_MUX_ERROR:
54 return MOBILEBACKUP_E_MUX_ERROR; 59 return MOBILEBACKUP_E_MUX_ERROR;
60 case DEVICE_LINK_SERVICE_E_SSL_ERROR:
61 return MOBILEBACKUP_E_SSL_ERROR;
62 case DEVICE_LINK_SERVICE_E_RECEIVE_TIMEOUT:
63 return MOBILEBACKUP_E_RECEIVE_TIMEOUT;
55 case DEVICE_LINK_SERVICE_E_BAD_VERSION: 64 case DEVICE_LINK_SERVICE_E_BAD_VERSION:
56 return MOBILEBACKUP_E_BAD_VERSION; 65 return MOBILEBACKUP_E_BAD_VERSION;
57 default: 66 default:
@@ -60,26 +69,13 @@ static mobilebackup_error_t mobilebackup_error(device_link_service_error_t err)
60 return MOBILEBACKUP_E_UNKNOWN_ERROR; 69 return MOBILEBACKUP_E_UNKNOWN_ERROR;
61} 70}
62 71
63/** 72mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilebackup_client_t * client)
64 * Connects to the mobilebackup service on the specified device.
65 *
66 * @param device The device to connect to.
67 * @param port Destination port (usually given by lockdownd_start_service).
68 * @param client Pointer that will be set to a newly allocated
69 * mobilebackup_client_t upon successful return.
70 *
71 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID ARG if one
72 * or more parameters are invalid, or DEVICE_LINK_SERVICE_E_BAD_VERSION if
73 * the mobilebackup version on the device is newer.
74 */
75mobilebackup_error_t mobilebackup_client_new(idevice_t device, uint16_t port,
76 mobilebackup_client_t * client)
77{ 73{
78 if (!device || port == 0 || !client || *client) 74 if (!device || !service || service->port == 0 || !client || *client)
79 return MOBILEBACKUP_E_INVALID_ARG; 75 return MOBILEBACKUP_E_INVALID_ARG;
80 76
81 device_link_service_client_t dlclient = NULL; 77 device_link_service_client_t dlclient = NULL;
82 mobilebackup_error_t ret = mobilebackup_error(device_link_service_client_new(device, port, &dlclient)); 78 mobilebackup_error_t ret = mobilebackup_error(device_link_service_client_new(device, service, &dlclient));
83 if (ret != MOBILEBACKUP_E_SUCCESS) { 79 if (ret != MOBILEBACKUP_E_SUCCESS) {
84 return ret; 80 return ret;
85 } 81 }
@@ -100,36 +96,26 @@ mobilebackup_error_t mobilebackup_client_new(idevice_t device, uint16_t port,
100 return ret; 96 return ret;
101} 97}
102 98
103/** 99mobilebackup_error_t mobilebackup_client_start_service(idevice_t device, mobilebackup_client_t * client, const char* label)
104 * Disconnects a mobilebackup client from the device and frees up the 100{
105 * mobilebackup client data. 101 mobilebackup_error_t err = MOBILEBACKUP_E_UNKNOWN_ERROR;
106 * 102 service_client_factory_start_service(device, MOBILEBACKUP_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(mobilebackup_client_new), &err);
107 * @param client The mobilebackup client to disconnect and free. 103 return err;
108 * 104}
109 * @return MOBILEBACKUP_E_SUCCESS on success, or MOBILEBACKUP_E_INVALID_ARG 105
110 * if client is NULL.
111 */
112mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) 106mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client)
113{ 107{
114 if (!client) 108 if (!client)
115 return MOBILEBACKUP_E_INVALID_ARG; 109 return MOBILEBACKUP_E_INVALID_ARG;
116 mobilebackup_error_t err = MOBILEBACKUP_E_SUCCESS; 110 mobilebackup_error_t err = MOBILEBACKUP_E_SUCCESS;
117 if (client->parent) { 111 if (client->parent) {
118 device_link_service_disconnect(client->parent); 112 device_link_service_disconnect(client->parent, NULL);
119 err = mobilebackup_error(device_link_service_client_free(client->parent)); 113 err = mobilebackup_error(device_link_service_client_free(client->parent));
120 } 114 }
121 free(client); 115 free(client);
122 return err; 116 return err;
123} 117}
124 118
125/**
126 * Polls the device for mobilebackup data.
127 *
128 * @param client The mobilebackup client
129 * @param plist A pointer to the location where the plist should be stored
130 *
131 * @return an error code
132 */
133mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist) 119mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t * plist)
134{ 120{
135 if (!client) 121 if (!client)
@@ -138,17 +124,6 @@ mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist_t
138 return ret; 124 return ret;
139} 125}
140 126
141/**
142 * Sends mobilebackup data to the device
143 *
144 * @note This function is low-level and should only be used if you need to send
145 * a new type of message.
146 *
147 * @param client The mobilebackup client
148 * @param plist The location of the plist to send
149 *
150 * @return an error code
151 */
152mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist) 127mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist_t plist)
153{ 128{
154 if (!client || !plist) 129 if (!client || !plist)
@@ -186,7 +161,7 @@ static mobilebackup_error_t mobilebackup_send_message(mobilebackup_client_t clie
186 } else { 161 } else {
187 dict = plist_new_dict(); 162 dict = plist_new_dict();
188 } 163 }
189 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string(message)); 164 plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string(message));
190 165
191 /* send it as DLMessageProcessMessage */ 166 /* send it as DLMessageProcessMessage */
192 err = mobilebackup_error(device_link_service_send_process_message(client->parent, dict)); 167 err = mobilebackup_error(device_link_service_send_process_message(client->parent, dict));
@@ -266,23 +241,6 @@ leave:
266 return err; 241 return err;
267} 242}
268 243
269/**
270 * Request a backup from the connected device.
271 *
272 * @param client The connected MobileBackup client to use.
273 * @param backup_manifest The backup manifest, a plist_t of type PLIST_DICT
274 * containing the backup state of the last backup. For a first-time backup
275 * set this parameter to NULL.
276 * @param base_path The base path on the device to use for the backup
277 * operation, usually "/".
278 * @param proto_version A string denoting the version of the backup protocol
279 * to use. Latest known version is "1.6"
280 *
281 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
282 * one of the parameters is invalid, MOBILEBACKUP_E_PLIST_ERROR if
283 * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR
284 * if a communication error occurs, MOBILEBACKUP_E_REPLY_NOT_OK
285 */
286mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version) 244mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist_t backup_manifest, const char *base_path, const char *proto_version)
287{ 245{
288 if (!client || !client->parent || !base_path || !proto_version) 246 if (!client || !client->parent || !base_path || !proto_version)
@@ -296,10 +254,10 @@ mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, p
296 /* construct request plist */ 254 /* construct request plist */
297 plist_t dict = plist_new_dict(); 255 plist_t dict = plist_new_dict();
298 if (backup_manifest) 256 if (backup_manifest)
299 plist_dict_insert_item(dict, "BackupManifestKey", plist_copy(backup_manifest)); 257 plist_dict_set_item(dict, "BackupManifestKey", plist_copy(backup_manifest));
300 plist_dict_insert_item(dict, "BackupComputerBasePathKey", plist_new_string(base_path)); 258 plist_dict_set_item(dict, "BackupComputerBasePathKey", plist_new_string(base_path));
301 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); 259 plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest"));
302 plist_dict_insert_item(dict, "BackupProtocolVersion", plist_new_string(proto_version)); 260 plist_dict_set_item(dict, "BackupProtocolVersion", plist_new_string(proto_version));
303 261
304 /* send request */ 262 /* send request */
305 err = mobilebackup_send_message(client, NULL, dict); 263 err = mobilebackup_send_message(client, NULL, dict);
@@ -322,7 +280,15 @@ mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, p
322 char *str = NULL; 280 char *str = NULL;
323 plist_get_string_val(node, &str); 281 plist_get_string_val(node, &str);
324 if (str) { 282 if (str) {
325 if (strcmp(str, proto_version) != 0) { 283 int maj = 0;
284 int min = 0;
285 sscanf(str, "%u.%u", &maj, &min);
286 uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
287 maj = 0;
288 min = 0;
289 sscanf(proto_version, "%u.%u", &maj, &min);
290 uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
291 if (this_ver > proto_ver) {
326 err = MOBILEBACKUP_E_BAD_VERSION; 292 err = MOBILEBACKUP_E_BAD_VERSION;
327 } 293 }
328 free(str); 294 free(str);
@@ -343,41 +309,11 @@ leave:
343 return err; 309 return err;
344} 310}
345 311
346/**
347 * Sends a confirmation to the device that a backup file has been received.
348 *
349 * @param client The connected MobileBackup client to use.
350 *
351 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
352 * client is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication error
353 * occurs.
354 */
355mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) 312mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client)
356{ 313{
357 return mobilebackup_send_message(client, "kBackupMessageBackupFileReceived", NULL); 314 return mobilebackup_send_message(client, "kBackupMessageBackupFileReceived", NULL);
358} 315}
359 316
360/**
361 * Request that a backup should be restored to the connected device.
362 *
363 * @param client The connected MobileBackup client to use.
364 * @param backup_manifest The backup manifest, a plist_t of type PLIST_DICT
365 * containing the backup state to be restored.
366 * @param flags Flags to send with the request. Currently this is a combination
367 * of the following mobilebackup_flags_t:
368 * MB_RESTORE_NOTIFY_SPRINGBOARD - let SpringBoard show a 'Restore' screen
369 * MB_RESTORE_PRESERVE_SETTINGS - do not overwrite any settings
370 * MB_RESTORE_PRESERVE_CAMERA_ROLL - preserve the photos of the camera roll
371 * @param proto_version A string denoting the version of the backup protocol
372 * to use. Latest known version is "1.6". Ideally this value should be
373 * extracted from the given manifest plist.
374 *
375 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
376 * one of the parameters is invalid, MOBILEBACKUP_E_PLIST_ERROR if
377 * backup_manifest is not of type PLIST_DICT, MOBILEBACKUP_E_MUX_ERROR
378 * if a communication error occurs, or MOBILEBACKUP_E_REPLY_NOT_OK
379 * if the device did not accept the request.
380 */
381mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version) 317mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist_t backup_manifest, mobilebackup_flags_t flags, const char *proto_version)
382{ 318{
383 if (!client || !client->parent || !backup_manifest || !proto_version) 319 if (!client || !client->parent || !backup_manifest || !proto_version)
@@ -390,13 +326,13 @@ mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client,
390 326
391 /* construct request plist */ 327 /* construct request plist */
392 plist_t dict = plist_new_dict(); 328 plist_t dict = plist_new_dict();
393 plist_dict_insert_item(dict, "BackupManifestKey", plist_copy(backup_manifest)); 329 plist_dict_set_item(dict, "BackupManifestKey", plist_copy(backup_manifest));
394 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("kBackupMessageRestoreRequest")); 330 plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("kBackupMessageRestoreRequest"));
395 plist_dict_insert_item(dict, "BackupProtocolVersion", plist_new_string(proto_version)); 331 plist_dict_set_item(dict, "BackupProtocolVersion", plist_new_string(proto_version));
396 /* add flags */ 332 /* add flags */
397 plist_dict_insert_item(dict, "BackupNotifySpringBoard", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_NOTIFY_SPRINGBOARD))); 333 plist_dict_set_item(dict, "BackupNotifySpringBoard", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_NOTIFY_SPRINGBOARD)));
398 plist_dict_insert_item(dict, "BackupPreserveSettings", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_SETTINGS))); 334 plist_dict_set_item(dict, "BackupPreserveSettings", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_SETTINGS)));
399 plist_dict_insert_item(dict, "BackupPreserveCameraRoll", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_CAMERA_ROLL))); 335 plist_dict_set_item(dict, "BackupPreserveCameraRoll", plist_new_bool(IS_FLAG_SET(flags, MB_RESTORE_PRESERVE_CAMERA_ROLL)));
400 336
401 /* send request */ 337 /* send request */
402 err = mobilebackup_send_message(client, NULL, dict); 338 err = mobilebackup_send_message(client, NULL, dict);
@@ -419,7 +355,15 @@ mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client,
419 char *str = NULL; 355 char *str = NULL;
420 plist_get_string_val(node, &str); 356 plist_get_string_val(node, &str);
421 if (str) { 357 if (str) {
422 if (strcmp(str, proto_version) != 0) { 358 int maj = 0;
359 int min = 0;
360 sscanf(str, "%u.%u", &maj, &min);
361 uint32_t this_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
362 maj = 0;
363 min = 0;
364 sscanf(proto_version, "%u.%u", &maj, &min);
365 uint32_t proto_ver = ((maj & 0xFF) << 8) | (min & 0xFF);
366 if (this_ver > proto_ver) {
423 err = MOBILEBACKUP_E_BAD_VERSION; 367 err = MOBILEBACKUP_E_BAD_VERSION;
424 } 368 }
425 free(str); 369 free(str);
@@ -432,63 +376,16 @@ leave:
432 return err; 376 return err;
433} 377}
434 378
435/**
436 * Receive a confirmation from the device that it successfully received
437 * a restore file.
438 *
439 * @param client The connected MobileBackup client to use.
440 * @param result Pointer to a plist_t that will be set to the received plist
441 * for further processing. The caller has to free it using plist_free().
442 * Note that it will be set to NULL if the operation itself fails due to
443 * a communication or plist error.
444 * If this parameter is NULL, it will be ignored.
445 *
446 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
447 * client is invalid, MOBILEBACKUP_E_REPLY_NOT_OK if the expected
448 * 'BackupMessageRestoreFileReceived' message could not be received,
449 * MOBILEBACKUP_E_PLIST_ERROR if the received message is not a valid backup
450 * message plist, or MOBILEBACKUP_E_MUX_ERROR if a communication error
451 * occurs.
452 */
453mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result) 379mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist_t *result)
454{ 380{
455 return mobilebackup_receive_message(client, "BackupMessageRestoreFileReceived", result); 381 return mobilebackup_receive_message(client, "BackupMessageRestoreFileReceived", result);
456} 382}
457 383
458/**
459 * Receive a confirmation from the device that it successfully received
460 * application data file.
461 *
462 * @param client The connected MobileBackup client to use.
463 * @param result Pointer to a plist_t that will be set to the received plist
464 * for further processing. The caller has to free it using plist_free().
465 * Note that it will be set to NULL if the operation itself fails due to
466 * a communication or plist error.
467 * If this parameter is NULL, it will be ignored.
468 *
469 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
470 * client is invalid, MOBILEBACKUP_E_REPLY_NOT_OK if the expected
471 * 'BackupMessageRestoreApplicationReceived' message could not be received,
472 * MOBILEBACKUP_E_PLIST_ERROR if the received message is not a valid backup
473 * message plist, or MOBILEBACKUP_E_MUX_ERROR if a communication error
474 * occurs.
475 */
476mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result) 384mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist_t *result)
477{ 385{
478 return mobilebackup_receive_message(client, "BackupMessageRestoreApplicationReceived", result); 386 return mobilebackup_receive_message(client, "BackupMessageRestoreApplicationReceived", result);
479} 387}
480 388
481/**
482 * Tells the device that the restore process is complete and waits for the
483 * device to close the connection. After that, the device should reboot.
484 *
485 * @param client The connected MobileBackup client to use.
486 *
487 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
488 * client is invalid, MOBILEBACKUP_E_PLIST_ERROR if the received disconnect
489 * message plist is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication
490 * error occurs.
491 */
492mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) 389mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client)
493{ 390{
494 mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL); 391 mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL);
@@ -534,16 +431,6 @@ mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t cl
534 return err; 431 return err;
535} 432}
536 433
537/**
538 * Sends a backup error message to the device.
539 *
540 * @param client The connected MobileBackup client to use.
541 * @param reason A string describing the reason for the error message.
542 *
543 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
544 * one of the parameters is invalid, or MOBILEBACKUP_E_MUX_ERROR if a
545 * communication error occurs.
546 */
547mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason) 434mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const char *reason)
548{ 435{
549 if (!client || !client->parent || !reason) 436 if (!client || !client->parent || !reason)
@@ -553,7 +440,7 @@ mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, const
553 440
554 /* construct error plist */ 441 /* construct error plist */
555 plist_t dict = plist_new_dict(); 442 plist_t dict = plist_new_dict();
556 plist_dict_insert_item(dict, "BackupErrorReasonKey", plist_new_string(reason)); 443 plist_dict_set_item(dict, "BackupErrorReasonKey", plist_new_string(reason));
557 444
558 err = mobilebackup_send_message(client, "BackupMessageError", dict); 445 err = mobilebackup_send_message(client, "BackupMessageError", dict);
559 plist_free(dict); 446 plist_free(dict);