void feedlist_node_added (nodePtr node) { gint position = -1; g_assert (NULL == node->parent); if (SELECTED && !IS_FOLDER(SELECTED)) { position = g_slist_index (SELECTED->parent->children, SELECTED); if (position > -1) position++; /* insert after selected child index */ } node_set_parent (node, feedlist_get_parent_node (), position); if (node->subscription) db_subscription_update (node->subscription); db_node_update(node); feedlist_node_imported (node); feed_list_view_select (node); }
/* process node register request */ static int __node_xml_register(xmlDoc * doc, xmlNode * node, int ent_id) { if (ly_entity_is_registered(ent_id)) { logwarn(_("received node register request again, ignored\n")); return -1; } LYNodeData * nd = ly_entity_data(ent_id); if (nd == NULL ) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); return -1; } NodeInfo * nf = &nd->node; /* Create xpath evaluation context */ xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); if (xpathCtx == NULL) { logerror(_("unable to create new XPath context %s, %d\n"), __func__, __LINE__); return -1; } int ret = -1; char *str; str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/status"); if (str == NULL) goto xml_err; nf->status = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/hypervisor"); if (str == NULL) goto xml_err; nf->hypervisor = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/host/tag"); int tag = -1; if (str) { tag = atoi(str); /* NULL str is allowed for new node */ free(str); } str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/host/name"); if (str == NULL) goto xml_err; nf->host_name = str; str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/host/ip"); if (str == NULL) goto xml_err; nf->host_ip = str; str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/cpu/arch"); if (str == NULL) goto xml_err; nf->cpu_arch = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/cpu/model"); if (str == NULL) goto xml_err; nf->cpu_model = str; str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/cpu/mhz"); if (str == NULL) goto xml_err; nf->cpu_mhz = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/cpu/max"); if (str == NULL) goto xml_err; nf->cpu_max = atoi(str); nf->cpu_vlimit = NODE_SCHEDULE_CPU_LIMIT(nf->cpu_max); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/cpu/commit"); if (str == NULL) goto xml_err; nf->cpu_commit = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/memory/total"); if (str == NULL) goto xml_err; nf->mem_max = atoi(str); nf->mem_vlimit = NODE_SCHEDULE_MEM_LIMIT(nf->mem_max); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/memory/free"); if (str == NULL) goto xml_err; nf->mem_free = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/memory/commit"); if (str == NULL) goto xml_err; nf->mem_commit = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/storage/total"); if (str == NULL) goto xml_err; nf->storage_total = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/storage/free"); if (str == NULL) goto xml_err; nf->storage_free = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/request/parameters/load/average"); if (str == NULL) goto xml_err; nf->load_average = atoi(str); free(str); if (nf->status >= NODE_STATUS_REGISTERED) { logwarn(_("node(%d, %s) tries to register from wrong status(%d)\n"), nf->host_tag, nf->host_ip, nf->status); ly_entity_release(ent_id); ret = 0; /* no need to continue node registration */ goto done; } if (ly_entity_node_active(nf->host_ip)) { logwarn(_("duplicate node ip received. something is wrong...\n")); ly_entity_release(ent_id); ret = 0; /* no need to continue node registration */ goto done; } if (tag > 0) { /* check authentication result */ if (nf->host_tag > 0 && tag != nf->host_tag) { logerror(_("node tag changed, %d -> %d. something is wrong.\n"), nf->host_tag, tag); goto done; } nf->host_tag = tag; ret = __node_register_auth(nf, ent_id); if (ret == LY_S_REGISTERING_DONE_SUCCESS) { AuthConfig * ac = ly_entity_auth(ent_id); if (db_node_update_secret(DB_NODE_FIND_BY_ID, &tag, ac->secret) < 0 || db_node_update_status(DB_NODE_FIND_BY_ID, &tag, NODE_STATUS_REGISTERED) < 0) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); ret = -1; goto done; } loginfo(_("node(tag:%d) registered\n"), tag); ly_entity_update(ent_id, tag, LY_ENTITY_FLAG_STATUS_REGISTERED); } goto done; } /* new node */ DBNodeRegInfo db_nf; bzero(&db_nf, sizeof(DBNodeRegInfo)); ret = db_node_find(DB_NODE_FIND_BY_IP, nf->host_ip, &db_nf); if (ret < 0 || ret > 1) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); ret = -1; goto done; } if (ret == 0 || db_nf.secret) { /* new node */ logdebug(_("new node\n")); if (nf->status != NODE_STATUS_UNINITIALIZED) { logwarn(_("node(%d, %s) tries to register from unexpected status(%d)\n"), nf->host_tag, nf->host_ip, nf->status); nf->status = NODE_STATUS_UNINITIALIZED; } if (db_nf.secret) { logwarn(_("new node takes ip(%s) used by tagged node\n"), nf->host_ip); db_node_reginfo_free(&db_nf); bzero(&db_nf, sizeof(DBNodeRegInfo)); } ret = db_node_insert(nf); if (ret < 0) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); goto new_done; } db_nf.id = ret; loginfo(_("new node %s added in db(%d)\n"), nf->host_ip, ret); /* enable node if node is control server */ if (ly_is_clc_ip(nf->host_ip)) { if (db_node_enable(ret, 1) != 0 || db_node_find(DB_NODE_FIND_BY_ID, &ret, &db_nf) != 1) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); ret = -1; goto new_done; } } } else logdebug(_("untagged node for ip(%s) found in db\n"), nf->host_ip); ly_entity_update(ent_id, db_nf.id, LY_ENTITY_FLAG_STATUS_ONLINE); if (db_nf.enabled) { AuthConfig * ac = ly_entity_auth(ent_id); ret = -1; if (ac->secret) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); goto new_done; } ac->secret = lyauth_secret(); if (ac->secret == NULL) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); goto new_done; } nf->host_tag = db_nf.id; ret = LY_S_REGISTERING_CONFIG; } else { logdebug(_("register request done, node %s not enabled\n"), nf->host_ip); ret = LY_S_REGISTERING_INIT; } nf->status = NODE_STATUS_ONLINE; if (db_node_update(DB_NODE_FIND_BY_ID, &db_nf.id, nf) < 0) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); ret = -1; } new_done: db_node_reginfo_free(&db_nf); goto done; xml_err: logerror(_("invalid node xml register request\n")); done: xmlXPathFreeContext(xpathCtx); logdebug(_("end of %s, node status %d\n"), __func__, nf->status); return ret; }
/* process node info query reply */ static int __node_info_update(xmlDoc * doc, xmlNode * node, int ent_id, int * j_status) { logdebug(_("%s called\n"), __func__); if (!ly_entity_is_online(ent_id)) { /* shouldn't come here */ logerror(_("error in %s(%d)\n"), __func__, __LINE__); *j_status = LY_S_FINISHED_FAILURE_NODE_NOT_AVAIL; return 0; } LYNodeData * nd = ly_entity_data(ent_id); if (nd == NULL) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); goto failed; } NodeInfo * nf = &nd->node; /* Create xpath evaluation context */ xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); if (xpathCtx == NULL) { logerror(_("unable to create new XPath context %s, %d\n"), __func__, __LINE__); *j_status = LY_S_FINISHED_FAILURE; return 0; } char *str; str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/status"); if (str == NULL) goto failed; nf->status = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/cpu/commit"); if (str == NULL) goto failed; nf->cpu_commit = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/memory/free"); if (str == NULL) goto failed; nf->mem_free = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/storage/free"); if (str == NULL) goto failed; nf->storage_free = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/memory/commit"); if (str == NULL) goto failed; nf->mem_commit = atoi(str); free(str); str = xml_xpath_text_from_ctx(xpathCtx, "/" LYXML_ROOT "/response/data/load/average"); if (str == NULL) goto failed; nf->load_average = atoi(str); free(str); int node_id = ly_entity_db_id(ent_id); logdebug(_("update info for node %d: %d %d %d %d %d\n"), node_id, nf->status, nf->cpu_commit, nf->mem_free, nf->mem_commit, nf->load_average); if (db_node_update(DB_NODE_FIND_BY_ID, &node_id, nf) < 0) { logerror(_("error in %s(%d)\n"), __func__, __LINE__); goto failed; } /* no need to update j_status */ goto done; failed: *j_status = LY_S_FINISHED_FAILURE; done: xmlXPathFreeContext(xpathCtx); return 0; }
static void subscription_process_update_result (const struct updateResult * const result, gpointer user_data, guint32 flags) { subscriptionPtr subscription = (subscriptionPtr)user_data; nodePtr node = subscription->node; gboolean processing = FALSE; GTimeVal now; /* 1. preprocessing */ g_assert (subscription->updateJob); /* update the subscription URL on permanent redirects */ if ((301 == result->httpstatus) && result->source && !g_str_equal (result->source, subscription->updateJob->request->source)) { debug2 (DEBUG_UPDATE, "The URL of \"%s\" has changed permanently and was updated with \"%s\"", node_get_title(node), result->source); subscription_set_source (subscription, result->source); liferea_shell_set_status_bar (_("The URL of \"%s\" has changed permanently and was updated"), node_get_title(node)); } if (401 == result->httpstatus) { /* unauthorized */ auth_dialog_new (subscription, flags); } else if (410 == result->httpstatus) { /* gone */ subscription->discontinued = TRUE; node->available = TRUE; liferea_shell_set_status_bar (_("\"%s\" is discontinued. Liferea won't updated it anymore!"), node_get_title (node)); } else if (304 == result->httpstatus) { node->available = TRUE; liferea_shell_set_status_bar (_("\"%s\" has not changed since last update"), node_get_title(node)); } else { processing = TRUE; } subscription_update_error_status (subscription, result->httpstatus, result->returncode, result->filterErrors); subscription->updateJob = NULL; /* 2. call subscription type specific processing */ if (processing) SUBSCRIPTION_TYPE (subscription)->process_update_result (subscription, result, flags); /* 3. call favicon updating after subscription processing to ensure we have valid baseUrl for feed nodes... */ g_get_current_time (&now); if (favicon_update_needed (subscription->node->id, subscription->updateState, &now)) subscription_update_favicon (subscription); /* 4. generic postprocessing */ update_state_set_lastmodified (subscription->updateState, update_state_get_lastmodified (result->updateState)); update_state_set_cookies (subscription->updateState, update_state_get_cookies (result->updateState)); update_state_set_etag (subscription->updateState, update_state_get_etag (result->updateState)); g_get_current_time (&subscription->updateState->lastPoll); // FIXME: use new-items signal in itemview class itemview_update_node_info (subscription->node); itemview_update (); db_subscription_update (subscription); db_node_update (subscription->node); if (subscription->node->newCount > 0) feedlist_new_items (subscription->node); }
static gboolean ui_dnd_feed_drag_data_received (GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData *selection_data) { GtkTreeIter iter, iter2, parentIter; nodePtr node, oldParent, newParent; gboolean result, valid, added; gint oldPos, pos; result = old_feed_drag_data_received (drag_dest, dest, selection_data); if (result) { if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &iter, dest)) { gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &iter, FS_PTR, &node, -1); /* If we don't do anything, then because DnD is implemented by removal and re-insertion, and the removed node is selected, the treeview selects the next row after the removal, which is supremely irritating. But setting a selection at this point is pointless, because the treeview will reset it as soon as the DnD callback returns. Instead, we set the cursor, which controls where treeview resets the selection later. */ gtk_tree_view_set_cursor(GTK_TREE_VIEW (liferea_shell_lookup ("feedlist")), dest, NULL, FALSE); /* remove from old parents child list */ oldParent = node->parent; g_assert (oldParent); oldPos = g_slist_index (oldParent->children, node); oldParent->children = g_slist_remove (oldParent->children, node); node_update_counters (oldParent); if (0 == g_slist_length (oldParent->children)) feed_list_node_add_empty_node (feed_list_node_to_iter (oldParent->id)); /* and rebuild new parents child list */ if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (drag_dest), &parentIter, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &parentIter, FS_PTR, &newParent, -1); } else { gtk_tree_model_get_iter_first (GTK_TREE_MODEL (drag_dest), &parentIter); newParent = feedlist_get_root (); } /* drop old list... */ debug3 (DEBUG_GUI, "old parent is %s (%d, position=%d)", oldParent->title, g_slist_length (oldParent->children), oldPos); debug2 (DEBUG_GUI, "new parent is %s (%d)", newParent->title, g_slist_length (newParent->children)); g_slist_free (newParent->children); newParent->children = NULL; node->parent = newParent; debug0 (DEBUG_GUI, "new newParent child list:"); /* and rebuild it from the tree model */ if (feedlist_get_root() != newParent) valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (drag_dest), &iter2, &parentIter); else valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (drag_dest), &iter2, NULL); pos = 0; added = FALSE; while (valid) { nodePtr child; gtk_tree_model_get (GTK_TREE_MODEL (drag_dest), &iter2, FS_PTR, &child, -1); if (child) { /* Well this is a bit complicated... If we move a feed inside a folder we need to skip the old insertion point (oldPos). This is easy if the feed is added behind this position. If it is dropped before the flag added is set once the new copy is encountered. The remaining copy is skipped automatically when the flag is set. */ /* check if this is a copy of the dragged node or the original itself */ if ((newParent == oldParent) && !strcmp(node->id, child->id)) { if ((pos == oldPos) || added) { /* it is the original */ debug2 (DEBUG_GUI, " -> %d: skipping old insertion point %s", pos, child->title); } else { /* it is a copy inserted before the original */ added = TRUE; debug2 (DEBUG_GUI, " -> %d: new insertion point of %s", pos, child->title); newParent->children = g_slist_append (newParent->children, child); } } else { /* all other nodes */ debug2 (DEBUG_GUI, " -> %d: adding %s", pos, child->title); newParent->children = g_slist_append (newParent->children, child); } } else { debug0 (DEBUG_GUI, " -> removing empty node"); /* remove possible existing "(empty)" node from newParent */ feed_list_node_remove_empty_node (&parentIter); } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (drag_dest), &iter2); pos++; } db_node_update (node); node_update_counters (newParent); feedlist_schedule_save (); } } return result; }