From c6982451d82c340ee8a57c76e39db160c625a1a3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 15 Dec 2009 00:02:50 +0100 Subject: Support for new SBServices interface This lockdown service has been introduced in firmware 3.1 and allows to re-arrange the Spr*ngboard icons from the computer. [#99 state:resolved] Signed-off-by: Matt Colyer --- src/SBServices.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/SBServices.c (limited to 'src/SBServices.c') diff --git a/src/SBServices.c b/src/SBServices.c new file mode 100644 index 0000000..9849415 --- /dev/null +++ b/src/SBServices.c @@ -0,0 +1,291 @@ +/* + * SBServices.c + * SpringBoard Services implementation. + * + * Copyright (c) 2009 Nikias Bassen, 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 +#include +#include +#include +#include + +#include "SBServices.h" +#include "iphone.h" +#include "utils.h" + +/** Locks an sbservices client, done for thread safety stuff. + * + * @param client The sbservices client to lock. + */ +static void sbs_lock(sbservices_client_t client) +{ + log_debug_msg("SBServices: Locked\n"); + g_mutex_lock(client->mutex); +} + +/** Unlocks an sbservices client, done for thread safety stuff. + * + * @param client The sbservices client to unlock + */ +static void sbs_unlock(sbservices_client_t client) +{ + log_debug_msg("SBServices: Unlocked\n"); + g_mutex_unlock(client->mutex); +} + +sbservices_error_t sbservices_client_new(iphone_device_t device, int dst_port, sbservices_client_t *client) +{ + /* makes sure thread environment is available */ + if (!g_thread_supported()) + g_thread_init(NULL); + + if (!device) + return SBSERVICES_E_INVALID_ARG; + + /* Attempt connection */ + iphone_connection_t connection = NULL; + if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { + return SBSERVICES_E_CONN_FAILED; + } + + sbservices_client_t client_loc = (sbservices_client_t) malloc(sizeof(struct sbservices_client_int)); + client_loc->connection = connection; + client_loc->mutex = g_mutex_new(); + + *client = client_loc; + return SBSERVICES_E_SUCCESS; +} + +sbservices_error_t sbservices_client_free(sbservices_client_t client) +{ + if (!client) + return SBSERVICES_E_INVALID_ARG; + + iphone_device_disconnect(client->connection); + client->connection = NULL; + if (client->mutex) { + g_mutex_free(client->mutex); + } + free(client); + + return SBSERVICES_E_SUCCESS; +} + +/** + * Sends a binary plist to the device using the connection specified in client. + * This function is only used internally. + * + * @param client InstallationProxy to send data to + * @param dict plist to send + * + * @return SBSERVICES_E_SUCCESS on success, SBSERVICES_E_INVALID_ARG when + * client or dict are NULL, SBSERVICES_E_PLIST_ERROR when dict is not a + * valid plist, or SBSERVICES_E_UNKNOWN_ERROR when an unspecified error + * occurs. + */ +static sbservices_error_t sbservices_plist_send(sbservices_client_t client, plist_t dict) +{ + char *content = NULL; + uint32_t length = 0; + uint32_t nlen = 0; + int bytes = 0; + sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; + + if (!client || !dict) { + return SBSERVICES_E_INVALID_ARG; + } + + plist_to_bin(dict, &content, &length); + + if (!content || length == 0) { + return SBSERVICES_E_PLIST_ERROR; + } + + nlen = htonl(length); + log_debug_msg("%s: sending %d bytes\n", __func__, length); + iphone_device_send(client->connection, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes); + if (bytes == sizeof(nlen)) { + iphone_device_send(client->connection, content, length, (uint32_t*)&bytes); + if (bytes > 0) { + if ((uint32_t)bytes == length) { + res = SBSERVICES_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(content); + + return res; +} + +sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist_t *state) +{ + if (!client || !client->connection || !state) + return SBSERVICES_E_INVALID_ARG; + + sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; + uint32_t pktlen = 0; + uint32_t bytes = 0; + + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "command", plist_new_string("getIconState")); + + sbs_lock(client); + + res = sbservices_plist_send(client, dict); + plist_free(dict); + if (res != SBSERVICES_E_SUCCESS) { + log_debug_msg("%s: could not send plist\n", __func__); + goto leave_unlock; + } + + iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); + log_debug_msg("%s: initial read=%i\n", __func__, bytes); + if (bytes < 4) { + log_debug_msg("%s: initial read failed!\n"); + res = 0; + } else { + if ((char)pktlen == 0) { + char *content = NULL; + uint32_t curlen = 0; + pktlen = ntohl(pktlen); + log_debug_msg("%s: %d bytes following\n", __func__, pktlen); + content = (char*)malloc(pktlen); + log_debug_msg("pointer %p\n", content); + + while (curlen < pktlen) { + iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); + if (bytes <= 0) { + res = SBSERVICES_E_UNKNOWN_ERROR; + break; + } + log_debug_msg("%s: received %d bytes\n", __func__, bytes); + curlen += bytes; + } + log_debug_buffer(content, pktlen); + plist_from_bin(content, pktlen, state); + res = SBSERVICES_E_SUCCESS; + free(content); + } else { + res = SBSERVICES_E_UNKNOWN_ERROR; + } + } + +leave_unlock: + sbs_unlock(client); + return res; +} + +sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist_t newstate) +{ + if (!client || !client->connection || !newstate) + return SBSERVICES_E_INVALID_ARG; + + sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; + + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "command", plist_new_string("setIconState")); + plist_dict_insert_item(dict, "iconState", plist_copy(newstate)); + + sbs_lock(client); + + res = sbservices_plist_send(client, dict); + plist_free(dict); + if (res != SBSERVICES_E_SUCCESS) { + log_debug_msg("%s: could not send plist\n", __func__); + goto leave_unlock; + } + // NO RESPONSE + +leave_unlock: + sbs_unlock(client); + return res; +} + +sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, const char *bundleId, char **pngdata, uint64_t *pngsize) +{ + if (!client || !client->connection || !pngdata) + return SBSERVICES_E_INVALID_ARG; + + sbservices_error_t res = SBSERVICES_E_UNKNOWN_ERROR; + uint32_t pktlen = 0; + uint32_t bytes = 0; + + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "command", plist_new_string("getIconPNGData")); + plist_dict_insert_item(dict, "bundleId", plist_new_string(bundleId)); + + sbs_lock(client); + + res = sbservices_plist_send(client, dict); + plist_free(dict); + if (res != SBSERVICES_E_SUCCESS) { + log_debug_msg("%s: could not send plist\n", __func__); + goto leave_unlock; + } + + iphone_device_recv(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes); + log_debug_msg("%s: initial read=%i\n", __func__, bytes); + if (bytes < 4) { + log_debug_msg("%s: initial read failed!\n"); + res = 0; + } else { + if ((char)pktlen == 0) { + char *content = NULL; + uint32_t curlen = 0; + pktlen = ntohl(pktlen); + log_debug_msg("%s: %d bytes following\n", __func__, pktlen); + content = (char*)malloc(pktlen); + log_debug_msg("pointer %p\n", content); + + while (curlen < pktlen) { + iphone_device_recv(client->connection, content+curlen, pktlen-curlen, &bytes); + if (bytes <= 0) { + res = SBSERVICES_E_UNKNOWN_ERROR; + break; + } + log_debug_msg("%s: received %d bytes\n", __func__, bytes); + curlen += bytes; + } + log_debug_buffer(content, pktlen); + plist_t pngdict = NULL; + plist_from_bin(content, pktlen, &pngdict); + plist_t node = plist_dict_get_item(pngdict, "pngData"); + if (node) { + plist_get_data_val(node, pngdata, pngsize); + } + plist_free(pngdict); + res = SBSERVICES_E_SUCCESS; + free(content); + } else { + res = SBSERVICES_E_UNKNOWN_ERROR; + } + } + +leave_unlock: + sbs_unlock(client); + return res; + +} + -- cgit v1.1-32-gdbae