Ejemplo n.º 1
0
static itemPtr
inoreader_source_load_item_from_sourceid (nodePtr node, gchar *sourceId, GHashTable *cache) 
{
	gpointer    ret = g_hash_table_lookup (cache, sourceId);
	itemSetPtr  itemset;
	int         num = g_hash_table_size (cache);
	GList       *iter; 
	itemPtr     item = NULL;

	if (ret) return item_load (GPOINTER_TO_UINT (ret));

	/* skip the top 'num' entries */
	itemset = node_get_itemset (node);
	iter = itemset->ids;
	while (num--) iter = g_list_next (iter);

	for (; iter; iter = g_list_next (iter)) {
		item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item) {
			if (item->sourceId) {
				/* save to cache */
				g_hash_table_insert (cache, g_strdup(item->sourceId), (gpointer) item->id);
				if (g_str_equal (item->sourceId, sourceId)) {
					itemset_free (itemset);
					return item;
				}
			}
			item_unload (item);
		}
	}

	g_warning ("Could not find item for %s!", sourceId);
	itemset_free (itemset);
	return NULL;
}
Ejemplo n.º 2
0
/* called when unselecting the item or unloading the item list */
static void
itemlist_check_for_deferred_action (void) 
{
	itemPtr	item;
	
	if(itemlist->priv->selectedId) {
		gulong id = itemlist->priv->selectedId;
		itemlist_set_selected(NULL);

		/* check for removals caused by itemlist filter rule */
		if(itemlist->priv->deferredFilter) {
			itemlist->priv->deferredFilter = FALSE;
			item = item_load(id);
			itemview_remove_item(item);
			ui_node_update(item->nodeId);
		}

		/* check for removals caused by vfolder rules */
		if(itemlist->priv->deferredRemove) {
			itemlist->priv->deferredRemove = FALSE;
			item = item_load(id);
			itemlist_remove_item(item);
		}
	}
}
Ejemplo n.º 3
0
itemPtr
item_list_view_find_unread_item (ItemListView *ilv, gulong startId)
{
	GtkTreeIter		iter;
	GtkTreeModel		*model;
	gboolean		valid = TRUE;
	
	model = gtk_tree_view_get_model (ilv->priv->treeview);
	
	if (startId)
		valid = item_list_view_id_to_iter (ilv, startId, &iter);
	else
		valid = gtk_tree_model_get_iter_first (model, &iter);
	
	while (valid) {
		itemPtr	item = item_load (item_list_view_iter_to_id (ilv, &iter));
		if (item) {
			if (!item->readStatus)
				return item;
			item_unload (item);
		}
		valid = gtk_tree_model_iter_next (model, &iter);
	}

	return NULL;
}
Ejemplo n.º 4
0
static gboolean
on_item_list_view_button_press_event (GtkWidget *treeview, GdkEventButton *event, gpointer user_data)
{
	ItemListView		*ilv = ITEM_LIST_VIEW (user_data);
	GtkTreePath		*path;
	GtkTreeIter		iter;
	GtkTreeViewColumn	*column;
	itemPtr			item = NULL;
	gboolean		result = FALSE;
	
	if (event->type != GDK_BUTTON_PRESS)
		return FALSE;

	/* avoid handling header clicks */
	if (event->window != gtk_tree_view_get_bin_window (ilv->priv->treeview))
		return FALSE;

	if (!gtk_tree_view_get_path_at_pos (ilv->priv->treeview, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
		return FALSE;

	if (gtk_tree_model_get_iter (gtk_tree_view_get_model (ilv->priv->treeview), &iter, path))
		item = item_load (item_list_view_iter_to_id (ilv, &iter));
		
	gtk_tree_path_free (path);
	
	if (item) {
		GdkEventButton *eb = (GdkEventButton*)event; 
		switch (eb->button) {
			case 1:
				column = gtk_tree_view_get_column (ilv->priv->treeview, 0);
				if (column) {
					/* Allow flag toggling when left clicking in the flagging column.
					   We depend on the fact that the state column is the first!!! */
					if (event->x <= gtk_tree_view_column_get_width (column)) {
						itemlist_toggle_flag (item);
						result = TRUE;
					}
				}
				break;
			case 2:
				/* Middle mouse click toggles read status... */
				itemlist_toggle_read_status (item);
				result = TRUE;
				break;
			case 3:
				item_list_view_select (ilv, item);
				ui_popup_item_menu (item, eb->button, eb->time);
				result = TRUE;
				break;
		}
		item_unload (item);
	}
		
	return result;
}
Ejemplo n.º 5
0
void
item_read_state_changed (itemPtr item, gboolean newState)
{
    nodePtr node;

    debug_start_measurement (DEBUG_GUI);

    /* 1. set values in memory */
    item->readStatus = newState;
    item->updateStatus = FALSE;

    /* 2. propagate to vfolders */
    vfolder_foreach_data (vfolder_merge_item, item);
    vfolder_foreach (node_update_counters);

    /* 3. apply to DB */
    db_item_state_update (item);

    /* 4. update item list GUI state */
    itemlist_update_item (item);

    /* 5. updated feed list unread counters */
    node = node_from_id (item->nodeId);
    node_update_counters (node);

    /* 6. update notification statistics */
    feedlist_reset_new_item_count ();

    /* 7. duplicate state propagation */
    if (item->validGuid) {
        GSList *duplicates, *iter;

        duplicates = iter = db_item_get_duplicates (item->sourceId);
        while (iter) {
            itemPtr duplicate = item_load (GPOINTER_TO_UINT (iter->data));

            /* The check on node_from_id() is an evil workaround
               to handle "lost" items in the DB that have no
               associated node in the feed list. This should be
               fixed by having the feed list in the DB too, so
               we can clean up correctly after crashes. */
            if (duplicate && duplicate->id != item->id && node_from_id (duplicate->nodeId)) {
                item_set_read_state (duplicate, newState);
            }
            if (duplicate) item_unload (duplicate);
            iter = g_slist_next (iter);
        }
        g_slist_free (duplicates);
    }

    debug_end_measurement (DEBUG_GUI, "set read status");
}
Ejemplo n.º 6
0
void
on_itemlist_selection_changed (GtkTreeSelection *selection, gpointer user_data)
{
	GtkTreeIter 	iter;
	GtkTreeModel	*model;
	itemPtr		item = NULL;

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
		item = item_load (item_list_view_iter_to_id (ITEM_LIST_VIEW (user_data), &iter));

	liferea_shell_update_item_menu (NULL != item);
	if (item)
		itemlist_selection_changed (item);
}
Ejemplo n.º 7
0
void
itemset_foreach (itemSetPtr itemSet, itemActionFunc callback)
{
	GList	*iter = itemSet->ids;

	while(iter) {
		itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item) {
			(*callback) (item);
			item_unload (item);
		}
		iter = g_list_next (iter);
	}
}
Ejemplo n.º 8
0
static void
item_list_view_update_item_foreach (gpointer key,
                                    gpointer value,
                                    gpointer user_data)
{
	itemPtr 	item;
	
	item = item_load (GPOINTER_TO_UINT (key) /* id */);
	if (!item)
		return;

	item_list_view_update_item (ITEM_LIST_VIEW (user_data), item);
	
	item_unload (item);
}
Ejemplo n.º 9
0
static gboolean
on_item_list_view_popup_menu (GtkWidget *widget, gpointer user_data)
{
	GtkTreeView	*treeview = GTK_TREE_VIEW (widget);
	GtkTreeModel	*model;
	GtkTreeIter	iter;

	if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (treeview), &model, &iter)) {
		itemPtr item = item_load (item_list_view_iter_to_id (ITEM_LIST_VIEW (user_data), &iter));
		ui_popup_item_menu (item, 3, 0);
		item_unload (item);
		return TRUE;
	}

	return FALSE;
}
Ejemplo n.º 10
0
/**
 * In difference to all the other item state handling methods
 * item_state_set_all_read does not immediately apply the
 * changes to the GUI because it is usually called recursively
 * and would be to slow. Instead the node structure flag for
 * recounting is set. By calling feedlist_update() afterwards
 * those recounts are executed and applied to the GUI.
 */
