summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libiphone/installation_proxy.h30
-rw-r--r--src/installation_proxy.c271
2 files changed, 165 insertions, 136 deletions
diff --git a/include/libiphone/installation_proxy.h b/include/libiphone/installation_proxy.h
index f796054..b7bbb60 100644
--- a/include/libiphone/installation_proxy.h
+++ b/include/libiphone/installation_proxy.h
@@ -28,6 +28,7 @@ extern "C" {
28#endif 28#endif
29 29
30#include <libiphone/libiphone.h> 30#include <libiphone/libiphone.h>
31#include <glib.h>
31 32
32/* Error Codes */ 33/* Error Codes */
33#define INSTPROXY_E_SUCCESS 0 34#define INSTPROXY_E_SUCCESS 0
@@ -41,15 +42,6 @@ extern "C" {
41 42
42typedef int16_t instproxy_error_t; 43typedef int16_t instproxy_error_t;
43 44
44typedef enum {
45 INSTPROXY_APPTYPE_ALL = 0,
46 INSTPROXY_APPTYPE_SYSTEM = 1,
47 INSTPROXY_APPTYPE_USER = 2
48} instproxy_apptype_t;
49
50#define INSTPROXY_ARCHIVE_APP_ONLY (1 << 0)
51#define INSTPROXY_ARCHIVE_SKIP_UNINSTALL (1 << 1)
52
53struct instproxy_client_int; 45struct instproxy_client_int;
54typedef struct instproxy_client_int *instproxy_client_t; 46typedef struct instproxy_client_int *instproxy_client_t;
55 47
@@ -59,15 +51,19 @@ typedef void (*instproxy_status_cb_t) (const char *operation, plist_t status);
59instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client); 51instproxy_error_t instproxy_client_new(iphone_device_t device, uint16_t port, instproxy_client_t *client);
60instproxy_error_t instproxy_client_free(instproxy_client_t client); 52instproxy_error_t instproxy_client_free(instproxy_client_t client);
61 53
62instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result); 54instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result);
63instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb); 55instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb);
64instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb); 56instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb);
65instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb); 57instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb);
58
59instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result);
60instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb);
61instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb);
62instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb);
66 63
67instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result); 64plist_t instproxy_client_options_new();
68instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb); 65void instproxy_client_options_add(plist_t client_options, ...) G_GNUC_NULL_TERMINATED;
69instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb); 66void instproxy_client_options_free(plist_t client_options);
70instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb);
71 67
72#ifdef __cplusplus 68#ifdef __cplusplus
73} 69}
diff --git a/src/installation_proxy.c b/src/installation_proxy.c
index a99b5cb..e0bccd3 100644
--- a/src/installation_proxy.c
+++ b/src/installation_proxy.c
@@ -143,55 +143,71 @@ instproxy_error_t instproxy_client_free(instproxy_client_t client)
143} 143}
144 144
145/** 145/**
146 * Send a command with specified options to the device.
147 * Internally used only.
148 *
149 * @param client The connected installation_proxy client.
150 * @param command The command to execute. Required.
151 * @param client_options The client options to use, as PLIST_DICT, or NULL.
152 * @param appid The ApplicationIdentifier to add or NULL if not required.
153 * @param package_path The installation package path or NULL if not required.
154 *
155 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if
156 * an error occured.
157 */
158static instproxy_error_t instproxy_send_command(instproxy_client_t client, const char *command, plist_t client_options, const char *appid, const char *package_path)
159{
160 if (!client || !command || (client_options && (plist_get_node_type(client_options) != PLIST_DICT)))
161 return INSTPROXY_E_INVALID_ARG;
162
163 plist_t dict = plist_new_dict();
164 if (appid) {
165 plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid));
166 }
167 if (client_options && (plist_dict_get_size(client_options) > 0)) {
168 plist_dict_insert_item(dict, "ClientOptions", plist_copy(client_options));
169 }
170 plist_dict_insert_item(dict, "Command", plist_new_string(command));
171 if (package_path) {
172 plist_dict_insert_item(dict, "PackagePath", plist_new_string(package_path));
173 }
174
175 instproxy_error_t err = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
176 plist_free(dict);
177 return err;
178}
179
180/**
146 * List installed applications. This function runs synchronously. 181 * List installed applications. This function runs synchronously.
147 * 182 *
148 * @param client The connected installation_proxy client 183 * @param client The connected installation_proxy client
149 * @param apptype The type of applications to list. 184 * @param client_options The client options to use, as PLIST_DICT, or NULL.
185 * Valid client options include:
186 * "ApplicationType" -> "User"
187 * "ApplicationType" -> "System"
150 * @param result Pointer that will be set to a plist that will hold an array 188 * @param result Pointer that will be set to a plist that will hold an array
151 * of PLIST_DICT holding information about the applications found. 189 * of PLIST_DICT holding information about the applications found.
152 * 190 *
153 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if 191 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if
154 * an error occured. 192 * an error occured.
155 */ 193 */
156instproxy_error_t instproxy_browse(instproxy_client_t client, instproxy_apptype_t apptype, plist_t *result) 194instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result)
157{ 195{
158 if (!client || !client->parent || !result) 196 if (!client || !client->parent || !result)
159 return INSTPROXY_E_INVALID_ARG; 197 return INSTPROXY_E_INVALID_ARG;
160 198
161 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; 199 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
162 int browsing = 0;
163 plist_t apps_array = NULL;
164
165 plist_t dict = plist_new_dict();
166 if (apptype != INSTPROXY_APPTYPE_ALL) {
167 plist_t client_opts = plist_new_dict();
168 plist_t p_apptype = NULL;
169 switch (apptype) {
170 case INSTPROXY_APPTYPE_SYSTEM:
171 p_apptype = plist_new_string("System");
172 break;
173 case INSTPROXY_APPTYPE_USER:
174 p_apptype = plist_new_string("User");
175 break;
176 default:
177 debug_info("unknown apptype %d given, using INSTPROXY_APPTYPE_USER instead", apptype);
178 p_apptype = plist_new_string("User");
179 break;
180 }
181 plist_dict_insert_item(client_opts, "ApplicationType", p_apptype);
182 plist_dict_insert_item(dict, "ClientOptions", client_opts);
183 }
184 plist_dict_insert_item(dict, "Command", plist_new_string("Browse"));
185 200
186 instproxy_lock(client); 201 instproxy_lock(client);
187 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 202 res = instproxy_send_command(client, "Browse", client_options, NULL, NULL);
188 plist_free(dict);
189 if (res != INSTPROXY_E_SUCCESS) { 203 if (res != INSTPROXY_E_SUCCESS) {
190 debug_info("could not send plist"); 204 debug_info("could not send plist");
191 goto leave_unlock; 205 goto leave_unlock;
192 } 206 }
193 207
194 apps_array = plist_new_array(); 208 int browsing = 0;
209 plist_t apps_array = plist_new_array();
210 plist_t dict = NULL;
195 211
196 do { 212 do {
197 browsing = 0; 213 browsing = 0;
@@ -393,8 +409,7 @@ static instproxy_error_t instproxy_create_status_updater(instproxy_client_t clie
393 * 409 *
394 * @param client The connected installation_proxy client 410 * @param client The connected installation_proxy client
395 * @param pkg_path Path of the installation package (inside the AFC jail) 411 * @param pkg_path Path of the installation package (inside the AFC jail)
396 * @param sinf PLIST_DATA node holding the package's SINF data or NULL. 412 * @param client_options The client options to use, as PLIST_DICT, or NULL.
397 * @param metadata PLIST_DATA node holding the packages's Metadata or NULL.
398 * @param status_cb Callback function for progress and status information. If 413 * @param status_cb Callback function for progress and status information. If
399 * NULL is passed, this function will run synchronously. 414 * NULL is passed, this function will run synchronously.
400 * @param command The command to execute. 415 * @param command The command to execute.
@@ -402,42 +417,19 @@ static instproxy_error_t instproxy_create_status_updater(instproxy_client_t clie
402 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if 417 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if
403 * an error occured. 418 * an error occured.
404 */ 419 */
405static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb, const char *command) 420static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb, const char *command)
406{ 421{
407 if (!client || !client->parent || !pkg_path) { 422 if (!client || !client->parent || !pkg_path) {
408 return INSTPROXY_E_INVALID_ARG; 423 return INSTPROXY_E_INVALID_ARG;
409 } 424 }
410 if (sinf && (plist_get_node_type(sinf) != PLIST_DATA)) {
411 debug_info("(%s): ERROR: sinf data is not a PLIST_DATA node!", command);
412 return INSTPROXY_E_INVALID_ARG;
413 }
414 if (metadata && (plist_get_node_type(metadata) != PLIST_DATA)) {
415 debug_info("(%s): ERROR: metadata is not a PLIST_DATA node!", command);
416 return INSTPROXY_E_INVALID_ARG;
417 }
418
419 if (client->status_updater) { 425 if (client->status_updater) {
420 return INSTPROXY_E_OP_IN_PROGRESS; 426 return INSTPROXY_E_OP_IN_PROGRESS;
421 } 427 }
422 428
423 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
424
425 plist_t dict = plist_new_dict();
426 if (sinf && metadata) {
427 plist_t client_opts = plist_new_dict();
428 plist_dict_insert_item(client_opts, "ApplicationSINF", plist_copy(sinf));
429 plist_dict_insert_item(client_opts, "iTunesMetadata", plist_copy(metadata));
430 plist_dict_insert_item(dict, "ClientOptions", client_opts);
431 }
432 plist_dict_insert_item(dict, "Command", plist_new_string(command));
433 plist_dict_insert_item(dict, "PackagePath", plist_new_string(pkg_path));
434
435 instproxy_lock(client); 429 instproxy_lock(client);
436 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 430 instproxy_error_t res = instproxy_send_command(client, command, client_options, NULL, pkg_path);
437 instproxy_unlock(client); 431 instproxy_unlock(client);
438 432
439 plist_free(dict);
440
441 if (res != INSTPROXY_E_SUCCESS) { 433 if (res != INSTPROXY_E_SUCCESS) {
442 debug_info("could not send plist, error %d", res); 434 debug_info("could not send plist, error %d", res);
443 return res; 435 return res;
@@ -451,8 +443,13 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client,
451 * 443 *
452 * @param client The connected installation_proxy client 444 * @param client The connected installation_proxy client
453 * @param pkg_path Path of the installation package (inside the AFC jail) 445 * @param pkg_path Path of the installation package (inside the AFC jail)
454 * @param sinf PLIST_DATA node holding the package's SINF data or NULL. 446 * @param client_options The client options to use, as PLIST_DICT, or NULL.
455 * @param metadata PLIST_DATA node holding the packages's Metadata or NULL. 447 * Valid options include:
448 * "iTunesMetadata" -> PLIST_DATA
449 * "ApplicationSINF" -> PLIST_DATA
450 * "PackageType" -> "Developer"
451 * If PackageType -> Developer is specified, then pkg_path points to
452 * an .app directory instead of an install package.
456 * @param status_cb Callback function for progress and status information. If 453 * @param status_cb Callback function for progress and status information. If
457 * NULL is passed, this function will run synchronously. 454 * NULL is passed, this function will run synchronously.
458 * 455 *
@@ -464,9 +461,9 @@ static instproxy_error_t instproxy_install_or_upgrade(instproxy_client_t client,
464 * created successfully; any error occuring during the operation has to be 461 * created successfully; any error occuring during the operation has to be
465 * handled inside the specified callback function. 462 * handled inside the specified callback function.
466 */ 463 */
467instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb) 464instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb)
468{ 465{
469 return instproxy_install_or_upgrade(client, pkg_path, sinf, metadata, status_cb, "Install"); 466 return instproxy_install_or_upgrade(client, pkg_path, client_options, status_cb, "Install");
470} 467}
471 468
472/** 469/**
@@ -476,8 +473,13 @@ instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_p
476 * 473 *
477 * @param client The connected installation_proxy client 474 * @param client The connected installation_proxy client
478 * @param pkg_path Path of the installation package (inside the AFC jail) 475 * @param pkg_path Path of the installation package (inside the AFC jail)
479 * @param sinf PLIST_DATA node holding the package's SINF data or NULL. 476 * @param client_options The client options to use, as PLIST_DICT, or NULL.
480 * @param metadata PLIST_DATA node holding the packages's Metadata or NULL. 477 * Valid options include:
478 * "iTunesMetadata" -> PLIST_DATA
479 * "ApplicationSINF" -> PLIST_DATA
480 * "PackageType" -> "Developer"
481 * If PackageType -> Developer is specified, then pkg_path points to
482 * an .app directory instead of an install package.
481 * @param status_cb Callback function for progress and status information. If 483 * @param status_cb Callback function for progress and status information. If
482 * NULL is passed, this function will run synchronously. 484 * NULL is passed, this function will run synchronously.
483 * 485 *
@@ -489,9 +491,9 @@ instproxy_error_t instproxy_install(instproxy_client_t client, const char *pkg_p
489 * created successfully; any error occuring during the operation has to be 491 * created successfully; any error occuring during the operation has to be
490 * handled inside the specified callback function. 492 * handled inside the specified callback function.
491 */ 493 */
492instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t sinf, plist_t metadata, instproxy_status_cb_t status_cb) 494instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_path, plist_t client_options, instproxy_status_cb_t status_cb)
493{ 495{
494 return instproxy_install_or_upgrade(client, pkg_path, sinf, metadata, status_cb, "Upgrade"); 496 return instproxy_install_or_upgrade(client, pkg_path, client_options, status_cb, "Upgrade");
495} 497}
496 498
497/** 499/**
@@ -499,6 +501,8 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p
499 * 501 *
500 * @param client The connected installation proxy client 502 * @param client The connected installation proxy client
501 * @param appid ApplicationIdentifier of the app to uninstall 503 * @param appid ApplicationIdentifier of the app to uninstall
504 * @param client_options The client options to use, as PLIST_DICT, or NULL.
505 * Currently there are no known client options, so pass NULL here.
502 * @param status_cb Callback function for progress and status information. If 506 * @param status_cb Callback function for progress and status information. If
503 * NULL is passed, this function will run synchronously. 507 * NULL is passed, this function will run synchronously.
504 * 508 *
@@ -510,7 +514,7 @@ instproxy_error_t instproxy_upgrade(instproxy_client_t client, const char *pkg_p
510 * created successfully; any error occuring during the operation has to be 514 * created successfully; any error occuring during the operation has to be
511 * handled inside the specified callback function. 515 * handled inside the specified callback function.
512 */ 516 */
513instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 517instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb)
514{ 518{
515 if (!client || !client->parent || !appid) { 519 if (!client || !client->parent || !appid) {
516 return INSTPROXY_E_INVALID_ARG; 520 return INSTPROXY_E_INVALID_ARG;
@@ -526,7 +530,7 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app
526 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall")); 530 plist_dict_insert_item(dict, "Command", plist_new_string("Uninstall"));
527 531
528 instproxy_lock(client); 532 instproxy_lock(client);
529 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 533 res = instproxy_send_command(client, "Uninstall", client_options, appid, NULL);
530 instproxy_unlock(client); 534 instproxy_unlock(client);
531 535
532 plist_free(dict); 536 plist_free(dict);
@@ -545,26 +549,21 @@ instproxy_error_t instproxy_uninstall(instproxy_client_t client, const char *app
545 * @see instproxy_archive 549 * @see instproxy_archive
546 * 550 *
547 * @param client The connected installation_proxy client 551 * @param client The connected installation_proxy client
552 * @param client_options The client options to use, as PLIST_DICT, or NULL.
553 * Currently there are no known client options, so pass NULL here.
548 * @param result Pointer that will be set to a plist containing a PLIST_DICT 554 * @param result Pointer that will be set to a plist containing a PLIST_DICT
549 * holding information about the archived applications found. 555 * holding information about the archived applications found.
550 * 556 *
551 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if 557 * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if
552 * an error occured. 558 * an error occured.
553 */ 559 */
554instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t *result) 560instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist_t client_options, plist_t *result)
555{ 561{
556 if (!client || !client->parent || !result) 562 if (!client || !client->parent || !result)
557 return INSTPROXY_E_INVALID_ARG; 563 return INSTPROXY_E_INVALID_ARG;
558 564
559 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
560
561 plist_t dict = plist_new_dict();
562 plist_dict_insert_item(dict, "Command", plist_new_string("LookupArchives"));
563
564 instproxy_lock(client); 565 instproxy_lock(client);
565 566 instproxy_error_t res = instproxy_send_command(client, "LookupArchives", client_options, NULL, NULL);
566 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict));
567 plist_free(dict);
568 567
569 if (res != INSTPROXY_E_SUCCESS) { 568 if (res != INSTPROXY_E_SUCCESS) {
570 debug_info("could not send plist, error %d", res); 569 debug_info("could not send plist, error %d", res);
@@ -592,11 +591,10 @@ leave_unlock:
592 * 591 *
593 * @param client The connected installation proxy client 592 * @param client The connected installation proxy client
594 * @param appid ApplicationIdentifier of the app to archive. 593 * @param appid ApplicationIdentifier of the app to archive.
595 * @param options This is either 0 for default behaviour (make an archive 594 * @param client_options The client options to use, as PLIST_DICT, or NULL.
596 * including app/user settings etc. AND uninstall the application), 595 * Valid options include:
597 * or one or a combination of the following options: 596 * "SkipUninstall" -> Boolean
598 * INSTPROXY_ARCHIVE_APP_ONLY (1) 597 * "ArchiveType" -> "ApplicationOnly"
599 * INSTPROXY_ARCHIVE_SKIP_UNINSTALL (2)
600 * @param status_cb Callback function for progress and status information. If 598 * @param status_cb Callback function for progress and status information. If
601 * NULL is passed, this function will run synchronously. 599 * NULL is passed, this function will run synchronously.
602 * 600 *
@@ -608,7 +606,7 @@ leave_unlock:
608 * created successfully; any error occuring during the operation has to be 606 * created successfully; any error occuring during the operation has to be
609 * handled inside the specified callback function. 607 * handled inside the specified callback function.
610 */ 608 */
611instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, uint32_t options, instproxy_status_cb_t status_cb) 609instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb)
612{ 610{
613 if (!client || !client->parent || !appid) 611 if (!client || !client->parent || !appid)
614 return INSTPROXY_E_INVALID_ARG; 612 return INSTPROXY_E_INVALID_ARG;
@@ -617,28 +615,10 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
617 return INSTPROXY_E_OP_IN_PROGRESS; 615 return INSTPROXY_E_OP_IN_PROGRESS;
618 } 616 }
619 617
620 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
621
622 plist_t dict = plist_new_dict();
623 plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid));
624 if (options > 0) {
625 plist_t client_opts = plist_new_dict();
626 if (options & INSTPROXY_ARCHIVE_APP_ONLY) {
627 plist_dict_insert_item(client_opts, "ArchiveType", plist_new_string("ApplicationOnly"));
628 }
629 if (options & INSTPROXY_ARCHIVE_SKIP_UNINSTALL) {
630 plist_dict_insert_item(client_opts, "SkipUninstall", plist_new_bool(1));
631 }
632 plist_dict_insert_item(dict, "ClientOptions", client_opts);
633 }
634 plist_dict_insert_item(dict, "Command", plist_new_string("Archive"));
635
636 instproxy_lock(client); 618 instproxy_lock(client);
637 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 619 instproxy_error_t res = instproxy_send_command(client, "Archive", client_options, appid, NULL);
638 instproxy_unlock(client); 620 instproxy_unlock(client);
639 621
640 plist_free(dict);
641
642 if (res != INSTPROXY_E_SUCCESS) { 622 if (res != INSTPROXY_E_SUCCESS) {
643 debug_info("could not send plist, error %d", res); 623 debug_info("could not send plist, error %d", res);
644 return res; 624 return res;
@@ -653,6 +633,8 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
653 * 633 *
654 * @param client The connected installation proxy client 634 * @param client The connected installation proxy client
655 * @param appid ApplicationIdentifier of the app to restore. 635 * @param appid ApplicationIdentifier of the app to restore.
636 * @param client_options The client options to use, as PLIST_DICT, or NULL.
637 * Currently there are no known client options, so pass NULL here.
656 * @param status_cb Callback function for progress and status information. If 638 * @param status_cb Callback function for progress and status information. If
657 * NULL is passed, this function will run synchronously. 639 * NULL is passed, this function will run synchronously.
658 * 640 *
@@ -664,7 +646,7 @@ instproxy_error_t instproxy_archive(instproxy_client_t client, const char *appid
664 * created successfully; any error occuring during the operation has to be 646 * created successfully; any error occuring during the operation has to be
665 * handled inside the specified callback function. 647 * handled inside the specified callback function.
666 */ 648 */
667instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 649instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb)
668{ 650{
669 if (!client || !client->parent || !appid) 651 if (!client || !client->parent || !appid)
670 return INSTPROXY_E_INVALID_ARG; 652 return INSTPROXY_E_INVALID_ARG;
@@ -673,18 +655,10 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
673 return INSTPROXY_E_OP_IN_PROGRESS; 655 return INSTPROXY_E_OP_IN_PROGRESS;
674 } 656 }
675 657
676 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
677
678 plist_t dict = plist_new_dict();
679 plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid));
680 plist_dict_insert_item(dict, "Command", plist_new_string("Restore"));
681
682 instproxy_lock(client); 658 instproxy_lock(client);
683 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 659 instproxy_error_t res = instproxy_send_command(client, "Restore", client_options, appid, NULL);
684 instproxy_unlock(client); 660 instproxy_unlock(client);
685 661
686 plist_free(dict);
687
688 if (res != INSTPROXY_E_SUCCESS) { 662 if (res != INSTPROXY_E_SUCCESS) {
689 debug_info("could not send plist, error %d", res); 663 debug_info("could not send plist, error %d", res);
690 return res; 664 return res;
@@ -699,6 +673,8 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
699 * 673 *
700 * @param client The connected installation proxy client 674 * @param client The connected installation proxy client
701 * @param appid ApplicationIdentifier of the archived app to remove. 675 * @param appid ApplicationIdentifier of the archived app to remove.
676 * @param client_options The client options to use, as PLIST_DICT, or NULL.
677 * Currently there are no known client options, so passing NULL is fine.
702 * @param status_cb Callback function for progress and status information. If 678 * @param status_cb Callback function for progress and status information. If
703 * NULL is passed, this function will run synchronously. 679 * NULL is passed, this function will run synchronously.
704 * 680 *
@@ -710,7 +686,7 @@ instproxy_error_t instproxy_restore(instproxy_client_t client, const char *appid
710 * created successfully; any error occuring during the operation has to be 686 * created successfully; any error occuring during the operation has to be
711 * handled inside the specified callback function. 687 * handled inside the specified callback function.
712 */ 688 */
713instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, instproxy_status_cb_t status_cb) 689instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char *appid, plist_t client_options, instproxy_status_cb_t status_cb)
714{ 690{
715 if (!client || !client->parent || !appid) 691 if (!client || !client->parent || !appid)
716 return INSTPROXY_E_INVALID_ARG; 692 return INSTPROXY_E_INVALID_ARG;
@@ -719,18 +695,10 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char
719 return INSTPROXY_E_OP_IN_PROGRESS; 695 return INSTPROXY_E_OP_IN_PROGRESS;
720 } 696 }
721 697
722 instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
723
724 plist_t dict = plist_new_dict();
725 plist_dict_insert_item(dict, "ApplicationIdentifier", plist_new_string(appid));
726 plist_dict_insert_item(dict, "Command", plist_new_string("RemoveArchive"));
727
728 instproxy_lock(client); 698 instproxy_lock(client);
729 res = instproxy_error(property_list_service_send_xml_plist(client->parent, dict)); 699 instproxy_error_t res = instproxy_send_command(client, "RemoveArchive", client_options, appid, NULL);
730 instproxy_unlock(client); 700 instproxy_unlock(client);
731 701
732 plist_free(dict);
733
734 if (res != INSTPROXY_E_SUCCESS) { 702 if (res != INSTPROXY_E_SUCCESS) {
735 debug_info("could not send plist, error %d", res); 703 debug_info("could not send plist, error %d", res);
736 return res; 704 return res;
@@ -738,3 +706,68 @@ instproxy_error_t instproxy_remove_archive(instproxy_client_t client, const char
738 return instproxy_create_status_updater(client, status_cb, "RemoveArchive"); 706 return instproxy_create_status_updater(client, status_cb, "RemoveArchive");
739} 707}
740 708
709/**
710 * Create a new client_options plist.
711 *
712 * @return A new plist_t of type PLIST_DICT.
713 */
714plist_t instproxy_client_options_new()
715{
716 return plist_new_dict();
717}
718
719/**
720 * Add one or more new key:value pairs to the given client_options.
721 *
722 * @param client_options The client options to modify.
723 * @param ... KEY, VALUE, [KEY, VALUE], NULL
724 *
725 * @note The keys and values passed are expected to be strings, except for
726 * "ApplicationSINF" and "iTunesMetadata" expecting a plist node of type
727 * PLIST_DATA as value, or "SkipUninstall" needing int as value.
728 */
729void instproxy_client_options_add(plist_t client_options, ...)
730{
731 if (!client_options)
732 return;
733 va_list args;
734 va_start(args, client_options);
735 char *arg = va_arg(args, char*);
736 while (arg) {
737 char *key = strdup(arg);
738 if (!strcmp(key, "SkipUninstall")) {
739 int intval = va_arg(args, int);
740 plist_dict_set_item(client_options, key, plist_new_bool(intval));
741 } else if (!strcmp(key, "ApplicationSINF") || !strcmp(key, "iTunesMetadata")) {
742 plist_t plistval = va_arg(args, plist_t);
743 if (!plistval) {
744 free(key);
745 break;
746 }
747 plist_dict_set_item(client_options, key, plist_copy(plistval));
748 } else {
749 char *strval = va_arg(args, char*);
750 if (!strval) {
751 free(key);
752 break;
753 }
754 plist_dict_set_item(client_options, key, plist_new_string(strval));
755 }
756 free(key);
757 arg = va_arg(args, char*);
758 }
759 va_end(args);
760}
761
762/**
763 * Free client_options plist.
764 *
765 * @param client_options The client options plist to free. Does nothing if NULL
766 * is passed.
767 */
768void instproxy_client_options_free(plist_t client_options)
769{
770 if (client_options) {
771 plist_free(client_options);
772 }
773}