diff options
| author | 2015-01-28 02:55:25 +0100 | |
|---|---|---|
| committer | 2015-01-28 02:55:25 +0100 | |
| commit | e8417d6b44efe2047805388836fffbc31b6a65a3 (patch) | |
| tree | 2c300d69339249dbbbb991cccd1c1885a9e72bcc | |
| parent | 24acd595323ab6c57339a901fcf67735c75becfb (diff) | |
| download | ideviceinstaller-e8417d6b44efe2047805388836fffbc31b6a65a3.tar.gz ideviceinstaller-e8417d6b44efe2047805388836fffbc31b6a65a3.tar.bz2 | |
Port code and bump dependency on libimobiledevice >= 1.2.0
This also drops compatibility with older releases but cleans up the code.
Listing apps is also now more efficient due to use of pagination callbacks.
| -rw-r--r-- | configure.ac | 18 | ||||
| -rw-r--r-- | src/ideviceinstaller.c | 345 | 
2 files changed, 177 insertions, 186 deletions
| diff --git a/configure.ac b/configure.ac index 0060140..ed19a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -15,23 +15,7 @@ AM_PROG_CC_C_O  AC_PROG_LIBTOOL  # Checks for libraries. -PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 0.9.7) -PKG_CHECK_MODULES(libimobiledevice100, libimobiledevice-1.0 >= 1.0.0, libimobiledevice_1_0=yes, libimobiledevice_1_0=no) -if test x"$libimobiledevice_1_0" = xyes; then -  AC_DEFINE([HAVE_LIBIMOBILEDEVICE_1_0], 1, [Define if libimobiledevice is using 1.0.0 API]) -fi -PKG_CHECK_MODULES(libimobiledevice110, libimobiledevice-1.0 >= 1.1.0, libimobiledevice_1_1=yes, libimobiledevice_1_1=no) -if test x"$libimobiledevice_1_1" = xyes; then -  AC_DEFINE([HAVE_LIBIMOBILEDEVICE_1_1], 1, [Define if libimobiledevice is using 1.1.0 API]) -fi -PKG_CHECK_MODULES(libimobiledevice112, libimobiledevice-1.0 >= 1.1.2, libimobiledevice_1_2=yes, libimobiledevice_1_2=no) -if test x"$libimobiledevice_1_2" = xno; then -  PKG_CHECK_MODULES(libglib2, glib-2.0 >= 2.14.1) -fi -PKG_CHECK_MODULES(libimobiledevice115, libimobiledevice-1.0 >= 1.1.5, libimobiledevice_1_1_5=yes, libimobiledevice_1_1_5=no) -if test x"$libimobiledevice_1_1_5" = xyes; then -  AC_DEFINE([HAVE_LIBIMOBILEDEVICE_1_1_5], 1, [Define if libimobiledevice is using 1.1.5 API]) -fi +PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.2.0)  PKG_CHECK_MODULES(libplist, libplist >= 0.15)  PKG_CHECK_MODULES(libzip, libzip >= 0.8) diff --git a/src/ideviceinstaller.c b/src/ideviceinstaller.c index 642d547..77650b8 100644 --- a/src/ideviceinstaller.c +++ b/src/ideviceinstaller.c @@ -81,69 +81,148 @@ enum cmd_mode {  int cmd = CMD_NONE;  char *last_status = NULL; -int wait_for_op_complete = 0; +int wait_for_command_complete = 0;  int notification_expected = 0;  int is_device_connected = 0; -int op_completed = 0; +int command_completed = 0;  int err_occurred = 0;  int notified = 0; -#ifdef HAVE_LIBIMOBILEDEVICE_1_1 +static void print_apps_header() +{ +	/* output app details header */ +	printf("%s", "CFBundleIdentifier"); +	printf(", %s", "CFBundleVersion"); +	printf(", %s", "CFBundleDisplayName"); +	printf("\n"); +} + +static void print_apps(plist_t apps) +{ +	uint32_t i = 0; +	for (i = 0; i < plist_array_get_size(apps); i++) { +		plist_t app = plist_array_get_item(apps, i); +		plist_t p_bundle_identifier = plist_dict_get_item(app, "CFBundleIdentifier"); +		char *s_bundle_identifier = NULL; +		char *s_display_name = NULL; +		char *s_version = NULL; +		plist_t display_name = plist_dict_get_item(app, "CFBundleDisplayName"); +		plist_t version = plist_dict_get_item(app, "CFBundleVersion"); + +		if (p_bundle_identifier) { +			plist_get_string_val(p_bundle_identifier, &s_bundle_identifier); +		} +		if (!s_bundle_identifier) { +			fprintf(stderr, "ERROR: Failed to get APPID!\n"); +			break; +		} + +		if (version) { +			plist_get_string_val(version, &s_version); +		} +		if (display_name) { +			plist_get_string_val(display_name, &s_display_name); +		} +		if (!s_display_name) { +			s_display_name = strdup(s_bundle_identifier); +		} + +		/* output app details */ +		printf("%s", s_bundle_identifier); +		if (s_version) { +			printf(", \"%s\"", s_version); +			free(s_version); +		} +		printf(", \"%s\"", s_display_name); +		printf("\n"); +		free(s_display_name); +		free(s_bundle_identifier); +	} +} +  static void notifier(const char *notification, void *unused) -#else -static void notifier(const char *notification) -#endif  {  	notified = 1;  } -#ifdef HAVE_LIBIMOBILEDEVICE_1_1 -static void status_cb(const char *operation, plist_t status, void *unused) -#else -static void status_cb(const char *operation, plist_t status) -#endif +static void status_cb(plist_t command, plist_t status, void *unused)  { -	if (status && operation) { -		plist_t npercent = plist_dict_get_item(status, "PercentComplete"); -		plist_t nstatus = plist_dict_get_item(status, "Status"); -		plist_t nerror = plist_dict_get_item(status, "Error"); -		int percent = 0; -		char *status_msg = NULL; -		if (npercent) { -			uint64_t val = 0; -			plist_get_uint_val(npercent, &val); -			percent = val; -		} -		if (nstatus) { -			plist_get_string_val(nstatus, &status_msg); -			if (!strcmp(status_msg, "Complete")) { -				op_completed = 1; +	if (command && status) { +		char* command_name = NULL; +		instproxy_command_get_name(command, &command_name); + +		/* get status */ +		char *status_name = NULL; +		instproxy_status_get_name(status, &status_name); + +		if (status_name) { +			if (!strcmp(status_name, "Complete")) { +				command_completed = 1;  			}  		} -		if (!nerror) { -			if (last_status && (strcmp(last_status, status_msg))) { -				printf("\r"); -			} -			if (!npercent) { -				printf("%s - %s\n", operation, status_msg); +		/* get error if any */ +		char* error_name = NULL; +		char* error_description = NULL; +		uint64_t error_code = 0; +		instproxy_status_get_error(status, &error_name, &error_description, &error_code); + +		/* output/handling */ +		if (!error_name) { +			if (!strcmp(command_name, "Browse")) { +				uint64_t total = 0; +				uint64_t current_index = 0; +				uint64_t current_amount = 0; +				plist_t current_list = NULL; +				instproxy_status_get_current_list(status, &total, ¤t_index, ¤t_amount, ¤t_list); +				if (current_list) { +					print_apps(current_list); +					plist_free(current_list); +				}  			} else { -				printf("%s - %s (%d%%)\n", operation, status_msg, percent); +				/* get progress if any */ +				int percent = -1; +				instproxy_status_get_percent_complete(status, &percent); + +				if (last_status && (strcmp(last_status, status_name))) { +					printf("\r"); +				} + +				if (percent >= 0) { +					printf("%s: %s (%d%%)\n", command_name, status_name, percent); +				} else { +					printf("%s: %s\n", command_name, status_name); +				}  			}  		} else { -			char *err_msg = NULL; -			plist_get_string_val(nerror, &err_msg); -			printf("%s - Error occurred: %s\n", operation, err_msg); -			free(err_msg); +			/* report error to the user */ +			if (error_description) +				fprintf(stderr, "ERROR: %s failed. Got error \"%s\" with code 0x%08"PRIx64": %s\n", command_name, error_name, error_code, error_description ? error_description: "N/A"); +			else +				fprintf(stderr, "ERROR: %s failed. Got error \"%s\".\n", command_name, error_name);  			err_occurred = 1;  		} + +		/* clean up */ +		if (error_name) +			free(error_name); + +		if (error_description) +			free(error_description); +  		if (last_status) {  			free(last_status);  			last_status = NULL;  		} -		if (status_msg) { -			last_status = strdup(status_msg); -			free(status_msg); + +		if (status_name) { +			last_status = strdup(status_name); +			free(status_name); +		} + +		if (command_name) { +			free(command_name); +			command_name = NULL;  		}  	} else {  		fprintf(stderr, "ERROR: %s was called with invalid arguments!\n", __func__); @@ -250,7 +329,7 @@ static void idevice_event_callback(const idevice_event_t* event, void* userdata)  	}  } -static void idevice_wait_for_operation_to_complete() +static void idevice_wait_for_command_to_complete()  {  	struct timespec ts;  	ts.tv_sec = 0; @@ -260,8 +339,8 @@ static void idevice_wait_for_operation_to_complete()  	/* subscribe to make sure to exit on device removal */  	idevice_event_subscribe(idevice_event_callback, NULL); -	/* wait for operation to complete */ -	while (wait_for_op_complete && !op_completed && !err_occurred +	/* wait for command to complete */ +	while (wait_for_command_complete && !command_completed && !err_occurred  		   && !notified && is_device_connected) {  		nanosleep(&ts, NULL);  	} @@ -453,7 +532,7 @@ static void parse_opts(int argc, char **argv)  	}  	if (cmd == CMD_NONE) { -		printf("ERROR: No mode/operation was supplied.\n"); +		printf("ERROR: No mode/command was supplied.\n");  	}  	if (cmd == CMD_NONE || optind <= 1 || (argc - optind > 0)) { @@ -565,11 +644,7 @@ int main(int argc, char **argv)  	instproxy_error_t err;  	np_client_t np = NULL;  	afc_client_t afc = NULL; -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5  	lockdownd_service_descriptor_t service = NULL; -#else -	uint16_t service = 0; -#endif  	int res = 0;  	char *bundleidentifier = NULL; @@ -597,38 +672,29 @@ int main(int argc, char **argv)  	}  	np_error_t nperr = np_client_new(phone, service, &np); -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 +  	if (service) {  		lockdownd_service_descriptor_free(service);  	}  	service = NULL; -#else -	service = 0; -#endif +  	if (nperr != NP_E_SUCCESS) {  		fprintf(stderr, "Could not connect to notification_proxy!\n");  		goto leave_cleanup;  	} -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  	np_set_notify_callback(np, notifier, NULL); -#else -	np_set_notify_callback(np, notifier); -#endif  	const char *noties[3] = { NP_APP_INSTALLED, NP_APP_UNINSTALLED, NULL };  	np_observe_notifications(np, noties);  run_again: -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5  	if (service) {  		lockdownd_service_descriptor_free(service);  	}  	service = NULL; -#else -	service = 0; -#endif +  	if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy",  		  &service) != LOCKDOWN_E_SUCCESS) || !service) {  		fprintf(stderr, @@ -637,14 +703,12 @@ run_again:  	}  	err = instproxy_client_new(phone, service, &ipc); -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 +  	if (service) {  		lockdownd_service_descriptor_free(service);  	}  	service = NULL; -#else -	service = 0; -#endif +  	if (err != INSTPROXY_E_SUCCESS) {  		fprintf(stderr, "Could not connect to installation_proxy!\n");  		goto leave_cleanup; @@ -670,13 +734,9 @@ run_again:  			char *elem = strtok(opts, ",");  			while (elem) {  				if (!strcmp(elem, "list_system")) { -					if (!client_opts) { -						client_opts = instproxy_client_options_new(); -					}  					instproxy_client_options_add(client_opts, "ApplicationType", "System", NULL);  				} else if (!strcmp(elem, "list_all")) { -					instproxy_client_options_free(client_opts); -					client_opts = NULL; +					plist_dict_remove_item(client_opts, "ApplicationType");  				} else if (!strcmp(elem, "list_user")) {  					/* do nothing, we're already set */  				} else if (!strcmp(elem, "xml")) { @@ -687,18 +747,26 @@ run_again:  			free(opts);  		} -		err = instproxy_browse(ipc, client_opts, &apps); -		instproxy_client_options_free(client_opts); -		if (err != INSTPROXY_E_SUCCESS) { -			fprintf(stderr, "ERROR: instproxy_browse returned %d\n", err); -			goto leave_cleanup; -		} -		if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { -			fprintf(stderr, -					"ERROR: instproxy_browse returnd an invalid plist!\n"); -			goto leave_cleanup; +		if (!xml_mode) { +			instproxy_client_options_set_return_attributes(client_opts, +				"CFBundleIdentifier", +				"CFBundleDisplayName", +				"CFBundleVersion", +				"StaticDiskUsage", +				"DynamicDiskUsage", +				NULL +			);  		} +  		if (xml_mode) { +			err = instproxy_browse(ipc, client_opts, &apps); + +			if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { +				fprintf(stderr, +						"ERROR: instproxy_browse returnd an invalid plist!\n"); +				goto leave_cleanup; +			} +  			char *xml = NULL;  			uint32_t len = 0; @@ -710,47 +778,22 @@ run_again:  			plist_free(apps);  			goto leave_cleanup;  		} -		printf("Total: %d apps\n", plist_array_get_size(apps)); -		uint32_t i = 0; -		for (i = 0; i < plist_array_get_size(apps); i++) { -			plist_t app = plist_array_get_item(apps, i); -			plist_t p_appid = -				plist_dict_get_item(app, "CFBundleIdentifier"); -			char *s_appid = NULL; -			char *s_dispName = NULL; -			char *s_version = NULL; -			plist_t dispName = -				plist_dict_get_item(app, "CFBundleDisplayName"); -			plist_t version = plist_dict_get_item(app, "CFBundleVersion"); - -			if (p_appid) { -				plist_get_string_val(p_appid, &s_appid); -			} -			if (!s_appid) { -				fprintf(stderr, "ERROR: Failed to get APPID!\n"); -				break; -			} -			if (dispName) { -				plist_get_string_val(dispName, &s_dispName); -			} -			if (version) { -				plist_get_string_val(version, &s_version); -			} +		print_apps_header(); -			if (!s_dispName) { -				s_dispName = strdup(s_appid); -			} -			if (s_version) { -				printf("%s - %s %s\n", s_appid, s_dispName, s_version); -				free(s_version); -			} else { -				printf("%s - %s\n", s_appid, s_dispName); -			} -			free(s_dispName); -			free(s_appid); +		err = instproxy_browse_with_callback(ipc, client_opts, status_cb, NULL); +		if (err == INSTPROXY_E_RECEIVE_TIMEOUT) { +			fprintf(stderr, "NOTE: timeout waiting for device to browse apps, trying again...\n"); +		} + +		instproxy_client_options_free(client_opts); +		if (err != INSTPROXY_E_SUCCESS) { +			fprintf(stderr, "ERROR: instproxy_browse returned %d\n", err); +			goto leave_cleanup;  		} -		plist_free(apps); + +		wait_for_command_complete = 1; +		notification_expected = 0;  	} else if (cmd == CMD_INSTALL || cmd == CMD_UPGRADE) {  		plist_t sinf = NULL;  		plist_t meta = NULL; @@ -759,14 +802,11 @@ run_again:  		uint64_t af = 0;  		char buf[8192]; -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5  		if (service) {  			lockdownd_service_descriptor_free(service);  		}  		service = NULL; -#else -		service = 0; -#endif +  		if ((lockdownd_start_service(client, "com.apple.afc", &service) !=  			 LOCKDOWN_E_SUCCESS) || !service) {  			fprintf(stderr, "Could not start com.apple.afc!\n"); @@ -1053,36 +1093,23 @@ run_again:  		/* perform installation or upgrade */  		if (cmd == CMD_INSTALL) {  			printf("Installing '%s'\n", bundleidentifier); -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  			instproxy_install(ipc, pkgname, client_opts, status_cb, NULL); -#else -			instproxy_install(ipc, pkgname, client_opts, status_cb); -#endif  		} else {  			printf("Upgrading '%s'\n", bundleidentifier); -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  			instproxy_upgrade(ipc, pkgname, client_opts, status_cb, NULL); -#else -			instproxy_upgrade(ipc, pkgname, client_opts, status_cb); -#endif  		}  		instproxy_client_options_free(client_opts);  		free(pkgname); -		wait_for_op_complete = 1; +		wait_for_command_complete = 1;  		notification_expected = 1;  	} else if (cmd == CMD_UNINSTALL) {  		printf("Uninstalling '%s'\n", appid); -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  		instproxy_uninstall(ipc, appid, NULL, status_cb, NULL); -#else -		instproxy_uninstall(ipc, appid, NULL, status_cb); -#endif -		wait_for_op_complete = 1; +		wait_for_command_complete = 1;  		notification_expected = 0;  	} else if (cmd == CMD_LIST_ARCHIVES) {  		int xml_mode = 0;  		plist_t dict = NULL; -		plist_t lres = NULL;  		/* look for options */  		if (options) { @@ -1101,24 +1128,18 @@ run_again:  			fprintf(stderr, "ERROR: lookup_archives returned %d\n", err);  			goto leave_cleanup;  		} +  		if (!dict) {  			fprintf(stderr,  					"ERROR: lookup_archives did not return a plist!?\n");  			goto leave_cleanup;  		} -		lres = plist_dict_get_item(dict, "LookupResult"); -		if (!lres || (plist_get_node_type(lres) != PLIST_DICT)) { -			plist_free(dict); -			fprintf(stderr, "ERROR: Could not get dict 'LookupResult'\n"); -			goto leave_cleanup; -		} -  		if (xml_mode) {  			char *xml = NULL;  			uint32_t len = 0; -			plist_to_xml(lres, &xml, &len); +			plist_to_xml(dict, &xml, &len);  			if (xml) {  				puts(xml);  				free(xml); @@ -1130,8 +1151,8 @@ run_again:  		plist_t node = NULL;  		char *key = NULL; -		printf("Total: %d archived apps\n", plist_dict_get_size(lres)); -		plist_dict_new_iter(lres, &iter); +		printf("Total: %d archived apps\n", plist_dict_get_size(dict)); +		plist_dict_new_iter(dict, &iter);  		if (!iter) {  			plist_free(dict);  			fprintf(stderr, "ERROR: Could not create plist_dict_iter!\n"); @@ -1140,7 +1161,7 @@ run_again:  		do {  			key = NULL;  			node = NULL; -			plist_dict_next_item(lres, iter, &key, &node); +			plist_dict_next_item(dict, iter, &key, &node);  			if (key && (plist_get_node_type(node) == PLIST_DICT)) {  				char *s_dispName = NULL;  				char *s_version = NULL; @@ -1225,14 +1246,11 @@ run_again:  				goto leave_cleanup;  			} -#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5  			if (service) {  				lockdownd_service_descriptor_free(service);  			}  			service = NULL; -#else -			service = 0; -#endif +  			if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) {  				fprintf(stderr, "Could not start com.apple.afc!\n");  				free(copy_path); @@ -1248,20 +1266,17 @@ run_again:  			}  		} -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  		instproxy_archive(ipc, appid, client_opts, status_cb, NULL); -#else -		instproxy_archive(ipc, appid, client_opts, status_cb); -#endif +  		instproxy_client_options_free(client_opts); -		wait_for_op_complete = 1; +		wait_for_command_complete = 1;  		if (skip_uninstall) {  			notification_expected = 0;  		} else {  			notification_expected = 1;  		} -		idevice_wait_for_operation_to_complete(); +		idevice_wait_for_command_to_complete();  		if (copy_path) {  			if (err_occurred) { @@ -1386,23 +1401,15 @@ run_again:  		}  		goto leave_cleanup;  	} else if (cmd == CMD_RESTORE) { -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  		instproxy_restore(ipc, appid, NULL, status_cb, NULL); -#else -		instproxy_restore(ipc, appid, NULL, status_cb); -#endif -		wait_for_op_complete = 1; +		wait_for_command_complete = 1;  		notification_expected = 1;  	} else if (cmd == CMD_REMOVE_ARCHIVE) { -#ifdef HAVE_LIBIMOBILEDEVICE_1_1  		instproxy_remove_archive(ipc, appid, NULL, status_cb, NULL); -#else -		instproxy_remove_archive(ipc, appid, NULL, status_cb); -#endif -		wait_for_op_complete = 1; +		wait_for_command_complete = 1;  	} else {  		printf -			("ERROR: no operation selected?! This should not be reached!\n"); +			("ERROR: no command selected?! This should not be reached!\n");  		res = -2;  		goto leave_cleanup;  	} @@ -1413,7 +1420,7 @@ run_again:  		client = NULL;  	} -	idevice_wait_for_operation_to_complete(); +	idevice_wait_for_command_to_complete();  leave_cleanup:  	if (bundleidentifier) { | 