void
itemset_mark_read (nodePtr node)
{
    itemSetPtr	itemSet;

    if (!node->unreadCount)
        return;

    itemSet = node_get_itemset (node);
    GList *iter = itemSet->ids;
    while (iter) {
        gulong id = GPOINTER_TO_UINT (iter->data);
        itemPtr item = item_load (id);
        if (item) {
            if (!item->readStatus) {
                nodePtr node;

                node = node_from_id (item->nodeId);
                if (node) {
                    item_state_set_recount_flag (node);
                    node_source_item_mark_read (node, item, TRUE);
                } else {
                    g_warning ("itemset_mark_read() on lost item (id=%lu, node id=%s)!", item->id, item->nodeId);
                }

                debug_start_measurement (DEBUG_GUI);

                GSList *duplicates = db_item_get_duplicate_nodes (item->sourceId);
                GSList *duplicate = duplicates;
                while (duplicate) {
                    gchar *nodeId = (gchar *)duplicate->data;
                    nodePtr affectedNode = node_from_id (nodeId);
                    if (affectedNode)
                        item_state_set_recount_flag (affectedNode);
                    g_free (nodeId);
                    duplicate = g_slist_next (duplicate);
                }
                g_slist_free(duplicates);

                debug_end_measurement (DEBUG_GUI, "mark read of duplicates");
            }
            item_unload (item);
        }
        iter = g_list_next (iter);
    }
}
Ejemplo n.º 11
0
void
inoreader_source_migrate_node(nodePtr node) 
{
	/* scan the node for bad ID's, if so, brutally remove the node */
	itemSetPtr itemset = node_get_itemset (node);
	GList *iter = itemset->ids;
	for (; iter; iter = g_list_next (iter)) {
		itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item && item->sourceId) {
			if (!g_str_has_prefix(item->sourceId, "tag:google.com")) {
				debug1(DEBUG_UPDATE, "Item with sourceId [%s] will be deleted.", item->sourceId);
				db_item_remove(GPOINTER_TO_UINT(iter->data));
			} 
		}
		if (item) item_unload (item);
	}

	/* cleanup */
	itemset_free (itemset);
}
Ejemplo n.º 12
0
/**
 * In difference to all the other item state handling methods
 * item_state_set_all_read does not immediately apply the 
 * changes to the GUI because it is usually called recursively
 * and would be to slow. Instead the node structure flag for
 * recounting is set. By calling feedlist_update() afterwards
 * those recounts are executed and applied to the GUI.
 */
