Blame gdata/gdata-batch-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 2010 <philip@tecnocode.co.uk>
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-batch-feed
Packit 4b6dd7
 * @short_description: GData batch feed helper object
Packit 4b6dd7
 * @stability: Stable
Packit 4b6dd7
 * @include: gdata/gdata-batch-feed.h
Packit 4b6dd7
 *
Packit 4b6dd7
 * Helper class to parse the feed returned from a batch operation and instantiate different types of #GDataEntry according to the batch operation
Packit 4b6dd7
 * associated with each one. It's tightly coupled with #GDataBatchOperation, and isn't exposed publicly.
Packit 4b6dd7
 *
Packit 4b6dd7
 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/docs/batch.html">online documentation</ulink>.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.7.0
Packit 4b6dd7
 */
Packit 4b6dd7
Packit 4b6dd7
#include <glib.h>
Packit 4b6dd7
#include <libxml/parser.h>
Packit 4b6dd7
Packit 4b6dd7
#include "gdata-batch-feed.h"
Packit 4b6dd7
#include "gdata-private.h"
Packit 4b6dd7
#include "gdata-batch-private.h"
Packit 4b6dd7
Packit 4b6dd7
static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
Packit 4b6dd7
Packit 4b6dd7
G_DEFINE_TYPE (GDataBatchFeed, gdata_batch_feed, GDATA_TYPE_FEED)
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_batch_feed_class_init (GDataBatchFeedClass *klass)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
Packit 4b6dd7
	parsable_class->parse_xml = parse_xml;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_batch_feed_init (GDataBatchFeed *self)
Packit 4b6dd7
{
Packit 4b6dd7
	/* Nothing to see here */
Packit 4b6dd7
}
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
	GDataBatchOperation *operation = GDATA_BATCH_OPERATION (user_data);
