[libgdata/wip/calendar-v3: 1/3] calendar: WIP work to port to the v3 API



commit d0fd1f22a15f0e47d80490ebd588287c4cac6bd0
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Dec 14 23:14:31 2014 +0000

    calendar: WIP work to port to the v3 API
    
    https://bugzilla.gnome.org/show_bug.cgi?id=664353

 gdata/gdata-entry.c                               |    2 +
 gdata/gdata-feed.c                                |    4 +-
 gdata/gdata-oauth2-authorizer.c                   |    9 +
 gdata/gdata-parsable.c                            |   14 +-
 gdata/gdata-parser.c                              |   91 +++++++++++
 gdata/gdata-parser.h                              |    8 +
 gdata/services/calendar/gdata-calendar-calendar.c |  179 ++++++++++-----------
 gdata/services/calendar/gdata-calendar-feed.c     |   73 ++-------
 gdata/services/calendar/gdata-calendar-service.c  |   88 ++++++----
 gdata/tests/calendar.c                            |  169 ++++++++++++--------
 10 files changed, 376 insertions(+), 261 deletions(-)
---
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index be242e5..c4430ea 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -884,10 +884,12 @@ gdata_entry_add_category (GDataEntry *self, GDataCategory *category)
                GDataEntryClass *klass = GDATA_ENTRY_GET_CLASS (self);
                GList *element;
 
+#if 0
                if (klass->kind_term != NULL && g_strcmp0 (gdata_category_get_term (category), 
klass->kind_term) != 0) {
                        g_warning ("Adding a kind category term, '%s', to an entry of kind '%s'.",
                                   gdata_category_get_term (category), klass->kind_term);
                }
+#endif
 
                /* If it is a kind category, remove the entry’s existing kind category to allow the new one
                 * to be added. This is necessary because the existing category was set in
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index 68ed7a0..9609c8f 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -612,8 +612,10 @@ parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GEr
 
                        /* Parse the node, passing it the reader cursor. */
                        entry = GDATA_ENTRY (_gdata_parsable_new_from_json_node (entry_type, reader, NULL, 
error));
-                       if (entry == NULL)
+                       if (entry == NULL) {
+                               json_reader_end_element (reader);
                                return FALSE;
+                       }
 
                        /* Calls the callbacks in the main thread */
                        if (data != NULL)
