summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2009-05-10 08:27:53 -0700
committerGravatar Matt Colyer2009-05-10 08:28:04 -0700
commit1351b686d450112ae55d26d81d9d59c5f542f12e (patch)
tree442c7e48eb83f96a22f7c6d889e8fe26151d6cba
parente91caeb1c9929f9dc8af747bb3a2e52ec06b03af (diff)
downloadlibimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.gz
libimobiledevice-1351b686d450112ae55d26d81d9d59c5f542f12e.tar.bz2
NotificationProxy support added.0.9.0
[#27 state:resolved] Signed-off-by: Matt Colyer <matt@colyer.name>
-rw-r--r--dev/main.c95
-rw-r--r--include/libiphone/libiphone.h32
-rw-r--r--src/NotificationProxy.c404
-rw-r--r--src/NotificationProxy.h16
-rw-r--r--src/iphone.c5
-rw-r--r--src/iphone.h2
-rw-r--r--src/lockdown.c13
-rw-r--r--src/usbmux.c31
8 files changed, 461 insertions, 137 deletions
diff --git a/dev/main.c b/dev/main.c
index e4eb686..510c75f 100644
--- a/dev/main.c
+++ b/dev/main.c
@@ -27,26 +27,14 @@
#include <libiphone/libiphone.h>
#include "../src/utils.h"
-void perform_syncWillStart(iphone_device_t phone, iphone_lckd_client_t control)
+void notifier(const char *notification)
{
- int nport = 0;
- iphone_np_client_t np;
-
- iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &nport);
- if (nport) {
- printf("::::::::::::::: np was started ::::::::::::\n");
- iphone_np_new_client(phone, 3555, nport, &np);
- if (np) {
- printf("::::::::: PostNotification com.apple.itunes-mobdev.syncWillStart\n");
- iphone_np_post_notification(np, "com.apple.itunes-mobdev.syncWillStart");
- iphone_np_free_client(np);
- }
- } else {
- printf("::::::::::::::: np was NOT started ::::::::::::\n");
- }
+ printf("---------------------------------------------------------\n");
+ printf("------> Notification received: %s\n", notification);
+ printf("---------------------------------------------------------\n");
}
-void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control)
+void perform_notification(iphone_device_t phone, iphone_lckd_client_t control, const char *notification)
{
int nport = 0;
iphone_np_client_t np;
@@ -54,11 +42,10 @@ void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control)
iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &nport);
if (nport) {
printf("::::::::::::::: np was started ::::::::::::\n");
- sleep(1);
iphone_np_new_client(phone, 3555, nport, &np);
if (np) {
- printf("::::::::: PostNotification com.apple.itunes-mobdev.syncDidStart\n");
- iphone_np_post_notification(np, "com.apple.itunes-mobdev.syncDidStart");
+ printf("::::::::: PostNotification %s\n", notification);
+ iphone_np_post_notification(np, notification);
iphone_np_free_client(np);
}
} else {
@@ -69,9 +56,11 @@ void perform_syncDidStart(iphone_device_t phone, iphone_lckd_client_t control)
int main(int argc, char *argv[])
{
int bytes = 0, port = 0, i = 0;
+ int npp;
iphone_lckd_client_t control = NULL;
iphone_device_t phone = NULL;
iphone_afc_file_t lockfile = NULL;
+ iphone_np_client_t gnp = NULL;
if (argc > 1 && !strcasecmp(argv[1], "--debug")) {
iphone_set_debug(1);
@@ -88,6 +77,7 @@ int main(int argc, char *argv[])
if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) {
iphone_free_device(phone);
+ printf("Exiting.\n");
return -1;
}
@@ -97,20 +87,45 @@ int main(int argc, char *argv[])
free(uid);
}
+
+ char *nnn = NULL;
+ if (IPHONE_E_SUCCESS == lockdownd_get_device_name(control, &nnn)) {
+ printf("DeviceName : %s\n", nnn);
+ free(nnn);
+ }
+
iphone_lckd_start_service(control, "com.apple.afc", &port);
if (port) {
iphone_afc_client_t afc = NULL;
iphone_afc_new_client(phone, 3432, port, &afc);
if (afc) {
- perform_syncWillStart(phone, control);
+ iphone_lckd_start_service(control, "com.apple.mobile.notification_proxy", &npp);
+ if (npp) {
+ printf("Notification Proxy started.\n");
+ iphone_np_new_client(phone, 3756, npp, &gnp);
+ } else {
+ printf("ERROR: Notification proxy could not be started.\n");
+ }
+ if (gnp) {
+ const char *nspec[4] = {
+ NP_SYNC_CANCEL_REQUEST,
+ NP_SYNC_SUSPEND_REQUEST,
+ NP_SYNC_RESUME_REQUEST,
+ NULL
+ };
+ iphone_np_observe_notifications(gnp, nspec);
+ //iphone_np_set_notify_callback(gnp, notifier);
+ }
+
+ perform_notification(phone, control, NP_SYNC_WILL_START);
iphone_afc_open_file(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
if (lockfile) {
printf("locking file\n");
iphone_afc_lock_file(afc, lockfile, 2 | 4);
- perform_syncDidStart(phone, control);
+ perform_notification(phone, control, NP_SYNC_DID_START);
}
char **dirs = NULL;
@@ -123,6 +138,8 @@ int main(int argc, char *argv[])
}
g_strfreev(dirs);
+
+ dirs = NULL;
iphone_afc_get_devinfo(afc, &dirs);
if (dirs) {
for (i = 0; dirs[i]; i += 2) {
@@ -189,9 +206,31 @@ int main(int argc, char *argv[])
iphone_afc_close_file(afc, my_file);
}
- if (lockfile) {
- printf("XXX sleeping 2 seconds\n");
- sleep(2);
+ if (gnp && lockfile) {
+ char *noti;
+
+ noti = NULL;
+ iphone_np_get_notification(gnp, &noti);
+ if (noti) {
+ printf("------> received notification '%s'\n", noti);
+ free(noti);
+ }
+
+ printf("XXX sleeping\n");
+ for (i = 0; i < 5; i++) {
+ noti = NULL;
+ printf("--- getting notification\n");
+ iphone_np_get_notification(gnp, &noti);
+ if (noti) {
+ printf("------> received notification '%s'\n", noti);
+ free(noti);
+ } else {
+ printf("---- no notification\n");
+ }
+ sleep(1);
+ }
+
+ //perform_notification(phone, control, NP_SYNC_DID_FINISH);
printf("XXX unlocking file\n");
iphone_afc_lock_file(afc, lockfile, 8 | 4);
@@ -199,6 +238,12 @@ int main(int argc, char *argv[])
printf("XXX closing file\n");
iphone_afc_close_file(afc, lockfile);
}
+
+ if (gnp) {
+ iphone_np_free_client(gnp);
+ gnp = NULL;
+ }
+
iphone_afc_free_client(afc);
} else {
printf("Start service failure.\n");
diff --git a/include/libiphone/libiphone.h b/include/libiphone/libiphone.h
index a45319f..dedc78f 100644
--- a/include/libiphone/libiphone.h
+++ b/include/libiphone/libiphone.h
@@ -101,6 +101,7 @@ iphone_error_t iphone_free_device ( iphone_device_t device );
//lockdownd related functions
iphone_error_t lockdownd_get_device_uid(iphone_lckd_client_t control, char **uid);
+iphone_error_t lockdownd_get_device_name ( iphone_lckd_client_t client, char **device_name );
iphone_error_t iphone_lckd_new_client ( iphone_device_t device, iphone_lckd_client_t *client );
iphone_error_t iphone_lckd_free_client( iphone_lckd_client_t client );
@@ -115,6 +116,7 @@ iphone_error_t iphone_mux_free_client ( iphone_umux_client_t client );
iphone_error_t iphone_mux_send ( iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t *sent_bytes );
iphone_error_t iphone_mux_recv ( iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t *recv_bytes );
+iphone_error_t iphone_mux_recv_timeout ( iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t *recv_bytes, int timeout);
//afc related functions
@@ -148,6 +150,36 @@ iphone_error_t iphone_msync_free_client(iphone_msync_client_t client);
iphone_error_t iphone_msync_recv(iphone_msync_client_t client, plist_t * plist);
iphone_error_t iphone_msync_send(iphone_msync_client_t client, plist_t plist);
+// NotificationProxy related
+// notifications for use with post_notification (client --> device)
+#define NP_SYNC_WILL_START "com.apple.itunes-mobdev.syncWillStart"
+#define NP_SYNC_DID_START "com.apple.itunes-mobdev.syncDidStart"
+#define NP_SYNC_DID_FINISH "com.apple.itunes-mobdev.syncDidFinish"
+
+// notifications for use with observe_notification (device --> client)
+#define NP_SYNC_CANCEL_REQUEST "com.apple.itunes-client.syncCancelRequest"
+#define NP_SYNC_SUSPEND_REQUEST "com.apple.itunes-client.syncSuspendRequest"
+#define NP_SYNC_RESUME_REQUEST "com.apple.itunes-client.syncResumeRequest"
+#define NP_PHONE_NUMBER_CHANGED "com.apple.mobile.lockdown.phone_number_changed"
+#define NP_DEVICE_NAME_CHANGED "com.apple.mobile.lockdown.device_name_changed"
+#define NP_ATTEMPTACTIVATION "com.apple.springboard.attemptactivation"
+#define NP_DS_DOMAIN_CHANGED "com.apple.mobile.data_sync.domain_changed"
+#define NP_APP_INSTALLED "com.apple.mobile.application_installed"
+#define NP_APP_UNINSTALLED "com.apple.mobile.application_uninstalled"
+
+iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client );
+iphone_error_t iphone_np_free_client ( iphone_np_client_t client );
+
+iphone_error_t iphone_np_post_notification ( iphone_np_client_t client, const char *notification );
+
+iphone_error_t iphone_np_observe_notification ( iphone_np_client_t client, const char *notification );
+iphone_error_t iphone_np_observe_notifications ( iphone_np_client_t client, const char **notification_spec );
+iphone_error_t iphone_np_get_notification ( iphone_np_client_t client, char **notification );
+
+typedef void (*iphone_np_notify_cb_t) ( const char *notification );
+
+iphone_error_t iphone_np_set_notify_callback ( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb );
+
#ifdef __cplusplus
}
#endif
diff --git a/src/NotificationProxy.c b/src/NotificationProxy.c
index bf837bf..d8bcc34 100644
--- a/src/NotificationProxy.c
+++ b/src/NotificationProxy.c
@@ -21,10 +21,16 @@
#include <string.h>
#include <stdio.h>
+#include <arpa/inet.h>
#include <plist/plist.h>
#include "NotificationProxy.h"
#include "utils.h"
+struct np_thread {
+ iphone_np_client_t client;
+ iphone_np_notify_cb_t cbfunc;
+};
+
/** Locks an NP client, done for thread safety stuff.
*
* @param client The NP
@@ -45,6 +51,54 @@ static void np_unlock(iphone_np_client_t client)
g_mutex_unlock(client->mutex);
}
+/**
+ * Sends an xml plist to the device using the connection specified in client.
+ * This function is only used internally.
+ *
+ * @param client NP to send data to
+ * @param dict plist to send
+ *
+ * @return IPHONE_E_SUCCESS or an error code.
+ */
+static iphone_error_t np_plist_send(iphone_np_client_t client, plist_t dict)
+{
+ char *XML_content = NULL;
+ uint32_t length = 0;
+ uint32_t nlen = 0;
+ int bytes = 0;
+ iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
+
+ if (!client || !dict) {
+ return IPHONE_E_INVALID_ARG;
+ }
+
+ plist_to_xml(dict, &XML_content, &length);
+
+ if (!XML_content || length == 0) {
+ return IPHONE_E_PLIST_ERROR;
+ }
+
+ nlen = htonl(length);
+ iphone_mux_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
+ if (bytes == sizeof(nlen)) {
+ iphone_mux_send(client->connection, XML_content, length, (uint32_t*)&bytes);
+ if (bytes > 0) {
+ if ((uint32_t)bytes == length) {
+ res = IPHONE_E_SUCCESS;
+ } else {
+ log_debug_msg("%s: ERROR: Could not send all data (%d of %d)!\n", __func__, bytes, length);
+ }
+ }
+ }
+ if (bytes <= 0) {
+ log_debug_msg("%s: ERROR: sending to device failed.\n", __func__);
+ }
+
+ free(XML_content);
+
+ return res;
+}
+
/** Makes a connection to the NP service on the phone.
*
* @param phone The iPhone to connect on.
@@ -53,7 +107,7 @@ static void np_unlock(iphone_np_client_t client)
*
* @return A handle to the newly-connected client or NULL upon error.
*/
-iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int dst_port, iphone_np_client_t * client)
+iphone_error_t iphone_np_new_client ( iphone_device_t device, int src_port, int dst_port, iphone_np_client_t *client )
{
int ret = IPHONE_E_SUCCESS;
@@ -75,6 +129,8 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds
client_loc->mutex = g_mutex_new();
+ client_loc->notifier = NULL;
+
*client = client_loc;
return IPHONE_E_SUCCESS;
}
@@ -83,91 +139,97 @@ iphone_error_t iphone_np_new_client(iphone_device_t device, int src_port, int ds
*
* @param client The client to disconnect.
*/
-iphone_error_t iphone_np_free_client(iphone_np_client_t client)
+iphone_error_t iphone_np_free_client ( iphone_np_client_t client )
{
- if (!client || !client->connection)
+ if (!client)
return IPHONE_E_INVALID_ARG;
- iphone_mux_free_client(client->connection);
+ if (client->connection) {
+ iphone_mux_free_client(client->connection);
+ client->connection = NULL;
+ if (client->notifier) {
+ log_debug_msg("joining np callback\n");
+ g_thread_join(client->notifier);
+ }
+ }
+ if (client->mutex) {
+ g_mutex_free(client->mutex);
+ }
free(client);
+
return IPHONE_E_SUCCESS;
}
-/** Sends a notification to the NP client.
+/** Sends a notification to the device's Notification Proxy.
*
* notification messages seen so far:
* com.apple.itunes-mobdev.syncWillStart
* com.apple.itunes-mobdev.syncDidStart
*
* @param client The client to send to
- * @param notification The notification Message
+ * @param notification The notification message to send
*/
-iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char *notification)
+iphone_error_t iphone_np_post_notification( iphone_np_client_t client, const char *notification )
{
- char *XML_content = NULL;
- uint32_t length = 0;
- int bytes = 0;
- iphone_error_t ret;
- unsigned char sndbuf[4096];
- int sndlen = 0;
- int nlen = 0;
- plist_t dict = NULL;
-
if (!client || !notification) {
return IPHONE_E_INVALID_ARG;
}
np_lock(client);
- dict = plist_new_dict();
+ plist_t dict = plist_new_dict();
plist_add_sub_key_el(dict, "Command");
plist_add_sub_string_el(dict, "PostNotification");
plist_add_sub_key_el(dict, "Name");
plist_add_sub_string_el(dict, notification);
- plist_to_xml(dict, &XML_content, &length);
-
- nlen = htonl(length);
-
- memcpy(sndbuf + sndlen, &nlen, 4);
- sndlen += 4;
- memcpy(sndbuf + sndlen, XML_content, length);
- sndlen += length;
+ iphone_error_t res = np_plist_send(client, dict);
plist_free(dict);
- dict = NULL;
- free(XML_content);
- XML_content = NULL;
dict = plist_new_dict();
plist_add_sub_key_el(dict, "Command");
plist_add_sub_string_el(dict, "Shutdown");
- plist_to_xml(dict, &XML_content, &length);
- nlen = htonl(length);
+ res = np_plist_send(client, dict);
+ plist_free(dict);
- memcpy(sndbuf + sndlen, &nlen, 4);
- sndlen += 4;
+ if (res != IPHONE_E_SUCCESS) {
+ log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
+ }
- memcpy(sndbuf + sndlen, XML_content, length);
- sndlen += length;
+ np_unlock(client);
+ return res;
+}
- plist_free(dict);
- dict = NULL;
- free(XML_content);
- XML_content = NULL;
+/** Notifies the iphone to send a notification on the specified event.
+ *
+ * @param client The client to send to
+ * @param notification The notifications that should be observed.
+ */
+iphone_error_t iphone_np_observe_notification( iphone_np_client_t client, const char *notification )
+{
+ if (!client || !notification) {
+ return IPHONE_E_INVALID_ARG;
+ }
+ np_lock(client);
- log_debug_buffer(sndbuf, sndlen);
+ plist_t dict = plist_new_dict();
+ plist_add_sub_key_el(dict, "Command");
+ plist_add_sub_string_el(dict, "ObserveNotification");
+ plist_add_sub_key_el(dict, "Name");
+ plist_add_sub_string_el(dict, notification);
- iphone_mux_send(client->connection, sndbuf, sndlen, &bytes);
- if (bytes <= 0) {
- np_unlock(client);
- return bytes;
+ iphone_error_t res = np_plist_send(client, dict);
+ if (res != IPHONE_E_SUCCESS) {
+ log_debug_msg("%s: Error sending XML plist to device!\n", __func__);
}
+ plist_free(dict);
np_unlock(client);
- return bytes;
+ return res;
}
-/** Notifies the iphone to send a notification on certain events.
+
+/** Notifies the iphone to send a notification on specified events.
*
* observation messages seen so far:
* com.apple.itunes-client.syncCancelRequest
@@ -181,85 +243,217 @@ iphone_error_t iphone_np_post_notification(iphone_np_client_t client, const char
* com.apple.mobile.application_uninstalled
*
* @param client The client to send to
+ * @param notification_spec Specification of the notifications that should be
+ * observed. This is expected to be an array of const char* that MUST have a
+ * terminating NULL entry. However this parameter can be NULL; in this case,
+ * the default set of notifications will be used.
*/
-iphone_error_t iphone_np_observe_notification(iphone_np_client_t client)
+iphone_error_t iphone_np_observe_notifications( iphone_np_client_t client, const char **notification_spec )
{
- plist_t dict = NULL;
- char *XML_content = NULL;
- uint32_t length = 0;
- int bytes = 0;
- iphone_error_t ret;
- unsigned char sndbuf[4096];
- int sndlen = 0;
- int nlen = 0;
int i = 0;
- const char *notifications[10] = {
- "com.apple.itunes-client.syncCancelRequest",
- "com.apple.itunes-client.syncSuspendRequest",
- "com.apple.itunes-client.syncResumeRequest",
- "com.apple.mobile.lockdown.phone_number_changed",
- "com.apple.mobile.lockdown.device_name_changed",
- "com.apple.springboard.attemptactivation",
- "com.apple.mobile.data_sync.domain_changed",
- "com.apple.mobile.application_installed",
- "com.apple.mobile.application_uninstalled",
- NULL
- };
-
- sndlen = 0;
+ iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
+ const char **notifications = notification_spec;
if (!client) {
return IPHONE_E_INVALID_ARG;
}
- np_lock(client);
+
+ if (!notifications) {
+ notifications = np_default_notifications;
+ }
while (notifications[i]) {
+ res = iphone_np_observe_notification(client, notifications[i]);
+ if (res != IPHONE_E_SUCCESS) {
+ break;
+ }
+ i++;
+ }
+
+ return res;
+}
- dict = plist_new_dict();
- plist_add_sub_key_el(dict, "Command");
- plist_add_sub_string_el(dict, "ObserveNotification");
- plist_add_sub_key_el(dict, "Name");
- plist_add_sub_string_el(dict, notifications[i++]);
- plist_to_xml(dict, &XML_content, &length);
-
- nlen = htonl(length);
- memcpy(sndbuf + sndlen, &nlen, 4);
- sndlen += 4;
- memcpy(sndbuf + sndlen, XML_content, length);
- sndlen += length;
-
- plist_free(dict);
- dict = NULL;
- free(XML_content);
- XML_content = NULL;
+/**
+ * Checks if a notification has been sent.
+ *
+ * @param client NP to get a notification from
+ * @param notification Pointer to a buffer that will be allocated and filled
+ * with the notification that has been received.
+ *
+ * @return IPHONE_E_SUCCESS if a notification has been received,
+ * IPHONE_E_TIMEOUT if nothing has been received,
+ * or an error value if an error occured.
+ *
+ * @note You probably want to check out iphone_np_set_notify_callback
+ * @see iphone_np_set_notify_callback
+ */
+iphone_error_t iphone_np_get_notification( iphone_np_client_t client, char **notification )
+{
+ uint32_t bytes = 0;
+ iphone_error_t res;
+ uint32_t pktlen = 0;
+ char *XML_content = NULL;
+ plist_t dict = NULL;
+
+ if (!client || !client->connection || *notification) {
+ return IPHONE_E_INVALID_ARG;
}
- dict = plist_new_dict();
- plist_add_sub_key_el(dict, "Command");
- plist_add_sub_string_el(dict, "Shutdown");
- plist_to_xml(dict, &XML_content, &length);
+ np_lock(client);
- nlen = htonl(length);
+ iphone_mux_recv_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, 500);
+ log_debug_msg("NotificationProxy: initial read=%i\n", bytes);
+ if (bytes < 4) {
+ log_debug_msg("NotificationProxy: no notification received!\n");
+ res = IPHONE_E_TIMEOUT;
+ } else {
+ if ((char)pktlen == 0) {
+ pktlen = ntohl(pktlen);
+ log_debug_msg("NotificationProxy: %d bytes following\n", pktlen);
+ XML_content = (char*)malloc(pktlen);
+ log_debug_msg("pointer %p\n", XML_content);
+
+ iphone_mux_recv_timeout(client->connection, XML_content, pktlen, &bytes, 1000);
+ if (bytes <= 0) {
+ res = IPHONE_E_UNKNOWN_ERROR;
+ } else {
+ log_debug_msg("NotificationProxy: received data:\n");
+ log_debug_buffer(XML_content, pktlen);
+
+ plist_from_xml(XML_content, bytes, &dict);
+ if (!dict) {
+ np_unlock(client);
+ return IPHONE_E_PLIST_ERROR;
+ }
+
+ plist_t cmd_key_node = plist_find_node_by_key(dict, "Command");
+ plist_t cmd_value_node = plist_get_next_sibling(cmd_key_node);
+ char *cmd_value = NULL;
+
+ if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
+ plist_get_string_val(cmd_value_node, &cmd_value);
+ }
+
+ if (cmd_value && !strcmp(cmd_value, "RelayNotification")) {
+ plist_t name_key_node = plist_get_next_sibling(cmd_value_node);
+ plist_t name_value_node = plist_get_next_sibling(name_key_node);
+
+ char *name_key = NULL;
+ char *name_value = NULL;
+
+ if (plist_get_node_type(name_key_node) == PLIST_KEY) {
+ plist_get_key_val(name_key_node, &name_key);
+ }
+ if (plist_get_node_type(name_value_node) == PLIST_STRING) {
+ plist_get_string_val(name_value_node, &name_value);
+ }
+
+ res = IPHONE_E_PLIST_ERROR;
+ if (name_key && name_value && !strcmp(name_key, "Name")) {
+ *notification = name_value;
+ log_debug_msg("%s: got notification %s\n", __func__, name_value);
+ res = IPHONE_E_SUCCESS;
+ }
+ free(name_key);
+ } else if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
+ log_debug_msg("%s: ERROR: NotificationProxy died!\n", __func__);
+ res = IPHONE_E_UNKNOWN_ERROR;
+ } else if (cmd_value) {
+ log_debug_msg("%d: unknown NotificationProxy command '%s' received!\n", __func__);
+ res = IPHONE_E_UNKNOWN_ERROR;
+ } else {
+ res = IPHONE_E_PLIST_ERROR;
+ }
+ if (cmd_value) {
+ free(cmd_value);
+ }
+ plist_free(dict);
+ dict = NULL;
+ free(XML_content);
+ XML_content = NULL;
+ }
+ } else {
+ res = IPHONE_E_UNKNOWN_ERROR;
+ }
+ }
- memcpy(sndbuf + sndlen, &nlen, 4);
- sndlen += 4;
+ np_unlock(client);
- memcpy(sndbuf + sndlen, XML_content, length);
- sndlen += length;
+ return res;
+}
- plist_free(dict);
- dict = NULL;
- free(XML_content);
- XML_content = NULL;
+/**
+ * Internally used thread function.
+ */
+gpointer iphone_np_notifier( gpointer arg )
+{
+ char *notification = NULL;
+ struct np_thread *npt = (struct np_thread*)arg;
+
+ if (!npt) return NULL;
+
+ log_debug_msg("%s: starting callback.\n", __func__);
+ while (npt->client->connection) {
+ iphone_np_get_notification(npt->client, &notification);
+ if (notification) {
+ npt->cbfunc(notification);
+ free(notification);
+ notification = NULL;
+ }
+ sleep(1);
+ }
+ if (npt) {
+ free(npt);
+ }
- log_debug_buffer(sndbuf, sndlen);
+ return NULL;
+}
- iphone_mux_send(client->connection, sndbuf, sndlen, &bytes);
- if (bytes <= 0) {
- np_unlock(client);
- return bytes;
+/**
+ * This function allows an application to define a callback function that will
+ * be called when a notification has been received.
+ * It will start a thread that polls for notifications and calls the callback
+ * function if a notification has been received.
+ *
+ * @param client the NP client
+ * @param notify_cb pointer to a callback function or NULL to de-register a
+ * previously set callback function
+ *
+ * @return IPHONE_E_SUCCESS when the callback was successfully registered,
+ * or an error value when an error occured.
+ */
+iphone_error_t iphone_np_set_notify_callback( iphone_np_client_t client, iphone_np_notify_cb_t notify_cb )
+{
+ if (!client) {
+ return IPHONE_E_INVALID_ARG;
+ }
+ iphone_error_t res = IPHONE_E_UNKNOWN_ERROR;
+
+ np_lock(client);
+ if (client->notifier) {
+ log_debug_msg("%s: callback already set, removing\n");
+ iphone_umux_client_t conn = client->connection;
+ client->connection = NULL;
+ g_thread_join(client->notifier);
+ client->notifier = NULL;
+ client->connection = conn;
}
+ if (notify_cb) {
+ struct np_thread *npt = (struct np_thread*)malloc(sizeof(struct np_thread));
+ if (npt) {
+ npt->client = client;
+ npt->cbfunc = notify_cb;
+
+ client->notifier = g_thread_create(iphone_np_notifier, npt, TRUE, NULL);
+ if (client->notifier) {
+ res = IPHONE_E_SUCCESS;
+ }
+ }
+ } else {
+ log_debug_msg("%s: no callback set\n", __func__);
+ }
np_unlock(client);
- return bytes;
+
+ return res;
}
diff --git a/src/NotificationProxy.h b/src/NotificationProxy.h
index 7b4b48d..3552b79 100644
--- a/src/NotificationProxy.h
+++ b/src/NotificationProxy.h
@@ -27,4 +27,20 @@
struct iphone_np_client_int {
iphone_umux_client_t connection;
GMutex *mutex;
+ GThread *notifier;
};
+
+static const char *np_default_notifications[10] = {
+ NP_SYNC_SUSPEND_REQUEST,
+ NP_SYNC_RESUME_REQUEST,
+ NP_PHONE_NUMBER_CHANGED,
+ NP_SYNC_CANCEL_REQUEST,
+ NP_DEVICE_NAME_CHANGED,
+ NP_ATTEMPTACTIVATION,
+ NP_DS_DOMAIN_CHANGED,
+ NP_APP_INSTALLED,
+ NP_APP_UNINSTALLED,
+ NULL
+};
+
+gpointer iphone_np_notifier( gpointer arg );
diff --git a/src/iphone.c b/src/iphone.c
index 3c3034e..9dd3c07 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -288,10 +288,11 @@ int send_to_phone(iphone_device_t phone, char *data, int datalen)
* @param phone The iPhone to receive data from
* @param data Where to put data read
* @param datalen How much data to read in
+ * @param timeout How many milliseconds to wait for data
*
* @return How many bytes were read in, or -1 on error.
*/
-int recv_from_phone(iphone_device_t phone, char *data, int datalen)
+int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout)
{
if (!phone)
return -1;
@@ -301,7 +302,7 @@ int recv_from_phone(iphone_device_t phone, char *data, int datalen)
return -1;
log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen);
- bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500);
+ bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeout);
if (bytes < 0) {
log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(),
strerror(-bytes));
diff --git a/src/iphone.h b/src/iphone.h
index 222a1be..15515e3 100644
--- a/src/iphone.h
+++ b/src/iphone.h
@@ -41,5 +41,5 @@ struct iphone_device_int {
// Function definitions
int send_to_phone(iphone_device_t phone, char *data, int datalen);
-int recv_from_phone(iphone_device_t phone, char *data, int datalen);
+int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout);
#endif
diff --git a/src/lockdown.c b/src/lockdown.c
index c017cdf..5ade79a 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -472,6 +472,19 @@ iphone_error_t lockdownd_get_device_public_key(iphone_lckd_client_t control, gnu
return lockdownd_generic_get_value(control, "Key", "DevicePublicKey", public_key);
}
+/** Askes for the device's name.
+ *
+ * @return IPHONE_E_SUCCESS on succes or an error value < 0 on failure.
+ */
+iphone_error_t lockdownd_get_device_name(iphone_lckd_client_t control, char **device_name)
+{
+ gnutls_datum_t temp = { NULL, 0 };
+ iphone_error_t res = lockdownd_generic_get_value(control, "Key", "DeviceName", &temp);
+ log_debug_msg("%s: %s\n", __func__, temp.data);
+ *device_name = (char*)temp.data;
+ return res;
+}
+
/** Completes the entire lockdownd handshake.
*
* @param phone The iPhone
diff --git a/src/usbmux.c b/src/usbmux.c
index 22ce588..7d74b4b 100644
--- a/src/usbmux.c
+++ b/src/usbmux.c
@@ -143,7 +143,7 @@ iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port,
if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) {
usbmux_tcp_header *response;
response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
- bytes = recv_from_phone(device, (char *) response, sizeof(*response));
+ bytes = recv_from_phone(device, (char *) response, sizeof(*response), 3500);
if (response->tcp_flags != 0x12) {
free(response);
return IPHONE_E_UNKNOWN_ERROR;
@@ -268,10 +268,13 @@ iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, ui
* @param connection The connection to receive data on.
* @param data Where to put the data we receive.
* @param datalen How much data to read.
+ * @param recv_bytes Pointer to a uint32_t that will be set
+ * to the number of bytes received.
+ * @param timeout How many milliseconds to wait for data.
*
- * @return How many bytes were read, or -1 if something bad happens.
+ * @return IPHONE_E_SUCCESS on success, or and error value.
*/
-iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes)
+iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout)
{
if (!client || !data || datalen == 0 || !recv_bytes)
@@ -323,7 +326,7 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t
buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;)
// See #3.
- bytes = recv_from_phone(client->phone, buffer, 131072);
+ bytes = recv_from_phone(client->phone, buffer, 131072, timeout);
if (bytes < 28) {
free(buffer);
log_debug_msg("mux_recv: Did not even get the header.\n");
@@ -385,3 +388,23 @@ iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t
log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n");
return IPHONE_E_UNKNOWN_ERROR;
}
+
+/**
+ * This function is just like 'iphone_mux_recv_timeout' but you do not need
+ * to specify a timeout. It simply calls iphone_mux_recv_timeout with a
+ * timeout value of 3500 milliseconds.
+ *
+ * @param connection The connection to receive data on.
+ * @param data Where to put the data we receive.
+ * @param datalen How much data to read.
+ * @param recv_bytes Pointer to a uint32_t that will be set
+ * to the number of bytes received.
+ *
+ * @return The return value of iphone_mux_recv_timeout.
+ *
+ * @see iphone_mux_recv_timeout
+ */
+iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes)
+{
+ return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 3500);
+}