void
itemset_mark_read (nodePtr node)
{
	itemSetPtr	itemSet;

	itemSet = node_get_itemset (node);
	GList *iter = itemSet->ids;
	while (iter) {
		gulong id = GPOINTER_TO_UINT (iter->data);
		itemPtr item = item_load (id);
		if (item) {
			if (!item->readStatus) {
				nodePtr node = node_from_id (item->nodeId);
				if (node) {
					item_state_set_recount_flag (node);
					node_source_item_mark_read (node, item, TRUE);
				}

				debug_start_measurement (DEBUG_GUI);

				GSList *duplicates = db_item_get_duplicate_nodes (item->sourceId);
				GSList *duplicate = duplicates;
				while (duplicate) {
					gchar *nodeId = (gchar *)duplicate->data;
					nodePtr affectedNode = node_from_id (nodeId);
					if (affectedNode)
						item_state_set_recount_flag (affectedNode);
					g_free (nodeId);
					duplicate = g_slist_next (duplicate);
				}
				g_slist_free(duplicates);

				debug_end_measurement (DEBUG_GUI, "mark read of duplicates");
			}
			item_unload (item);
		}
		iter = g_list_next (iter);
	}

	// FIXME: why not call itemset_free (itemSet); here? Crashes!
}
Ejemplo n.º 13
0
enum protoCmd rx_request(const struct protocol *req, int fd)
{
    struct protocol *reqnew;
    struct item *list = NULL, *item;
    enum protoCmd pend;