diff --git a/gdata/gdata-oauth2-authorizer.c b/gdata/gdata-oauth2-authorizer.c
index 3117b9d..52d6614 100644
--- a/gdata/gdata-oauth2-authorizer.c
+++ b/gdata/gdata-oauth2-authorizer.c
@@ -1019,6 +1019,15 @@ parse_grant_error (GDataOAuth2Authorizer *self, guint status,
        /* Parse the error response */
        parser = json_parser_new ();
 
+       if (response_body == NULL) {
+               g_clear_error (&child_error);
+               g_set_error_literal (&child_error, GDATA_SERVICE_ERROR,
+                                    GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
+                                    _("The server returned a malformed response."));
+
+               goto done;
+       }
+
        json_parser_load_from_data (parser, response_body, length,
                                    &child_error);
 
diff --git a/gdata/gdata-parsable.c b/gdata/gdata-parsable.c
index 242f6b8..e1822ec 100644
--- a/gdata/gdata-parsable.c
+++ b/gdata/gdata-parsable.c
@@ -209,17 +209,20 @@ _json_reader_dup_current_node (JsonReader *reader)
                }
        } else if (json_reader_is_object (reader) == TRUE) {
                /* Object nodes require deep copies. */
-               gint i, members;
+               gint i;
+               gchar **members;
                JsonObject *obj;
 
                obj = json_object_new ();
 
-               for (i = 0, members = json_reader_count_members (reader); i < members; i++) {
-                       json_reader_read_element (reader, i);
-                       json_object_set_member (obj, json_reader_get_member_name (reader), 
_json_reader_dup_current_node (reader));
-                       json_reader_end_element (reader);
+               for (i = 0, members = json_reader_list_members (reader); members[i] != NULL; i++) {
+                       json_reader_read_member (reader, members[i]);
+                       json_object_set_member (obj, members[i], _json_reader_dup_current_node (reader));
+                       json_reader_end_member (reader);
                }
 
+               g_strfreev (members);
+
                value = json_node_new (JSON_NODE_OBJECT);
                json_node_take_object (value, obj);
        } else if (json_reader_is_array (reader) == TRUE) {
@@ -526,6 +529,7 @@ _gdata_parsable_new_from_json_node (GType parsable_type, JsonReader *reader, gpo
                g_return_val_if_fail (json_reader_read_element (reader, i), NULL);
 
                if (klass->parse_json (parsable, reader, user_data, error) == FALSE) {
+                       json_reader_end_element (reader);
                        g_object_unref (parsable);
                        return NULL;
                }
diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c
index 0e655a5..bde97c9 100644
--- a/gdata/gdata-parser.c
+++ b/gdata/gdata-parser.c
@@ -29,6 +29,7 @@
 
 #include "gdata-parser.h"
 #include "gdata-service.h"
+#include "gdata-types.h"
 #include "gdata-private.h"
 
 static gchar *
@@ -916,6 +917,96 @@ gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_n
        return TRUE;
 }
 
+/*
+ * gdata_parser_color_from_json_member:
+ * @reader: #JsonReader cursor object to read JSON node from
+ * @element_name: the name of the element to parse
+ * @options: a bitwise combination of parsing options from #GDataParserOptions,
+ *   or %P_NONE
+ * @output: (out caller-allocates): the return location for the parsed colour
+ *   value
+ * @success: the return location for a value which is %TRUE if the colour was
+ *   parsed successfully, %FALSE if an error was encountered, and undefined if
+ *   @element didn't match @element_name
+ * @error: a #GError, or %NULL
+ *
+ * TODO
+ * Gets the colour value of @element if its name is @element_name, subject to various checks specified by 
@options. It expects the text content
+ * of @element to be a date or time value in ISO 8601 format. The returned time value will be a UNIX 
timestamp (seconds since the epoch).
+ *
+ * If @element doesn't match @element_name, %FALSE will be returned, @error will be unset and @success will 
be unset.
+ *
+ * If @element matches @element_name but one of the checks specified by @options fails, %TRUE will be 
returned, @error will be set to a
+ * %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error and @success will be set to %FALSE.
+ *
+ * If @element matches @element_name and all of the checks specified by @options pass, %TRUE will be 
returned, @error will be unset and
+ * @success will be set to %TRUE.
+ *
+ * The reason for returning the success of the parsing in @success is so that calls to 
gdata_parser_int64_time_from_element() can be chained
+ * together in a large "or" statement based on their return values, for the purposes of determining whether 
any of the calls matched
+ * a given @element. If any of the calls to gdata_parser_int64_time_from_element() return %TRUE, the value 
of @success can be examined.
+ *
+ * Return value: %TRUE if @element matched @element_name, %FALSE otherwise
+ *
+ * Since: UNRELEASED
+ */
+gboolean
+gdata_parser_color_from_json_member (JsonReader *reader,
+                                     const gchar *member_name,
+                                     GDataParserOptions options,
+                                     GDataColor *output,
+                                     gboolean *success,
+                                     GError **error)
+{
+       const gchar *text;
+       GDataColor colour;
+       const GError *child_error = NULL;
+
+       /* Check if there's such an element */
+       if (g_strcmp0 (json_reader_get_member_name (reader), member_name) != 0) {
+               return FALSE;
+       }
+
+       /* Check if the output colour has already been set. The JSON parser
+        * guarantees this can't happen. */
+       g_assert (!(options & P_NO_DUPES) ||
+                 (output->red == 0 && output->green == 0 && output->blue == 0));
+
+       /* Get the string and check it for NULLness. Check for errors first. */
+       text = json_reader_get_string_value (reader);
+       child_error = json_reader_get_error (reader);
+       if (child_error != NULL) {
+               *success = parser_error_from_json_error (reader, child_error, error);
+               return TRUE;
+       } else if (options & P_REQUIRED && (text == NULL || *text == '\0')) {
+               *success = gdata_parser_error_required_json_content_missing (reader, error);
+               return TRUE;
+       }
+
+       /* Attempt to parse the string as a hexadecimal colour. */
+       if (gdata_color_from_hexadecimal (text, &colour) == FALSE) {
+               /* Error */
+               g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
+                            /* Translators: the first parameter is the name of an XML element (including the 
angle brackets
+                             * ("<" and ">"), and the second parameter is the erroneous value (which was not 
in hexadecimal
+                             * RGB format).
+                             *
+                             * For example:
+                             *  The content of a <entry/gCal:color> element ("00FG56") was not in 
hexadecimal RGB format. */
+                            _("The content of a %s element (\"%s\") was not in hexadecimal RGB format."),
+                            member_name, text);
+               *success = FALSE;
+
+               return TRUE;
+       }
+
+       /* Success! */
+       *output = colour;
+       *success = TRUE;
+
+       return TRUE;
+}
+
 void
 gdata_parser_string_append_escaped (GString *xml_string, const gchar *pre, const gchar *element_content, 
const gchar *post)
 {
diff --git a/gdata/gdata-parser.h b/gdata/gdata-parser.h
index 2c5ad2f..31567f7 100644
--- a/gdata/gdata-parser.h
+++ b/gdata/gdata-parser.h
@@ -20,6 +20,7 @@
 #include <glib.h>
 
 #include "gdata-parsable.h"
+#include "gdata-types.h"
 
 #ifndef GDATA_PARSER_H
 #define GDATA_PARSER_H
@@ -90,6 +91,13 @@ gboolean gdata_parser_int64_time_from_json_member (JsonReader *reader, const gch
                                                    gint64 *output, gboolean *success, GError **error);
 gboolean gdata_parser_boolean_from_json_member (JsonReader *reader, const gchar *member_name, 
GDataParserOptions options,
                                                 gboolean *output, gboolean *success, GError **error);
+gboolean
+gdata_parser_color_from_json_member (JsonReader *reader,
+                                     const gchar *member_name,
+                                     GDataParserOptions options,
+                                     GDataColor *output,
+                                     gboolean *success,
+                                     GError **error);
 
 void gdata_parser_string_append_escaped (GString *xml_string, const gchar *pre, const gchar 
*element_content, const gchar *post);
 gchar *gdata_parser_utf8_trim_whitespace (const gchar *s) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
diff --git a/gdata/services/calendar/gdata-calendar-calendar.c 
b/gdata/services/calendar/gdata-calendar-calendar.c
index 93f1453..da0135b 100644
--- a/gdata/services/calendar/gdata-calendar-calendar.c
+++ b/gdata/services/calendar/gdata-calendar-calendar.c
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
  * GData Client
- * Copyright (C) Philip Withnall 2009–2010 <philip tecnocode co uk>
+ * Copyright (C) Philip Withnall 2009, 2010, 2014 <philip tecnocode co uk>
  *
  * GData Client is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -32,6 +32,8 @@
  * For more details of Google Calendar's GData API, see the <ulink type="http" 
url="http://code.google.com/apis/calendar/docs/2.0/reference.html";>
  * online documentation</ulink>.
  *
+ * TODO: update examples, etags
+ *
  * <example>
  *     <title>Listing Calendars</title>
  *     <programlisting>
@@ -77,7 +79,6 @@
 #include <config.h>
 #include <glib.h>
 #include <glib/gi18n-lib.h>
-#include <libxml/parser.h>
 #include <string.h>
 
 #include "gdata-calendar-calendar.h"
@@ -93,9 +94,9 @@ static GObject *gdata_calendar_calendar_constructor (GType type, guint n_constru
 static void gdata_calendar_calendar_finalize (GObject *object);
 static void gdata_calendar_calendar_get_property (GObject *object, guint property_id, GValue *value, 
GParamSpec *pspec);
 static void gdata_calendar_calendar_set_property (GObject *object, guint property_id, const GValue *value, 
GParamSpec *pspec);
-static void get_xml (GDataParsable *parsable, GString *xml_string);
-static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError 
**error);
-static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
+static void get_json (GDataParsable *parsable, JsonBuilder *builder);
+static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
+static const gchar *get_content_type (void);
 
 struct _GDataCalendarCalendarPrivate {
        gchar *timezone;
@@ -136,17 +137,17 @@ gdata_calendar_calendar_class_init (GDataCalendarCalendarClass *klass)
        gobject_class->get_property = gdata_calendar_calendar_get_property;
        gobject_class->finalize = gdata_calendar_calendar_finalize;
 
-       parsable_class->parse_xml = parse_xml;
-       parsable_class->get_xml = get_xml;
-       parsable_class->get_namespaces = get_namespaces;
+       parsable_class->parse_json = parse_json;
+       parsable_class->get_json = get_json;
+       parsable_class->get_content_type = get_content_type;
 
-       entry_class->kind_term = "http://schemas.google.com/gCal/2005#calendarmeta";;
+       entry_class->kind_term = "calendar#calendarListEntry";
 
        /**
         * GDataCalendarCalendar:timezone:
         *
         * The timezone in which the calendar's times are given. This is a timezone name in tz database 
notation: <ulink type="http"
-        * url="http://en.wikipedia.org/wiki/Tz_database#Names_of_time_zones";>reference</ulink>.
+        * url="http://en.wikipedia.org/wiki/Tz_database#Names_of_time_zones";>reference</ulink>. TODO: is it?
         **/
        g_object_class_install_property (gobject_class, PROP_TIMEZONE,
                                         g_param_spec_string ("timezone",
@@ -182,7 +183,7 @@ gdata_calendar_calendar_class_init (GDataCalendarCalendarClass *klass)
         * GDataCalendarCalendar:color:
         *
         * The color used to highlight the calendar in the user's browser. This must be one of a limited set 
of colors listed in the
-        * <ulink type="http" 
url="http://code.google.com/apis/calendar/data/2.0/reference.html#gCalcolor";>online documentation</ulink>.
+        * <ulink type="http" 
url="http://code.google.com/apis/calendar/data/2.0/reference.html#gCalcolor";>online documentation</ulink>. 
TODO
         **/
        g_object_class_install_property (gobject_class, PROP_COLOR,
                                         g_param_spec_boxed ("color",
@@ -360,113 +361,103 @@ gdata_calendar_calendar_set_property (GObject *object, guint property_id, const
 }
 
 static gboolean
-parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
 {
        gboolean success;
+       gchar *summary = NULL;
        GDataCalendarCalendar *self = GDATA_CALENDAR_CALENDAR (parsable);
 
-       if (gdata_parser_is_namespace (node, "http://www.w3.org/2007/app";) == TRUE &&
-           gdata_parser_int64_time_from_element (node, "edited", P_REQUIRED | P_NO_DUPES, 
&(self->priv->edited), &success, error) == TRUE) {
-               return success;
-       } else if (gdata_parser_is_namespace (node, "http://schemas.google.com/gCal/2005";) == TRUE) {
-               if (xmlStrcmp (node->name, (xmlChar*) "timezone") == 0) {
-                       /* gCal:timezone */
-                       xmlChar *_timezone = xmlGetProp (node, (xmlChar*) "value");
-                       if (_timezone == NULL)
-                               return gdata_parser_error_required_property_missing (node, "value", error);
-                       self->priv->timezone = (gchar*) _timezone;
-               } else if (xmlStrcmp (node->name, (xmlChar*) "timesCleaned") == 0) {
-                       /* gCal:timesCleaned */
-                       xmlChar *times_cleaned = xmlGetProp (node, (xmlChar*) "value");
-                       if (times_cleaned == NULL)
-                               return gdata_parser_error_required_property_missing (node, "value", error);
-                       self->priv->times_cleaned = g_ascii_strtoull ((gchar*) times_cleaned, NULL, 10);
-                       xmlFree (times_cleaned);
-               } else if (xmlStrcmp (node->name, (xmlChar*) "hidden") == 0) {
-                       /* gCal:hidden */
-                       if (gdata_parser_boolean_from_property (node, "value", &(self->priv->is_hidden), -1, 
error) == FALSE)
-                               return FALSE;
-               } else if (xmlStrcmp (node->name, (xmlChar*) "color") == 0) {
-                       /* gCal:color */
-                       xmlChar *value;
-                       GDataColor colour;
-
-                       value = xmlGetProp (node, (xmlChar*) "value");
-                       if (value == NULL)
-                               return gdata_parser_error_required_property_missing (node, "value", error);
-                       if (gdata_color_from_hexadecimal ((gchar*) value, &colour) == FALSE) {
-                               /* Error */
-                               g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
-                                            /* Translators: the first parameter is the name of an XML 
element (including the angle brackets
-                                             * ("<" and ">"), and the second parameter is the erroneous 
value (which was not in hexadecimal
-                                             * RGB format).
-                                             *
-                                             * For example:
-                                             *  The content of a <entry/gCal:color> element ("00FG56") was 
not in hexadecimal RGB format. */
-                                            _("The content of a %s element (\"%s\") was not in hexadecimal 
RGB format."),
-                                            "<entry/gCal:color>", value);
-                               xmlFree (value);
-
-                               return FALSE;
-                       }
-
-                       gdata_calendar_calendar_set_color (self, &colour);
-                       xmlFree (value);
-               } else if (xmlStrcmp (node->name, (xmlChar*) "selected") == 0) {
-                       /* gCal:selected */
-                       if (gdata_parser_boolean_from_property (node, "value", &(self->priv->is_selected), 
-1, error) == FALSE)
-                               return FALSE;
-               } else if (xmlStrcmp (node->name, (xmlChar*) "accesslevel") == 0) {
-                       /* gCal:accesslevel */
-                       self->priv->access_level = (gchar*) xmlGetProp (node, (xmlChar*) "value");
-                       if (self->priv->access_level == NULL)
-                               return gdata_parser_error_required_property_missing (node, "value", error);
-               } else {
-                       return GDATA_PARSABLE_CLASS (gdata_calendar_calendar_parent_class)->parse_xml 
(parsable, doc, node, user_data, error);
+       /* TODO: things removed:
+        * edited
+        * timesCleaned
+        *
+        * things not yet implemented
+        * description
+        * location
+        * summaryOverride
+        * colorId
+        * foregroundColor
+        * defaultReminders
+        * notificationSettings
+        * primary
+        * deleted
+        *
+        * TODO: check values for accesslevel
+        */
+
+       if (gdata_parser_string_from_json_member (reader, "timeZone", P_DEFAULT, &self->priv->timezone, 
&success, error) ||
+           gdata_parser_string_from_json_member (reader, "accessRole", P_DEFAULT, &self->priv->access_level, 
&success, error) ||
+           gdata_parser_color_from_json_member (reader, "backgroundColor", P_DEFAULT, &self->priv->colour, 
&success, error) ||
+           gdata_parser_boolean_from_json_member (reader, "hidden", P_DEFAULT, &self->priv->is_hidden, 
&success, error) ||
+           gdata_parser_boolean_from_json_member (reader, "selected", P_DEFAULT, &self->priv->is_selected, 
&success, error) ||
+           gdata_parser_string_from_json_member (reader, "summary", P_DEFAULT, &summary, &success, error)) {
+               if (success) {
+                       gdata_entry_set_title (GDATA_ENTRY (parsable), summary);
                }
+
+               g_free (summary);
+
+               return success;
        } else {
-               return GDATA_PARSABLE_CLASS (gdata_calendar_calendar_parent_class)->parse_xml (parsable, doc, 
node, user_data, error);
+               g_free (summary);
+               return GDATA_PARSABLE_CLASS (gdata_calendar_calendar_parent_class)->parse_json (parsable, 
reader, user_data, error);
        }
 
        return TRUE;
 }
 
 static void
-get_xml (GDataParsable *parsable, GString *xml_string)
+get_json (GDataParsable *parsable, JsonBuilder *builder)
 {
+       const gchar *id, *etag, *title;
        gchar *colour;
        GDataCalendarCalendarPrivate *priv = GDATA_CALENDAR_CALENDAR (parsable)->priv;
 
-       /* Chain up to the parent class */
-       GDATA_PARSABLE_CLASS (gdata_calendar_calendar_parent_class)->get_xml (parsable, xml_string);
+       id = gdata_entry_get_id (GDATA_ENTRY (parsable));
+       if (id != NULL) {
+               json_builder_set_member_name (builder, "id");
+               json_builder_add_string_value (builder, id);
+       }
 
-       /* Add all the Calendar-specific XML */
-       if (priv->timezone != NULL)
-               gdata_parser_string_append_escaped (xml_string, "<gCal:timezone value='", priv->timezone, 
"'/>");
+       json_builder_set_member_name (builder, "kind");
+       json_builder_add_string_value (builder, "calendar#calendar");
 
-       if (priv->is_hidden == TRUE)
-               g_string_append (xml_string, "<gCal:hidden value='true'/>");
-       else
-               g_string_append (xml_string, "<gCal:hidden value='false'/>");
+       /* Add the ETag, if available. */
+       etag = gdata_entry_get_etag (GDATA_ENTRY (parsable));
+       if (etag != NULL) {
+               json_builder_set_member_name (builder, "etag");
+               json_builder_add_string_value (builder, etag);
+       }
+
+       /* Calendar labels titles as ‘summary’. */
+       title = gdata_entry_get_title (GDATA_ENTRY (parsable));
+       if (title != NULL) {
+               json_builder_set_member_name (builder, "summary");
+               json_builder_add_string_value (builder, title);
+       }
+
+       /* Add all the calendar-specific JSON */
+       if (priv->timezone != NULL) {
+               json_builder_set_member_name (builder, "timeZone");
+               json_builder_add_string_value (builder, priv->timezone);
+       }
 
-       colour = gdata_color_to_hexadecimal (&(priv->colour));
-       g_string_append_printf (xml_string, "<gCal:color value='%s'/>", colour);
+       json_builder_set_member_name (builder, "hidden");
+       json_builder_add_boolean_value (builder, priv->is_hidden);
+
+       colour = gdata_color_to_hexadecimal (&priv->colour);
+       json_builder_set_member_name (builder, "backgroundColor");
+       json_builder_add_string_value (builder, colour);
        g_free (colour);
 
-       if (priv->is_selected == TRUE)
-               g_string_append (xml_string, "<gCal:selected value='true'/>");
-       else
-               g_string_append (xml_string, "<gCal:selected value='false'/>");
+       json_builder_set_member_name (builder, "selected");
+       json_builder_add_boolean_value (builder, priv->is_selected);
 }
 
-static void
-get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
+static const gchar *
+get_content_type (void)
 {
-       /* Chain up to the parent class */
-       GDATA_PARSABLE_CLASS (gdata_calendar_calendar_parent_class)->get_namespaces (parsable, namespaces);
-
-       g_hash_table_insert (namespaces, (gchar*) "gCal", (gchar*) "http://schemas.google.com/gCal/2005";);
-       g_hash_table_insert (namespaces, (gchar*) "app", (gchar*) "http://www.w3.org/2007/app";);
+       return "application/json";
 }
 
 /**
diff --git a/gdata/services/calendar/gdata-calendar-feed.c b/gdata/services/calendar/gdata-calendar-feed.c
index ce0ca91..78a6720 100644
--- a/gdata/services/calendar/gdata-calendar-feed.c
+++ b/gdata/services/calendar/gdata-calendar-feed.c
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
  * GData Client
- * Copyright (C) Philip Withnall 2009–2010 <philip tecnocode co uk>
+ * Copyright (C) Philip Withnall 2009, 2010, 2014 <philip tecnocode co uk>
  *
  * GData Client is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,8 @@
  *
  * #GDataCalendarFeed is a subclass of #GDataFeed to represent a results feed from Google Calendar. It adds 
a couple of
  * properties which are specific to the Google Calendar API.
+ *
+ * TODO: deprecate things?
  **/
 
 #include <glib.h>
@@ -34,14 +36,7 @@
 #include "gdata-feed.h"
 #include "gdata-private.h"
 
-static void gdata_calendar_feed_finalize (GObject *object);
 static void gdata_calendar_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec 
*pspec);
-static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError 
**error);
-
-struct _GDataCalendarFeedPrivate {
-       gchar *timezone;
-       guint times_cleaned;
-};
 
 enum {
        PROP_TIMEZONE = 1,
@@ -54,14 +49,8 @@ static void
 gdata_calendar_feed_class_init (GDataCalendarFeedClass *klass)
 {
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-       GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
-
-       g_type_class_add_private (klass, sizeof (GDataCalendarFeedPrivate));
 
        gobject_class->get_property = gdata_calendar_feed_get_property;
-       gobject_class->finalize = gdata_calendar_feed_finalize;
-
-       parsable_class->parse_xml = parse_xml;
 
        /**
         * GDataCalendarFeed:timezone:
@@ -94,31 +83,22 @@ gdata_calendar_feed_class_init (GDataCalendarFeedClass *klass)
 static void
 gdata_calendar_feed_init (GDataCalendarFeed *self)
 {
-       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_CALENDAR_FEED, GDataCalendarFeedPrivate);
-}
-
-static void
-gdata_calendar_feed_finalize (GObject *object)
-{
-       GDataCalendarFeedPrivate *priv = GDATA_CALENDAR_FEED (object)->priv;
-
-       g_free (priv->timezone);
-
-       /* Chain up to the parent class */
-       G_OBJECT_CLASS (gdata_calendar_feed_parent_class)->finalize (object);
+       /* Nothing to see here. */
 }
 
 static void
 gdata_calendar_feed_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
 {
-       GDataCalendarFeedPrivate *priv = GDATA_CALENDAR_FEED (object)->priv;
+       GDataCalendarFeed *self = GDATA_CALENDAR_FEED (object);
 
        switch (property_id) {
                case PROP_TIMEZONE:
-                       g_value_set_string (value, priv->timezone);
+                       g_value_set_string (value,
+                                           gdata_calendar_feed_get_timezone (self));
                        break;
                case PROP_TIMES_CLEANED:
-                       g_value_set_uint (value, priv->times_cleaned);
+                       g_value_set_uint (value,
+                                         gdata_calendar_feed_get_times_cleaned (self));
                        break;
                default:
                        /* We don't have any other property... */
@@ -127,35 +107,6 @@ gdata_calendar_feed_get_property (GObject *object, guint property_id, GValue *va
        }
 }
 
-static gboolean
-parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
-{
-       GDataCalendarFeed *self = GDATA_CALENDAR_FEED (parsable);
-
-       if (gdata_parser_is_namespace (node, "http://schemas.google.com/gCal/2005";) == FALSE)
-               return GDATA_PARSABLE_CLASS (gdata_calendar_feed_parent_class)->parse_xml (parsable, doc, 
node, user_data, error);
-
-       if (xmlStrcmp (node->name, (xmlChar*) "timezone") == 0) {
-               /* gCal:timezone */
-               xmlChar *_timezone = xmlGetProp (node, (xmlChar*) "value");
-               if (_timezone == NULL)
-                       return gdata_parser_error_required_property_missing (node, "value", error);
-               g_free (self->priv->timezone);
-               self->priv->timezone = (gchar*) _timezone;
-       } else if (xmlStrcmp (node->name, (xmlChar*) "timesCleaned") == 0) {
-               /* gCal:timesCleaned */
-               xmlChar *times_cleaned = xmlGetProp (node, (xmlChar*) "value");
-               if (times_cleaned == NULL)
-                       return gdata_parser_error_required_property_missing (node, "value", error);
-               self->priv->times_cleaned = g_ascii_strtoull ((gchar*) times_cleaned, NULL, 10);
-               xmlFree (times_cleaned);
-       } else {
-               return GDATA_PARSABLE_CLASS (gdata_calendar_feed_parent_class)->parse_xml (parsable, doc, 
node, user_data, error);
-       }
-
-       return TRUE;
-}
-
 /**
  * gdata_calendar_feed_get_timezone:
  * @self: a #GDataCalendarFeed
@@ -169,8 +120,9 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 const gchar *
 gdata_calendar_feed_get_timezone (GDataCalendarFeed *self)
 {
+       /* Not supported any more by version 3 of the API. */
        g_return_val_if_fail (GDATA_IS_CALENDAR_FEED (self), NULL);
-       return self->priv->timezone;
+       return NULL;
 }
 
 /**
@@ -186,6 +138,7 @@ gdata_calendar_feed_get_timezone (GDataCalendarFeed *self)
 guint
 gdata_calendar_feed_get_times_cleaned (GDataCalendarFeed *self)
 {
+       /* Not supported any more by version 3 of the API. */
        g_return_val_if_fail (GDATA_IS_CALENDAR_FEED (self), 0);
-       return self->priv->times_cleaned;
+       return 0;
 }
diff --git a/gdata/services/calendar/gdata-calendar-service.c 
b/gdata/services/calendar/gdata-calendar-service.c
index e326eab..a141498 100644
--- a/gdata/services/calendar/gdata-calendar-service.c
+++ b/gdata/services/calendar/gdata-calendar-service.c
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
  * GData Client
- * Copyright (C) Philip Withnall 2009 <philip tecnocode co uk>
+ * Copyright (C) Philip Withnall 2009, 2014 <philip tecnocode co uk>
  *
  * GData Client is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -15,6 +15,12 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * TODO: parse_error_response
+ * TODO: ACLs, batchable
+ * TODO: update links to references; proofread documentation
+ * TODO: add new API to avoid naked calls to gdata_service_insert_entry() (for example)
+ * TODO: port Evo and Geary code
  */
 
 /**
@@ -316,7 +322,7 @@ gdata_calendar_service_query_all_calendars (GDataCalendarService *self, GDataQue
                return NULL;
        }
 
-       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/allcalendars/full", NULL);
+       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.googleapis.com/calendar/v3/users/me/calendarList", NULL);
        feed = gdata_service_query (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, 
query, GDATA_TYPE_CALENDAR_CALENDAR,
                                    cancellable, progress_callback, progress_user_data, error);
        g_free (request_uri);
@@ -370,7 +376,7 @@ gdata_calendar_service_query_all_calendars_async (GDataCalendarService *self, GD
                return;
        }
 
-       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/allcalendars/full", NULL);
+       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.googleapis.com/calendar/v3/users/me/calendarList", NULL);
        gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, 
query, GDATA_TYPE_CALENDAR_CALENDAR,
                                   cancellable, progress_callback, progress_user_data, 
destroy_progress_user_data, callback, user_data);
        g_free (request_uri);
@@ -413,7 +419,7 @@ gdata_calendar_service_query_own_calendars (GDataCalendarService *self, GDataQue
                return NULL;
        }
 
-       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/owncalendars/full", NULL);
+       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.googleapis.com/calendar/v3/users/me/calendarList?minAccessRole=owner", NULL);
        feed = gdata_service_query (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, 
query, GDATA_TYPE_CALENDAR_CALENDAR,
                                    cancellable, progress_callback, progress_user_data, error);
        g_free (request_uri);
@@ -467,7 +473,7 @@ gdata_calendar_service_query_own_calendars_async (GDataCalendarService *self, GD
                return;
        }
 
-       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/owncalendars/full", NULL);
+       request_uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.googleapis.com/calendar/v3/users/me/calendarList?minAccessRole=owner", NULL);
        gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, 
query, GDATA_TYPE_CALENDAR_CALENDAR,
                                   cancellable, progress_callback, progress_user_data, 
destroy_progress_user_data, callback, user_data);
        g_free (request_uri);
@@ -493,7 +499,8 @@ GDataFeed *
 gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCalendar *calendar, GDataQuery 
*query, GCancellable *cancellable,
                                      GDataQueryProgressCallback progress_callback, gpointer 
progress_user_data, GError **error)
 {
-       const gchar *uri;
+       gchar *request_uri;
+       GDataFeed *feed;
 
        g_return_val_if_fail (GDATA_IS_CALENDAR_SERVICE (self), NULL);
        g_return_val_if_fail (GDATA_IS_CALENDAR_CALENDAR (calendar), NULL);
@@ -509,18 +516,21 @@ gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCa
                return NULL;
        }
 
-       /* Use the calendar's content src */
-       uri = gdata_entry_get_content_uri (GDATA_ENTRY (calendar));
-       if (uri == NULL) {
-               /* Erroring out is probably the safest thing to do */
-               g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
-                                    _("The calendar did not have a content URI."));
-               return NULL;
-       }
+       /* Execute the query. TODO: escaping? */
+       request_uri = g_strconcat (_gdata_service_get_scheme (),
+                                  "://www.googleapis.com/calendar/v3/calendars/",
+                                  gdata_entry_get_id (GDATA_ENTRY (calendar)),
+                                  "/events",
+                                  NULL);
+       feed = gdata_service_query (GDATA_SERVICE (self),
+                                   get_calendar_authorization_domain (),
+                                   request_uri, query,
+                                   GDATA_TYPE_CALENDAR_EVENT, cancellable,
+                                   progress_callback, progress_user_data,
+                                   error);
+       g_free (request_uri);
 
-       /* Execute the query */
-       return gdata_service_query (GDATA_SERVICE (self), get_calendar_authorization_domain (), uri, query, 
GDATA_TYPE_CALENDAR_EVENT, cancellable,
-                                   progress_callback, progress_user_data, error);
+       return feed;
 }
 
 /**
@@ -552,7 +562,7 @@ gdata_calendar_service_query_events_async (GDataCalendarService *self, GDataCale
                                            GDestroyNotify destroy_progress_user_data,
                                            GAsyncReadyCallback callback, gpointer user_data)
 {
-       const gchar *uri;
+       gchar *request_uri;
 
        g_return_if_fail (GDATA_IS_CALENDAR_SERVICE (self));
        g_return_if_fail (GDATA_IS_CALENDAR_CALENDAR (calendar));
@@ -572,22 +582,20 @@ gdata_calendar_service_query_events_async (GDataCalendarService *self, GDataCale
                return;
        }
 
-       /* Use the calendar's content src */
-       uri = gdata_entry_get_content_uri (GDATA_ENTRY (calendar));
-       if (uri == NULL) {
-               /* Erroring out is probably the safest thing to do */
-               GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, 
gdata_service_query_async);
-               g_simple_async_result_set_error (result, GDATA_SERVICE_ERROR, 
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED, "%s",
-                                                _("The calendar did not have a content URI."));
-               g_simple_async_result_complete_in_idle (result);
-               g_object_unref (result);
-
-               return;
-       }
-
        /* Execute the query */
-       gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), uri, query, 
GDATA_TYPE_CALENDAR_EVENT, cancellable,
-                                  progress_callback, progress_user_data, destroy_progress_user_data, 
callback, user_data);
+       request_uri = g_strconcat (_gdata_service_get_scheme (),
+                                  "://www.googleapis.com/calendar/v3/calendars/",
+                                  gdata_entry_get_id (GDATA_ENTRY (calendar)),
+                                  "/events",
+                                  NULL);
+       gdata_service_query_async (GDATA_SERVICE (self),
+                                  get_calendar_authorization_domain (),
+                                  request_uri, query,
+                                  GDATA_TYPE_CALENDAR_EVENT, cancellable,
+                                  progress_callback, progress_user_data,
+                                  destroy_progress_user_data, callback,
+                                  user_data);
+       g_free (request_uri);
 }
 
 /**
@@ -611,13 +619,18 @@ gdata_calendar_service_insert_event (GDataCalendarService *self, GDataCalendarEv
        /* TODO: How do we choose which calendar? */
        gchar *uri;
        GDataEntry *entry;
+       const gchar *calendar_id = "default";
 
        g_return_val_if_fail (GDATA_IS_CALENDAR_SERVICE (self), NULL);
        g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (event), NULL);
        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-       uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/private/full", NULL);
