summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Szulecki <m.szulecki@libimobiledevice.org>2014-05-22 17:46:52 +0200
committerMartin Szulecki <m.szulecki@libimobiledevice.org>2014-11-30 16:51:10 +0100
commitce3ecba6e9fb703bd13079e3906e4428ba5aaaf7 (patch)
tree95acc30f8666071557c707f22bfc35d41762c820
parent53eb963f8e6d607cca6b50381c10820a5e8357f4 (diff)
downloadlibimobiledevice-ideviceinternational.tar.gz
Add new "ideviceinternational" dev tool to manage device language and localeideviceinternational
-rw-r--r--dev/Makefile.am9
-rw-r--r--dev/ideviceinternational.c270
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, &notification_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;
+}