Blame gdata/gdata-feed.c

Packit 4b6dd7
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Packit 4b6dd7
/*
Packit 4b6dd7
 * GData Client
Packit 4b6dd7
 * Copyright (C) Philip Withnall 2008–2010 <philip@tecnocode.co.uk>
Packit 4b6dd7
 * Copyright (C) Red Hat, Inc. 2015
Packit 4b6dd7
 *
Packit 4b6dd7
 * GData Client is free software; you can redistribute it and/or
Packit 4b6dd7
 * modify it under the terms of the GNU Lesser General Public
Packit 4b6dd7
 * License as published by the Free Software Foundation; either
Packit 4b6dd7
 * version 2.1 of the License, or (at your option) any later version.
Packit 4b6dd7
 *
Packit 4b6dd7
 * GData Client is distributed in the hope that it will be useful,
Packit 4b6dd7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4b6dd7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4b6dd7
 * Lesser General Public License for more details.
Packit 4b6dd7
 *
Packit 4b6dd7
 * You should have received a copy of the GNU Lesser General Public
Packit 4b6dd7
 * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
Packit 4b6dd7
 */
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * SECTION:gdata-feed
Packit 4b6dd7
 * @short_description: GData feed object
Packit 4b6dd7
 * @stability: Stable
Packit 4b6dd7
 * @include: gdata/gdata-feed.h
Packit 4b6dd7
 *
Packit 4b6dd7
 * #GDataFeed is a list of entries (#GDataEntry) returned as the result of a query to a #GDataService, or given as the input to another
Packit 4b6dd7
 * operation on the online service. It also has pieces of data associated with the query on the #GDataService, such as the query title
Packit 4b6dd7
 * or timestamp when it was last updated.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Each #GDataEntry represents a single object on the online service, such as a playlist, video or calendar entry, and the #GDataFeed
Packit 4b6dd7
 * represents a collection of similar objects.
Packit 4b6dd7
 */