+       uri = g_strconcat (_gdata_service_get_scheme (),
+                          "://www.googleapis.com/calendar/v3/calendars/",
+                          calendar_id,
+                          "/events",
+                          NULL);
        entry = gdata_service_insert_entry (GDATA_SERVICE (self), get_calendar_authorization_domain (), uri, 
GDATA_ENTRY (event), cancellable, error);
        g_free (uri);
 
@@ -648,12 +661,17 @@ gdata_calendar_service_insert_event_async (GDataCalendarService *self, GDataCale
                                            GAsyncReadyCallback callback, gpointer user_data)
 {
        gchar *uri;
+       const gchar *calendar_id = "default";
 
        g_return_if_fail (GDATA_IS_CALENDAR_SERVICE (self));
        g_return_if_fail (GDATA_IS_CALENDAR_EVENT (event));
        g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-       uri = g_strconcat (_gdata_service_get_scheme (), 
"://www.google.com/calendar/feeds/default/private/full", NULL);
+       uri = g_strconcat (_gdata_service_get_scheme (),
+                          "://www.googleapis.com/calendar/v3/calendars/",
+                          calendar_id,
+                          "/events",
+                          NULL);
        gdata_service_insert_entry_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), uri, 
GDATA_ENTRY (event), cancellable,
                                          callback, user_data);
        g_free (uri);
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index c54ddda..85b6da3 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
  * GData Client
