DeviceStatus Device::getApps() { plist_t apps = NULL; plist_t opts; opts = instproxy_client_options_new(); instproxy_client_options_add(opts, "ApplicationType", "Any", NULL); if (instproxy_browse(this->mInstProxy, opts, &apps) != INSTPROXY_E_SUCCESS) { instproxy_client_options_free(opts); return StatusError; } int count = plist_array_get_size(apps) / 2; for (int i = 0; i < count; i++) { plist_t app; app = plist_array_get_item(apps, i); plist_t appId; appId = plist_dict_get_item(app, "CFBundleIdentifier"); char *sAppId; plist_get_string_val(appId, &sAppId); this->mApps.insert(sAppId); //cout << i << "\t" << sAppId << endl; free(sAppId); plist_free(appId); plist_free(app); } plist_free(apps); instproxy_client_options_free(opts); return StatusOK; }
/** * Internally used function to extract the message string from a DL* message * plist. * * @param dl_msg The DeviceLink property list to parse. * @param message A pointer that will be set to a newly allocated char* * containing the DLMessage* string from the given plist. It is up to * the caller to free the allocated memory. If this parameter is NULL * it will be ignored. * * @return 1 if the given plist is a DL* message, or 0 if the plist does not * contain any DL* message. */ static int device_link_service_get_message(plist_t dl_msg, char **message) { plist_t cmd = NULL; char *cmd_str = NULL; /* sanity check */ if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || (plist_array_get_size(dl_msg) < 1)) { return 0; } /* get dl command */ cmd = plist_array_get_item(dl_msg, 0); if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) { return 0; } plist_get_string_val(cmd, &cmd_str); if (!cmd_str) { return 0; } if ((strlen(cmd_str) < 9) || (strncmp(cmd_str, "DL", 2))) { free(cmd_str); return 0; } if (message) *message = cmd_str; /* we got a DL* message */ return 1; }
/** * Internally used function to extract the message string from a DLMessage* * plist. * * @param dl_msg The DeviceLink property list to parse. * * @return An allocated char* with the DLMessage from the given plist, * or NULL when the plist does not contain any DLMessage. It is up to * the caller to free the allocated memory. */ static char *device_link_service_get_message(plist_t dl_msg) { uint32_t cnt = 0; plist_t cmd = 0; char *cmd_str = NULL; /* sanity check */ if ((plist_get_node_type(dl_msg) != PLIST_ARRAY) || ((cnt = plist_array_get_size(dl_msg)) < 1)) { return NULL; } /* get dl command */ cmd = plist_array_get_item(dl_msg, 0); if (!cmd || (plist_get_node_type(cmd) != PLIST_STRING)) { return NULL; } plist_get_string_val(cmd, &cmd_str); if (!cmd_str) { return NULL; } if ((strlen(cmd_str) < (strlen("DLMessage")+1)) || (strncmp(cmd_str, "DLMessage", strlen("DLMessage")))) { free(cmd_str); return NULL; } /* we got a DLMessage* command */ return cmd_str; }
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_get_app_path_by_name(instproxy_client_t client, const char* app_name, char ** app_path, char ** exec_path) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t apps = NULL; plist_t client_options = instproxy_client_options_new(); instproxy_client_options_add(client_options, "ApplicationType", "Any", NULL); res = instproxy_browse(client, client_options, &apps); instproxy_client_options_free(client_options); int app_count = plist_array_get_size(apps); for(int app_index = 0; app_index < app_count; app_index++){ plist_t app_info_plist = plist_array_get_item(apps, app_index); plist_t app_bundle_display_name_plist = plist_dict_get_item(app_info_plist, "CFBundleDisplayName"); char* app_name_tmp = NULL; plist_t app_path_plist = NULL; plist_t exec_path_plist = NULL; if (app_bundle_display_name_plist) { plist_get_string_val(app_bundle_display_name_plist, &app_name_tmp); } if (app_name_tmp == NULL || strcasecmp(app_name_tmp, app_name) != 0) { continue; } char * app_path_tmp = NULL; char * exec_path_tmp = NULL; app_path_plist = plist_dict_get_item(app_info_plist, "Path"); if (app_path_plist) { plist_get_string_val(app_path_plist, &app_path_tmp); } exec_path_plist = plist_dict_get_item(app_info_plist, "CFBundleExecutable"); if (exec_path_plist) { plist_get_string_val(exec_path_plist, &exec_path_tmp); } size_t app_path_length = strlen(app_path_tmp); size_t exec_path_length = strlen(exec_path_tmp); *app_path = (char *)alloca(app_path_length + 1); *exec_path = (char *)alloca(exec_path_length + 1); memset(*app_path, 0, app_path_length + 1); memset(*exec_path, 0, exec_path_length + 1); memcpy(*app_path, app_path_tmp, strlen(app_path_tmp)); memcpy(*exec_path, exec_path_tmp, strlen(exec_path_tmp)); break; } return res; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!client->session_id) return LOCKDOWN_E_NO_RUNNING_SESSION; plist_t dict = NULL; lockdownd_error_t err = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; char **newlist = NULL; char *val = NULL; *classes = NULL; *count = 0; err = lockdownd_get_value(client, "com.apple.mobile.iTunes", "SyncDataClasses", &dict); if (err != LOCKDOWN_E_SUCCESS) { if (dict) { plist_free(dict); } return err; } if (plist_get_node_type(dict) != PLIST_ARRAY) { plist_free(dict); return LOCKDOWN_E_PLIST_ERROR; } while((value = plist_array_get_item(dict, *count)) != NULL) { plist_get_string_val(value, &val); newlist = realloc(*classes, sizeof(char*) * (*count+1)); str_remove_spaces(val); if (asprintf(&newlist[*count], "com.apple.%s", val) < 0) { debug_info("ERROR: asprintf failed"); } free(val); val = NULL; *classes = newlist; *count = *count+1; } newlist = realloc(*classes, sizeof(char*) * (*count+1)); newlist[*count] = NULL; *classes = newlist; if (dict) { plist_free(dict); } return LOCKDOWN_E_SUCCESS; }
Array::Array(plist_t node, Node* parent) : Structure(parent) { _node = node; uint32_t size = plist_array_get_size(_node); for (uint32_t i = 0; i < size; i++) { plist_t subnode = plist_array_get_item(_node, i); _array.push_back( Node::FromPlist(subnode, this) ); } }
Array::Array(PList::Array& a) : Structure() { _array.clear(); _node = plist_copy(a.GetPlist()); uint32_t size = plist_array_get_size(_node); for (uint32_t i = 0; i < size; i++) { plist_t subnode = plist_array_get_item(_node, i); _array.push_back( Node::FromPlist(subnode, this) ); } }
void plist_array_remove_item(plist_t node, uint32_t n) { if (node && PLIST_ARRAY == plist_get_node_type(node)) { plist_t old_item = plist_array_get_item(node, n); if (old_item) { plist_free(old_item); } } return; }
static void process_pl_items(plist_t items, int pl_id, const char *name) { plist_t trk; uint64_t itml_id; uint32_t db_id; uint32_t alen; uint32_t i; int ntracks; int ret; db_transaction_begin(); ntracks = 0; alen = plist_array_get_size(items); for (i = 0; i < alen; i++) { trk = plist_array_get_item(items, i); if (plist_get_node_type(trk) != PLIST_DICT) continue; ret = get_dictval_int_from_key(trk, "Track ID", &itml_id); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "No Track ID found for playlist item %u in '%s'\n", i, name); continue; } db_id = id_map_get(itml_id); if (!db_id) { DPRINTF(E_INFO, L_SCAN, "Did not find a match for track ID %" PRIu64 " in '%s'\n", itml_id, name); continue; } ret = db_pl_add_item_byid(pl_id, db_id); if (ret < 0) DPRINTF(E_WARN, L_SCAN, "Could not add ID %d to playlist '%s'\n", db_id, name); ntracks++; if (ntracks % 200 == 0) { DPRINTF(E_LOG, L_SCAN, "Processed %d tracks from playlist '%s'...\n", ntracks, name); db_transaction_end(); db_transaction_begin(); } } db_transaction_end(); }
static void plist_array_to_string(plist_t node) { int i, count; plist_t subnode = NULL; count = plist_array_get_size(node); for (i = 0; i < count; i++) { subnode = plist_array_get_item(node, i); printf("%*s", indent_level, ""); printf("%d: ", i); plist_node_to_string(subnode); } }
int isManifestSignedForDevice(char *buildManifestPath, char **device, uint64_t ecid, int checkBaseband, char **version){ int isSigned = 0; #define reterror(a ...) {error(a); isSigned = -1; goto error;} plist_t manifest = NULL; plist_t ProductVersion = NULL; plist_t SupportedProductTypes = NULL; plist_t mDevice = NULL; info("[TSSC] opening %s\n",buildManifestPath); //filehandling FILE *fmanifest = fopen(buildManifestPath, "r"); if (!fmanifest) reterror("[TSSC] ERROR: file %s nof found!\n",buildManifestPath); fseek(fmanifest, 0, SEEK_END); long fsize = ftell(fmanifest); fseek(fmanifest, 0, SEEK_SET); char *bufManifest = (char*)malloc(fsize + 1); fread(bufManifest, fsize, 1, fmanifest); fclose(fmanifest); plist_from_xml(bufManifest, (unsigned)strlen(bufManifest), &manifest); if (version && !*version){ if (!manifest){ warning("[TSSC] WARNING: could not find ProductVersion in BuildManifest.plist, failing to properly display iOS version\n"); }else{ ProductVersion = plist_dict_get_item(manifest, "ProductVersion"); plist_get_string_val(ProductVersion, version); } } if (!*device) { if (manifest){ SupportedProductTypes = plist_dict_get_item(manifest, "SupportedProductTypes"); if (SupportedProductTypes) { mDevice = plist_array_get_item(SupportedProductTypes, 0); plist_get_string_val(mDevice, device); } } if (!*device) reterror("[TSSR] ERROR: device wasn't specified and could not be fetched from BuildManifest\n") else info("[TSSR] requesting ticket for %s\n",*device); } isSigned = isManifestBufSignedForDevice(bufManifest, *device, ecid, checkBaseband); error: if (manifest) plist_free(manifest); free(bufManifest); return isSigned; #undef reterror }
void plist_array_set_item(plist_t node, plist_t item, uint32_t n) { if (node && PLIST_ARRAY == plist_get_node_type(node)) { plist_t old_item = plist_array_get_item(node, n); if (old_item) { int idx = plist_free_node(old_item); if (idx < 0) { node_attach(node, item); } else { node_insert(node, idx, item); } } } return; }
/** * Tells the device that the restore process is complete and waits for the * device to close the connection. After that, the device should reboot. * * @param client The connected MobileBackup client to use. * * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if * client is invalid, MOBILEBACKUP_E_PLIST_ERROR if the received disconnect * message plist is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication * error occurs. */ mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) { mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL); if (err != MOBILEBACKUP_E_SUCCESS) { return err; } plist_t dlmsg = NULL; err = mobilebackup_receive(client, &dlmsg); if ((err != MOBILEBACKUP_E_SUCCESS) || !dlmsg || (plist_get_node_type(dlmsg) != PLIST_ARRAY) || (plist_array_get_size(dlmsg) != 2)) { if (dlmsg) { debug_info("ERROR: Did not receive DLMessageDisconnect:"); debug_plist(dlmsg); plist_free(dlmsg); } if (err == MOBILEBACKUP_E_SUCCESS) { err = MOBILEBACKUP_E_PLIST_ERROR; } return err; } plist_t node = plist_array_get_item (dlmsg, 0); char *msg = NULL; if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &msg); } if (msg && !strcmp(msg, "DLMessageDisconnect")) { err = MOBILEBACKUP_E_SUCCESS; /* we need to do this here, otherwise mobilebackup_client_free will fail */ device_link_service_client_free(client->parent); client->parent = NULL; } else { debug_info("ERROR: Malformed plist received:"); debug_plist(dlmsg); err = MOBILEBACKUP_E_PLIST_ERROR; } plist_free(dlmsg); if (msg) free(msg); return err; }
Array& Array::operator=(PList::Array& a) { plist_free(_node); for (unsigned int it = 0; it < _array.size(); it++) { delete _array.at(it); } _array.clear(); _node = plist_copy(a.GetPlist()); uint32_t size = plist_array_get_size(_node); for (uint32_t i = 0; i < size; i++) { plist_t subnode = plist_array_get_item(_node, i); _array.push_back( Node::FromPlist(subnode, this) ); } return *this; }
/** * Receives a DLMessageProcessMessage plist. * * @param client The connected device link service client used for receiving. * @param message Pointer to a plist that will be set to the contents of the * message contents upon successful return. * * @return DEVICE_LINK_SERVICE_E_SUCCESS when a DLMessageProcessMessage was * received, DEVICE_LINK_SERVICE_E_INVALID_ARG when client or message is * invalid, DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is * invalid or is not a DLMessageProcessMessage, * or DEVICE_LINK_SERVICE_E_MUX_ERROR if receiving from device fails. */ device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message) { if (!client || !client->parent || !message) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t pmsg = NULL; if (property_list_service_receive_plist(client->parent, &pmsg) != PROPERTY_LIST_SERVICE_E_SUCCESS) { return DEVICE_LINK_SERVICE_E_MUX_ERROR; } device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; char *msg = NULL; device_link_service_get_message(pmsg, &msg); if (!msg || strcmp(msg, "DLMessageProcessMessage")) { debug_info("Did not receive DLMessageProcessMessage as expected!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } if (plist_array_get_size(pmsg) != 2) { debug_info("Malformed plist received for DLMessageProcessMessage"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } plist_t msg_loc = plist_array_get_item(pmsg, 1); if (msg_loc) { *message = plist_copy(msg_loc); err = DEVICE_LINK_SERVICE_E_SUCCESS; } else { *message = NULL; err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; } leave: if (msg) free(msg); if (pmsg) plist_free(pmsg); return err; }
plist_t build_manifest_get_build_identity(plist_t build_manifest, uint32_t identity) { // fetch build identities array from BuildManifest plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { error("ERROR: Unable to find build identities node\n"); return NULL; } // check and make sure this identity exists in buildmanifest if (identity >= plist_array_get_size(build_identities_array)) { return NULL; } plist_t build_identity = plist_array_get_item(build_identities_array, identity); if (!build_identity || plist_get_node_type(build_identity) != PLIST_DICT) { error("ERROR: Unable to find build identities node\n"); return NULL; } return plist_copy(build_identity); }
static void instproxy_append_current_list_to_result_cb(plist_t command, plist_t status, void *user_data) { plist_t *result_array = (plist_t*)user_data; uint64_t current_amount = 0; plist_t current_list = NULL; uint64_t i; instproxy_status_get_current_list(status, NULL, NULL, ¤t_amount, ¤t_list); debug_info("current_amount: %d", current_amount); if (current_amount > 0) { for (i = 0; current_list && (i < current_amount); i++) { plist_t item = plist_array_get_item(current_list, i); plist_array_append_item(*result_array, plist_copy(item)); } } if (current_list) plist_free(current_list); }
int build_manifest_check_compatibility(plist_t build_manifest, const char* product) { int res = -1; plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes"); if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) { debug("%s: ERROR: SupportedProductTypes key missing\n", __func__); return -1; } uint32_t pc = plist_array_get_size(node); uint32_t i; for (i = 0; i < pc; i++) { plist_t prod = plist_array_get_item(node, i); if (plist_get_node_type(prod) == PLIST_STRING) { char *val = NULL; plist_get_string_val(prod, &val); if (val && (strcmp(val, product) == 0)) { res = 0; break; } } } return res; }
plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v) { plist_t current = plist; plist_type type = PLIST_NONE; uint32_t i = 0; for (i = 0; i < length && current; i++) { type = plist_get_node_type(current); if (type == PLIST_ARRAY) { uint32_t n = va_arg(v, uint32_t); current = plist_array_get_item(current, n); } else if (type == PLIST_DICT) { const char* key = va_arg(v, const char*); current = plist_dict_get_item(current, key); } } return current; }
static void process_pl_items(plist_t items, int pl_id) { plist_t trk; uint64_t itml_id; uint32_t db_id; uint32_t alen; uint32_t i; int ret; alen = plist_array_get_size(items); for (i = 0; i < alen; i++) { trk = plist_array_get_item(items, i); if (plist_get_node_type(trk) != PLIST_DICT) continue; ret = get_dictval_int_from_key(trk, "Track ID", &itml_id); if (ret < 0) { DPRINTF(E_WARN, L_SCAN, "No Track ID found for playlist item %u\n", i); continue; } db_id = id_map_get(itml_id); if (!db_id) { DPRINTF(E_INFO, L_SCAN, "Track ID %" PRIu64 " dropped\n", itml_id); continue; } ret = db_pl_add_item_byid(pl_id, db_id); if (ret < 0) DPRINTF(E_WARN, L_SCAN, "Could not add ID %d to playlist\n", db_id); } }
int build_manifest_check_compatibility(plist_t build_manifest, const char* product) { int res = -1; plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes"); if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) { debug("%s: ERROR: SupportedProductTypes key missing\n", __func__); debug("%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the", __func__); debug("%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.", __func__); return -1; } uint32_t pc = plist_array_get_size(node); uint32_t i; for (i = 0; i < pc; i++) { plist_t prod = plist_array_get_item(node, i); if (plist_get_node_type(prod) == PLIST_STRING) { char *val = NULL; plist_get_string_val(prod, &val); if (val && (strcmp(val, product) == 0)) { res = 0; break; } } } return res; }
/** * Receives any remapped identifiers reported after the device merged submitted changes. * * @param client The mobilesync client * @param mapping A pointer to an array plist containing a dict of identifier remappings * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid * form * @retval MOBILESYNC_E_WRONG_DIRECTION if the current sync direction does * not permit this call * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * session */ mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } if (client->direction == MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER) { return MOBILESYNC_E_WRONG_DIRECTION; } plist_t msg = NULL; plist_t response_type_node = NULL; char *response_type = NULL; mobilesync_error_t err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(response_type, "SDMessageCancelSession")) { char *reason = NULL; err = MOBILESYNC_E_CANCELLED; plist_get_string_val(plist_array_get_item(msg, 2), &reason); debug_info("Device cancelled: %s", reason); free(reason); goto out; } if (strcmp(response_type, "SDMessageRemapRecordIdentifiers") != 0) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (mapping != NULL) { plist_t map = plist_array_get_item(msg, 2); if (plist_get_node_type(map) == PLIST_DICT) { *mapping = plist_copy(map); } else { *mapping = NULL; } } err = MOBILESYNC_E_SUCCESS; out: if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } return err; }
/** * List installed applications. This function runs synchronously. * * @param client The connected installation_proxy client * @param client_options The client options to use, as PLIST_DICT, or NULL. * Valid client options include: * "ApplicationType" -> "User" * "ApplicationType" -> "System" * @param result Pointer that will be set to a plist that will hold an array * of PLIST_DICT holding information about the applications found. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occured. */ instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) { if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; instproxy_lock(client); res = instproxy_send_command(client, "Browse", client_options, NULL, NULL); if (res != INSTPROXY_E_SUCCESS) { debug_info("could not send plist"); goto leave_unlock; } int browsing = 0; plist_t apps_array = plist_new_array(); plist_t dict = NULL; do { browsing = 0; dict = NULL; res = instproxy_error(property_list_service_receive_plist(client->parent, &dict)); if (res != INSTPROXY_E_SUCCESS) { break; } if (dict) { uint64_t i; uint64_t current_amount = 0; char *status = NULL; plist_t camount = plist_dict_get_item(dict, "CurrentAmount"); plist_t pstatus = plist_dict_get_item(dict, "Status"); if (camount) { plist_get_uint_val(camount, ¤t_amount); } if (current_amount > 0) { plist_t current_list = plist_dict_get_item(dict, "CurrentList"); for (i = 0; current_list && (i < current_amount); i++) { plist_t item = plist_array_get_item(current_list, i); plist_array_append_item(apps_array, plist_copy(item)); } } if (pstatus) { plist_get_string_val(pstatus, &status); } if (status) { if (!strcmp(status, "BrowsingApplications")) { browsing = 1; } else if (!strcmp(status, "Complete")) { debug_info("Browsing applications completed"); res = INSTPROXY_E_SUCCESS; } free(status); } plist_free(dict); } } while (browsing); if (res == INSTPROXY_E_SUCCESS) { *result = apps_array; } else { plist_free(apps_array); } leave_unlock: instproxy_unlock(client); return res; }
static void process_pls(plist_t playlists, const char *file) { plist_t pl; plist_t items; struct playlist_info *pli; char *name; uint64_t id; int pl_id; uint32_t alen; uint32_t i; char virtual_path[PATH_MAX]; int ret; alen = plist_array_get_size(playlists); for (i = 0; i < alen; i++) { pl = plist_array_get_item(playlists, i); if (plist_get_node_type(pl) != PLIST_DICT) continue; ret = get_dictval_int_from_key(pl, "Playlist ID", &id); if (ret < 0) { DPRINTF(E_DBG, L_SCAN, "Playlist ID not found!\n"); continue; } ret = get_dictval_string_from_key(pl, "Name", &name); if (ret < 0) { DPRINTF(E_DBG, L_SCAN, "Name not found!\n"); continue; } if (ignore_pl(pl, name)) { free(name); continue; } ret = get_dictval_array_from_key(pl, "Playlist Items", &items); if (ret < 0) { DPRINTF(E_INFO, L_SCAN, "Playlist '%s' has no items\n", name); free(name); continue; } CHECK_NULL(L_SCAN, pli = calloc(1, sizeof(struct playlist_info))); pli->type = PL_PLAIN; pli->title = strdup(name); pli->path = strdup(file); snprintf(virtual_path, sizeof(virtual_path), "/file:%s/%s", file, name); pli->virtual_path = strdup(virtual_path); ret = db_pl_add(pli, &pl_id); free_pli(pli, 0); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error adding iTunes playlist '%s' (%s)\n", name, file); free(name); continue; } DPRINTF(E_INFO, L_SCAN, "Added playlist as id %d\n", pl_id); process_pl_items(items, pl_id, name); free(name); } }
int tssrequest(plist_t *tssrequest, char *buildManifest, char *device, uint64_t ecid, int checkBaseband){ #define reterror(a) {error(a); error = -1; goto error;} int error = 0; plist_t manifest = NULL; plist_t tssparameter = plist_new_dict(); plist_t tssreq = tss_request_new(NULL); plist_from_xml(buildManifest, (unsigned)strlen(buildManifest), &manifest); plist_t buildidentities = plist_dict_get_item(manifest, "BuildIdentities"); if (!buildidentities || plist_get_node_type(buildidentities) != PLIST_ARRAY){ reterror("[TSSR] Error: could not get BuildIdentities\n"); } plist_t id0 = plist_array_get_item(buildidentities, 0); if (!id0 || plist_get_node_type(id0) != PLIST_DICT){ reterror("[TSSR] Error: could not get id0\n"); } plist_t manifestdict = plist_dict_get_item(id0, "Manifest"); if (!manifestdict || plist_get_node_type(manifestdict) != PLIST_DICT){ reterror("[TSSR] Error: could not get manifest\n"); } plist_t sep = plist_dict_get_item(manifestdict, "SEP"); int is64Bit = !(!sep || plist_get_node_type(sep) != PLIST_DICT); tss_populate_random(tssparameter,is64Bit,ecid); tss_parameters_add_from_manifest(tssparameter, id0); if (tss_request_add_common_tags(tssreq, tssparameter, NULL) < 0) { reterror("[TSSR] ERROR: Unable to add common tags to TSS request\n"); } if (tss_request_add_ap_tags(tssreq, tssparameter, NULL) < 0) { reterror("[TSSR] ERROR: Unable to add common tags to TSS request\n"); } if (is64Bit) { if (tss_request_add_ap_img4_tags(tssreq, tssparameter) < 0) { reterror("[TSSR] ERROR: Unable to add img4 tags to TSS request\n"); } } else { if (tss_request_add_ap_img3_tags(tssreq, tssparameter) < 0) { reterror("[TSSR] ERROR: Unable to add img3 tags to TSS request\n"); } } if (checkBaseband) { int64_t BbGoldCertId = getBBGCIDForDevice(device); if (BbGoldCertId < 0) { warning("[TSSR] WARNING: there was an error getting BasebandGoldCertID, continuing without requesting Baseband ticket\n"); }else if (BbGoldCertId) { tss_populate_basebandvals(tssreq,tssparameter,BbGoldCertId); tss_request_add_baseband_tags(tssreq, tssparameter, NULL); }else{ log("[TSSR] LOG: device %s doesn't need a Baseband ticket, continuing without requesting a Baseband ticket\n",device); } }else{ info("[TSSR] User specified not to request a Baseband ticket.\n"); } *tssrequest = tssreq; error: if (manifest) plist_free(manifest); if (tssparameter) plist_free(tssparameter); if (error) plist_free(tssreq), *tssrequest = NULL; return error; #undef reterror }
int main(int argc, char *argv[]) { lockdownd_client_t client = NULL; lockdownd_service_descriptor_t service = NULL; idevice_t device = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; int i; int op = -1; const char* udid = NULL; const char* param = 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], "install")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_INSTALL; continue; } else if (!strcmp(argv[i], "list")) { op = OP_LIST; } else if (!strcmp(argv[i], "copy")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_COPY; continue; } else if (!strcmp(argv[i], "remove")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_REMOVE; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); return 0; } else { print_usage(argc, argv); return 0; } } if ((op == -1) || (op >= NUM_OPS)) { print_usage(argc, argv); return 0; } ret = idevice_new(&device, udid); if (ret != 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"); } return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "ideviceprovision")) { idevice_free(device); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &service)) { fprintf(stderr, "Could not start service \"com.apple.misagent\"\n"); lockdownd_client_free(client); idevice_free(device); return -1; } lockdownd_client_free(client); client = NULL; misagent_client_t mis = NULL; if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) { fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n"); if (service) lockdownd_service_descriptor_free(service); lockdownd_client_free(client); idevice_free(device); return -1; } if (service) lockdownd_service_descriptor_free(service); switch (op) { case OP_INSTALL: { FILE* f = fopen(param, "rb"); if (!f) { fprintf(stderr, "Could not open file '%s'\n", param); break; } fseek(f, 0, SEEK_END); long int size = ftell(f); fseek(f, 0, SEEK_SET); if (size >= 0x1000000) { fprintf(stderr, "The file '%s' is too large for processing.\n", param); fclose(f); break; } char* buf = (char *)malloc(size); if (!buf) { fprintf(stderr, "Could not allocate memory...\n"); fclose(f); break; } long int cur = 0; while (cur < size) { ssize_t r = fread(buf+cur, 1, 512, f); if (r <= 0) { break; } cur += r; } fclose(f); if (cur != size) { free(buf); fprintf(stderr, "Could not read in file '%s' (size %ld read %ld)\n", param, size, cur); break; } uint64_t psize = size; plist_t pdata = plist_new_data(buf, psize); if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) { printf("Profile '%s' installed successfully.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not install profile '%s', status code: 0x%x\n", param, sc); } free(buf); } break; case OP_LIST: case OP_COPY: { plist_t profiles = NULL; if (misagent_copy(mis, &profiles) == MISAGENT_E_SUCCESS) { uint32_t num_profiles = plist_array_get_size(profiles); printf("Device has %d provisioning %s installed:\n", num_profiles, (num_profiles == 1) ? "profile" : "profiles"); uint32_t j; for (j = 0; j < num_profiles; j++) { char* p_name = NULL; char* p_uuid = NULL; plist_t profile = plist_array_get_item(profiles, j); plist_t pl = profile_get_embedded_plist(profile); if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_t node; node = plist_dict_get_item(pl, "Name"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_name); } node = plist_dict_get_item(pl, "UUID"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_uuid); } } printf("%s - %s\n", (p_uuid) ? p_uuid : "(unknown id)", (p_name) ? p_name : "(no name)"); if (op == OP_COPY) { char pfname[512]; if (p_uuid) { sprintf(pfname, "%s/%s.mobileprovision", param, p_uuid); } else { sprintf(pfname, "%s/profile%d.mobileprovision", param, j); } FILE* f = fopen(pfname, "wb"); if (f) { char* dt = NULL; uint64_t ds = 0; plist_get_data_val(profile, &dt, &ds); fwrite(dt, 1, (size_t) ds, f); fclose(f); printf(" => %s\n", pfname); } else { fprintf(stderr, "Could not open '%s' for writing\n", pfname); } } if (p_uuid) { free(p_uuid); } if (p_name) { free(p_name); } } } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not get installed profiles from device, status code: 0x%x\n", sc); } } break; case OP_REMOVE: if (misagent_remove(mis, param) == MISAGENT_E_SUCCESS) { printf("Profile '%s' removed.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not remove profile '%s', status code 0x%x\n", param, sc); } break; default: break; } misagent_client_free(mis); idevice_free(device); return 0; }
int main(int argc, char *argv[]) { lockdownd_client_t client = NULL; lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR; lockdownd_service_descriptor_t service = NULL; idevice_t device = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; int i; int op = -1; int output_xml = 0; const char* udid = NULL; const char* param = 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], "install")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_INSTALL; continue; } else if (!strcmp(argv[i], "list")) { op = OP_LIST; } else if (!strcmp(argv[i], "copy")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_COPY; continue; } else if (!strcmp(argv[i], "remove")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_REMOVE; continue; } else if (!strcmp(argv[i], "dump")) { i++; if (!argv[i] || (strlen(argv[i]) < 1)) { print_usage(argc, argv); return 0; } param = argv[i]; op = OP_DUMP; continue; } else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) { output_xml = 1; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); return 0; } else { print_usage(argc, argv); return 0; } } if ((op == -1) || (op >= NUM_OPS)) { print_usage(argc, argv); return 0; } if (op == OP_DUMP) { int res = 0; unsigned char* profile_data = NULL; unsigned int profile_size = 0; if (profile_read_from_file(param, &profile_data, &profile_size) != 0) { return -1; } plist_t pdata = plist_new_data((char*)profile_data, profile_size); plist_t pl = profile_get_embedded_plist(pdata); plist_free(pdata); free(profile_data); if (pl) { if (output_xml) { char* xml = NULL; uint32_t xlen = 0; plist_to_xml(pl, &xml, &xlen); if (xml) { printf("%s\n", xml); free(xml); } } else { if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_print_to_stream(pl, stdout); } else { fprintf(stderr, "ERROR: unexpected node type in profile plist (not PLIST_DICT)\n"); res = -1; } } } else { fprintf(stderr, "ERROR: could not extract embedded plist from profile!\n"); } plist_free(pl); return res; } ret = idevice_new(&device, udid); if (ret != 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"); } return -1; } if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "ideviceprovision"))) { fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ldret); idevice_free(device); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.misagent", &service)) { fprintf(stderr, "Could not start service \"com.apple.misagent\"\n"); lockdownd_client_free(client); idevice_free(device); return -1; } lockdownd_client_free(client); client = NULL; misagent_client_t mis = NULL; if (misagent_client_new(device, service, &mis) != MISAGENT_E_SUCCESS) { fprintf(stderr, "Could not connect to \"com.apple.misagent\" on device\n"); if (service) lockdownd_service_descriptor_free(service); lockdownd_client_free(client); idevice_free(device); return -1; } if (service) lockdownd_service_descriptor_free(service); switch (op) { case OP_INSTALL: { unsigned char* profile_data = NULL; unsigned int profile_size = 0; if (profile_read_from_file(param, &profile_data, &profile_size) != 0) { break; } uint64_t psize = profile_size; plist_t pdata = plist_new_data((const char*)profile_data, psize); free(profile_data); if (misagent_install(mis, pdata) == MISAGENT_E_SUCCESS) { printf("Profile '%s' installed successfully.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not install profile '%s', status code: 0x%x\n", param, sc); } } break; case OP_LIST: case OP_COPY: { plist_t profiles = NULL; if (misagent_copy(mis, &profiles) == MISAGENT_E_SUCCESS) { uint32_t num_profiles = plist_array_get_size(profiles); printf("Device has %d provisioning %s installed:\n", num_profiles, (num_profiles == 1) ? "profile" : "profiles"); uint32_t j; for (j = 0; j < num_profiles; j++) { char* p_name = NULL; char* p_uuid = NULL; plist_t profile = plist_array_get_item(profiles, j); plist_t pl = profile_get_embedded_plist(profile); if (pl && (plist_get_node_type(pl) == PLIST_DICT)) { plist_t node; node = plist_dict_get_item(pl, "Name"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_name); } node = plist_dict_get_item(pl, "UUID"); if (node && (plist_get_node_type(node) == PLIST_STRING)) { plist_get_string_val(node, &p_uuid); } } printf("%s - %s\n", (p_uuid) ? p_uuid : "(unknown id)", (p_name) ? p_name : "(no name)"); if (op == OP_COPY) { char pfname[512]; if (p_uuid) { sprintf(pfname, "%s/%s.mobileprovision", param, p_uuid); } else { sprintf(pfname, "%s/profile%d.mobileprovision", param, j); } FILE* f = fopen(pfname, "wb"); if (f) { char* dt = NULL; uint64_t ds = 0; plist_get_data_val(profile, &dt, &ds); fwrite(dt, 1, ds, f); fclose(f); printf(" => %s\n", pfname); } else { fprintf(stderr, "Could not open '%s' for writing\n", pfname); } } if (p_uuid) { free(p_uuid); } if (p_name) { free(p_name); } } } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not get installed profiles from device, status code: 0x%x\n", sc); } } break; case OP_REMOVE: if (misagent_remove(mis, param) == MISAGENT_E_SUCCESS) { printf("Profile '%s' removed.\n", param); } else { int sc = misagent_get_status_code(mis); fprintf(stderr, "Could not remove profile '%s', status code 0x%x\n", param, sc); } break; default: break; } misagent_client_free(mis); idevice_free(device); return 0; }
DeviceStatus Device::backup() { mobilebackup2_client_t mb_client = NULL; DeviceStatus status = StatusError; if (mobilebackup2_client_start_service(this->mDevice, &mb_client, NULL) == MOBILEBACKUP2_E_SUCCESS) { afc_client_t afc = this->getAfcFromApp(""); if (afc) { uint64_t handle; if (afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &handle) == AFC_E_SUCCESS && afc_file_lock(afc, handle, AFC_LOCK_EX) == AFC_E_SUCCESS) { if (mobilebackup2_send_request(mb_client, "Backup", this->mUdid.c_str(), this->mUdid.c_str(), NULL) == MOBILEBACKUP2_E_SUCCESS) { plist_t msg = NULL; char *dl = NULL; if (mobilebackup2_receive_message(mb_client, &msg, &dl) == MOBILEBACKUP2_E_SUCCESS) { plist_t files = plist_array_get_item(msg, 1); int count = plist_array_get_size(files); for (int i = 0; i < count; i++) { plist_t val = plist_array_get_item(files, i); if (plist_get_node_type(val) != PLIST_STRING) { continue; } char *str = NULL; plist_get_string_val(val, &str); if (!str) { continue; } uint32_t nlen = 0, bytes = 0; mobilebackup2_error_t err; err = mobilebackup2_send_raw(mb_client, (const char*)&nlen, sizeof(nlen), &bytes); const char *path = "/tmp/test"; uint32_t pathlen = strlen(path); err = mobilebackup2_send_raw(mb_client, path, pathlen, &bytes); free(str); } uint32_t zero = 0, sent = 0; mobilebackup2_send_raw(mb_client, (char*)&zero, sizeof(zero), &sent); plist_free(msg); free(dl); status = StatusOK; } } afc_file_close(afc, handle); } } mobilebackup2_client_free(mb_client); } return status; }
/** * Performs the DLMessageVersionExchange with the connected device. * This should be the first operation to be executed by an implemented * device link service client. * * @param client The device_link_service client to use. * @param version_major The major version number to check. * @param version_minor The minor version number to check. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL, * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs, * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version * given by the device is larger than the given version, * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise. */ device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor) { if (!client) return DEVICE_LINK_SERVICE_E_INVALID_ARG; device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; /* perform version exchange */ plist_t array = NULL; char *msg = NULL; /* receive DLMessageVersionExchange from device */ if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Did not receive initial message from device!"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } msg = device_link_service_get_message(array); if (!msg || strcmp(msg, "DLMessageVersionExchange")) { debug_info("Did not receive DLMessageVersionExchange from device!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } free(msg); msg = NULL; /* get major and minor version number */ if (plist_array_get_size(array) < 3) { debug_info("DLMessageVersionExchange has unexpected format!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } plist_t maj = plist_array_get_item(array, 1); plist_t min = plist_array_get_item(array, 2); uint64_t vmajor = 0; uint64_t vminor = 0; if (maj) { plist_get_uint_val(maj, &vmajor); } if (min) { plist_get_uint_val(min, &vminor); } if (vmajor > version_major) { debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); err = DEVICE_LINK_SERVICE_E_BAD_VERSION; goto leave; } else if ((vmajor == version_major) && (vminor > version_minor)) { debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); err = DEVICE_LINK_SERVICE_E_BAD_VERSION; goto leave; } plist_free(array); /* version is ok, send reply */ array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); plist_array_append_item(array, plist_new_string("DLVersionsOk")); plist_array_append_item(array, plist_new_uint(version_major)); if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Error when sending DLVersionsOk"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } plist_free(array); /* receive DeviceReady message */ array = NULL; if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Error when receiving DLMessageDeviceReady!"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } msg = device_link_service_get_message(array); if (!msg || strcmp(msg, "DLMessageDeviceReady")) { debug_info("Did not get DLMessageDeviceReady!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } err = DEVICE_LINK_SERVICE_E_SUCCESS; leave: if (msg) { free(msg); } if (array) { plist_free(array); } return err; }
static void tss_entry_apply_restore_request_rules(plist_t tss_entry, plist_t parameters, plist_t rules) { if (!tss_entry || !rules) { return; } if (plist_get_node_type(tss_entry) != PLIST_DICT) { return; } if (plist_get_node_type(rules) != PLIST_ARRAY) { return; } uint32_t i; for (i = 0; i < plist_array_get_size(rules); i++) { plist_t rule = plist_array_get_item(rules, i); plist_t conditions = plist_dict_get_item(rule, "Conditions"); plist_dict_iter iter = NULL; plist_dict_new_iter(conditions, &iter); char* key = NULL; plist_t value = NULL; plist_t value2 = NULL; int conditions_fulfilled = 1; while (conditions_fulfilled) { plist_dict_next_item(conditions, iter, &key, &value); if (key == NULL) break; if (!strcmp(key, "ApRawProductionMode")) { value2 = plist_dict_get_item(parameters, "ApProductionMode"); } else if (!strcmp(key, "ApCurrentProductionMode")) { value2 = plist_dict_get_item(parameters, "ApProductionMode"); } else if (!strcmp(key, "ApRawSecurityMode")) { value2 = plist_dict_get_item(parameters, "ApSecurityMode"); } else if (!strcmp(key, "ApRequiresImage4")) { value2 = plist_dict_get_item(parameters, "ApSupportsImg4"); } else if (!strcmp(key, "ApDemotionPolicyOverride")) { value2 = plist_dict_get_item(parameters, "DemotionPolicy"); } else if (!strcmp(key, "ApInRomDFU")) { value2 = plist_dict_get_item(parameters, "ApInRomDFU"); } else { error("WARNING: Unhandled condition '%s' while parsing RestoreRequestRules\n", key); value2 = NULL; } if (value2) { conditions_fulfilled = plist_compare_node_value(value, value2); } else { conditions_fulfilled = 0; } free(key); } free(iter); iter = NULL; if (!conditions_fulfilled) { continue; } plist_t actions = plist_dict_get_item(rule, "Actions"); plist_dict_new_iter(actions, &iter); while (1) { plist_dict_next_item(actions, iter, &key, &value); if (key == NULL) break; uint8_t bv = 0; plist_get_bool_val(value, &bv); if (bv) { value2 = plist_dict_get_item(tss_entry, key); if (value2) { plist_dict_remove_item(tss_entry, key); } debug("DEBUG: Adding action %s to TSS entry\n", key); plist_dict_set_item(tss_entry, key, plist_new_bool(1)); } free(key); } } }