    // Upgrade version 1 to version 2
    if (req->ver == 1) {
        reqnew = (struct protocol *)malloc(sizeof(struct protocol));
        memcpy(reqnew, req, sizeof(struct protocol_v1));
        reqnew->xmlname[0] = 0;
        req = reqnew;
    }
    else if (req->ver != 2) {
        syslog(LOG_ERR, "Bad protocol version %d", req->ver);
        return cmdIgnore;
    }

    syslog(LOG_DEBUG, "DEBUG: Got command %s fd(%d) xml(%s), z(%d), x(%d), y(%d)",
            cmdStr(req->cmd), fd, req->xmlname, req->z, req->x, req->y);

    if ((req->cmd != cmdRender) && (req->cmd != cmdRenderPrio) && (req->cmd != cmdDirty) && (req->cmd != cmdRenderBulk))
        return cmdIgnore;

    item = (struct item *)malloc(sizeof(*item));
    if (!item) {
            syslog(LOG_ERR, "malloc failed");
            return cmdNotDone;
    }

    item->req = *req;
    item->duplicates = NULL;
    item->fd = (req->cmd == cmdDirty) ? FD_INVALID : fd;

    item_load(item, req);

#ifdef METATILE
    /* Round down request co-ordinates to the neareast N (should be a power of 2)
     * Note: request path is no longer consistent but this will be recalculated
     * when the metatile is being rendered.
     */
    item->mx = item->req.x & ~(METATILE-1);
    item->my = item->req.y & ~(METATILE-1);
#else
    item->mx = item->req.x;
    item->my = item->req.y;
#endif

    pthread_mutex_lock(&qLock);

    // Check for a matching request in the current rendering or dirty queues
    pend = pending(item);
    if (pend == cmdNotDone) {
        // We found a match in the dirty queue, can not wait for it
        pthread_mutex_unlock(&qLock);
        free(item);
        return cmdNotDone;
    }
    if (pend == cmdIgnore) {
        // Found a match in render queue, item added as duplicate
        pthread_mutex_unlock(&qLock);
        return cmdIgnore;
    }

    // New request, add it to render or dirty queue
    if ((req->cmd == cmdRender) && (reqNum < REQ_LIMIT)) {
        list = &reqHead;
        item->inQueue = queueRequest;
        reqNum++;
    } else if ((req->cmd == cmdRenderPrio) && (reqPrioNum < REQ_LIMIT)) {
        list = &reqPrioHead;
        item->inQueue = queueRequestPrio;
        reqPrioNum++;
    } else if ((req->cmd == cmdRenderBulk) && (reqBulkNum < REQ_LIMIT)) {
        list = &reqBulkHead;
        item->inQueue = queueRequestBulk;
        reqBulkNum++;
    } else if (dirtyNum < DIRTY_LIMIT) {
        list = &dirtyHead;
        item->inQueue = queueDirty;
        dirtyNum++;
        item->fd = FD_INVALID; // No response after render
    } else {
        // The queue is severely backlogged. Drop request
        stats.noReqDroped++;
        pthread_mutex_unlock(&qLock);
        free(item);
        return cmdNotDone;
    }

    if (list) {
        item->next = list;
        item->prev = list->prev;
        item->prev->next = item;
        list->prev = item;
        /* In addition to the linked list, add item to a hash table index
         * for faster lookup of pending requests.
         */
        insert_item_idx(item);

        pthread_cond_signal(&qCond);
    } else
        free(item);

    pthread_mutex_unlock(&qLock);