- * Copyright (C) Philip Withnall 2009–2010 <philip tecnocode co uk>
+ * Copyright (C) Philip Withnall 2009, 2010, 2014 <philip tecnocode co uk>
  *
  * GData Client is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,9 +23,16 @@
 
 #include "gdata.h"
 #include "common.h"
+#include "gdata-dummy-authorizer.h"
 
 static UhmServer *mock_server = NULL;
 
+#undef CLIENT_ID  /* from common.h */
+
+#define CLIENT_ID "352818697630-nqu2cmt5quqd6lr17ouoqmb684u84l1f.apps.googleusercontent.com"
+#define CLIENT_SECRET "-fA4pHQJxR3zJ-FyAMPQsikg"
+#define REDIRECT_URI "urn:ietf:wg:oauth:2.0:oob"
+
 typedef struct {
        GDataCalendarCalendar *calendar;
 } TempCalendarData;
@@ -46,7 +53,7 @@ set_up_temp_calendar (TempCalendarData *data, gconstpointer service)
        gdata_calendar_calendar_set_color (calendar, &colour);
        data->calendar = GDATA_CALENDAR_CALENDAR (gdata_service_insert_entry (GDATA_SERVICE (service),
                                                                              
gdata_calendar_service_get_primary_authorization_domain (),
-                                                                             
"https://www.google.com/calendar/feeds/default/owncalendars/full";,
+                                                                             
"https://www.googleapis.com/calendar/v3/calendars";,
                                                                              GDATA_ENTRY (calendar), NULL, 
NULL));
        g_assert (GDATA_IS_CALENDAR_CALENDAR (data->calendar));
        g_object_unref (calendar);
