|
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 |
}
|