[libgrss] Added grss_feed_channel_fetch_all_async() and relative _finish functions RSSCloud handler fetches it



commit b6d10a5021ee6636ca20a519efd7dafd079063b2
Author: Roberto Guido <bob4mail gmail com>
Date:   Wed Dec 28 10:46:42 2011 -0800

    Added grss_feed_channel_fetch_all_async() and relative _finish functions
    RSSCloud handler fetches items asyncronously
    Added an example about asyncronous feed fetching
    Removed some unused variables

 doc/reference/libgrss-sections.txt  |    5 ++
 examples/async-fetcher.c            |   83 ++++++++++++++++++++++++
 src/Makefile.am                     |    1 +
 src/feed-atom-handler.c             |   14 +----
 src/feed-channel.c                  |  120 ++++++++++++++++++++++++++++++++---
 src/feed-channel.h                  |    4 +
 src/feed-parser.c                   |    3 -
 src/feed-pie-handler.c              |    3 -
 src/feed-rss-handler.c              |    3 -
 src/feeds-group.c                   |   14 +++-
 src/feeds-opml-group-handler.c      |    5 --
 src/feeds-pool.c                    |    2 +-
 src/feeds-publisher.c               |    4 +-
 src/feeds-pubsubhubbub-subscriber.c |    2 +-
 src/feeds-rsscloud-subscriber.c     |   22 ++++++-
 src/feeds-subscriber-private.h      |   26 ++++++++
 src/feeds-subscriber.c              |   66 ++++++++++++++++++--
 src/feeds-xbel-group-handler.c      |    5 --
 src/feeds-xoxo-group-handler.c      |    5 --
 19 files changed, 328 insertions(+), 59 deletions(-)
---
diff --git a/doc/reference/libgrss-sections.txt b/doc/reference/libgrss-sections.txt
index 488af51..96707d9 100644
--- a/doc/reference/libgrss-sections.txt
+++ b/doc/reference/libgrss-sections.txt
@@ -17,6 +17,7 @@ GrssFeedsPool
 grss_feeds_pool_new
 grss_feeds_pool_listen
 grss_feeds_pool_get_listened
+grss_feeds_pool_get_listened_num
 grss_feeds_pool_switch
 grss_feeds_pool_get_session
 </SECTION>
@@ -147,6 +148,10 @@ grss_feed_channel_set_update_interval
 grss_feed_channel_get_update_interval
 grss_feed_channel_fetch
 grss_feed_channel_fetch_async
+grss_feed_channel_fetch_finish
+grss_feed_channel_fetch_all
+grss_feed_channel_fetch_all_async
+grss_feed_channel_fetch_all_finish
 </SECTION>
 
 <SECTION>
