示例#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;
}
示例#2
0
static void
reedah_feed_subscription_process_update_result (subscriptionPtr subscription, const struct updateResult* const result, updateFlags flags)
{
	if (result->data && result->httpstatus == 200) {
		GList		*items = NULL;
		jsonApiMapping	mapping;

		/*
		   We expect to get something like this
		   
		   [{"crawlTimeMsec":"1375821312282",
		     "id"::"tag:google.com,reader:2005\/item\/4ee371db36f84de2",
		     "categories":["user\/15724899091976567759\/state\/com.google\/reading-list",
		     "user\/15724899091976567759\/state\/com.google\/fresh"],
		     "title":"Firefox 23 Arrives With New Logo, Mixed Content Blocker, and Network Monitor",
		     "published":1375813680,
		     "updated":1375821312,
		     "alternate":[{"href":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/Q4450FchLQo/story01.htm","type":"text/html"}],
		     "canonical":[{"href":"http://slashdot.feedsportal.com/c/35028/f/647410/s/2fa2b59c/sc[...]", "type":"text/html"}],
		     "summary":{"direction":"ltr","content":"An anonymous reader writes [...]"},
		     "author":"Soulskill",
		     "origin":{"streamId":"feed/http://rss.slashdot.org/Slashdot/slashdot","title":"Slashdot",
		     "htmlurl":"http://slashdot.org/"
		    },

                   [...]
                 */

		/* Note: The link and read status cannot be mapped as there might be multiple ones
 		   so the callback helper function extracts the first from the array */
		mapping.id		= "id";
		mapping.title		= "title";
		mapping.link		= NULL;
		mapping.description	= "summary/content";
		mapping.read		= NULL;
		mapping.updated		= "updated";
		mapping.author		= "author";
		mapping.flag		= "marked";

		mapping.xhtml		= TRUE;
		mapping.negateRead	= TRUE;

		items = json_api_get_items (result->data, "items", &mapping, &reedah_item_callback);
				
		/* merge against feed cache */
		if (items) {
			itemSetPtr itemSet = node_get_itemset (subscription->node);
			subscription->node->newCount = itemset_merge_items (itemSet, items, TRUE /* feed valid */, FALSE /* markAsRead */);
			itemlist_merge_itemset (itemSet);
			itemset_free (itemSet);

			subscription->node->available = TRUE;
		} else {
			subscription->node->available = FALSE;
			g_string_append (((feedPtr)subscription->node->data)->parseErrors, _("Could not parse JSON returned by Reedah API!"));
		}
	} else {
		subscription->node->available = FALSE;
	}
}
示例#3
0
static void
itemlist_finalize (GObject *object)
{
	itemset_free (itemlist->priv->filter);
	itemlist_duplicate_list_free ();

	G_OBJECT_CLASS (parent_class)->finalize (object);
}
示例#4
0
static void
vfolder_free (nodePtr node) 
{
	vfolderPtr	vfolder = (vfolderPtr) node->data;

	debug_enter ("vfolder_free");
	
	vfolders = g_slist_remove (vfolders, vfolder);
	itemset_free (vfolder->itemset);
		
	debug_exit ("vfolder_free");
}
示例#5
0
/** 
 * Loads a search result into the item list and renders
 * some info text into the HTML view pane.
 *
 * @param searchResult		valid search result node
 * @param searchString		search text (or NULL)
 */