    return (list == &reqHead)?cmdIgnore:cmdNotDone;
}
Ejemplo n.º 14
0
static void
notif_libnotify_callback_show_details (NotifyNotification *n, gchar *action, gpointer user_data)
{
	nodePtr node_p;

	GList *list_p;
	itemPtr item_p;

	gchar *labelText_p;
	gchar *labelText_now_p = NULL;
	gchar *labelText_prev_p;

	gchar *labelHeadline_p;
	const gchar *labelURL_p;

	gint item_count = 0;

	g_assert (action != NULL);
	g_assert (strcmp(action, "show_details") == 0);
	node_p = node_from_id (user_data);

	if (node_p) {
		itemSetPtr itemSet = node_get_itemset (node_p);

		labelText_now_p = g_strdup ("");

		/* Gather the feed's headlines */
		list_p = itemSet->ids;
		while (list_p) {
			item_p = item_load (GPOINTER_TO_UINT (list_p->data));
			if (item_p->popupStatus && !item_p->readStatus) {
				item_p->popupStatus = FALSE;
				item_count += 1;

				labelHeadline_p = g_strdup (item_get_title (item_p));
				if (labelHeadline_p == NULL ) {
					labelHeadline_p = g_strdup_printf (_("This news entry has no headline"));
				}

				labelURL_p = item_get_base_url (item_p);
				if (labelURL_p) {
					labelText_p = g_strdup_printf ("%s <a href='%s'>%s</a>\n", labelHeadline_p, labelURL_p, _("Visit"));
				} else {
					labelText_p = g_strdup_printf ("%s\n", labelHeadline_p);
				}

				labelText_prev_p = labelText_now_p;
				labelText_now_p = g_strconcat(labelText_now_p, labelText_p, NULL);

				g_free(labelHeadline_p);
				g_free(labelText_p);
				g_free(labelText_prev_p);
			}
			item_unload (item_p);
			list_p = g_list_next (list_p);
		}
		itemset_free (itemSet);

		if (item_count == 0) {
			g_free (labelText_now_p);
			return;
		}
	} else {
		ui_show_error_box(_("This feed does not exist anymore!"));
	}

	notify_notification_close (n, NULL);

	if (node_p) {
//		notify_notification_update ( n, node_get_title(node_p), labelText_now_p, NULL);
//		notify_notification_clear_actions(n);

		n = notify_notification_new (node_get_title (node_p), labelText_now_p, NULL, NULL);

		notify_notification_set_icon_from_pixbuf (n, node_get_icon (node_p));
		notify_notification_set_category (n, "feed");
		notify_notification_set_timeout (n, NOTIFY_EXPIRES_NEVER);

		if (supports_actions) {
			notify_notification_add_action (n, "open", _("Open feed"),
							(NotifyActionCallback)notif_libnotify_callback_open,
							node_p->id, NULL);
			notify_notification_add_action (n, "mark_read", _("Mark all as read"),
							(NotifyActionCallback)notif_libnotify_callback_mark_read,
							node_p->id, NULL);
		}

		notify_notification_attach_to_status_icon (n, ui_tray_get_status_icon ());

		if (!notify_notification_show (n, NULL)) {
			g_warning ("libnotify.c - failed to update notification via libnotify\n");
		}

		g_free (labelText_now_p);
	}
}
Ejemplo n.º 15
0
static void
notif_libnotify_node_has_new_items (nodePtr node, gboolean enforced)
{
	itemSetPtr	itemSet;
	GList		*iter;

	NotifyNotification *n;

	gchar		*labelSummary_p;
	gint		item_count = 0;

	gboolean	show_popup_windows;

	conf_get_bool_value(SHOW_POPUP_WINDOWS, &show_popup_windows);

	if (!show_popup_windows && !enforced)
		return;

	/* Count updated feed */
	itemSet = node_get_itemset (node);
	iter = itemSet->ids;
	while (iter) {
		itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item->popupStatus && !item->readStatus)
			item_count++;
		item_unload (item);
		iter = g_list_next (iter);
	}
	itemset_free (itemSet);

	if (item_count == 0)
		return;

	labelSummary_p = g_strdup_printf (ngettext ("<b>%s</b> has <b>%d</b> update", "<b>%s</b> has <b>%d</b> updates", item_count), 
	                                  node_get_title (node), item_count);
	n = notify_notification_new (_("Feed Update"), labelSummary_p, "liferea", NULL);
	g_free (labelSummary_p);

 	if (supports_append) {
 		notify_notification_set_hint_string(n, "append", "allow");
 	} else {
		notify_notification_set_icon_from_pixbuf (n, node_get_icon (node));
	}
	
	notify_notification_set_timeout (n, NOTIFY_EXPIRES_DEFAULT);
	if (supports_actions) {
		notify_notification_add_action (n, "show_details", _("Show details"),
	                                (NotifyActionCallback)notif_libnotify_callback_show_details,
	                                node->id, NULL);
		notify_notification_add_action (n, "open", _("Open feed"),
	                                (NotifyActionCallback)notif_libnotify_callback_open,
	                                node->id, NULL);
		notify_notification_add_action (n, "mark_read", _("Mark all as read"),
	                                (NotifyActionCallback)notif_libnotify_callback_mark_read,
	                                node->id, NULL);
	}
	notify_notification_set_category (n, "feed");

	notify_notification_attach_to_status_icon (n, ui_tray_get_status_icon ());

	if (!notify_notification_show (n, NULL))
		g_warning ("notif_libnotify.c - failed to send notification via libnotify");
}
Ejemplo n.º 16
0
void addItem(std::string type) {
	Item newItem;
	item_load(&newItem, type);
	danmakux.items.push_back(newItem);
}
Ejemplo n.º 17
0
guint
itemset_merge_items (itemSetPtr itemSet, GList *list, gboolean allowUpdates, gboolean markAsRead)
{
	GList	*iter, *droppedItems = NULL, *items = NULL;
	guint	i, max, length, toBeDropped, newCount = 0, flagCount = 0;
	nodePtr	node;

	debug_start_measurement (DEBUG_UPDATE);

	debug2 (DEBUG_UPDATE, "old item set %p of (node id=%s):", itemSet, itemSet->nodeId);

	/* 1. Preparation: determine effective maximum cache size

	   The problem here is that the configured maximum cache
	   size might not always be sufficient. We need to check
	   border use cases in the following. */

	length = g_list_length (list);
	max = itemset_get_max_item_count (itemSet);

	/* Preload all items for flag counting and later merging comparison */
	iter = itemSet->ids;
	while (iter) {
		itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item) {
			items = g_list_append (items, item);
			if (item->flagStatus)
				flagCount++;
		}
		iter = g_list_next (iter);
	}
	debug1(DEBUG_UPDATE, "current cache size: %d", g_list_length(itemSet->ids));
	debug1(DEBUG_UPDATE, "current cache limit: %d", max);
	debug1(DEBUG_UPDATE, "downloaded feed size: %d", g_list_length(list));
	debug1(DEBUG_UPDATE, "flag count: %d", flagCount);

	/* Case #1: Avoid having too many flagged items. We count the
	   flagged items and check if they are fewer than

	      <cache limit> - <downloaded items>

	   to ensure that all new items fit in a feed cache full of
	   flagged items.

	   This handling MUST NOT be invoked when the number of items
	   is larger then the cache size, otherwise we would never
	   remove any items for large feeds. */
	if ((length < max) && (max < length + flagCount)) {
		max = flagCount + length;
		debug2 (DEBUG_UPDATE, "too many flagged items -> increasing cache limit to %u (node id=%s)", max, itemSet->nodeId);
	}

	/* 2. Avoid cache wrapping (if feed size > cache size)

	   Truncate the new itemset if it is longer than
	   the maximum cache size which could cause items
	   to be dropped and added again on subsequent
	   merges with the same feed content */
	if (length > max) {
		debug2 (DEBUG_UPDATE, "item list too long (%u, max=%u) for merging!", length, max);

		/* reach max element */
		for(i = 0, iter = list; (i < max) && iter; ++i)
			iter = g_list_next (iter);

		/* and remove all following elements */
		while (iter) {
			itemPtr item = (itemPtr) iter->data;
			debug2 (DEBUG_UPDATE, "ignoring item nr %u (%s)...", ++i, item_get_title (item));
			item_unload (item);
			iter = g_list_next (iter);
			list = g_list_remove (list, item);
		}
	}

	/* 3. Merge received items to existing item set

	   Items are given in top to bottom display order.
	   Adding them in this order would mean to reverse
	   their order in the merged list, so merging needs
	   to be done bottom to top. During this step the
	   item list (items) may exceed the cache limit. */
	iter = g_list_last (list);
	while (iter) {
		itemPtr item = (itemPtr)iter->data;

		if (markAsRead)
			item->readStatus = TRUE;

		if (itemset_merge_item (itemSet, items, item, length, allowUpdates)) {
			newCount++;
			items = g_list_prepend (items, iter->data);
		}
		iter = g_list_previous (iter);
	}
	g_list_free (list);

	vfolder_foreach (node_update_counters);

	node = node_from_id (itemSet->nodeId);
	if (node && (NODE_SOURCE_TYPE (node)->capabilities & NODE_SOURCE_CAPABILITY_ITEM_STATE_SYNC))
		node_update_counters (node);

	debug1(DEBUG_UPDATE, "added %d new items", newCount);

	/* 4. Apply cache limit for effective item set size
	      and unload older items as necessary. In this step
	      it is important never to drop flagged items and
	      to drop the oldest items only. */

	if (g_list_length (items) > max)
		toBeDropped = g_list_length (items) - max;
	else
		toBeDropped = 0;

	debug3 (DEBUG_UPDATE, "%u new items, cache limit is %u -> dropping %u items", newCount, max, toBeDropped);
	items = g_list_sort (items, itemset_sort_by_date);
	iter = g_list_last (items);
	while (iter) {
		itemPtr item = (itemPtr) iter->data;
		if (toBeDropped > 0 && !item->flagStatus) {
			debug2 (DEBUG_UPDATE, "dropping item nr %u (%s)....", item->id, item_get_title (item));
			droppedItems = g_list_append (droppedItems, item);
			/* no unloading here, it's done in itemlist_remove_items() */
			toBeDropped--;
		} else {
			item_unload (item);
		}
		iter = g_list_previous (iter);
	}

	if (droppedItems) {
		itemlist_remove_items (itemSet, droppedItems);
		g_list_free (droppedItems);
	}

	/* 5. Sanity check to detect merging bugs */
	if (g_list_length (items) > itemset_get_max_item_count (itemSet) + flagCount)
		debug0 (DEBUG_CACHE, "Fatal: Item merging bug! Resulting item list is too long! Cache limit does not work. This is a severe program bug!");

	g_list_free (items);

	debug_end_measurement (DEBUG_UPDATE, "merge itemset");

	return newCount;
}
Ejemplo n.º 18
0
itemPtr
itemlist_get_selected (void)
{
	return item_load(itemlist->priv->selectedId);
}
Ejemplo n.º 19
0
void
htmlview_update (LifereaHtmlView *htmlview, itemViewMode mode) 
{
	GSList		*iter;
	GString		*output;
	itemPtr		item = NULL;
	gchar		*baseURL = NULL;
	gboolean	summaryMode;

	/* determine base URL */
	switch (mode) {
		case ITEMVIEW_SINGLE_ITEM:
			item = itemlist_get_selected ();
			if(item) {
				baseURL = (gchar *)node_get_base_url (node_from_id (item->nodeId));
				item_unload (item);
			}
			break;
		default:
			if (htmlView_priv.node)
				baseURL = (gchar *) node_get_base_url (htmlView_priv.node);
			break;
	}

	if (baseURL)
		baseURL = g_markup_escape_text (baseURL, -1);
		
	output = g_string_new (NULL);
	htmlview_start_output (output, baseURL, TRUE, TRUE);

	/* HTML view updating means checking which items
	   need to be updated, render them and then 
	   concatenate everything from cache and output it */
	switch (mode) {
		case ITEMVIEW_SINGLE_ITEM:
			item = itemlist_get_selected ();
			if (item) {
				gchar *html = htmlview_render_item (item, mode, FALSE);
				if (html) {
					g_string_append (output, html);
					g_free (html);
				}
				
				item_unload (item);
			}
			break;
		case ITEMVIEW_ALL_ITEMS:
			/* Output optimization for feeds without item content. This
			   is not done for folders, because we only support all items
			   in summary mode or all in detailed mode. With folder item 
			   sets displaying everything in summary because of only a
			   single feed without item descriptions would make no sense. */

			summaryMode = (NULL != htmlView_priv.node) &&
			              !IS_FOLDER (htmlView_priv.node) && 
	        		      !IS_VFOLDER (htmlView_priv.node) && 
	        		      (htmlView_priv.missingContent > 3);

			/* concatenate all items */
			iter = htmlView_priv.orderedChunks;
			while (iter) {
				/* try to retrieve item HTML chunk from cache */
				htmlChunkPtr chunk = (htmlChunkPtr)iter->data;
				
				/* if not found: render new item now and add to cache */
				if (!chunk->html) {
					item = item_load (chunk->id);
					if (item) {
						debug1 (DEBUG_HTML, "rendering item to HTML view: >>>%s<<<", item_get_title (item));
						chunk->html = htmlview_render_item (item, mode, summaryMode);
						item_unload (item);
					}
				}
				
				if (chunk->html)
					g_string_append (output, chunk->html);
					
				iter = g_slist_next (iter);
			}
			break;
		case ITEMVIEW_NODE_INFO:
			{
				gchar *html;
				
				if (htmlView_priv.node) {
					html = node_render (htmlView_priv.node);	
					if (html) {
						g_string_append (output, html);
						g_free (html);
					}
				}
			}
			break;
		default:
			g_warning ("HTML view: invalid viewing mode!!!");
			break;
	}
	
	htmlview_finish_output (output);

	debug1 (DEBUG_HTML, "writing %d bytes to HTML view", strlen (output->str));
	liferea_htmlview_write (htmlview, output->str, baseURL);
	
	g_string_free (output, TRUE);
	g_free (baseURL);
}
Ejemplo n.º 20
0
gboolean
liferea_htmlview_handle_URL (LifereaHtmlView *htmlview, const gchar *url)
{
	struct internalUriType	*uriType;
	gboolean browse_inside_application;
	
	g_return_val_if_fail (htmlview, TRUE);
	g_return_val_if_fail (url, TRUE);

	conf_get_bool_value (BROWSE_INSIDE_APPLICATION, &browse_inside_application);

	debug3 (DEBUG_GUI, "handle URL: %s %s %s",
	        browse_inside_application?"true":"false",
	        htmlview->priv->forceInternalBrowsing?"true":"false",
		htmlview->priv->internal?"true":"false");

	/* first catch all links with special URLs... */
	if (liferea_htmlview_is_special_url (url)) {
		if (htmlview->priv->internal) {
	
			/* it is a generic item list URI type */		
			uriType = internalUriTypes;
			while (uriType->suffix) {
				if (!strncmp (url + strlen ("liferea-"), uriType->suffix, strlen (uriType->suffix))) {
					gchar *nodeid, *itemnr;
					nodeid = strstr (url, "://");
					if (nodeid) {
						nodeid += 3;
						itemnr = strchr (nodeid, '-');
						if (itemnr) {
							itemPtr item;

							*itemnr = 0;
							itemnr++;

							item = item_load (atol (itemnr));
							if (item) {
								(*uriType->func) (item);
								item_unload (item);
							} else {
								g_warning ("Fatal: no item with id (node=%s, item=%s) found!!!", nodeid, itemnr);
							}

							return TRUE;
						}
					}
				}
				uriType++;
			}
			g_warning ("Internal error: unhandled protocol in URL \"%s\"!", url);
		} else {
			g_warning ("Security: Prevented external HTML document to use internal link scheme (%s)!", url);
		}
		return TRUE;
	}
	
	if(htmlview->priv->forceInternalBrowsing || browse_inside_application) {	   
	   	/* before loading external content suppress internal link schema again */
		htmlview->priv->internal = FALSE;
		
		return FALSE;
	} else {
		(void)browser_launch_URL_external (url);
	}
	
	return TRUE;
}