diff options
author | Martin Szulecki <m.szulecki@libimobiledevice.org> | 2014-05-22 17:46:52 +0200 |
---|---|---|
committer | Martin Szulecki <m.szulecki@libimobiledevice.org> | 2014-11-30 16:51:10 +0100 |
commit | ce3ecba6e9fb703bd13079e3906e4428ba5aaaf7 (patch) | |
tree | 95acc30f8666071557c707f22bfc35d41762c820 | |
parent | 53eb963f8e6d607cca6b50381c10820a5e8357f4 (diff) | |
download | libimobiledevice-ideviceinternational.tar.gz |
Add new "ideviceinternational" dev tool to manage device language and localeideviceinternational
-rw-r--r-- | dev/Makefile.am | 9 | ||||
-rw-r--r-- | dev/ideviceinternational.c | 270 |
2 files changed, 277 insertions, 2 deletions
diff --git a/dev/Makefile.am b/dev/Makefile.am index 89ef75b..00f3208 100644 --- a/dev/Makefile.am +++ b/dev/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CF AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS) if ENABLE_DEVTOOLS -noinst_PROGRAMS = ideviceclient afccheck filerelaytest housearresttest lckd-client ideviceheartbeat +noinst_PROGRAMS = ideviceclient afccheck filerelaytest housearresttest lckd-client ideviceheartbeat ideviceinternational ideviceclient_SOURCES = ideviceclient.c ideviceclient_CFLAGS = $(AM_CFLAGS) @@ -36,6 +36,11 @@ ideviceheartbeat_CFLAGS = $(AM_CFLAGS) ideviceheartbeat_LDFLAGS = $(AM_LDFLAGS) ideviceheartbeat_LDADD = $(top_builddir)/src/libimobiledevice.la +ideviceinternational_SOURCES = ideviceinternational.c +ideviceinternational_CFLAGS = $(AM_CFLAGS) +ideviceinternational_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) +ideviceinternational_LDADD = $(top_builddir)/src/libimobiledevice.la + endif # ENABLE_DEVTOOLS -EXTRA_DIST = ideviceclient.c lckdclient.c afccheck.c filerelaytest.c housearresttest.c ideviceheartbeat.c +EXTRA_DIST = ideviceclient.c lckdclient.c afccheck.c filerelaytest.c housearresttest.c ideviceheartbeat.c ideviceinternational.c diff --git a/dev/ideviceinternational.c b/dev/ideviceinternational.c new file mode 100644 index 0000000..2e18b32 --- /dev/null +++ b/dev/ideviceinternational.c @@ -0,0 +1,270 @@ +/* + * ideviceinternational.c + * Manage language and locale of a device. + * + * Copyright (c) 2014 Martin Szulecki. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifdef WIN32 +#include <windows.h> +#define sleep(x) Sleep(x*1000) +#else +#include <unistd.h> +#endif + +#include <libimobiledevice/libimobiledevice.h> +#include <libimobiledevice/lockdown.h> +#include <libimobiledevice/notification_proxy.h> +#include "common/utils.h" + +enum cmd_mode { + CMD_NONE = 0, + CMD_LANGUAGE, + CMD_LOCALE, + CMD_SUPPORT +}; + +static int language_changed_notification_received = 0; + +#define LANGUAGE_CHANGED_NOTIFICATION "com.apple.springboard.finishedstartup.afterlanguagechange" + +static void language_changed_notification(const char *notification, void *user_data) +{ + if (!strcmp(notification, LANGUAGE_CHANGED_NOTIFICATION)) { + language_changed_notification_received = 1; + } + + if (notification == NULL) { + language_changed_notification_received = 1; + } +} + +static void print_usage(int argc, char **argv) +{ + char *name = NULL; + + name = strrchr(argv[0], '/'); + printf("Usage: %s COMMAND [OPTIONS]\n", (name ? name + 1: argv[0])); + printf("Manage language and locale of a device.\n"); + printf("\n"); + printf("Where COMMAND is one of:\n"); + printf(" language [CODE]\tprint the current device language or sets it to CODE\n"); + printf(" locale [CODE]\t\tprint the current device locale or sets it to CODE\n"); + printf(" support\t\tprint language, locale and keyboard codes supported by the device\n"); + printf("\n"); + printf("The following OPTIONS are accepted:\n"); + printf(" -d, --debug\t\tenable communication debugging\n"); + printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n"); + printf(" -h, --help\t\tprints usage information\n"); + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + int result = -1; + + idevice_t device = NULL; + lockdownd_client_t lockdownd = NULL; + np_client_t notification_proxy = NULL; + + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdownd_error = LOCKDOWN_E_SUCCESS; + np_error_t notification_proxy_error = NP_E_SUCCESS; + + int i; + const char* udid = NULL; + int cmd = CMD_NONE; + char* cmd_arg = NULL; + plist_t node = NULL; + char* value = NULL; + + /* parse cmdline args */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { + idevice_set_debug_level(1); + continue; + } + else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { + i++; + if (!argv[i] || (strlen(argv[i]) != 40)) { + print_usage(argc, argv); + return 0; + } + udid = argv[i]; + continue; + } + else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + print_usage(argc, argv); + return 0; + } + else if (!strcmp(argv[i], "support")) { + cmd = CMD_SUPPORT; + } + else if (!strcmp(argv[i], "language")) { + cmd = CMD_LANGUAGE; + /* read code */ + i++; + if (argv[i]) { + cmd_arg = strdup(argv[i]); + } + continue; + } + else if (!strcmp(argv[i], "locale")) { + cmd = CMD_LOCALE; + /* read code */ + i++; + if (argv[i]) { + cmd_arg = strdup(argv[i]); + } + continue; + } + else { + print_usage(argc, argv); + return 0; + } + } + + /* verify options */ + if (cmd == CMD_NONE) { + print_usage(argc, argv); + goto cleanup; + } + + device_error = idevice_new(&device, udid); + if (device_error != IDEVICE_E_SUCCESS) { + if (udid) { + printf("No device found with udid %s, is it plugged in?\n", udid); + } else { + printf("No device found, is it plugged in?\n"); + } + goto cleanup; + } + + lockdownd_error = lockdownd_client_new_with_handshake(device, &lockdownd, "ideviceinternational"); + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + printf("Unable to connect to lockdownd.\n"); + goto cleanup; + } + + switch (cmd) { + case CMD_LANGUAGE: + case CMD_LOCALE: + /* retrieve current setting */ + lockdownd_error = lockdownd_get_value(lockdownd, "com.apple.international", cmd == CMD_LANGUAGE ? "Language": "Locale", &node); + if (node && plist_get_node_type(node) == PLIST_STRING) { + plist_get_string_val(node, &value); + } + + if (cmd_arg && strcmp(cmd_arg, value) != 0) { + if (cmd != CMD_LOCALE) { + /* if we set language, we'll need to wait for a notification */ + notification_proxy_error = np_client_start_service(device, ¬ification_proxy, "ideviceinternational"); + if (notification_proxy_error != NP_E_SUCCESS) { + printf("Unable to connect start notification proxy.\n"); + goto cleanup; + } + + np_observe_notification(notification_proxy, LANGUAGE_CHANGED_NOTIFICATION); + np_set_notify_callback(notification_proxy, language_changed_notification, NULL); + } + + lockdownd_error = lockdownd_set_value(lockdownd, "com.apple.international", cmd == CMD_LANGUAGE ? "Language": "Locale", plist_new_string(cmd_arg)); + printf("lockdownd_error %d\n", lockdownd_error); + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + printf("Unable to set lockdown value\n"); + goto cleanup; + } + + while (cmd == CMD_LANGUAGE && !language_changed_notification_received) { + sleep(1); + } + } + + if (cmd_arg == NULL) { + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + printf("Unable to get lockdown value\n"); + goto cleanup; + } + + if (value) { + printf("%s\n", value); + free(value); + } + } + break; + case CMD_SUPPORT: + default: + lockdownd_error = lockdownd_get_value(lockdownd, "com.apple.international", NULL, &node); + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + printf("Unable to get international information from device\n"); + goto cleanup; + } + + if (node && plist_get_node_type(node) == PLIST_DICT) { + char* key = NULL; + plist_t list_node = NULL; + plist_dict_iter iter = NULL; + plist_dict_new_iter(node, &iter); + if (iter) { + list_node = NULL; + plist_dict_next_item(node, iter, &key, &list_node); + while (list_node) { + if (!strncmp(key, "Supported", 9)) { + printf("%s:\n", key); + plist_print_to_stream(list_node, stdout); + } + list_node = NULL; + free(key); + key = NULL; + plist_dict_next_item(node, iter, &key, &list_node); + } + free(iter); + } + } + break; + } + + result = 0; + +cleanup: + if (notification_proxy) { + np_client_free(notification_proxy); + } + + if (lockdownd) { + lockdownd_client_free(lockdownd); + } + + if (device) { + idevice_free(device); + } + + if (cmd_arg) { + free(cmd_arg); + } + + if (node) { + plist_free(node); + } + + return result; +} |