Packit 4b6dd7
Packit 4b6dd7
	if (xmlStrcmp (node->name, (xmlChar*) "entry") == 0) {
Packit 4b6dd7
		GDataEntry *entry = NULL;
Packit 4b6dd7
		xmlBuffer *status_response = NULL;
Packit 4b6dd7
		gchar *status_reason = NULL;
Packit 4b6dd7
		guint id = 0, status_code = 0;
Packit 4b6dd7
		xmlNode *entry_node;
Packit 4b6dd7
		BatchOperation *op;
Packit 4b6dd7
Packit 4b6dd7
		status_response = xmlBufferCreate ();
Packit 4b6dd7
Packit 4b6dd7
		/* Parse the child nodes of the <entry> to get the batch namespace elements containing information about this operation */
Packit 4b6dd7
		for (entry_node = node->children; entry_node != NULL; entry_node = entry_node->next) {
Packit 4b6dd7
			/* We have to be careful about namespaces here, and we can skip text nodes (since none of the nodes we're looking for
Packit 4b6dd7
			 * are text nodes) */
Packit 4b6dd7
			if (entry_node->type == XML_TEXT_NODE ||
Packit 4b6dd7
			    gdata_parser_is_namespace (entry_node, "http://schemas.google.com/gdata/batch") == FALSE)
Packit 4b6dd7
				continue;
Packit 4b6dd7
Packit 4b6dd7
			if (xmlStrcmp (entry_node->name, (xmlChar*) "id") == 0) {
Packit 4b6dd7
				/* batch:id */
Packit 4b6dd7
				xmlChar *id_string = xmlNodeListGetString (doc, entry_node->children, TRUE);
Packit 4b6dd7
				id = g_ascii_strtoull ((char*) id_string, NULL, 10);
Packit 4b6dd7
				xmlFree (id_string);
Packit 4b6dd7
			} else if (xmlStrcmp (entry_node->name, (xmlChar*) "status") == 0) {
Packit 4b6dd7
				/* batch:status */
Packit 4b6dd7
				xmlChar *status_code_string;
Packit 4b6dd7
				xmlNode *child_node;
Packit 4b6dd7
Packit 4b6dd7
				status_code_string = xmlGetProp (entry_node, (xmlChar*) "code");
Packit 4b6dd7
				status_code = g_ascii_strtoull ((char*) status_code_string, NULL, 10);
Packit 4b6dd7
				xmlFree (status_code_string);
Packit 4b6dd7
Packit 4b6dd7
				status_reason = (gchar*) xmlGetProp (entry_node, (xmlChar*) "reason");
Packit 4b6dd7
Packit 4b6dd7
				/* Dump the content of the status node, since it's service-specific, and could be anything from plain text to XML */
Packit 4b6dd7
				for (child_node = entry_node->children; child_node != NULL; child_node = child_node->next)
Packit 4b6dd7
					xmlNodeDump (status_response, doc, child_node, 0, 0);
Packit 4b6dd7
			}
Packit 4b6dd7
Packit 4b6dd7
			if (id != 0 && status_code != 0)
Packit 4b6dd7
				break;
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		/* Check we've got all the required data */
Packit 4b6dd7
		if (id == 0) {
Packit 4b6dd7
			gdata_parser_error_required_element_missing ("batch:id", "entry", error);
Packit 4b6dd7
			goto error;
Packit 4b6dd7
		} else if (status_code == 0) {
Packit 4b6dd7
			gdata_parser_error_required_element_missing ("batch:status", "entry", error);
Packit 4b6dd7
			goto error;
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		op = _gdata_batch_operation_get_operation (operation, id);
Packit 4b6dd7
Packit 4b6dd7
		/* Check for errors */
Packit 4b6dd7
		if (SOUP_STATUS_IS_SUCCESSFUL (status_code) == FALSE) {
Packit 4b6dd7
			/* Handle the error */
Packit 4b6dd7
			GDataService *service = gdata_batch_operation_get_service (operation);
Packit 4b6dd7
			GDataServiceClass *klass = GDATA_SERVICE_GET_CLASS (service);
Packit 4b6dd7
			GError *child_error = NULL;
Packit 4b6dd7
Packit 4b6dd7
			/* Parse the error (it's returned in a service-specific format */
Packit 4b6dd7
			g_assert (klass->parse_error_response != NULL);
Packit 4b6dd7
			klass->parse_error_response (service, (GDataOperationType) op->type, status_code,
Packit 4b6dd7
			                             status_reason, (gchar*) xmlBufferContent (status_response),
Packit 4b6dd7
			                             xmlBufferLength (status_response), &child_error);
Packit 4b6dd7
Packit 4b6dd7
			/* Run the operation's callback. This takes ownership of @child_error. */
Packit 4b6dd7
			_gdata_batch_operation_run_callback (operation, op, NULL, child_error);
Packit 4b6dd7
Packit 4b6dd7
			g_free (status_reason);
Packit 4b6dd7
			xmlBufferFree (status_response);
Packit 4b6dd7
Packit 4b6dd7
			/* We return TRUE because we parsed the XML successfully; despite it being an error that we parsed */
Packit 4b6dd7
			return TRUE;
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		/* If there wasn't an error, parse the resulting GDataEntry and run the operation's callback */
Packit 4b6dd7
		if (op->type == GDATA_BATCH_OPERATION_QUERY)
Packit 4b6dd7
			entry = GDATA_ENTRY (_gdata_parsable_new_from_xml_node (op->entry_type, doc, node, NULL, error));
Packit 4b6dd7
		else if (op->type != GDATA_BATCH_OPERATION_DELETION)
Packit 4b6dd7
			entry = GDATA_ENTRY (_gdata_parsable_new_from_xml_node (G_OBJECT_TYPE (op->entry), doc, node, NULL, error));
Packit 4b6dd7
Packit 4b6dd7
		if (op->type != GDATA_BATCH_OPERATION_DELETION && entry == NULL)
Packit 4b6dd7
			goto error;
Packit 4b6dd7
Packit 4b6dd7
		_gdata_batch_operation_run_callback (operation, op, entry, NULL);
Packit 4b6dd7
Packit 4b6dd7
		if (entry != NULL)
Packit 4b6dd7
			g_object_unref (entry);
Packit 4b6dd7
Packit 4b6dd7
		g_free (status_reason);
Packit 4b6dd7
		xmlBufferFree (status_response);
Packit 4b6dd7
Packit 4b6dd7
		return TRUE;
Packit 4b6dd7
Packit 4b6dd7
error:
Packit 4b6dd7
		g_free (status_reason);
Packit 4b6dd7
		xmlBufferFree (status_response);
Packit 4b6dd7
Packit 4b6dd7
		return FALSE;
Packit 4b6dd7
	} else if (GDATA_PARSABLE_CLASS (gdata_batch_feed_parent_class)->parse_xml (parsable, doc, node, user_data, error) == FALSE) {
Packit 4b6dd7
		/* Error! */
Packit 4b6dd7
		return FALSE;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}