@@ -70,75 +77,48 @@ tear_down_temp_calendar (TempCalendarData *data, gconstpointer service)
 static void
 test_authentication (void)
 {
-       gboolean retval;
-       GDataClientLoginAuthorizer *authorizer;
-       GError *error = NULL;
+       GDataOAuth2Authorizer *authorizer = NULL;  /* owned */
+       gchar *authentication_uri, *authorisation_code;
 
        gdata_test_mock_server_start_trace (mock_server, "authentication");
 
-       /* Create an authorizer */
-       authorizer = gdata_client_login_authorizer_new (CLIENT_ID, GDATA_TYPE_CALENDAR_SERVICE);
+       authorizer = gdata_oauth2_authorizer_new (CLIENT_ID, CLIENT_SECRET,
+                                                 REDIRECT_URI,
+                                                 GDATA_TYPE_CALENDAR_SERVICE);
 
-       g_assert_cmpstr (gdata_client_login_authorizer_get_client_id (authorizer), ==, CLIENT_ID);
+       /* Get an authentication URI. */
+       authentication_uri = gdata_oauth2_authorizer_build_authentication_uri (authorizer, NULL, FALSE);
+       g_assert (authentication_uri != NULL);
 
-       /* Log in */
-       retval = gdata_client_login_authorizer_authenticate (authorizer, USERNAME, PASSWORD, NULL, &error);
-       g_assert_no_error (error);
-       g_assert (retval == TRUE);
-       g_clear_error (&error);
+       /* Get the authorisation code off the user. */
+       if (uhm_server_get_enable_online (mock_server)) {
+               authorisation_code = gdata_test_query_user_for_verifier (authentication_uri);
+       } else {
+               /* Hard coded, extracted from the trace file. TODO */
+               authorisation_code = g_strdup 
("4/OEX-S1iMbOA_dOnNgUlSYmGWh3TK.QrR73axcNMkWoiIBeO6P2m_su7cwkQI");
+       }
 
-       /* Check all is as it should be */
-       g_assert_cmpstr (gdata_client_login_authorizer_get_username (authorizer), ==, USERNAME);
-       g_assert_cmpstr (gdata_client_login_authorizer_get_password (authorizer), ==, PASSWORD);
+       g_free (authentication_uri);
+
+       if (authorisation_code == NULL) {
+               /* Skip tests. */
+               goto skip_test;
+       }
+
+       /* Authorise the token */
+       g_assert (gdata_oauth2_authorizer_request_authorization (authorizer, authorisation_code, NULL, NULL) 
== TRUE);
 
+       /* Check all is as it should be */
        g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer),
                                                             