Packit 4b6dd7
Packit 4b6dd7
#include <config.h>
Packit 4b6dd7
#include <glib.h>
Packit 4b6dd7
#include <glib/gi18n-lib.h>
Packit 4b6dd7
#include <libxml/parser.h>
Packit 4b6dd7
#include <string.h>
Packit 4b6dd7
#include <json-glib/json-glib.h>
Packit 4b6dd7
Packit 4b6dd7
#include "gdata-feed.h"
Packit 4b6dd7
#include "gdata-entry.h"
Packit 4b6dd7
#include "gdata-types.h"
Packit 4b6dd7
#include "gdata-private.h"
Packit 4b6dd7
#include "gdata-service.h"
Packit 4b6dd7
#include "gdata-parsable.h"
Packit 4b6dd7
Packit 4b6dd7
static void gdata_feed_dispose (GObject *object);
Packit 4b6dd7
static void gdata_feed_finalize (GObject *object);
Packit 4b6dd7
static void gdata_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
Packit 4b6dd7
static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
Packit 4b6dd7
static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
Packit 4b6dd7
static gboolean post_parse_xml (GDataParsable *parsable, gpointer user_data, GError **error);
Packit 4b6dd7
static void get_xml (GDataParsable *parsable, GString *xml_string);
Packit 4b6dd7
static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
Packit 4b6dd7
Packit 4b6dd7
static void _gdata_feed_add_category (GDataFeed *self, GDataCategory *category);
Packit 4b6dd7
static void _gdata_feed_add_author (GDataFeed *self, GDataAuthor *author);
Packit 4b6dd7
Packit 4b6dd7
static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
Packit 4b6dd7
static gboolean post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error);
Packit 4b6dd7
Packit 4b6dd7
struct _GDataFeedPrivate {
Packit 4b6dd7
	GList *entries;
Packit 4b6dd7
	gchar *title;
Packit 4b6dd7
	gchar *subtitle;
Packit 4b6dd7
	gchar *id;
Packit 4b6dd7
	gchar *etag;
Packit 4b6dd7
	gint64 updated;
Packit 4b6dd7
	GList *categories; /* GDataCategory */
Packit 4b6dd7
	gchar *logo;
Packit 4b6dd7
	gchar *icon;
Packit 4b6dd7
	GList *links; /* GDataLink */
Packit 4b6dd7
	GList *authors; /* GDataAuthor */
Packit 4b6dd7
	GDataGenerator *generator;
Packit 4b6dd7
	guint items_per_page;
Packit 4b6dd7
	guint start_index;
Packit 4b6dd7
	guint total_results;
Packit 4b6dd7
	gchar *rights;
Packit 4b6dd7
	gchar *next_page_token;
Packit 4b6dd7
};
Packit 4b6dd7
Packit 4b6dd7
enum {
Packit 4b6dd7
	PROP_ID = 1,
Packit 4b6dd7
	PROP_ETAG,
Packit 4b6dd7
	PROP_UPDATED,
Packit 4b6dd7
	PROP_TITLE,
Packit 4b6dd7
	PROP_SUBTITLE,
Packit 4b6dd7
	PROP_LOGO,
Packit 4b6dd7
	PROP_ICON,
Packit 4b6dd7
	PROP_GENERATOR,
Packit 4b6dd7
	PROP_ITEMS_PER_PAGE,
Packit 4b6dd7
	PROP_START_INDEX,
Packit 4b6dd7
	PROP_TOTAL_RESULTS,
Packit 4b6dd7
	PROP_RIGHTS,
Packit 4b6dd7
	PROP_NEXT_PAGE_TOKEN,
Packit 4b6dd7
};
Packit 4b6dd7
Packit 4b6dd7
G_DEFINE_TYPE (GDataFeed, gdata_feed, GDATA_TYPE_PARSABLE)
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_feed_class_init (GDataFeedClass *klass)
Packit 4b6dd7
{
Packit 4b6dd7
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 4b6dd7
	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
Packit 4b6dd7
Packit 4b6dd7
	g_type_class_add_private (klass, sizeof (GDataFeedPrivate));
Packit 4b6dd7
Packit 4b6dd7
	gobject_class->get_property = gdata_feed_get_property;
Packit 4b6dd7
	gobject_class->dispose = gdata_feed_dispose;
Packit 4b6dd7
	gobject_class->finalize = gdata_feed_finalize;
Packit 4b6dd7
Packit 4b6dd7
	parsable_class->pre_parse_xml = pre_parse_xml;
Packit 4b6dd7
	parsable_class->parse_xml = parse_xml;
Packit 4b6dd7
	parsable_class->post_parse_xml = post_parse_xml;
Packit 4b6dd7
	parsable_class->get_xml = get_xml;
Packit 4b6dd7
	parsable_class->get_namespaces = get_namespaces;
Packit 4b6dd7
	parsable_class->element_name = "feed";
Packit 4b6dd7
Packit 4b6dd7
	parsable_class->parse_json = parse_json;
Packit 4b6dd7
	parsable_class->post_parse_json = post_parse_json;
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:title:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The title of the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference:
Packit 4b6dd7
	 * <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_title">atom:title</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_TITLE,
Packit 4b6dd7
	                                 g_param_spec_string ("title",
Packit 4b6dd7
	                                                      "Title", "The title of the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:subtitle:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The subtitle of the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://atomenabled.org/developers/syndication/">atom:subtitle</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_SUBTITLE,
Packit 4b6dd7
	                                 g_param_spec_string ("subtitle",
Packit 4b6dd7
	                                                      "Subtitle", "The subtitle of the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:id:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The unique and permanent URN ID for the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_id">atom:id</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_ID,
Packit 4b6dd7
	                                 g_param_spec_string ("id",
Packit 4b6dd7
	                                                      "ID", "The unique and permanent URN ID for the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:etag:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The unique ETag for this version of the feed. See the
Packit 4b6dd7
	 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/reference.html#ResourceVersioning">online documentation</ulink> for
Packit 4b6dd7
	 * more information.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.2.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_ETAG,
Packit 4b6dd7
	                                 g_param_spec_string ("etag",
Packit 4b6dd7
	                                                      "ETag", "The unique ETag for this version of the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:updated:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The time the feed was last updated.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_updated">
Packit 4b6dd7
	 * atom:updated</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_UPDATED,
Packit 4b6dd7
	                                 g_param_spec_int64 ("updated",
Packit 4b6dd7
	                                                     "Updated", "The time the feed was last updated.",
Packit 4b6dd7
	                                                     0, G_MAXINT64, 0,
Packit 4b6dd7
	                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:logo:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The URI of a logo for the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_logo">atom:logo</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_LOGO,
Packit 4b6dd7
	                                 g_param_spec_string ("logo",
Packit 4b6dd7
	                                                      "Logo", "The URI of a logo for the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:icon:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The URI of an icon for the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference:
Packit 4b6dd7
	 * <ulink type="http" url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.icon">atom:icon</ulink>
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.6.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_ICON,
Packit 4b6dd7
	                                 g_param_spec_string ("icon",
Packit 4b6dd7
	                                                      "Icon", "The URI of an icon for the feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:generator:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Details of the software used to generate the feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_generator">
Packit 4b6dd7
	 * atom:generator</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_GENERATOR,
Packit 4b6dd7
	                                 g_param_spec_object ("generator",
Packit 4b6dd7
	                                                      "Generator", "Details of the software used to generate the feed.",
Packit 4b6dd7
	                                                      GDATA_TYPE_GENERATOR,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:rights:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The ownership rights pertaining to the entire feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * For more information, see the 
Packit 4b6dd7
	 * url="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.rights">Atom specification</ulink>.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.7.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_RIGHTS,
Packit 4b6dd7
	                                 g_param_spec_string ("rights",
Packit 4b6dd7
	                                                      "Rights", "The ownership rights pertaining to the entire feed.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:items-per-page:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The number of items per results page feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference:
Packit 4b6dd7
	 * <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_openSearch:itemsPerPage">
Packit 4b6dd7
	 * openSearch:itemsPerPage</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_ITEMS_PER_PAGE,
Packit 4b6dd7
	                                 g_param_spec_uint ("items-per-page",
Packit 4b6dd7
	                                                    "Items per page", "The number of items per results page feed.",
Packit 4b6dd7
	                                                    0, G_MAXUINT, 0,
Packit 4b6dd7
	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:start-index:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The one-based index of the first item in the results feed.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * This should <emphasis>not</emphasis> be used manually for pagination. Instead, use a #GDataQuery and call its gdata_query_next_page()
Packit 4b6dd7
	 * or gdata_query_previous_page() functions before making the query to the service.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference: <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_openSearch:startIndex">
Packit 4b6dd7
	 * openSearch:startIndex</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_START_INDEX,
Packit 4b6dd7
	                                 g_param_spec_uint ("start-index",
Packit 4b6dd7
	                                                    "Start index", "The one-based index of the first item in the results feed.",
Packit 4b6dd7
	                                                    1, G_MAXUINT, 1,
Packit 4b6dd7
	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:total-results:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The number of items in the result set for the feed, including those on other pages. If this is zero, the total number is unknown.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * This should <emphasis>not</emphasis> be used manually for pagination. Instead, use a #GDataQuery and call its gdata_query_next_page()
Packit 4b6dd7
	 * or gdata_query_previous_page() functions before making the query to the service.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * API reference:
Packit 4b6dd7
	 * <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_openSearch:totalResults">
Packit 4b6dd7
	 * openSearch:totalResults</ulink>
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_TOTAL_RESULTS,
Packit 4b6dd7
	                                 g_param_spec_uint ("total-results",
Packit 4b6dd7
	                                                    "Total results", "The total number of results in the feed.",
Packit 4b6dd7
	                                                    0, 1000000, 0,
Packit 4b6dd7
	                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataFeed:next-page-token:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The next page token for feeds. Pass this to
Packit 4b6dd7
	 * gdata_query_set_page_token() to advance to the next page when
Packit 4b6dd7
	 * querying APIs which use page tokens rather than page numbers or
Packit 4b6dd7
	 * offsets.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.17.7
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_NEXT_PAGE_TOKEN,
Packit 4b6dd7
	                                 g_param_spec_string ("next-page-token",
Packit 4b6dd7
	                                                      "Next page token", "The next page token for feeds.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_feed_init (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FEED, GDataFeedPrivate);
Packit 4b6dd7
	self->priv->updated = -1;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_feed_dispose (GObject *object)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->entries != NULL) {
Packit 4b6dd7
		g_list_foreach (priv->entries, (GFunc) g_object_unref, NULL);
Packit 4b6dd7
		g_list_free (priv->entries);
Packit 4b6dd7
	}
Packit 4b6dd7
	priv->entries = NULL;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->categories != NULL) {
Packit 4b6dd7
		g_list_foreach (priv->categories, (GFunc) g_object_unref, NULL);
Packit 4b6dd7
		g_list_free (priv->categories);
Packit 4b6dd7
	}
Packit 4b6dd7
	priv->categories = NULL;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->links != NULL) {
Packit 4b6dd7
		g_list_foreach (priv->links, (GFunc) g_object_unref, NULL);
Packit 4b6dd7
		g_list_free (priv->links);
Packit 4b6dd7
	}
Packit 4b6dd7
	priv->links = NULL;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->authors != NULL) {
Packit 4b6dd7
		g_list_foreach (priv->authors, (GFunc) g_object_unref, NULL);
Packit 4b6dd7
		g_list_free (priv->authors);
Packit 4b6dd7
	}
Packit 4b6dd7
	priv->authors = NULL;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->generator != NULL)
Packit 4b6dd7
		g_object_unref (priv->generator);
Packit 4b6dd7
	priv->generator = NULL;
Packit 4b6dd7
Packit 4b6dd7
	/* Chain up to the parent class */
Packit 4b6dd7
	G_OBJECT_CLASS (gdata_feed_parent_class)->dispose (object);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_feed_finalize (GObject *object)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	g_free (priv->title);
Packit 4b6dd7
	g_free (priv->subtitle);
Packit 4b6dd7
	g_free (priv->id);
Packit 4b6dd7
	g_free (priv->etag);
Packit 4b6dd7
	g_free (priv->logo);
Packit 4b6dd7
	g_free (priv->icon);
Packit 4b6dd7
	g_free (priv->rights);
Packit 4b6dd7
	g_free (priv->next_page_token);
Packit 4b6dd7
Packit 4b6dd7
	/* Chain up to the parent class */
Packit 4b6dd7
	G_OBJECT_CLASS (gdata_feed_parent_class)->finalize (object);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	switch (property_id) {
Packit 4b6dd7
		case PROP_TITLE:
Packit 4b6dd7
			g_value_set_string (value, priv->title);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_SUBTITLE:
Packit 4b6dd7
			g_value_set_string (value, priv->subtitle);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_ID:
Packit 4b6dd7
			g_value_set_string (value, priv->id);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_ETAG:
Packit 4b6dd7
			g_value_set_string (value, priv->etag);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_UPDATED:
Packit 4b6dd7
			g_value_set_int64 (value, priv->updated);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_LOGO:
Packit 4b6dd7
			g_value_set_string (value, priv->logo);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_ICON:
Packit 4b6dd7
			g_value_set_string (value, priv->icon);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_GENERATOR:
Packit 4b6dd7
			g_value_set_object (value, priv->generator);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_RIGHTS:
Packit 4b6dd7
			g_value_set_string (value, priv->rights);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_ITEMS_PER_PAGE:
Packit 4b6dd7
			g_value_set_uint (value, priv->items_per_page);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_START_INDEX:
Packit 4b6dd7
			g_value_set_uint (value, priv->start_index);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_TOTAL_RESULTS:
Packit 4b6dd7
			g_value_set_uint (value, priv->total_results);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_NEXT_PAGE_TOKEN:
Packit 4b6dd7
			g_value_set_string (value, priv->next_page_token);
Packit 4b6dd7
			break;
Packit 4b6dd7
		default:
Packit 4b6dd7
			/* We don't have any other property... */
Packit 4b6dd7
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 4b6dd7
			break;
Packit 4b6dd7
	}
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
typedef struct {
Packit 4b6dd7
	GType entry_type;
Packit 4b6dd7
	GDataQueryProgressCallback progress_callback;
Packit 4b6dd7
	gpointer progress_user_data;
Packit 4b6dd7
	guint entry_i;
Packit 4b6dd7
} ParseData;
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	/* Extract the ETag */
Packit 4b6dd7
	GDATA_FEED (parsable)->priv->etag = (gchar*) xmlGetProp (root_node, (xmlChar*) "etag");
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
typedef struct {
Packit 4b6dd7
	GDataQueryProgressCallback progress_callback;
Packit 4b6dd7
	gpointer progress_user_data;
Packit 4b6dd7
	GDataEntry *entry;
Packit 4b6dd7
	guint entry_i;
Packit 4b6dd7
	guint total_results;
Packit 4b6dd7
} ProgressCallbackData;
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	gboolean success;
Packit 4b6dd7
	GDataFeed *self = GDATA_FEED (parsable);
Packit 4b6dd7
	ParseData *data = user_data;
Packit 4b6dd7
Packit 4b6dd7
	if (gdata_parser_is_namespace (node, "http://www.w3.org/2005/Atom") == TRUE) {
Packit 4b6dd7
		if (xmlStrcmp (node->name, (xmlChar*) "entry") == 0) {
Packit 4b6dd7
			/* atom:entry */
Packit 4b6dd7
			GDataEntry *entry;
Packit 4b6dd7
			GType entry_type;
Packit 4b6dd7
Packit 4b6dd7
			/* Allow @data to be %NULL, and assume we're parsing a vanilla feed, so that we can test #GDataFeed in tests/general.c.
Packit 4b6dd7
			 * A little hacky, but not too much so, and valuable for testing. */
Packit 4b6dd7
			entry_type = (data != NULL) ? data->entry_type : GDATA_TYPE_ENTRY;
Packit 4b6dd7
			entry = GDATA_ENTRY (_gdata_parsable_new_from_xml_node (entry_type, doc, node, NULL, error));
Packit 4b6dd7
			if (entry == NULL)
Packit 4b6dd7
				return FALSE;
Packit 4b6dd7
Packit 4b6dd7
			/* Calls the callbacks in the main thread */
Packit 4b6dd7
			if (data != NULL)
Packit 4b6dd7
				_gdata_feed_call_progress_callback (self, data, entry);
Packit 4b6dd7
			_gdata_feed_add_entry (self, entry);
Packit 4b6dd7
			g_object_unref (entry);
Packit 4b6dd7
		} else if (gdata_parser_string_from_element (node, "title", P_DEFAULT | P_NO_DUPES, &(self->priv->title), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_string_from_element (node, "subtitle", P_NO_DUPES, &(self->priv->subtitle), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_string_from_element (node, "id", P_REQUIRED | P_NON_EMPTY | P_NO_DUPES,
Packit 4b6dd7
		                                             &(self->priv->id), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_string_from_element (node, "logo", P_NO_DUPES, &(self->priv->logo), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_string_from_element (node, "icon", P_NO_DUPES, &(self->priv->icon), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_CATEGORY,
Packit 4b6dd7
		                                                    _gdata_feed_add_category, self, &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_object_from_element_setter (node, "link", P_REQUIRED, GDATA_TYPE_LINK,
Packit 4b6dd7
		                                                    _gdata_feed_add_link, self, &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_object_from_element_setter (node, "author", P_REQUIRED, GDATA_TYPE_AUTHOR,
Packit 4b6dd7
		                                                    _gdata_feed_add_author, self, &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_object_from_element (node, "generator", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_GENERATOR,
Packit 4b6dd7
		                                             &(self->priv->generator), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_int64_time_from_element (node, "updated", P_REQUIRED | P_NO_DUPES,
Packit 4b6dd7
		                                                 &(self->priv->updated), &success, error) == TRUE ||
Packit 4b6dd7
		           gdata_parser_string_from_element (node, "rights", P_NONE, &(self->priv->rights), &success, error) == TRUE) {
Packit 4b6dd7
			return success;
Packit 4b6dd7
		} else {
Packit 4b6dd7
			return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_xml (parsable, doc, node, user_data, error);
Packit 4b6dd7
		}
Packit 4b6dd7
	} else if (gdata_parser_is_namespace (node, "http://a9.com/-/spec/opensearch/1.1/") == TRUE) {
Packit 4b6dd7
		if (xmlStrcmp (node->name, (xmlChar*) "totalResults") == 0) {
Packit 4b6dd7
			/* openSearch:totalResults */
Packit 4b6dd7
			xmlChar *total_results_string;
Packit 4b6dd7
Packit 4b6dd7
			/* Duplicate checking */
Packit 4b6dd7
			if (self->priv->total_results != 0)
Packit 4b6dd7
				return gdata_parser_error_duplicate_element (node, error);
Packit 4b6dd7
Packit 4b6dd7
			/* Parse the number */
Packit 4b6dd7
			total_results_string = xmlNodeListGetString (doc, node->children, TRUE);
Packit 4b6dd7
			if (total_results_string == NULL)
Packit 4b6dd7
				return gdata_parser_error_required_content_missing (node, error);
Packit 4b6dd7
Packit 4b6dd7
			self->priv->total_results = g_ascii_strtoull ((gchar*) total_results_string, NULL, 10);
Packit 4b6dd7
			xmlFree (total_results_string);
Packit 4b6dd7
		} else if (xmlStrcmp (node->name, (xmlChar*) "startIndex") == 0) {
Packit 4b6dd7
			/* openSearch:startIndex */
Packit 4b6dd7
			xmlChar *start_index_string;
Packit 4b6dd7
Packit 4b6dd7
			/* Duplicate checking */
Packit 4b6dd7
			if (self->priv->start_index != 0)
Packit 4b6dd7
				return gdata_parser_error_duplicate_element (node, error);
Packit 4b6dd7
Packit 4b6dd7
			/* Parse the number */
Packit 4b6dd7
			start_index_string = xmlNodeListGetString (doc, node->children, TRUE);
Packit 4b6dd7
			if (start_index_string == NULL)
Packit 4b6dd7
				return gdata_parser_error_required_content_missing (node, error);
Packit 4b6dd7
Packit 4b6dd7
			self->priv->start_index = g_ascii_strtoull ((gchar*) start_index_string, NULL, 10);
Packit 4b6dd7
			xmlFree (start_index_string);
Packit 4b6dd7
		} else if (xmlStrcmp (node->name, (xmlChar*) "itemsPerPage") == 0) {
Packit 4b6dd7
			/* openSearch:itemsPerPage */
Packit 4b6dd7
			xmlChar *items_per_page_string;
Packit 4b6dd7
Packit 4b6dd7
			/* Duplicate checking */
Packit 4b6dd7
			if (self->priv->items_per_page != 0)
Packit 4b6dd7
				return gdata_parser_error_duplicate_element (node, error);
Packit 4b6dd7
Packit 4b6dd7
			/* Parse the number */
Packit 4b6dd7
			items_per_page_string = xmlNodeListGetString (doc, node->children, TRUE);
Packit 4b6dd7
			if (items_per_page_string == NULL)
Packit 4b6dd7
				return gdata_parser_error_required_content_missing (node, error);
Packit 4b6dd7
Packit 4b6dd7
			self->priv->items_per_page = g_ascii_strtoull ((gchar*) items_per_page_string, NULL, 10);
Packit 4b6dd7
			xmlFree (items_per_page_string);
Packit 4b6dd7
		} else {
Packit 4b6dd7
			return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_xml (parsable, doc, node, user_data, error);
Packit 4b6dd7
		}
Packit 4b6dd7
	} else {
Packit 4b6dd7
		return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_xml (parsable, doc, node, user_data, error);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
post_parse_xml (GDataParsable *parsable, gpointer user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (parsable)->priv;
Packit 4b6dd7
Packit 4b6dd7
	/* Check for missing required elements */
Packit 4b6dd7
	/* FIXME: The YouTube comments feed seems to have lost its <feed/title> element, making it an invalid Atom feed and meaning
Packit 4b6dd7
	 * the check below has to be commented out.
Packit 4b6dd7
	 * Filed as: https://code.google.com/p/gdata-issues/issues/detail?id=2908.
Packit 4b6dd7
	 * Discovered in: https://bugzilla.gnome.org/show_bug.cgi?id=679072#c12. */
Packit 4b6dd7
	/*if (priv->title == NULL)
Packit 4b6dd7
		return gdata_parser_error_required_element_missing ("title", "feed", error);*/
Packit 4b6dd7
	if (priv->id == NULL)
Packit 4b6dd7
		return gdata_parser_error_required_element_missing ("id", "feed", error);
Packit 4b6dd7
	if (priv->updated == -1)
Packit 4b6dd7
		return gdata_parser_error_required_element_missing ("updated", "feed", error);
Packit 4b6dd7
Packit 4b6dd7
	/* Reverse our lists of stuff */
Packit 4b6dd7
	priv->entries = g_list_reverse (priv->entries);
Packit 4b6dd7
	priv->categories = g_list_reverse (priv->categories);
Packit 4b6dd7
	priv->links = g_list_reverse (priv->links);
Packit 4b6dd7
	priv->authors = g_list_reverse (priv->authors);
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
get_xml (GDataParsable *parsable, GString *xml_string)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (parsable)->priv;
Packit 4b6dd7
	GList *entries;
Packit 4b6dd7
	gchar *updated;
Packit 4b6dd7
Packit 4b6dd7
	/* NOTE: Only the required elements are implemented at the moment */
Packit 4b6dd7
	gdata_parser_string_append_escaped (xml_string, "<title type='text'>", priv->title, "</title>");
Packit 4b6dd7
	gdata_parser_string_append_escaped (xml_string, "<id>", priv->id, "</id>");
Packit 4b6dd7
Packit 4b6dd7
	updated = gdata_parser_int64_to_iso8601 (priv->updated);
Packit 4b6dd7
	g_string_append_printf (xml_string, "<updated>%s</updated>", updated);
Packit 4b6dd7
	g_free (updated);
Packit 4b6dd7
Packit 4b6dd7
	/* Entries */
Packit 4b6dd7
	for (entries = priv->entries; entries != NULL; entries = entries->next)
Packit 4b6dd7
		_gdata_parsable_get_xml (GDATA_PARSABLE (entries->data), xml_string, FALSE);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (parsable)->priv;
Packit 4b6dd7
	GList *i;
Packit 4b6dd7
Packit 4b6dd7
	/* We can't assume that all the entries in the feed have identical namespaces, so we have to call get_namespaces() for all of them.
Packit 4b6dd7
	 * GDataBatchFeeds, for example, can easily contain entries with differing sets of namespaces. */
Packit 4b6dd7
	for (i = priv->entries; i != NULL; i = i->next)
Packit 4b6dd7
		GDATA_PARSABLE_GET_CLASS (i->data)->get_namespaces (GDATA_PARSABLE (i->data), namespaces);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeed *self = GDATA_FEED (parsable);
Packit 4b6dd7
	ParseData *data = user_data;
Packit 4b6dd7
Packit 4b6dd7
	if (g_strcmp0 (json_reader_get_member_name (reader), "items") == 0) {
Packit 4b6dd7
		gint i, elements;
Packit 4b6dd7
Packit 4b6dd7
		/* Loop through the elements array. */
Packit 4b6dd7
		for (i = 0, elements = json_reader_count_elements (reader); i < elements; i++) {
Packit 4b6dd7
			GDataEntry *entry;
Packit 4b6dd7
			GType entry_type;
Packit 4b6dd7
Packit 4b6dd7
			json_reader_read_element (reader, i);
Packit 4b6dd7
Packit 4b6dd7
			/* Allow @data to be %NULL, and assume we're parsing a vanilla feed, so that we can test #GDataFeed in tests/general.c.
Packit 4b6dd7
			 * A little hacky, but not too much so, and valuable for testing. */
Packit 4b6dd7
			entry_type = (data != NULL) ? data->entry_type : GDATA_TYPE_ENTRY;
Packit 4b6dd7
Packit 4b6dd7
			/* Parse the node, passing it the reader cursor. */
Packit 4b6dd7
			entry = GDATA_ENTRY (_gdata_parsable_new_from_json_node (entry_type, reader, NULL, error));
Packit 4b6dd7
			if (entry == NULL) {
Packit 4b6dd7
				json_reader_end_element (reader);
Packit 4b6dd7
				return FALSE;
Packit 4b6dd7
			}
Packit 4b6dd7
Packit 4b6dd7
			/* Calls the callbacks in the main thread */
Packit 4b6dd7
			if (data != NULL)
Packit 4b6dd7
				_gdata_feed_call_progress_callback (self, data, entry);
Packit 4b6dd7
			_gdata_feed_add_entry (self, entry);
Packit 4b6dd7
			g_object_unref (entry);
Packit 4b6dd7
Packit 4b6dd7
			json_reader_end_element (reader);
Packit 4b6dd7
		}
Packit 4b6dd7
	} else if (g_strcmp0 (json_reader_get_member_name (reader), "selfLink") == 0) {
Packit 4b6dd7
		GDataLink *_link;
Packit 4b6dd7
		const gchar *uri;
Packit 4b6dd7
Packit 4b6dd7
		/* Empty URI? */
Packit 4b6dd7
		uri = json_reader_get_string_value (reader);
Packit 4b6dd7
		if (uri == NULL || *uri == '\0') {
Packit 4b6dd7
			return gdata_parser_error_required_json_content_missing (reader, error);
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		_link = gdata_link_new (uri, GDATA_LINK_SELF);
Packit 4b6dd7
		_gdata_feed_add_link (self, _link);
Packit 4b6dd7
		g_object_unref (_link);
Packit 4b6dd7
	} else if (g_strcmp0 (json_reader_get_member_name (reader), "kind") == 0) {
Packit 4b6dd7
		/* Ignore. */
Packit 4b6dd7
	} else if (g_strcmp0 (json_reader_get_member_name (reader), "etag") == 0) {
Packit 4b6dd7
		GDATA_FEED (parsable)->priv->etag = g_strdup (json_reader_get_string_value (reader));
Packit 4b6dd7
	} else if (g_strcmp0 (json_reader_get_member_name (reader), "nextPageToken") == 0) {
Packit 4b6dd7
		GDATA_FEED (parsable)->priv->next_page_token = g_strdup (json_reader_get_string_value (reader));
Packit 4b6dd7
	} else {
Packit 4b6dd7
		return GDATA_PARSABLE_CLASS (gdata_feed_parent_class)->parse_json (parsable, reader, user_data, error);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
post_parse_json (GDataParsable *parsable, gpointer user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeedPrivate *priv = GDATA_FEED (parsable)->priv;
Packit 4b6dd7
Packit 4b6dd7
	/* Reverse our lists of stuff. */
Packit 4b6dd7
	priv->entries = g_list_reverse (priv->entries);
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/* Internal helper method to set these properties. */
Packit 4b6dd7
void
Packit 4b6dd7
_gdata_feed_set_page_info (GDataFeed *self, guint total_results,
Packit 4b6dd7
                           guint items_per_page)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_FEED (self));
Packit 4b6dd7
Packit 4b6dd7
	self->priv->total_results = total_results;
Packit 4b6dd7
	self->priv->items_per_page = items_per_page;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/*
Packit 4b6dd7
 * _gdata_feed_new:
Packit 4b6dd7
 * @feed_type: the type of #GDataFeed subclass
Packit 4b6dd7
 * @title: the feed's title
Packit 4b6dd7
 * @id: the feed's ID
Packit 4b6dd7
 * @updated: when the feed was last updated
Packit 4b6dd7
 *
Packit 4b6dd7
 * Creates a new #GDataFeed or subclass with the bare minimum of data to be
Packit 4b6dd7
 * valid.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: a new #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.17.0
Packit 4b6dd7
 */
Packit 4b6dd7
GDataFeed *
Packit 4b6dd7
_gdata_feed_new (GType feed_type,
Packit 4b6dd7
                 const gchar *title,
Packit 4b6dd7
                 const gchar *id,
Packit 4b6dd7
                 gint64 updated)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataFeed *feed;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (feed_type, GDATA_TYPE_FEED), NULL);
Packit 4b6dd7
	g_return_val_if_fail (title != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (id != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (updated >= 0, NULL);
Packit 4b6dd7
Packit 4b6dd7
	feed = g_object_new (feed_type, NULL);
Packit 4b6dd7
	feed->priv->title = g_strdup (title);
Packit 4b6dd7
	feed->priv->id = g_strdup (id);
Packit 4b6dd7
	feed->priv->updated = updated;
Packit 4b6dd7
Packit 4b6dd7
	return feed;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
GDataFeed *
Packit 4b6dd7
_gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType entry_type,
Packit 4b6dd7
                          GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	ParseData *data;
Packit 4b6dd7
	GDataFeed *feed;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (feed_type, GDATA_TYPE_FEED), NULL);
Packit 4b6dd7
	g_return_val_if_fail (xml != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY), NULL);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	data = _gdata_feed_parse_data_new (entry_type, progress_callback, progress_user_data);
Packit 4b6dd7
	feed = GDATA_FEED (_gdata_parsable_new_from_xml (feed_type, xml, length, data, error));
Packit 4b6dd7
	_gdata_feed_parse_data_free (data);
Packit 4b6dd7
Packit 4b6dd7
	return feed;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
GDataFeed *
Packit 4b6dd7
_gdata_feed_new_from_json (GType feed_type, const gchar *json, gint length, GType entry_type,
Packit 4b6dd7
                          GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	ParseData *data;
Packit 4b6dd7
	GDataFeed *feed;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (feed_type, GDATA_TYPE_FEED), NULL);
Packit 4b6dd7
	g_return_val_if_fail (json != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY), NULL);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	data = _gdata_feed_parse_data_new (entry_type, progress_callback, progress_user_data);
Packit 4b6dd7
	feed = GDATA_FEED (_gdata_parsable_new_from_json (feed_type, json, length, data, error));
Packit 4b6dd7
	_gdata_feed_parse_data_free (data);
Packit 4b6dd7
Packit 4b6dd7
	return feed;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_entries:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns a list of the entries contained in this feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (element-type GData.Entry) (transfer none): a #GList of #GDataEntrys
Packit 4b6dd7
 */
Packit 4b6dd7
GList *
Packit 4b6dd7
gdata_feed_get_entries (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->entries;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gint
Packit 4b6dd7
entry_compare_cb (const GDataEntry *entry, const gchar *id)
Packit 4b6dd7
{
Packit 4b6dd7
	return strcmp (gdata_entry_get_id (GDATA_ENTRY (entry)), id);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_look_up_entry:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 * @id: the entry's ID
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the entry in the feed with the given @id, if found.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer none): the #GDataEntry, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.2.0
Packit 4b6dd7
 */
Packit 4b6dd7
GDataEntry *
Packit 4b6dd7
gdata_feed_look_up_entry (GDataFeed *self, const gchar *id)
Packit 4b6dd7
{
Packit 4b6dd7
	GList *element;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	g_return_val_if_fail (id != NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	element = g_list_find_custom (self->priv->entries, id, (GCompareFunc) entry_compare_cb);
Packit 4b6dd7
	if (element == NULL)
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	return GDATA_ENTRY (element->data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_categories:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns a list of the categories listed in this feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (element-type GData.Category) (transfer none): a #GList of #GDataCategorys
Packit 4b6dd7
 */
Packit 4b6dd7
GList *
Packit 4b6dd7
gdata_feed_get_categories (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->categories;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
_gdata_feed_add_category (GDataFeed *self, GDataCategory *category)
Packit 4b6dd7
{
Packit 4b6dd7
	self->priv->categories = g_list_prepend (self->priv->categories, g_object_ref (category));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_links:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns a list of the links listed in this feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (element-type GData.Link) (transfer none): a #GList of #GDataLinks
Packit 4b6dd7
 */
Packit 4b6dd7
GList *
Packit 4b6dd7
gdata_feed_get_links (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->links;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gint
Packit 4b6dd7
link_compare_cb (const GDataLink *_link, const gchar *rel)
Packit 4b6dd7
{
Packit 4b6dd7
	return strcmp (gdata_link_get_relation_type ((GDataLink*) _link), rel);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_look_up_link:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 * @rel: the value of the #GDataLink:relation-type property of the desired link
Packit 4b6dd7
 *
Packit 4b6dd7
 * Looks up a link by #GDataLink:relation-type value from the list of links in the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer none): a #GDataLink, or %NULL if one was not found
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.1.1
Packit 4b6dd7
 */
Packit 4b6dd7
GDataLink *
Packit 4b6dd7
gdata_feed_look_up_link (GDataFeed *self, const gchar *rel)
Packit 4b6dd7
{
Packit 4b6dd7
	GList *element;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	g_return_val_if_fail (rel != NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	element = g_list_find_custom (self->priv->links, rel, (GCompareFunc) link_compare_cb);
Packit 4b6dd7
	if (element == NULL)
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	return GDATA_LINK (element->data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
void
Packit 4b6dd7
_gdata_feed_add_link (GDataFeed *self, GDataLink *_link)
Packit 4b6dd7
{
Packit 4b6dd7
	self->priv->links = g_list_prepend (self->priv->links, g_object_ref (_link));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_authors:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns a list of the authors listed in this feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (element-type GData.Author) (transfer none): a #GList of #GDataAuthors
Packit 4b6dd7
 */
Packit 4b6dd7
GList *
Packit 4b6dd7
gdata_feed_get_authors (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->authors;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
_gdata_feed_add_author (GDataFeed *self, GDataAuthor *author)
Packit 4b6dd7
{
Packit 4b6dd7
	self->priv->authors = g_list_prepend (self->priv->authors, g_object_ref (author));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_title:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the title of the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's title
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_title (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->title;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_subtitle:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the subtitle of the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's subtitle, or %NULL
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_subtitle (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->subtitle;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_id:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the feed's unique and permanent URN ID.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's ID
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_id (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->id;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_etag:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the feed's unique ETag for this version.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's ETag
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.2.0
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_etag (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->etag;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_updated:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Gets the time the feed was last updated.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the UNIX timestamp for the time the feed was last updated
Packit 4b6dd7
 */
Packit 4b6dd7
gint64
Packit 4b6dd7
gdata_feed_get_updated (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), -1);
Packit 4b6dd7
	return self->priv->updated;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_logo:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the logo URI of the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's logo URI, or %NULL
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_logo (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->logo;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_icon:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the icon URI of the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's icon URI, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.6.0
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_icon (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->icon;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_generator:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns details about the software which generated the feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer none): a #GDataGenerator, or %NULL
Packit 4b6dd7
 */
Packit 4b6dd7
GDataGenerator *
Packit 4b6dd7
gdata_feed_get_generator (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->generator;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_rights:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the rights pertaining to the entire feed, or %NULL if not set.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the feed's rights information
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.7.0
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_rights (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->rights;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_items_per_page:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the number of items per results page feed.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the number of items per results page feed, or 0
Packit 4b6dd7
 */
Packit 4b6dd7
guint
Packit 4b6dd7
gdata_feed_get_items_per_page (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), 0);
Packit 4b6dd7
	return self->priv->items_per_page;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_start_index:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the one-based start index of the results feed in the result set.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the one-based start index, or 0
Packit 4b6dd7
 */
Packit 4b6dd7
guint
Packit 4b6dd7
gdata_feed_get_start_index (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), 0);
Packit 4b6dd7
	return self->priv->start_index;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_total_results:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the total number of results in the result set, including results on other
Packit 4b6dd7
 * pages. If this is zero, the total number is unknown.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the total number of results, or 0
Packit 4b6dd7
 */
Packit 4b6dd7
guint
Packit 4b6dd7
gdata_feed_get_total_results (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), 0);
Packit 4b6dd7
	return self->priv->total_results;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_feed_get_next_page_token:
Packit 4b6dd7
 * @self: a #GDataFeed
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the next page token for a query result, or %NULL if not set.
Packit 4b6dd7
 * This is #GDataFeed:next-page-token. The page token might not be set if there
Packit 4b6dd7
 * is no next page, or if this service does not use token based paging (for
Packit 4b6dd7
 * example, if it uses page number or offset based paging instead). Most more
Packit 4b6dd7
 * recent services use token based paging.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (nullable): the next page token
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.17.7
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_feed_get_next_page_token (GDataFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_FEED (self), NULL);
Packit 4b6dd7
	return self->priv->next_page_token;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
void
Packit 4b6dd7
_gdata_feed_add_entry (GDataFeed *self, GDataEntry *entry)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_FEED (self));
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_ENTRY (entry));
Packit 4b6dd7
	self->priv->entries = g_list_prepend (self->priv->entries, g_object_ref (entry));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
gpointer
Packit 4b6dd7
_gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progress_callback, gpointer progress_user_data)
Packit 4b6dd7
{
Packit 4b6dd7
	ParseData *data;
Packit 4b6dd7
	data = g_slice_new (ParseData);
Packit 4b6dd7
	data->entry_type = entry_type;
Packit 4b6dd7
	data->progress_callback = progress_callback;
Packit 4b6dd7
	data->progress_user_data = progress_user_data;
Packit 4b6dd7
	data->entry_i = 0;
Packit 4b6dd7
Packit 4b6dd7
	return data;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
void
Packit 4b6dd7
_gdata_feed_parse_data_free (gpointer data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_slice_free (ParseData, data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
progress_callback_idle (ProgressCallbackData *data)
Packit 4b6dd7
{
Packit 4b6dd7
	data->progress_callback (data->entry, data->entry_i, data->total_results, data->progress_user_data);
Packit 4b6dd7
Packit 4b6dd7
	return G_SOURCE_REMOVE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
progress_callback_data_free (ProgressCallbackData *data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_object_unref (data->entry);
Packit 4b6dd7
	g_slice_free (ProgressCallbackData, data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
void
Packit 4b6dd7
_gdata_feed_call_progress_callback (GDataFeed *self, gpointer user_data, GDataEntry *entry)
Packit 4b6dd7
{
Packit 4b6dd7
	ParseData *data = user_data;
Packit 4b6dd7
Packit 4b6dd7
	if (data->progress_callback != NULL) {
Packit 4b6dd7
		ProgressCallbackData *progress_data;
Packit 4b6dd7
Packit 4b6dd7
		/* Build the data for the callback */
Packit 4b6dd7
		progress_data = g_slice_new (ProgressCallbackData);
Packit 4b6dd7
		progress_data->progress_callback = data->progress_callback;
Packit 4b6dd7
		progress_data->progress_user_data = data->progress_user_data;
Packit 4b6dd7
		progress_data->entry = g_object_ref (entry);
Packit 4b6dd7
		progress_data->entry_i = data->entry_i;
Packit 4b6dd7
		progress_data->total_results = MIN (self->priv->items_per_page, self->priv->total_results);
Packit 4b6dd7
Packit 4b6dd7
		/* Send the callback; use G_PRIORITY_DEFAULT rather than G_PRIORITY_DEFAULT_IDLE
Packit 4b6dd7
		 * to contend with the priorities used by the callback functions in GAsyncResult */
Packit 4b6dd7
		g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT,
Packit 4b6dd7
		                            (GSourceFunc) progress_callback_idle,
Packit 4b6dd7
		                            progress_data,
Packit 4b6dd7
		                            (GDestroyNotify) progress_callback_data_free);
Packit 4b6dd7
	}
Packit 4b6dd7
	data->entry_i++;
Packit 4b6dd7
}
Packit 4b6dd7