static void
search_load_results (nodePtr searchResult, const gchar *searchString)
{
	GString	*buffer;
	itemSetPtr itemSet;
	nodeViewType viewMode;
	
	/* Clear feed and item display and load search results */
	feed_list_view_select (NULL);
	itemlist_unload (FALSE);
	
	/* Ensure that we are in a useful viewing mode (3 paned) */
	viewMode = itemlist_get_view_mode ();
	if ((NODE_VIEW_MODE_NORMAL != viewMode) &&
	    (NODE_VIEW_MODE_WIDE != viewMode))
		itemview_set_layout (NODE_VIEW_MODE_NORMAL);
		
	itemSet = node_get_itemset (searchResult);
	itemlist_load_search_result (itemSet);
	itemset_free (itemSet);

	buffer = g_string_new (NULL);
	htmlview_start_output (buffer, NULL, TRUE, FALSE);
	g_string_append_printf (buffer, "<div class='content'><h2>");
	
	if (searchString)
		g_string_append_printf (buffer, ngettext("%d Search Result for \"%s\"", 
	                                        	 "%d Search Results for \"%s\"",
	                                        	 searchResult->itemCount),
	                        	searchResult->itemCount, searchString);
	else 
		g_string_append_printf (buffer, ngettext("%d Search Result", 
	                                        	 "%d Search Results",
	                                        	 searchResult->itemCount),
	                        	searchResult->itemCount);
					
	g_string_append_printf (buffer, "</h2><p>");
	g_string_append_printf (buffer, _("The item list now contains all items matching the "
	                                "specified search pattern. If you want to save this search "
	                                "result permanently you can click the \"Search Folder\" button in "
	                                "the search dialog and Liferea will add a search folder to your "
	                                "feed list."));
	g_string_append_printf (buffer, "</p></div>");
	htmlview_finish_output (buffer);
	itemview_display_info (buffer->str);
	g_string_free (buffer, TRUE);
}
示例#6
0
static gboolean
vfolder_loader_fetch_cb (gpointer user_data, GSList **resultItems)
{
	vfolderPtr	vfolder = (vfolderPtr)user_data;
	itemSetPtr	items = g_new0 (struct itemSet, 1);
	GList		*iter;
	gboolean	result;

	/* 1. Fetch a batch of items */
	result = db_itemset_get (items, vfolder->loadOffset, VFOLDER_LOADER_BATCH_SIZE);
	vfolder->loadOffset += VFOLDER_LOADER_BATCH_SIZE;

	if (result) {
		/* 2. Match all items against search folder */
		iter = items->ids;
		while (iter) {
			gulong id = GPOINTER_TO_UINT (iter->data);

			itemPtr	item = db_item_load (id);
			if (itemset_check_item (vfolder->itemset, item))
				*resultItems = g_slist_append (*resultItems, item);
			else
				item_unload (item);

			iter = g_list_next (iter);
		}
	} else {
		debug1 (DEBUG_CACHE, "search folder '%s' reload complete", vfolder->node->title);
		vfolder->reloading = FALSE;
	}

	itemset_free (items);

	/* 3. Save items to DB and update UI (except for search results) */
	if (vfolder->node) {
		db_search_folder_add_items (vfolder->node->id, *resultItems);
		node_update_counters (vfolder->node);
		ui_node_update (vfolder->node->id);
	}

	return result;	/* FALSE on last fetch */
}
示例#7
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);
}
示例#8
0
static void
ttrss_feed_subscription_process_update_result (subscriptionPtr subscription, const struct updateResult* const result, updateFlags flags)
{
	if (result->data && result->httpstatus == 200) {
		JsonParser	*parser = json_parser_new ();

		if (json_parser_load_from_data (parser, result->data, -1, NULL)) {
			JsonArray	*array = json_node_get_array (json_get_node (json_parser_get_root (parser), "content"));
			GList		*elements = json_array_get_elements (array);
			GList		*iter = elements;
			GList		*items = NULL;

			/*
			   We expect to get something like this
			   
			   [{"id":118,
			     "unread":true,
			     "marked":false,
			     "updated":1287927675,
			     "is_updated":false,
			     "title":"IBM Says New ...",
			     "link":"http:\/\/rss.slashdot.org\/~r\/Slashdot\/slashdot\/~3\/ALuhNKO3NV4\/story01.htm",
			     "feed_id":"5",
			     "content":"coondoggie writes ..."
			    },
			    {"id":117,
			     "unread":true,
			     "marked":false,
			     "updated":1287923814,
                           [...]
                         */
                         
			while (iter) {
				JsonNode *node = (JsonNode *)iter->data;
				itemPtr item = item_new ();
				gchar *id;
				const gchar *content; 
				gchar *xhtml;

				id = g_strdup_printf ("%" G_GINT64_FORMAT, json_get_int (node, "id"));
				item_set_id (item, id);
				g_free (id);
				item_set_title (item, json_get_string (node, "title"));
				item_set_source (item, json_get_string (node, "link"));

				content = json_get_string (node, "content");
				xhtml = xhtml_extract_from_string (content, NULL);
				item_set_description (item, xhtml);
				xmlFree (xhtml);

				item->time = json_get_int (node, "updated");
				
				if (json_get_bool (node, "unread")) {
					item->readStatus = FALSE;
				}
				else {
					item->readStatus = TRUE;
				}
				if (json_get_bool (node, "marked"))
					item->flagStatus = TRUE;
					
				items = g_list_append (items, (gpointer)item);
				
				iter = g_list_next (iter);
			}

			g_list_free (elements);

			/* merge against feed cache */
			if (items) {
				itemSetPtr itemSet = node_get_itemset (subscription->node);
				gint newCount = itemset_merge_items (itemSet, items, TRUE /* feed valid */, FALSE /* markAsRead */);
				itemlist_merge_itemset (itemSet);
				itemset_free (itemSet);

				feedlist_node_was_updated (subscription->node, newCount);
			}

			subscription->node->available = TRUE;
		} else {
			subscription->node->available = FALSE;

			g_string_append (((feedPtr)subscription->node->data)->parseErrors, _("Could not parse JSON returned by TinyTinyRSS API!"));
		}

		g_object_unref (parser);
	} else {
		subscription->node->available = FALSE;
	}
}
示例#9
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);
	}
}
示例#10
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");
}
示例#11
0
void
itemlist_free (void)
{
	itemset_free (itemlist_priv.filter);
	itemlist_duplicate_list_free ();
}