gdata_calendar_service_get_primary_authorization_domain ()) == TRUE);
 
+skip_test:
+       g_free (authorisation_code);
        g_object_unref (authorizer);
 
        uhm_server_end_trace (mock_server);
 }
 
-GDATA_ASYNC_TEST_FUNCTIONS (authentication, void,
-G_STMT_START {
-       GDataClientLoginAuthorizer *authorizer;
-
-       /* Create an authorizer */
-       authorizer = gdata_client_login_authorizer_new (CLIENT_ID, GDATA_TYPE_CALENDAR_SERVICE);
-
-       g_assert_cmpstr (gdata_client_login_authorizer_get_client_id (authorizer), ==, CLIENT_ID);
-
-       gdata_client_login_authorizer_authenticate_async (authorizer, USERNAME, PASSWORD, cancellable, 
async_ready_callback, async_data);
-
-       g_object_unref (authorizer);
-} G_STMT_END,
-G_STMT_START {
-       gboolean retval;
-       GDataClientLoginAuthorizer *authorizer = GDATA_CLIENT_LOGIN_AUTHORIZER (obj);
-
-       retval = gdata_client_login_authorizer_authenticate_finish (authorizer, async_result, &error);
-
-       if (error == NULL) {
-               g_assert (retval == TRUE);
-
-               /* Check all is as it should be */
-               g_assert_cmpstr (gdata_client_login_authorizer_get_username (authorizer), ==, USERNAME);
-               g_assert_cmpstr (gdata_client_login_authorizer_get_password (authorizer), ==, PASSWORD);
-
-               g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer),
-                                                                    
gdata_calendar_service_get_primary_authorization_domain ()) == TRUE);
-       } else {
-               g_assert (retval == FALSE);
-
-               /* Check nothing's changed */
-               g_assert_cmpstr (gdata_client_login_authorizer_get_username (authorizer), ==, NULL);
-               g_assert_cmpstr (gdata_client_login_authorizer_get_password (authorizer), ==, NULL);
-
-               g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer),
-                                                                    
gdata_calendar_service_get_primary_authorization_domain ()) == FALSE);
-       }
-} G_STMT_END);
-
 typedef struct {
        GDataCalendarCalendar *calendar1;
        GDataCalendarCalendar *calendar2;
@@ -158,9 +138,10 @@ set_up_query_calendars (QueryCalendarsData *data, gconstpointer service)
        calendar = gdata_calendar_calendar_new (NULL);
        gdata_entry_set_title (GDATA_ENTRY (calendar), "Test Calendar 1");
        gdata_calendar_calendar_set_color (calendar, &colour);
+       /* TODO: abstract this */
        data->calendar1 = GDATA_CALENDAR_CALENDAR (gdata_service_insert_entry (GDATA_SERVICE (service),
                                                                               
gdata_calendar_service_get_primary_authorization_domain (),
-                                                                              
"https://www.google.com/calendar/feeds/default/owncalendars/full";,
+                                                                              
"https://www.googleapis.com/calendar/v3/calendars";,
                                                                               GDATA_ENTRY (calendar), NULL, 
NULL));
        g_assert (GDATA_IS_CALENDAR_CALENDAR (data->calendar1));
        g_object_unref (calendar);
@@ -170,7 +151,7 @@ set_up_query_calendars (QueryCalendarsData *data, gconstpointer service)
        gdata_calendar_calendar_set_color (calendar, &colour);
        data->calendar2 = GDATA_CALENDAR_CALENDAR (gdata_service_insert_entry (GDATA_SERVICE (service),
                                                                               
gdata_calendar_service_get_primary_authorization_domain (),
-                                                                              
"https://www.google.com/calendar/feeds/default/owncalendars/full";,
+                                                                              
"https://www.googleapis.com/calendar/v3/calendars";,
                                                                               GDATA_ENTRY (calendar), NULL, 
NULL));
        g_assert (GDATA_IS_CALENDAR_CALENDAR (data->calendar2));
        g_object_unref (calendar);
@@ -184,6 +165,7 @@ tear_down_query_calendars (QueryCalendarsData *data, gconstpointer service)
        gdata_test_mock_server_start_trace (mock_server, "teardown-query-calendars");
 
        /* Delete the calendars */
+       /* TODO: Crashes because there’s no self link. Maybe insert one manually? */
        g_assert (gdata_service_delete_entry (GDATA_SERVICE (service), 
gdata_calendar_service_get_primary_authorization_domain (),
                                              GDATA_ENTRY (data->calendar1), NULL, NULL) == TRUE);
        g_object_unref (data->calendar1);
@@ -1442,9 +1424,68 @@ mock_server_notify_resolver_cb (GObject *object, GParamSpec *pspec, gpointer use
                const gchar *ip_address = uhm_server_get_address (server);
 
                uhm_resolver_add_A (resolver, "www.google.com", ip_address);
+               uhm_resolver_add_A (resolver, "www.googleapis.com", ip_address);
+               uhm_resolver_add_A (resolver,
+                                   "accounts.google.com", ip_address);
        }
 }
 