diff --git a/examples/async-fetcher.c b/examples/async-fetcher.c
new file mode 100644
index 0000000..351422b
--- /dev/null
+++ b/examples/async-fetcher.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011, Roberto Guido <rguido src gnome org>
+ *                     Michele Tameni <michele amdplanet it>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <libgrss.h>
+
+static int i;
+static GMainLoop *loop;
+
+static gboolean mark_time (gpointer useless)
+{
+	printf ("%d\n", i++);
+
+	if (i >= 10)
+		g_main_loop_quit (loop);
+
+	return TRUE;
+}
+
+static void
+print_items (GObject *source, GAsyncResult *res, gpointer useless)
+{
+	GList *items;
+	GList *iter;
+	GError *error;
+	GrssFeedChannel *channel;
+	GrssFeedItem *it;
+
+	error = NULL;
+	channel = GRSS_FEED_CHANNEL (source);
+	items = grss_feed_channel_fetch_all_finish (channel, res, &error);
+	
+	if (items == NULL) {
+		printf ("%s\n", error->message);
+	}
+	else {
+		for (iter = items; iter; iter = g_list_next (iter)) {
+			it = (GrssFeedItem*) iter->data;
+			printf ("%s\n", grss_feed_item_get_title (it));
+		}
+	}
+}
+
+static gboolean do_work (gpointer useless)
+{
+	GrssFeedChannel *feed;
+
+	i = 0;
+	g_timeout_add (100, mark_time, NULL);
+
+	feed = grss_feed_channel_new_from_source ("http://rss.slashdot.org/Slashdot/slashdot";);
+	grss_feed_channel_fetch_all_async (feed, print_items, NULL);
+
+	return FALSE;
+}
+
+int main ()
+{
+	g_type_init ();
+	g_thread_init (NULL);
+
+	loop = g_main_loop_new (NULL, FALSE);
+	g_idle_add (do_work, NULL);
+
+	g_main_run (loop);
+	exit (0);
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 7643455..8587d73 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ sources_private_h = \
 	feeds-pubsubhubbub-subscriber.h \
 	feeds-rsscloud-subscriber.h     \
 	feeds-subscriber-handler.h      \
+	feeds-subscriber-private.h	\
 	feeds-xbel-group-handler.h      \
 	feeds-xoxo-group-handler.h      \
 	ns-handler.h                    \
diff --git a/src/feed-atom-handler.c b/src/feed-atom-handler.c
index acf05d4..fdfaf04 100644
--- a/src/feed-atom-handler.c
+++ b/src/feed-atom-handler.c
@@ -62,9 +62,6 @@ feed_atom_handler_error_quark ()
 static void
 feed_atom_handler_finalize (GObject *object)
 {
-	FeedAtomHandler *parser;
-
-	parser = FEED_ATOM_HANDLER (object);
 	G_OBJECT_CLASS (feed_atom_handler_parent_class)->finalize (object);
 }
 
@@ -277,7 +274,6 @@ atom10_parse_person_construct (xmlNodePtr cur)
 	gchar *name = NULL;
 	gchar *uri = NULL;
 	gchar *email = NULL;
-	gboolean invalid = FALSE;
 
 	cur = cur->xmlChildrenNode;
 	while (cur) {
@@ -293,8 +289,6 @@ atom10_parse_person_construct (xmlNodePtr cur)
 			}
 
 			if (xmlStrEqual (cur->name, BAD_CAST"email")) {
-				if (email)
-					invalid = TRUE;
 				g_free (email);
 				tmp = (gchar *)xmlNodeListGetString(cur->doc, cur->xmlChildrenNode, 1);
 				email = g_strdup_printf(" - <a href=\"mailto:%s\";>%s</a>", tmp, tmp);
@@ -302,8 +296,6 @@ atom10_parse_person_construct (xmlNodePtr cur)
 			}
 
 			if (xmlStrEqual (cur->name, BAD_CAST"uri")) {
-				if (!uri)
-					invalid = TRUE;
 				g_free (uri);
 				tmp = (gchar *)xmlNodeListGetString (cur->doc, cur->xmlChildrenNode, 1);
 				uri = g_strdup_printf (" (<a href=\"%s\">Website</a>)", tmp);
@@ -316,12 +308,10 @@ atom10_parse_person_construct (xmlNodePtr cur)
 
 		cur = cur->next;
 	}
-	if (!name) {
-		invalid = TRUE;
+
+	if (!name)
 		name = g_strdup ("Invalid Atom feed: unknown author");
-	}
 
-	/* FIXME: so somthing with "invalid" flag */
 	tmp = g_strdup_printf ("%s%s%s", name, uri ? uri : "", email ? email : "");
 
 	if (uri)
diff --git a/src/feed-channel.c b/src/feed-channel.c
index 9be471f..530d344 100644
--- a/src/feed-channel.c
+++ b/src/feed-channel.c
@@ -68,6 +68,7 @@ struct _GrssFeedChannelPrivate {
 
 enum {
 	FEEDS_CHANNEL_FETCH_ERROR,
+	FEEDS_CHANNEL_PARSE_ERROR
 };
 
 G_DEFINE_TYPE (GrssFeedChannel, grss_feed_channel, G_TYPE_OBJECT);
@@ -827,7 +828,9 @@ feed_downloaded (SoupSession *session, SoupMessage *msg, gpointer user_data) {
 	g_object_get (msg, "status-code", &status, NULL);
 
 	if (status >= 200 && status <= 299) {
-		quick_and_dirty_parse (channel, msg, NULL);
+		if (quick_and_dirty_parse (channel, msg, NULL) == FALSE)
+			g_simple_async_result_set_error (result, FEEDS_CHANNEL_ERROR, FEEDS_CHANNEL_PARSE_ERROR,
+						 "Unable to parse feed from %s", grss_feed_channel_get_source (channel));
 	}
 	else {
 		g_simple_async_result_set_error (result, FEEDS_CHANNEL_ERROR, FEEDS_CHANNEL_FETCH_ERROR,
@@ -839,6 +842,25 @@ feed_downloaded (SoupSession *session, SoupMessage *msg, gpointer user_data) {
 }
 
 /**
+ * grss_feed_channel_fetch_finish:
+ * @channel: a #GrssFeedChannel
+ * @res: the #GAsyncResult passed to the callback
+ * @error: if an error occourred, FALSE is returned and this is filled with the message
+ *
+ * Finalizes an asyncronous operation started with grss_feed_channel_fetch_async()
+ *
+ * Return value: TRUE if @channel informations have been successfully fetched, FALSE otherwise
+ */
+gboolean
+grss_feed_channel_fetch_finish (GrssFeedChannel *channel, GAsyncResult *res, GError **error)
+{
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+/**
  * grss_feed_channel_fetch_async:
  * @channel: a #GrssFeedChannel
  * @callback: function to invoke at the end of the download
@@ -873,7 +895,6 @@ grss_feed_channel_fetch_async (GrssFeedChannel *channel, GAsyncReadyCallback cal
 GList*
 grss_feed_channel_fetch_all (GrssFeedChannel *channel)
 {
-	gboolean ret;
 	guint status;
 	GList *items;
 	SoupMessage *msg;
@@ -884,15 +905,98 @@ grss_feed_channel_fetch_all (GrssFeedChannel *channel)
 	status = soup_session_send_message (session, msg);
 	items = NULL;
 
-	if (status >= 200 && status <= 299) {
-		ret = quick_and_dirty_parse (channel, msg, &items);
-	}
-	else {
+	if (status >= 200 && status <= 299)
+		quick_and_dirty_parse (channel, msg, &items);
+	else
 		g_warning ("Unable to fetch feed from %s: %s", grss_feed_channel_get_source (channel), soup_status_get_phrase (status));
-		ret = FALSE;
-	}
 
 	g_object_unref (session);
 	g_object_unref (msg);
 	return items;
 }
+
+static void
+free_items_list (gpointer list)
+{
+	GList *items;
+	GList *iter;
+
+	items = list;
+
+	for (iter = items; iter; iter = g_list_next (iter))
+		g_object_unref (iter->data);
+
+	g_list_free (items);
+}
+
+static void
+feed_downloaded_return_items (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+	guint status;
+	GList *items;
+	GSimpleAsyncResult *result;
+	GrssFeedChannel *channel;
+
+	result = user_data;
+	channel = GRSS_FEED_CHANNEL (g_async_result_get_source_object (G_ASYNC_RESULT (result)));
+	g_object_get (msg, "status-code", &status, NULL);
+
+	if (status >= 200 && status <= 299) {
+		items = NULL;
+
+		if (quick_and_dirty_parse (channel, msg, &items) == TRUE)
+			g_simple_async_result_set_op_res_gpointer (result, items, free_items_list);
+		else
+			g_simple_async_result_set_error (result, FEEDS_CHANNEL_ERROR, FEEDS_CHANNEL_PARSE_ERROR,
+						 "Unable to parse feed from %s", grss_feed_channel_get_source (channel));
+	}
+	else {
+		g_simple_async_result_set_error (result, FEEDS_CHANNEL_ERROR, FEEDS_CHANNEL_FETCH_ERROR,
+						 "Unable to download from %s", grss_feed_channel_get_source (channel));
+	}
+
+	g_simple_async_result_complete_in_idle (result);
+	g_object_unref (result);
+}
+
+/**
+ * grss_feed_channel_fetch_all_async:
+ * @channel: a #GrssFeedChannel
+ * @callback: function to invoke at the end of the download
+ * @user_data: data passed to the callback
+ *
+ * Similar to grss_feed_channel_fetch_all(), but asyncronous
+ */
+void
+grss_feed_channel_fetch_all_async (GrssFeedChannel *channel, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GSimpleAsyncResult *result;
+	SoupMessage *msg;
+	SoupSession *session;
+
+	result = g_simple_async_result_new (G_OBJECT (channel), callback, user_data, grss_feed_channel_fetch_async);
+
+	session = soup_session_async_new ();
+	msg = soup_message_new ("GET", grss_feed_channel_get_source (channel));
+	soup_session_queue_message (session, msg, feed_downloaded_return_items, result);
+}
+
+/**
+ * grss_feed_channel_fetch_all_finish:
+ * @channel: a #GrssFeedChannel
+ * @res: the #GAsyncResult passed to the callback
+ * @error: if an error occourred, NULL is returned and this is filled with the message
+ *
+ * Finalizes an asyncronous operation started with grss_feed_channel_fetch_all_async()
+ *
+ * Return value: list of items fetched from the #GrssFeedChannel, or NULL if @error is set. The
+ * list (and contained items) is freed at the end of the callback
+ */
+GList*
+grss_feed_channel_fetch_all_finish (GrssFeedChannel *channel, GAsyncResult *res, GError **error)
+{
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+		return NULL;
+	else
+		return (GList*) g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+}
diff --git a/src/feed-channel.h b/src/feed-channel.h
index bb04ba7..4582d6b 100644
--- a/src/feed-channel.h
+++ b/src/feed-channel.h
@@ -45,6 +45,7 @@ typedef struct {
 GType			grss_feed_channel_get_type		(void) G_GNUC_CONST;
 
 GrssFeedChannel*	grss_feed_channel_new			();
+GrssFeedChannel*	grss_feed_channel_new_from_source	(gchar *source);
 GrssFeedChannel*	grss_feed_channel_new_from_file		(const gchar *path);
 
 void			grss_feed_channel_set_source		(GrssFeedChannel *channel, gchar *source);
@@ -88,6 +89,9 @@ int			grss_feed_channel_get_update_interval	(GrssFeedChannel *channel);
 
 gboolean		grss_feed_channel_fetch			(GrssFeedChannel *channel);
 void			grss_feed_channel_fetch_async		(GrssFeedChannel *channel, GAsyncReadyCallback callback, gpointer user_data);
+gboolean		grss_feed_channel_fetch_finish		(GrssFeedChannel *channel, GAsyncResult *res, GError **error);
 GList*			grss_feed_channel_fetch_all		(GrssFeedChannel *channel);
+void			grss_feed_channel_fetch_all_async	(GrssFeedChannel *channel, GAsyncReadyCallback callback, gpointer user_data);
+GList*			grss_feed_channel_fetch_all_finish	(GrssFeedChannel *channel, GAsyncResult *res, GError **error);
 
 #endif /* __FEED_CHANNEL_H__ */
diff --git a/src/feed-parser.c b/src/feed-parser.c
index 37f5d5d..1774ccd 100644
--- a/src/feed-parser.c
+++ b/src/feed-parser.c
@@ -65,9 +65,6 @@ grss_feed_parser_error_quark ()
 static void
 grss_feed_parser_finalize (GObject *object)
 {
-	GrssFeedParser *parser;
-
-	parser = GRSS_FEED_PARSER (object);
 	G_OBJECT_CLASS (grss_feed_parser_parent_class)->finalize (object);
 }
 
diff --git a/src/feed-pie-handler.c b/src/feed-pie-handler.c
index 056ffa2..1e32f09 100644
--- a/src/feed-pie-handler.c
+++ b/src/feed-pie-handler.c
@@ -61,9 +61,6 @@ feed_pie_handler_error_quark ()
 static void
 feed_pie_handler_finalize (GObject *object)
 {
-	FeedPieHandler *parser;
-
-	parser = FEED_PIE_HANDLER (object);
 	G_OBJECT_CLASS (feed_pie_handler_parent_class)->finalize (object);
 }
 
diff --git a/src/feed-rss-handler.c b/src/feed-rss-handler.c
index bbcfa05..339db79 100644
--- a/src/feed-rss-handler.c
+++ b/src/feed-rss-handler.c
@@ -74,9 +74,6 @@ feed_rss_handler_error_quark ()
 static void
 feed_rss_handler_finalize (GObject *object)
 {
-	FeedRssHandler *parser;
-
-	parser = FEED_RSS_HANDLER (object);
 	G_OBJECT_CLASS (feed_rss_handler_parent_class)->finalize (object);
 }
 
diff --git a/src/feeds-group.c b/src/feeds-group.c
index f09e565..fc21966 100644
--- a/src/feeds-group.c
+++ b/src/feeds-group.c
@@ -57,9 +57,6 @@ grss_feeds_group_error_quark ()
 static void
 grss_feeds_group_finalize (GObject *object)
 {
-	GrssFeedsGroup *group;
-
-	group = FEEDS_GROUP (object);
 	G_OBJECT_CLASS (grss_feeds_group_parent_class)->finalize (object);
 }
 
@@ -192,8 +189,17 @@ grss_feeds_group_parse_file (GrssFeedsGroup *group, const gchar *path, GError **
 	return items;
 }
 
+/**
+ * grss_feeds_group_export_file:
+ * @group:
+ * @channels:
+ * @path:
+ * @error:
+ *
+ * Return value: FALSE
+ */
 gboolean
-grss_feeds_group_export_file (GrssFeedsGroup *groups, GList *channels, const gchar *path, GError *error)
+grss_feeds_group_export_file (GrssFeedsGroup *group, GList *channels, const gchar *path, GError *error)
 {
 	return FALSE;
 }
diff --git a/src/feeds-opml-group-handler.c b/src/feeds-opml-group-handler.c
index 38c21ef..009a42b 100644
--- a/src/feeds-opml-group-handler.c
+++ b/src/feeds-opml-group-handler.c
@@ -45,9 +45,6 @@ G_DEFINE_TYPE_WITH_CODE (FeedsOpmlGroupHandler, feeds_opml_group_handler, G_TYPE
 static void
 feeds_opml_group_handler_finalize (GObject *object)
 {
-	FeedsOpmlGroupHandler *parser;
-
-	parser = FEEDS_OPML_GROUP_HANDLER (object);
 	G_OBJECT_CLASS (feeds_opml_group_handler_parent_class)->finalize (object);
 }
 
@@ -188,10 +185,8 @@ feeds_opml_group_handler_parse (GrssFeedsGroupHandler *self, xmlDocPtr doc, GErr
 {
 	xmlNodePtr cur;
 	GList *items;
-	FeedsOpmlGroupHandler *parser;
 
 	items = NULL;
-	parser = FEEDS_OPML_GROUP_HANDLER (self);
 	cur = xmlDocGetRootElement (doc);
 
 	while (cur) {
diff --git a/src/feeds-pool.c b/src/feeds-pool.c
index d3233bf..ac73e25 100644
--- a/src/feeds-pool.c
+++ b/src/feeds-pool.c
@@ -239,7 +239,7 @@ grss_feeds_pool_get_listened (GrssFeedsPool *pool)
 }
 
 /**
- * grss_feeds_pool_get_listened:
+ * grss_feeds_pool_get_listened_num:
  * @pool: a #GrssFeedsPool
  *
  * Returns number of feeds under the @pool control, as provided by
diff --git a/src/feeds-publisher.c b/src/feeds-publisher.c
index 6bc438a..00b61b9 100644
--- a/src/feeds-publisher.c
+++ b/src/feeds-publisher.c
@@ -164,7 +164,7 @@ grss_feeds_publisher_class_init (GrssFeedsPublisherClass *klass)
 	gobject_class->finalize = grss_feeds_publisher_finalize;
 
 	/**
-	 * GrssFeedsSubscriber::new_subscription:
+	 * GrssFeedsPublisher::new_subscription:
 	 * @pub: the #GrssFeedsPublisher emitting the signal
 	 * @topic: #GrssFeedChannel for which subscription has been added
 	 * @callback: callback required for new subscriber
@@ -176,7 +176,7 @@ grss_feeds_publisher_class_init (GrssFeedsPublisherClass *klass)
 	                                             G_TYPE_NONE, 2, GRSS_FEED_CHANNEL_TYPE, G_TYPE_STRING);
 
 	/**
-	 * GrssFeedsSubscriber::new_subscription:
+	 * GrssFeedsPublisher::new_subscription:
 	 * @pub: the #GrssFeedsPublisher emitting the signal
 	 * @topic: #GrssFeedChannel for which subscription has been removed
 	 * @callback: callback revoked by the subscriber
diff --git a/src/feeds-pubsubhubbub-subscriber.c b/src/feeds-pubsubhubbub-subscriber.c
index 5b38789..9556cda 100644
--- a/src/feeds-pubsubhubbub-subscriber.c
+++ b/src/feeds-pubsubhubbub-subscriber.c
@@ -153,9 +153,9 @@ feeds_pubsubhubbub_subscriber_handler_handle_message (GrssFeedsSubscriberHandler
 		mode = (gchar*) g_hash_table_lookup (query, "hub.mode");
 
 		if (*status == FEED_SUBSCRIPTION_SUBSCRIBING && strcmp (mode, "subscribe") == 0) {
+			*status = FEED_SUBSCRIPTION_SUBSCRIBED;
 			challenge = g_strdup ((gchar*) g_hash_table_lookup (query, "hub.challenge"));
 			soup_message_set_response (msg, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, challenge, strlen (challenge));
-
 			soup_message_set_status (msg, 200);
 		}
 		else if (*status == FEED_SUBSCRIPTION_UNSUBSCRIBING && strcmp (mode, "unsubscribe") == 0) {
diff --git a/src/feeds-rsscloud-subscriber.c b/src/feeds-rsscloud-subscriber.c
index 24c3445..a8bc172 100644
--- a/src/feeds-rsscloud-subscriber.c
+++ b/src/feeds-rsscloud-subscriber.c
@@ -20,6 +20,7 @@
 
 #include "feeds-rsscloud-subscriber.h"
 #include "feeds-subscriber.h"
+#include "feeds-subscriber-private.h"
 #include "feeds-subscriber-handler.h"
 #include "utils.h"
 #include "feed-parser.h"
@@ -81,7 +82,7 @@ subscribe_response_cb (SoupSession *session,
                        gpointer user_data)
 {
 	gboolean done;
-	const xmlChar *success;
+	xmlChar *success;
 	guint status;
 	xmlDocPtr doc;
 	xmlNodePtr cur;
@@ -152,6 +153,22 @@ feeds_rsscloud_subscriber_handler_subscribe (GrssFeedsSubscriberHandler *handler
 	soup_session_queue_message (grss_feeds_subscriber_get_session (myself->priv->parent), msg, subscribe_response_cb, NULL);
 }
 
+static void
+fetched_items_cb (GObject *source_object,
+                  GAsyncResult *res,
+                  gpointer user_data)
+{
+	GList *items;
+	GrssFeedChannel *channel;
+	GrssFeedsRsscloudSubscriber *handler;
+
+	items = g_async_result_get_user_data (res);
+	channel = GRSS_FEED_CHANNEL (g_async_result_get_source_object (res));
+	handler = user_data;
+
+	grss_feeds_subscriber_dispatch (handler->priv->parent, channel, items);
+}
+
 GList*
 feeds_rsscloud_subscriber_handler_handle_message (GrssFeedsSubscriberHandler *handler,
                                                   GrssFeedChannel *channel,
@@ -171,13 +188,14 @@ feeds_rsscloud_subscriber_handler_handle_message (GrssFeedsSubscriberHandler *ha
 		challenge = (gchar*) g_hash_table_lookup (query, "challenge");
 
 		if (*status == FEED_SUBSCRIPTION_SUBSCRIBING && challenge != NULL) {
+			*status = FEED_SUBSCRIPTION_SUBSCRIBED;
 			challenge = g_strdup (challenge);
 			soup_message_set_response (msg, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, challenge, strlen (challenge));
 			soup_message_set_status (msg, 200);
 		}
 	}
 	else if (*status == FEED_SUBSCRIPTION_SUBSCRIBED) {
-		ret = grss_feed_channel_fetch_all (channel);
+		grss_feed_channel_fetch_all_async (channel, fetched_items_cb, handler);
 		soup_message_set_status (msg, 202);
 	}
 	else {
diff --git a/src/feeds-subscriber-private.h b/src/feeds-subscriber-private.h
new file mode 100644
index 0000000..da1a56f
--- /dev/null
+++ b/src/feeds-subscriber-private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011, Roberto Guido <rguido src gnome org>
+ *                     Michele Tameni <michele amdplanet it>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __FEEDS_SUBSCRIBER_PRIVATE_H__
+#define __FEEDS_SUBSCRIBER_PRIVATE_H__
+
+void		grss_feeds_subscriber_dispatch	(GrssFeedsSubscriber *sub, GrssFeedChannel *channel, GList *items);
+
+#endif
diff --git a/src/feeds-subscriber.c b/src/feeds-subscriber.c
index df56694..9b5be45 100644
--- a/src/feeds-subscriber.c
+++ b/src/feeds-subscriber.c
@@ -77,6 +77,8 @@ typedef struct {
 
 	GrssFeedsSubscriber		*sub;
 	GrssFeedsSubscriberHandler	*handler;
+
+	GList				*items_cache;
 } GrssFeedChannelWrap;
 
 enum {
@@ -92,11 +94,19 @@ static void
 remove_currently_listened (GrssFeedsSubscriber *sub)
 {
 	GList *iter;
+	GList *cache_iter;
 	GrssFeedChannelWrap *wrap;
 
 	if (sub->priv->feeds_list != NULL) {
 		for (iter = sub->priv->feeds_list; iter; iter = g_list_next (iter)) {
 			wrap = (GrssFeedChannelWrap*) iter->data;
+
+			if (wrap->items_cache != NULL) {
+				for (cache_iter = wrap->items_cache; cache_iter; cache_iter = g_list_next (cache_iter))
+					g_object_unref (cache_iter->data);
+				g_list_free (wrap->items_cache);
+			}
+
 			g_free (wrap->path);
 			g_object_unref (wrap->channel);
 			g_free (wrap);
@@ -142,7 +152,8 @@ grss_feeds_subscriber_class_init (GrssFeedsSubscriberClass *klass)
 	 * @item: the #GrssFeedItem received
 	 *
 	 * Emitted when a notification has been received and parsed. The
-	 * @item is unref'd at the end of signal
+	 * @item is cached and unref'd when the #GrssFeedsSubscriber is
+	 * destroyed or a new set of feeds is provided
 	 */
 	signals [NOTIFICATION_RECEIVED] = g_signal_new ("notification-received", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0,
 	                                                NULL, NULL, feed_marshal_VOID__OBJECT_OBJECT,
@@ -279,19 +290,64 @@ grss_feeds_subscriber_get_listened (GrssFeedsSubscriber *sub)
 }
 
 static void
+dispatch_items (GrssFeedChannelWrap *feed, GList *items)
+{
+	gboolean exists;
+	const gchar* item_id;
+	GList *iter;
+	GList *cache_iter;
+	GrssFeedItem *item;
+	GrssFeedItem *cache_item;
+
+	for (iter = items; iter; iter = g_list_next (iter)) {
+		item = (GrssFeedItem*) iter->data;
+		item_id = grss_feed_item_get_id (item);
+
+		exists = FALSE;
+
+		for (cache_iter = feed->items_cache; cache_iter; cache_iter = g_list_next (cache_iter)) {
+			cache_item = (GrssFeedItem*) cache_iter->data;
+			if (strcmp (item_id, grss_feed_item_get_id (cache_item)) == 0)
+				exists = TRUE;
+		}
+
+		if (exists == FALSE) {
+			g_signal_emit (feed->sub, signals [NOTIFICATION_RECEIVED], 0, feed->channel, item, NULL);
+			feed->items_cache = g_list_prepend (feed->items_cache, item);
+		}
+	}
+}
+
+static void
 handle_incoming_notification_cb (SoupServer *server, SoupMessage *msg, const char *path,
                                  GHashTable *query, SoupClientContext *client, gpointer user_data)
 {
-	GList *iter;
 	GList *items;
 	GrssFeedChannelWrap *feed;
 
 	feed = (GrssFeedChannelWrap*) user_data;
 	items = grss_feeds_subscriber_handler_handle_incoming_message (feed->handler, feed->channel, &(feed->status), server, msg, path, query, client);
 
-	for (iter = items; iter; iter = g_list_next (iter))
-		g_signal_emit (feed->sub, signals [NOTIFICATION_RECEIVED], 0, feed->channel, (GrssFeedItem*) iter->data, NULL);
-	g_list_free (items);
+	if (items != NULL) {
+		dispatch_items (feed, items);
+		g_list_free (items);
+	}
+}
+
+void
+grss_feeds_subscriber_dispatch (GrssFeedsSubscriber *sub, GrssFeedChannel *channel, GList *items)
+{
+	GList *iter;
+	GrssFeedChannelWrap *wrap;
+
+	for (iter = sub->priv->feeds_list; iter; iter = g_list_next (iter)) {
+		wrap = (GrssFeedChannelWrap*) iter->data;
+
+		if (wrap->channel == channel) {
+			dispatch_items (wrap, items);
+			break;
+		}
+	}
 }
 
 static void
diff --git a/src/feeds-xbel-group-handler.c b/src/feeds-xbel-group-handler.c
index 1a57dee..1984e9d 100644
--- a/src/feeds-xbel-group-handler.c
+++ b/src/feeds-xbel-group-handler.c
@@ -37,9 +37,6 @@ G_DEFINE_TYPE_WITH_CODE (FeedsXbelGroupHandler, feeds_xbel_group_handler, G_TYPE
 static void
 feeds_xbel_group_handler_finalize (GObject *object)
 {
-	FeedsXbelGroupHandler *parser;
-
-	parser = FEEDS_XBEL_GROUP_HANDLER (object);
 	G_OBJECT_CLASS (feeds_xbel_group_handler_parent_class)->finalize (object);
 }
 
@@ -63,10 +60,8 @@ feeds_xbel_group_handler_parse (GrssFeedsGroupHandler *self, xmlDocPtr doc, GErr
 	xmlXPathObjectPtr xpathObj;
 	xmlXPathContextPtr xpathCtx;
 	GrssFeedChannel *channel;
-	FeedsXbelGroupHandler *parser;
 
 	items = NULL;
-	parser = FEEDS_XBEL_GROUP_HANDLER (self);
 
 	xpathCtx = xmlXPathNewContext (doc);
 
diff --git a/src/feeds-xoxo-group-handler.c b/src/feeds-xoxo-group-handler.c
index 14fae46..cad963a 100644
--- a/src/feeds-xoxo-group-handler.c
+++ b/src/feeds-xoxo-group-handler.c
@@ -57,9 +57,6 @@ static xmlNode* find_first_element (xmlDocPtr doc)
 static void
 feeds_xoxo_group_handler_finalize (GObject *object)
 {
-	FeedsXoxoGroupHandler *parser;
-
-	parser = FEEDS_XOXO_GROUP_HANDLER (object);
 	G_OBJECT_CLASS (feeds_xoxo_group_handler_parent_class)->finalize (object);
 }
 
@@ -79,10 +76,8 @@ feeds_xoxo_group_handler_parse (GrssFeedsGroupHandler *self, xmlDocPtr doc, GErr
 	xmlXPathObjectPtr xpathObj;
 	xmlXPathContextPtr xpathCtx;
 	GrssFeedChannel *channel;
-	FeedsXoxoGroupHandler *parser;
 
 	items = NULL;
-	parser = FEEDS_XOXO_GROUP_HANDLER (self);
 
 	xpathCtx = xmlXPathNewContext (doc);
 	xmlXPathRegisterNs (xpathCtx, BAD_CAST"xhtml", BAD_CAST"http://www.w3.org/1999/xhtml";);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]