+/* Set up a global GDataAuthorizer to be used for all the tests. Unfortunately,
+ * the Google Calendar API is limited to OAuth1 and OAuth2 authorisation, so
+ * this requires user interaction when online.
+ *
+ * If not online, use a dummy authoriser. */
+static GDataAuthorizer *
+create_global_authorizer (void)
+{
+       GDataOAuth2Authorizer *authorizer = NULL;  /* owned */
+       gchar *authentication_uri, *authorisation_code;
+       GError *error = NULL;
+
+       /* If not online, just return a dummy authoriser. */
+       if (!uhm_server_get_enable_online (mock_server)) {
+               return GDATA_AUTHORIZER (gdata_dummy_authorizer_new (GDATA_TYPE_CALENDAR_SERVICE));
+       }
+
+       /* Otherwise, go through the interactive OAuth dance. */
+       gdata_test_mock_server_start_trace (mock_server, "global-authentication");
+       authorizer = gdata_oauth2_authorizer_new (CLIENT_ID, CLIENT_SECRET,
+                                                 REDIRECT_URI,
+                                                 GDATA_TYPE_CALENDAR_SERVICE);
+
+       /* Get an authentication URI */
+       authentication_uri = gdata_oauth2_authorizer_build_authentication_uri (authorizer, NULL, FALSE);
+       g_assert (authentication_uri != NULL);
+
+       /* Get the authorisation code off the user. */
+       if (uhm_server_get_enable_online (mock_server)) {
+               authorisation_code = gdata_test_query_user_for_verifier (authentication_uri);
+       } else {
+               /* Hard coded, extracted from the trace file. TODO */
+               authorisation_code = g_strdup 
("4/hmXZtrXmXMqK1hwiWPZs9F_N6DK-.Ap4OICAUIe0WoiIBeO6P2m8IDoMxkQI");
+       }
+
+       g_free (authentication_uri);
+
+       if (authorisation_code == NULL) {
+               /* Skip tests. */
+               g_object_unref (authorizer);
+               authorizer = NULL;
+               goto skip_test;
+       }
+
+       /* Authorise the token */
+       g_assert (gdata_oauth2_authorizer_request_authorization (authorizer, authorisation_code, NULL, 
&error));
+       g_assert_no_error (error);
+
+skip_test:
+       g_free (authorisation_code);
+
+       uhm_server_end_trace (mock_server);
+
+       return GDATA_AUTHORIZER (authorizer);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1461,18 +1502,11 @@ main (int argc, char *argv[])
        uhm_server_set_trace_directory (mock_server, trace_directory);
        g_object_unref (trace_directory);
 
-       gdata_test_mock_server_start_trace (mock_server, "global-authentication");
-       authorizer = GDATA_AUTHORIZER (gdata_client_login_authorizer_new (CLIENT_ID, 
GDATA_TYPE_CALENDAR_SERVICE));
-       gdata_client_login_authorizer_authenticate (GDATA_CLIENT_LOGIN_AUTHORIZER (authorizer), USERNAME, 
PASSWORD, NULL, NULL);
-       uhm_server_end_trace (mock_server);
+       authorizer = create_global_authorizer ();
 
        service = GDATA_SERVICE (gdata_calendar_service_new (authorizer));
 
        g_test_add_func ("/calendar/authentication", test_authentication);
-       g_test_add ("/calendar/authentication/async", GDataAsyncTestData, NULL, gdata_set_up_async_test_data, 
test_authentication_async,
-                   gdata_tear_down_async_test_data);
-       g_test_add ("/calendar/authentication/async/cancellation", GDataAsyncTestData, NULL, 
gdata_set_up_async_test_data,
-                   test_authentication_async_cancellation, gdata_tear_down_async_test_data);
 
        g_test_add ("/calendar/query/all_calendars", QueryCalendarsData, service, set_up_query_calendars, 
test_query_all_calendars,
                    tear_down_query_calendars);
@@ -1515,10 +1549,13 @@ main (int argc, char *argv[])
        g_test_add ("/calendar/access-rule/delete", TempCalendarAclsData, service, set_up_temp_calendar_acls, 
test_access_rule_delete,
                    tear_down_temp_calendar_acls);
 
+#if 0
+TODO
        g_test_add_data_func ("/calendar/batch", service, test_batch);
        g_test_add ("/calendar/batch/async", BatchAsyncData, service, setup_batch_async, test_batch_async, 
teardown_batch_async);
        g_test_add ("/calendar/batch/async/cancellation", BatchAsyncData, service, setup_batch_async, 
test_batch_async_cancellation,
                    teardown_batch_async);
+#endif
 
        g_test_add_func ("/calendar/event/xml", test_event_xml);
        g_test_add_func ("/calendar/event/xml/dates", test_event_xml_dates);


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