[evolution-data-server] Bug 580021 — Port to external libgdata



commit 28897beab5dcd4aab3586322a96280be92585db6
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Apr 19 08:37:27 2009 +0100

    Bug 580021 â?? Port to external libgdata
    
    Convert Google calendar and contacts backends to use the external libgdata,
    depending on version >= 0.6.3. The e-d-s internal libgdata-1.2 has been
    dropped completely.
    
    The conversion of the Google calendar backend is untested and probably not
    working, but since people should be using CalDAV to access their Google
    Calendars, this shouldn't be a problem.
    
    The conversion of the Google contacts backend is fairly well tested, and
    has had support for a few new properties added. Most notably, addresses and
    names are now stored on Google's servers in a structured format which more
    closely maps to e-d-s' vCard representation than the previous flat string.
    
    Closes: bgo#580021

 addressbook/backends/google/Makefile.am            |   12 +-
 .../backends/google/e-book-backend-google.c        |  171 ++-
 addressbook/backends/google/google-book.c          |  420 ++---
 addressbook/backends/google/google-book.h          |   15 -
 addressbook/backends/google/util.c                 |  647 ++++---
 addressbook/backends/google/util.h                 |    6 +-
 calendar/backends/google/Makefile.am               |   12 +-
 .../backends/google/e-cal-backend-google-utils.c   |  874 +++++---
 .../backends/google/e-cal-backend-google-utils.h   |   22 +-
 calendar/backends/google/e-cal-backend-google.c    |  226 +--
 calendar/backends/google/e-cal-backend-google.h    |   23 +-
 configure.ac                                       |   29 +-
 servers/Makefile.am                                |    2 +-
 servers/google/Makefile.am                         |    3 -
 servers/google/libgdata-google/Makefile.am         |   38 -
 .../google/libgdata-google/gdata-google-service.c  |  689 -------
 .../google/libgdata-google/gdata-google-service.h  |   73 -
 .../google/libgdata-google/libgdata-google.pc.in   |   16 -
 servers/google/libgdata/Makefile.am                |   42 -
 servers/google/libgdata/gdata-entry.c              | 2155 --------------------
 servers/google/libgdata/gdata-entry.h              |  265 ---
 servers/google/libgdata/gdata-feed.c               |  680 ------
 servers/google/libgdata/gdata-feed.h               |   74 -
 servers/google/libgdata/gdata-service-iface.c      |  113 -
 servers/google/libgdata/gdata-service-iface.h      |   82 -
 servers/google/libgdata/libgdata.pc.in             |   15 -
 26 files changed, 1347 insertions(+), 5357 deletions(-)
---
diff --git a/addressbook/backends/google/Makefile.am b/addressbook/backends/google/Makefile.am
index f967f5e..a54ceb9 100644
--- a/addressbook/backends/google/Makefile.am
+++ b/addressbook/backends/google/Makefile.am
@@ -7,12 +7,9 @@ libebookbackendgoogle_la_CPPFLAGS = \
 	-I$(top_builddir) 				\
 	-I$(top_srcdir)/addressbook 			\
 	-I$(top_builddir)/addressbook 			\
-	-I$(top_srcdir)/servers/google/libgdata 	\
-	-I$(top_builddir)/servers/google/libgdata 	\
-	-I$(top_srcdir)/servers/google/libgdata-google 	\
-	-I$(top_builddir)/servers/google/libgdata-google \
 	$(SOUP_CFLAGS) 					\
-	$(EVOLUTION_ADDRESSBOOK_CFLAGS)
+	$(EVOLUTION_ADDRESSBOOK_CFLAGS)			\
+	$(GDATA_CFLAGS)
 
 libebookbackendgoogle_la_SOURCES = \
 	util.h \
@@ -27,11 +24,10 @@ libebookbackendgoogle_la_LIBADD = \
 	$(top_builddir)/addressbook/libebook/libebook-1.2.la \
 	$(top_builddir)/addressbook/libedata-book/libedata-book-1.2.la \
 	$(top_builddir)/libedataserver/libedataserver-1.2.la \
-	$(top_builddir)/servers/google/libgdata/libgdata-1.2.la \
-	$(top_builddir)/servers/google/libgdata-google/libgdata-google-1.2.la \
 	$(top_builddir)/libebackend/libebackend-1.2.la \
 	$(SOUP_LIBS) \
-	$(EVOLUTION_ADDRESSBOOK_LIBS)
+	$(EVOLUTION_ADDRESSBOOK_LIBS) \
+	$(GDATA_LIBS)
 
 libebookbackendgoogle_la_LDFLAGS = \
 	-module -avoid-version $(NO_UNDEFINED)
diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c
index eddd9bf..7f31afe 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -1,6 +1,7 @@
 /* e-book-backend-google.c - Google contact backendy.
  *
  * Copyright (C) 2008 Joergen Scheibengruber
+ * Copyright (C) 2010 Philip Withnall
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by the
@@ -27,6 +28,7 @@
 #include <libedata-book/e-data-book.h>
 #include <libedata-book/e-data-book-view.h>
 #include <libedata-book/e-book-backend-sexp.h>
+#include <gdata/gdata-service.h>
 
 #include "e-book-backend-google.h"
 #include "google-book.h"
@@ -36,7 +38,7 @@ G_DEFINE_TYPE (EBookBackendGoogle, e_book_backend_google, E_TYPE_BOOK_BACKEND_SY
 
 struct _EBookBackendGooglePrivate
 {
-    gint mode;
+    GNOME_Evolution_Addressbook_BookMode mode;
     GoogleBook *book;
     GList *bookviews;
 };
@@ -48,7 +50,7 @@ struct _EBookBackendGooglePrivate
 
 gboolean __e_book_backend_google_debug__;
 
-static EBookBackendSyncStatus e_book_backend_status_from_google_book_error (GoogleBookError error_code);
+static EBookBackendSyncStatus e_book_backend_status_from_google_book_error (GError *error);
 
 static EBookBackendSyncStatus
 e_book_backend_google_create_contact (EBookBackendSync	*backend,
@@ -76,7 +78,7 @@ e_book_backend_google_create_contact (EBookBackendSync	*backend,
     google_book_add_contact (priv->book, contact, out_contact, &error);
     g_object_unref (contact);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Creating contact failed: %s", error->message);
 	g_clear_error (&error);
 	*out_contact = NULL;
@@ -114,7 +116,7 @@ e_book_backend_google_remove_contacts (EBookBackendSync *backend,
 	google_book_remove_contact (priv->book, uid, &error);
 	if (error) {
 	    /* Only last error will be reported */
-	    status = e_book_backend_status_from_google_book_error (error->code);
+	    status = e_book_backend_status_from_google_book_error (error);
 	    __debug__ ("Deleting contact %s failed: %s", uid, error->message);
 	    g_clear_error (&error);
 	} else {
@@ -154,7 +156,7 @@ e_book_backend_google_modify_contact (EBookBackendSync	*backend,
     google_book_update_contact (priv->book, contact, out_contact, &error);
     g_object_unref (contact);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Modifying contact failed: %s", error->message);
 	g_clear_error (&error);
 	*out_contact = NULL;
@@ -181,7 +183,7 @@ e_book_backend_google_get_contact (EBookBackendSync	*backend,
 
     contact = google_book_get_contact (priv->book, uid, &error);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Getting contact with uid %s failed: %s", uid, error->message);
 	g_clear_error (&error);
 	return status;
@@ -212,7 +214,7 @@ e_book_backend_google_get_contact_list (EBookBackendSync *backend,
 
     all_contacts = google_book_get_all_contacts (priv->book, &error);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Getting all contacts failed: %s", error->message);
 	g_clear_error (&error);
 	return status;
@@ -283,9 +285,8 @@ on_google_book_sequence_complete (GoogleBook *book, GError *error, gpointer user
 
     priv = GET_PRIVATE (user_data);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Book-view query failed: %s", error->message);
-	status = e_book_backend_status_from_google_book_error (error->code);
 	g_clear_error (&error);
     }
     for (iter = priv->bookviews; iter; iter = iter->next) {
@@ -378,9 +379,8 @@ e_book_backend_google_authenticate_user (EBookBackendSync *backend,
 
     google_book_connect_to_google (priv->book, password, &error);
     if (error) {
-	status = e_book_backend_status_from_google_book_error (error->code);
+	status = e_book_backend_status_from_google_book_error (error);
 	__debug__ ("Authentication failed: %s", error->message);
-	status = e_book_backend_status_from_google_book_error (error->code);
 	g_clear_error (&error);
     } else {
 	e_book_backend_notify_writable (E_BOOK_BACKEND (backend), TRUE);
@@ -449,10 +449,77 @@ e_book_backend_google_get_supported_fields (EBookBackendSync	*backend,
 	E_CONTACT_ADDRESS,
 	E_CONTACT_ADDRESS_HOME,
 	E_CONTACT_ADDRESS_WORK,
-	E_CONTACT_ADDRESS_OTHER
+	E_CONTACT_ADDRESS_OTHER,
+	E_CONTACT_NAME,
+	E_CONTACT_GIVEN_NAME,
+	E_CONTACT_FAMILY_NAME,
+	E_CONTACT_PHONE_ASSISTANT,
+	E_CONTACT_PHONE_BUSINESS_2,
+	E_CONTACT_PHONE_CALLBACK,
+	E_CONTACT_PHONE_CAR,
+	E_CONTACT_PHONE_COMPANY,
+	E_CONTACT_PHONE_HOME_2,
+	E_CONTACT_PHONE_ISDN,
+	E_CONTACT_PHONE_OTHER,
+	E_CONTACT_PHONE_OTHER_FAX,
+	E_CONTACT_PHONE_PRIMARY,
+	E_CONTACT_PHONE_RADIO,
+	E_CONTACT_PHONE_TELEX,
+	E_CONTACT_PHONE_TTYTDD,
+	E_CONTACT_IM_AIM_HOME_1,
+	E_CONTACT_IM_AIM_HOME_2,
+	E_CONTACT_IM_AIM_HOME_3,
+	E_CONTACT_IM_AIM_WORK_1,
+	E_CONTACT_IM_AIM_WORK_2,
+	E_CONTACT_IM_AIM_WORK_3,
+	E_CONTACT_IM_GROUPWISE_HOME_1,
+	E_CONTACT_IM_GROUPWISE_HOME_2,
+	E_CONTACT_IM_GROUPWISE_HOME_3,
+	E_CONTACT_IM_GROUPWISE_WORK_1,
+	E_CONTACT_IM_GROUPWISE_WORK_2,
+	E_CONTACT_IM_GROUPWISE_WORK_3,
+	E_CONTACT_IM_JABBER_HOME_1,
+	E_CONTACT_IM_JABBER_HOME_2,
+	E_CONTACT_IM_JABBER_HOME_3,
+	E_CONTACT_IM_JABBER_WORK_1,
+	E_CONTACT_IM_JABBER_WORK_2,
+	E_CONTACT_IM_JABBER_WORK_3,
+	E_CONTACT_IM_YAHOO_HOME_1,
+	E_CONTACT_IM_YAHOO_HOME_2,
+	E_CONTACT_IM_YAHOO_HOME_3,
+	E_CONTACT_IM_YAHOO_WORK_1,
+	E_CONTACT_IM_YAHOO_WORK_2,
+	E_CONTACT_IM_YAHOO_WORK_3,
+	E_CONTACT_IM_MSN_HOME_1,
+	E_CONTACT_IM_MSN_HOME_2,
+	E_CONTACT_IM_MSN_HOME_3,
+	E_CONTACT_IM_MSN_WORK_1,
+	E_CONTACT_IM_MSN_WORK_2,
+	E_CONTACT_IM_MSN_WORK_3,
+	E_CONTACT_IM_ICQ_HOME_1,
+	E_CONTACT_IM_ICQ_HOME_2,
+	E_CONTACT_IM_ICQ_HOME_3,
+	E_CONTACT_IM_ICQ_WORK_1,
+	E_CONTACT_IM_ICQ_WORK_2,
+	E_CONTACT_IM_ICQ_WORK_3,
+	E_CONTACT_EMAIL,
+	E_CONTACT_IM_GADUGADU_HOME_1,
+	E_CONTACT_IM_GADUGADU_HOME_2,
+	E_CONTACT_IM_GADUGADU_HOME_3,
+	E_CONTACT_IM_GADUGADU_WORK_1,
+	E_CONTACT_IM_GADUGADU_WORK_2,
+	E_CONTACT_IM_GADUGADU_WORK_3,
+	E_CONTACT_TEL,
+	E_CONTACT_IM_SKYPE_HOME_1,
+	E_CONTACT_IM_SKYPE_HOME_2,
+	E_CONTACT_IM_SKYPE_HOME_3,
+	E_CONTACT_IM_SKYPE_WORK_1,
+	E_CONTACT_IM_SKYPE_WORK_2,
+	E_CONTACT_IM_SKYPE_WORK_3,
+	E_CONTACT_SIP
     };
     GList *fields = NULL;
-    gint i;
+    guint i;
 
     __debug__ (G_STRFUNC);
 
@@ -582,6 +649,7 @@ static void
 e_book_backend_google_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbook_BookMode mode)
 {
     EBookBackendGooglePrivate *priv = GET_PRIVATE (backend);
+    gboolean online = (mode == GNOME_Evolution_Addressbook_MODE_REMOTE);
 
     __debug__ (G_STRFUNC);
 
@@ -591,15 +659,14 @@ e_book_backend_google_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbo
 
     priv->mode = mode;
 
-    if (NULL == priv->book) {
-	return;
-    }
+    if (priv->book)
+        google_book_set_offline_mode (priv->book, !online);
+    e_book_backend_notify_connection_status (backend, online);
 
-    if (mode == GNOME_Evolution_Addressbook_MODE_REMOTE) {
-	google_book_set_offline_mode (priv->book, FALSE);
-    } else {
-	google_book_set_offline_mode (priv->book, TRUE);
-    }
+    /* Mark the book as unwriteable if we're going offline, but don't do the inverse when we go online;
+     * e_book_backend_google_authenticate_user() will mark us as writeable again once the user's authenticated again. */
+    if (!online)
+        e_book_backend_notify_writable (backend, FALSE);
 }
 
 static void
@@ -684,25 +751,51 @@ e_book_backend_google_new (void)
 }
 
 static EBookBackendSyncStatus
-e_book_backend_status_from_google_book_error (GoogleBookError error_code)
+e_book_backend_status_from_google_book_error (GError *error)
 {
-	switch (error_code) {
-	case GOOGLE_BOOK_ERROR_NONE:
-		return GNOME_Evolution_Addressbook_Success;
-	case GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND:
-		return GNOME_Evolution_Addressbook_ContactNotFound;
-	case GOOGLE_BOOK_ERROR_CONFLICT:
-		return GNOME_Evolution_Addressbook_ContactIdAlreadyExists;
-	case GOOGLE_BOOK_ERROR_AUTH_FAILED:
-		return GNOME_Evolution_Addressbook_AuthenticationFailed;
-	case GOOGLE_BOOK_ERROR_AUTH_REQUIRED:
-		return GNOME_Evolution_Addressbook_AuthenticationRequired;
-	case GOOGLE_BOOK_ERROR_INVALID_CONTACT:
-	case GOOGLE_BOOK_ERROR_NETWORK_ERROR:
-	case GOOGLE_BOOK_ERROR_HTTP_ERROR:
-		break;
-	}
+    if (!error)
+        return GNOME_Evolution_Addressbook_Success;
+
+    if (error->domain == GDATA_AUTHENTICATION_ERROR) {
+        /* Authentication errors */
+        switch (error->code) {
+        case GDATA_AUTHENTICATION_ERROR_BAD_AUTHENTICATION:
+            return GNOME_Evolution_Addressbook_AuthenticationFailed;
+        case GDATA_AUTHENTICATION_ERROR_NOT_VERIFIED:
+        case GDATA_AUTHENTICATION_ERROR_TERMS_NOT_AGREED:
+        case GDATA_AUTHENTICATION_ERROR_CAPTCHA_REQUIRED:
+        case GDATA_AUTHENTICATION_ERROR_ACCOUNT_DELETED:
+        case GDATA_AUTHENTICATION_ERROR_ACCOUNT_DISABLED:
+            return GNOME_Evolution_Addressbook_PermissionDenied;
+        case GDATA_AUTHENTICATION_ERROR_SERVICE_DISABLED:
+            return GNOME_Evolution_Addressbook_RepositoryOffline;
+        default:
+            return GNOME_Evolution_Addressbook_OtherError;
+        }
+    } else if (error->domain == GDATA_SERVICE_ERROR) {
+        /* General service errors */
+        switch (error->code) {
+        case GDATA_SERVICE_ERROR_UNAVAILABLE:
+            return GNOME_Evolution_Addressbook_RepositoryOffline;
+        case GDATA_SERVICE_ERROR_PROTOCOL_ERROR:
+            return GNOME_Evolution_Addressbook_InvalidQuery;
+        case GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED:
+            return GNOME_Evolution_Addressbook_ContactIdAlreadyExists;
+        case GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED:
+            return GNOME_Evolution_Addressbook_AuthenticationRequired;
+        case GDATA_SERVICE_ERROR_NOT_FOUND:
+            return GNOME_Evolution_Addressbook_ContactNotFound;
+        case GDATA_SERVICE_ERROR_CONFLICT:
+            return GNOME_Evolution_Addressbook_ContactIdAlreadyExists;
+        case GDATA_SERVICE_ERROR_FORBIDDEN:
+            return GNOME_Evolution_Addressbook_QueryRefused;
+        case GDATA_SERVICE_ERROR_BAD_QUERY_PARAMETER:
+            return GNOME_Evolution_Addressbook_InvalidQuery;
+        default:
+            return GNOME_Evolution_Addressbook_OtherError;
+        }
+    }
 
-	return GNOME_Evolution_Addressbook_OtherError;
+    return GNOME_Evolution_Addressbook_OtherError;
 }
 
diff --git a/addressbook/backends/google/google-book.c b/addressbook/backends/google/google-book.c
index 405343f..c3b9ce3 100644
--- a/addressbook/backends/google/google-book.c
+++ b/addressbook/backends/google/google-book.c
@@ -1,6 +1,7 @@
 /* goggle-book.c - Google contact list abstraction with caching.
  *
  * Copyright (C) 2008 Joergen Scheibengruber
+ * Copyright (C) 2010 Philip Withnall
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by the
@@ -16,20 +17,25 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Author: Joergen Scheibengruber <joergen.scheibengruber AT googlemail.com>
+ * Author: Joergen Scheibengruber <joergen.scheibengruber AT googlemail.com>,
+ * Philip Withnall <philip tecnocode co uk>
  */
 
 #include <string.h>
 #include <libedata-book/e-book-backend-cache.h>
 #include <libedataserver/e-proxy.h>
-#include <gdata-service-iface.h>
-#include <gdata-google-service.h>
+#include <gdata/gdata-service.h>
+#include <gdata/services/contacts/gdata-contacts-service.h>
+#include <gdata/services/contacts/gdata-contacts-query.h>
+#include <gdata/services/contacts/gdata-contacts-contact.h>
 
 #include "util.h"
 #include "google-book.h"
 
 G_DEFINE_TYPE (GoogleBook, google_book, G_TYPE_OBJECT)
 
+#define URI_GET_CONTACTS "://www.google.com/m8/feeds/contacts/default/full"
+
 #define GET_PRIVATE(o) \
     (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_GOOGLE_BOOK, GoogleBookPrivate))
 
@@ -82,9 +88,7 @@ struct _GoogleBookPrivate
     GDataService *service;
     EProxy *proxy;
     guint refresh_interval;
-    gchar *base_uri;
-    /* FIXME - this one should not be needed */
-    gchar *add_base_uri;
+    gboolean use_ssl;
 
     gboolean live_mode;
 
@@ -100,11 +104,6 @@ google_book_get_new_contacts_in_chunks (GoogleBook *book,
                                         GError    **error);
 
 static void
-google_book_error_from_soup_error      (GError *soup_error,
-                                        GError **error,
-                                        const gchar *message);
-
-static void
 google_book_cache_init (GoogleBook *book, gboolean on_disk)
 {
     GoogleBookPrivate *priv = GET_PRIVATE (book);
@@ -145,6 +144,7 @@ google_book_cache_add_contact (GoogleBook *book, GDataEntry *entry)
                              g_strdup (uid), g_object_ref (entry));
         return contact;
     case NO_CACHE:
+    default:
         break;
     }
     return NULL;
@@ -163,7 +163,25 @@ google_book_cache_remove_contact (GoogleBook *book, const gchar *uid)
         success = g_hash_table_remove (priv->cache.in_memory.contacts, uid);
         return success && g_hash_table_remove (priv->cache.in_memory.gdata_entries, uid);
     case NO_CACHE:
-    break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+static gboolean
+google_book_cache_has_contact (GoogleBook *book, const gchar *uid)
+{
+    GoogleBookPrivate *priv = GET_PRIVATE (book);
+
+    switch (priv->cache_type) {
+    case ON_DISK_CACHE:
+        return e_book_backend_cache_check_contact (priv->cache.on_disk, uid);
+    case IN_MEMORY_CACHE:
+        return g_hash_table_lookup (priv->cache.in_memory.contacts, uid) ? TRUE : FALSE;
+    case NO_CACHE:
+    default:
+        break;
     }
     return FALSE;
 }
@@ -179,9 +197,16 @@ google_book_cache_get_contact (GoogleBook *book, const gchar *uid, GDataEntry **
         contact = e_book_backend_cache_get_contact (priv->cache.on_disk, uid);
         if (contact) {
             if (entry) {
-                const gchar *entry_xml;
-                entry_xml = _e_contact_get_gdata_entry_xml (contact);
-                *entry = gdata_entry_new_from_xml (entry_xml);
+                const gchar *entry_xml, *edit_link;
+
+                entry_xml = _e_contact_get_gdata_entry_xml (contact, &edit_link);
+                *entry = GDATA_ENTRY (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT, entry_xml, -1, NULL));
+
+                if (*entry != NULL) {
+                    GDataLink *link = gdata_link_new (edit_link, GDATA_LINK_EDIT);
+                    gdata_entry_add_link (*entry, link);
+                    g_object_unref (link);
+                }
             }
             _e_contact_remove_gdata_entry_xml (contact);
         }
@@ -199,6 +224,7 @@ google_book_cache_get_contact (GoogleBook *book, const gchar *uid, GDataEntry **
         }
         return contact;
     case NO_CACHE:
+    default:
         break;
     }
     return NULL;
@@ -238,6 +264,7 @@ google_book_cache_get_contacts (GoogleBook *book)
     case IN_MEMORY_CACHE:
         return _g_hash_table_to_list (priv->cache.in_memory.contacts);
     case NO_CACHE:
+    default:
         break;
     }
         return NULL;
@@ -272,11 +299,11 @@ google_book_cache_get_last_update (GoogleBook *book)
     case ON_DISK_CACHE:
         return e_book_backend_cache_get_time (priv->cache.on_disk);
     case IN_MEMORY_CACHE:
-        if (priv->cache.in_memory.contacts) {
+        if (priv->cache.in_memory.contacts)
             return g_time_val_to_iso8601 (&priv->cache.in_memory.last_updated);
-        }
         break;
     case NO_CACHE:
+    default:
         break;
     }
     return NULL;
@@ -299,6 +326,7 @@ google_book_cache_get_last_update_tv (GoogleBook *book, GTimeVal *tv)
         memcpy (tv, &priv->cache.in_memory.last_updated, sizeof (GTimeVal));
         return priv->cache.in_memory.contacts != NULL;
     case NO_CACHE:
+    default:
         break;
     }
     return FALSE;
@@ -308,19 +336,20 @@ static void
 google_book_cache_set_last_update (GoogleBook *book, GTimeVal *tv)
 {
     GoogleBookPrivate *priv = GET_PRIVATE (book);
-    gchar *time;
+    gchar *_time;
 
     switch (priv->cache_type) {
     case ON_DISK_CACHE:
-        time = g_time_val_to_iso8601 (tv);
+        _time = g_time_val_to_iso8601 (tv);
         /* Work around a bug in EBookBackendCache */
         e_file_cache_remove_object (E_FILE_CACHE (priv->cache.on_disk), "last_update_time");
-        e_book_backend_cache_set_time (priv->cache.on_disk, time);
-        g_free (time);
+        e_book_backend_cache_set_time (priv->cache.on_disk, _time);
+        g_free (_time);
         return;
     case IN_MEMORY_CACHE:
         memcpy (&priv->cache.in_memory.last_updated, tv, sizeof (GTimeVal));
     case NO_CACHE:
+    default:
         break;
     }
 }
@@ -439,38 +468,17 @@ google_book_cache_destroy (GoogleBook *book)
         g_hash_table_destroy (priv->cache.in_memory.gdata_entries);
         break;
     case NO_CACHE:
+    default:
         break;
     }
     priv->cache_type = NO_CACHE;
 }
 
 static void
-google_book_construct_base_uri (GoogleBook *book, gboolean use_ssl)
-{
-    const gchar format[] = "%swww.google.com/m8/feeds/contacts/%s/base";
-    gchar *esc_username;
-    GoogleBookPrivate *priv = GET_PRIVATE (book);
-
-    __debug__ (G_STRFUNC);
-    g_free (priv->base_uri);
-    g_free (priv->add_base_uri);
-
-    esc_username = g_uri_escape_string (priv->username, NULL, FALSE);
-    priv->base_uri = g_strdup_printf (format, use_ssl ? "https://"; : "http://";, esc_username);
-    /* FIXME - always use non ssl mode when adding entries. Somehow this does not
-     * work on SSL; i.e. get duplicate entries and SOUP returns error 7 - connection
-     * terminated unexpectedly
-     */
-    priv->add_base_uri = g_strdup_printf (format, "http://";, esc_username);
-    g_free (esc_username);
-}
-
-static void
 google_book_get_property (GObject *object, guint property_id,
                           GValue *value,   GParamSpec *pspec)
 {
     GoogleBookPrivate *priv = GET_PRIVATE (object);
-    gboolean use_ssl = FALSE;
 
     switch (property_id) {
     case PROP_USERNAME:
@@ -483,12 +491,7 @@ google_book_get_property (GObject *object, guint property_id,
         g_value_set_uint (value, priv->refresh_interval);
         break;
     case PROP_USE_SSL:
-        if (priv->base_uri) {
-            if (strstr (priv->base_uri, "https://";)) {
-                use_ssl = TRUE;
-            }
-        }
-        g_value_set_boolean (value, use_ssl);
+        g_value_set_boolean (value, priv->use_ssl);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -510,10 +513,15 @@ google_book_set_property (GObject *object, guint property_id,
         break;
     case PROP_REFRESH_INTERVAL:
         priv->refresh_interval = g_value_get_uint (value);
-        /* FIXME - actually apply this */
+
+        /* Remove and re-add the timeout */
+        if (priv->refresh_id != 0) {
+            g_source_remove (priv->refresh_id);
+            priv->refresh_id = g_timeout_add_seconds (priv->refresh_interval, on_refresh_timeout, GOOGLE_BOOK (object));
+        }
         break;
     case PROP_USE_SSL:
-        google_book_construct_base_uri (GOOGLE_BOOK (object), g_value_get_boolean (value));
+        priv->use_ssl = g_value_get_boolean (value);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -530,14 +538,14 @@ google_book_dispose (GObject *object)
         priv->idle_id = 0;
     }
 
-    if (priv->service) {
+    if (priv->service)
         g_object_unref (priv->service);
-        priv->service = NULL;
-    }
-    if (priv->proxy) {
+    priv->service = NULL;
+
+    if (priv->proxy)
 	g_object_unref (priv->proxy);
-	priv->proxy = NULL;
-    }
+    priv->proxy = NULL;
+
     google_book_cache_destroy (GOOGLE_BOOK (object));
 
     if (G_OBJECT_CLASS (google_book_parent_class)->dispose)
@@ -549,8 +557,6 @@ google_book_finalize (GObject *object)
 {
     GoogleBookPrivate *priv = GET_PRIVATE (object);
 
-    g_free (priv->base_uri);
-    g_free (priv->add_base_uri);
     g_free (priv->username);
 
     if (G_OBJECT_CLASS (google_book_parent_class)->finalize)
@@ -636,21 +642,21 @@ google_book_class_init (GoogleBookClass *klass)
                                      PROP_USERNAME,
                                      g_param_spec_string ("username",
                                                           "Username",
-                                                          "The username",
+                                                          "The username.",
                                                           NULL,
                                                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
     g_object_class_install_property (object_class,
                                      PROP_USE_CACHE,
                                      g_param_spec_boolean ("use-cache",
-                                                           "UseCache",
-                                                           "Whether a on-disk cache should be used",
+                                                           "Use Cache?",
+                                                           "Whether an on-disk cache should be used.",
                                                            TRUE,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
     g_object_class_install_property (object_class,
                                      PROP_REFRESH_INTERVAL,
                                      g_param_spec_uint ("refresh-interval",
-                                                        "RefreshInterval",
+                                                        "Refresh Interval",
                                                         "Specifies the number of seconds until "
                                                         "the local cache is updated from the "
                                                         "server. 0 means no updates.",
@@ -659,8 +665,8 @@ google_book_class_init (GoogleBookClass *klass)
     g_object_class_install_property (object_class,
                                      PROP_USE_SSL,
                                      g_param_spec_boolean ("use-ssl",
-                                                           "UseSSL",
-                                                           "Whether SSL should be used or not",
+                                                           "Use SSL?",
+                                                           "Whether SSL should be used.",
                                                            TRUE,
                                                            G_PARAM_READWRITE));
     google_book_signals [CONTACT_CHANGED] =
@@ -734,24 +740,27 @@ static void
 proxy_settings_changed (EProxy *proxy, gpointer user_data)
 {
 	SoupURI *proxy_uri = NULL;
-
+	gchar *uri;
 	GoogleBookPrivate *priv = (GoogleBookPrivate*) user_data;
-	if (!priv || !priv->base_uri)
+
+	if (!priv || !priv->service)
 		return;
 
+	/* Build the URI which libgdata would use to query contacts */
+	uri = g_strconcat (priv->use_ssl ? "https" : "http", URI_GET_CONTACTS, NULL);
+
 	/* use proxy if necessary */
-	if (e_proxy_require_proxy_for_uri (proxy, priv->base_uri)) {
-		proxy_uri = e_proxy_peek_uri_for (proxy, priv->base_uri);
-	}
-	gdata_service_set_proxy (GDATA_SERVICE (priv->service), proxy_uri);
+	if (e_proxy_require_proxy_for_uri (proxy, uri))
+		proxy_uri = e_proxy_peek_uri_for (proxy, uri);
+	gdata_service_set_proxy_uri (GDATA_SERVICE (priv->service), proxy_uri);
+
+	g_free (uri);
 }
 
 gboolean
 google_book_connect_to_google (GoogleBook *book, const gchar *password, GError **error)
 {
     GoogleBookPrivate *priv;
-    GDataService *service;
-    GError *soup_error = NULL;
 
     __debug__ (G_STRFUNC);
     g_return_val_if_fail (IS_GOOGLE_BOOK (book), FALSE);
@@ -760,32 +769,24 @@ google_book_connect_to_google (GoogleBook *book, const gchar *password, GError *
     priv = GET_PRIVATE (book);
 
     if (priv->service) {
-        g_warning ("Connection to google already established.");
+        g_warning ("Connection to Google already established.");
         return TRUE;
     }
 
-    service = (GDataService*)gdata_google_service_new ("cp", "evolution-client-0.0.1");
+    priv->service = GDATA_SERVICE (gdata_contacts_service_new ("evolution-client-0.0.1"));
     priv->proxy = e_proxy_new ();
     e_proxy_setup_proxy (priv->proxy);
-    priv->service = service;
     proxy_settings_changed (priv->proxy, priv);
-    priv->service = NULL;
-
-    gdata_service_set_credentials (GDATA_SERVICE (service), priv->username, password);
-    gdata_google_service_authenticate (GDATA_GOOGLE_SERVICE (service), &soup_error);
 
-    if (soup_error) {
-        google_book_error_from_soup_error (soup_error, error,
-                                           "Connecting to google failed");
-        priv->service = NULL;
-	g_object_unref (service);
+    if (!gdata_service_authenticate (priv->service, priv->username, password, NULL, error)) {
+	g_object_unref (priv->service);
+	priv->service = NULL;
 	g_object_unref (priv->proxy);
 	priv->proxy = NULL;
         return FALSE;
     }
 
     g_signal_connect (priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), priv);
-    priv->service = service;
 
     return google_book_cache_refresh_if_needed (book, error);
 }
@@ -802,21 +803,18 @@ google_book_set_offline_mode (GoogleBook *book, gboolean offline)
 
     priv->offline = offline;
     if (offline) {
-	if (priv->service) {
+        /* Going offline, so we can free our service and proxy */
+	if (priv->service)
 		g_object_unref (priv->service);
-		priv->service = NULL;
-	}
-	if (priv->proxy) {
+	priv->service = NULL;
+
+	if (priv->proxy)
 		g_object_unref (priv->proxy);
-		priv->proxy = NULL;
-	}
-    }
-    if (offline == FALSE) {
-        if (priv->service) {
-            google_book_cache_refresh_if_needed (book, NULL);
-        } else {
-            google_book_emit_auth_required (book);
-        }
+	priv->proxy = NULL;
+    } else {
+        /* Going online, so we need to re-authenticate and re-create the service and proxy.
+         * This is done in google_book_connect_to_google(), which is called by EBookBackendGoogle when it gets the authentication data. */
+        google_book_emit_auth_required (book);
     }
 }
 
@@ -828,7 +826,7 @@ google_book_add_contact (GoogleBook *book,
 {
     GoogleBookPrivate *priv;
     GDataEntry *entry, *new_entry;
-    GError *soup_error = NULL;
+    gchar *xml;
 
     *out_contact = NULL;
 
@@ -840,18 +838,17 @@ google_book_add_contact (GoogleBook *book,
     g_return_val_if_fail (priv->service, FALSE);
 
     entry = _gdata_entry_new_from_e_contact (contact);
-    __debug__ ("new entry with xml: %s", gdata_entry_generate_xml (entry));
-    new_entry = gdata_service_insert_entry (GDATA_SERVICE (priv->service),
-                                            priv->add_base_uri, entry, &soup_error);
+    xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
+    __debug__ ("new entry with xml: %s", xml);
+    g_free (xml);
+
+    new_entry = GDATA_ENTRY (gdata_contacts_service_insert_contact (GDATA_CONTACTS_SERVICE (priv->service), GDATA_CONTACTS_CONTACT (entry),
+                                                                    NULL, error));
     g_object_unref (entry);
-    if (soup_error) {
-        google_book_error_from_soup_error (soup_error, error,
-                                           "Adding entry failed");
+    if (!new_entry)
         return FALSE;
-    }
 
     *out_contact = google_book_cache_add_contact (book, new_entry);
-
     g_object_unref (new_entry);
 
     return TRUE;
@@ -865,8 +862,8 @@ google_book_update_contact (GoogleBook *book,
 {
     GoogleBookPrivate *priv;
     GDataEntry *entry, *new_entry;
-    GError *soup_error = NULL;
     EContact *cached_contact;
+    gchar *xml;
     const gchar *uid;
 
     *out_contact = NULL;
@@ -884,27 +881,32 @@ google_book_update_contact (GoogleBook *book,
     cached_contact = google_book_cache_get_contact (book, uid, &entry);
     if (NULL == cached_contact) {
         g_set_error (error,
-                    GOOGLE_BOOK_ERROR,
-                    GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND,
-                    "Contact with uid %s not found in cache.", uid);
+                     GDATA_SERVICE_ERROR,
+                     GDATA_SERVICE_ERROR_NOT_FOUND,
+                     "Contact with uid %s not found in cache.", uid);
         return FALSE;
     }
     g_object_unref (cached_contact);
     _gdata_entry_update_from_e_contact (entry, contact);
 
-    __debug__ ("Before:\n%s", gdata_entry_generate_xml (entry));
-    new_entry = gdata_service_update_entry (GDATA_SERVICE (priv->service), entry, &soup_error);
+    xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
+    __debug__ ("Before:\n%s", xml);
+    g_free (xml);
+
+    new_entry = GDATA_ENTRY (gdata_contacts_service_update_contact (GDATA_CONTACTS_SERVICE (priv->service), GDATA_CONTACTS_CONTACT (entry),
+                                                                    NULL, error));
     g_object_unref (entry);
 
-    if (soup_error) {
-        google_book_error_from_soup_error (soup_error, error,
-                                           "Updating entry failed");
+    if (!new_entry)
         return FALSE;
-    }
-    __debug__ ("After:\n%s", new_entry ? gdata_entry_generate_xml (new_entry) : NULL);
 
-    *out_contact = google_book_cache_add_contact (book, new_entry);
+    xml = NULL;
+    if (new_entry)
+        xml = gdata_parsable_get_xml (GDATA_PARSABLE (new_entry));
+    __debug__ ("After:\n%s", xml);
+    g_free (xml);
 
+    *out_contact = google_book_cache_add_contact (book, new_entry);
     g_object_unref (new_entry);
 
     return TRUE;
@@ -915,8 +917,8 @@ google_book_remove_contact (GoogleBook *book, const gchar *uid, GError **error)
 {
     GoogleBookPrivate *priv;
     GDataEntry *entry = NULL;
-    GError *soup_error = NULL;
     EContact *cached_contact;
+    gboolean success;
 
     __debug__ (G_STRFUNC);
     g_return_val_if_fail (IS_GOOGLE_BOOK (book), FALSE);
@@ -927,25 +929,16 @@ google_book_remove_contact (GoogleBook *book, const gchar *uid, GError **error)
 
     cached_contact = google_book_cache_get_contact (book, uid, &entry);
     if (NULL == cached_contact) {
-        g_set_error (error,
-                    GOOGLE_BOOK_ERROR,
-                    GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND,
-                    "Contact with uid %s not found in cache.", uid);
+        g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NOT_FOUND, "Contact with uid %s not found in cache.", uid);
         return FALSE;
     }
 
     google_book_cache_remove_contact (book, uid);
-    gdata_service_delete_entry (GDATA_SERVICE (priv->service), entry, &soup_error);
+    success = gdata_service_delete_entry (GDATA_SERVICE (priv->service), entry, NULL, error);
     g_object_unref (entry);
     g_object_unref (cached_contact);
 
-    if (soup_error) {
-        google_book_error_from_soup_error (soup_error, error,
-                                           "Removing entry failed");
-        return FALSE;
-    }
-
-    return TRUE;
+    return success;
 }
 
 static void
@@ -954,20 +947,19 @@ process_subsequent_entry (gpointer list_data, gpointer user_data)
     GoogleBookPrivate *priv;
     GoogleBook *book = user_data;
     GDataEntry *entry;
-    EContact *cached_contact;
-    gboolean is_deleted;
+    gboolean is_deleted, is_cached;
     const gchar *uid;
 
     __debug__ (G_STRFUNC);
     priv = GET_PRIVATE (book);
     entry = GDATA_ENTRY (list_data);
     uid = gdata_entry_get_id (entry);
-    is_deleted = gdata_entry_is_deleted (entry);
+    is_deleted = gdata_contacts_contact_is_deleted (GDATA_CONTACTS_CONTACT (entry));
 
-    cached_contact = google_book_cache_get_contact (book, uid, NULL);
+    is_cached = google_book_cache_has_contact (book, uid);
     if (is_deleted) {
         /* Do we have this item in our cache? */
-        if (NULL != cached_contact) {
+        if (is_cached) {
             google_book_cache_remove_contact (book, uid);
             google_book_emit_contact_removed (book, uid);
         }
@@ -976,16 +968,13 @@ process_subsequent_entry (gpointer list_data, gpointer user_data)
 
         contact = google_book_cache_add_contact (book, entry);
 
-        if (cached_contact) {
+        if (is_cached) {
             google_book_emit_contact_changed (book, contact);
         } else {
             google_book_emit_contact_added (book, contact);
         }
         g_object_unref (contact);
     }
-    if (cached_contact) {
-        g_object_unref (cached_contact);
-    }
 }
 
 static void
@@ -994,13 +983,11 @@ process_initial_entry (gpointer list_data, gpointer user_data)
     GoogleBookPrivate *priv;
     GoogleBook *book = user_data;
     GDataEntry *entry;
-    const gchar * uid;
     EContact *contact;
 
     __debug__ (G_STRFUNC);
     priv = GET_PRIVATE (book);
     entry = GDATA_ENTRY (list_data);
-    uid = gdata_entry_get_id (entry);
 
     contact = google_book_cache_add_contact (book, entry);
 
@@ -1014,10 +1001,13 @@ google_book_get_new_contacts_in_chunks (GoogleBook *book,
                                         GError    **error)
 {
     GoogleBookPrivate *priv;
-    gint start_index = 1;
+    GDataFeed *feed;
+    GDataQuery *query;
     gchar *last_updated;
     GError *our_error = NULL;
     gboolean rv = TRUE;
+    GTimeVal current_time;
+    int results;
 
     priv = GET_PRIVATE (book);
 
@@ -1028,28 +1018,24 @@ google_book_get_new_contacts_in_chunks (GoogleBook *book,
 
     google_book_cache_freeze (book);
 
-    while (start_index > 0) {
-        GDataFeed *feed;
-        GSList *entries;
-        GString *uri;
-        gint results;
-        GError *soup_error = NULL;
-
-        uri = g_string_new (priv->base_uri);
-        g_string_append_printf (uri, "?max-results=%d&start-index=%d",
-                                chunk_size, start_index);
-        if (last_updated) {
-            g_string_append_printf (uri, "&updated-min=%s&showdeleted=true",
-                                    last_updated);
-        }
+    /* Build our query */
+    query = GDATA_QUERY (gdata_contacts_query_new_with_limits (NULL, 1, chunk_size));
+    if (last_updated) {
+        GTimeVal updated;
+
+        g_assert (g_time_val_from_iso8601 (last_updated, &updated) == TRUE);
+        gdata_query_set_updated_min (query, &updated);
+        gdata_contacts_query_set_show_deleted (GDATA_CONTACTS_QUERY (query), TRUE);
+    }
 
-        __debug__ ("URI is '%s'", uri->str);
-        feed = gdata_service_get_feed (priv->service, uri->str, &soup_error);
-        g_string_free (uri, TRUE);
+    /* Get the paginated results */
+    do {
+        GList *entries;
 
-        if (soup_error) {
-            google_book_error_from_soup_error (soup_error, &our_error,
-                                               "Downloading feed failed");
+        /* Run the query */
+        feed = gdata_contacts_service_query_contacts (GDATA_CONTACTS_SERVICE (priv->service), query, NULL, NULL, NULL, &our_error);
+
+        if (our_error) {
             google_book_emit_sequence_complete (book, our_error);
             g_propagate_error (error, our_error);
 
@@ -1058,27 +1044,25 @@ google_book_get_new_contacts_in_chunks (GoogleBook *book,
         }
 
         entries = gdata_feed_get_entries (feed);
-        results = entries ? g_slist_length (entries) : 0;
+        results = entries ? g_list_length (entries) : 0;
         __debug__ ("Feed has %d entries", results);
 
-        if (last_updated) {
-            g_slist_foreach (entries, process_subsequent_entry, book);
-        } else {
-            g_slist_foreach (entries, process_initial_entry, book);
-        }
+        /* Process the entries from this page */
+        if (last_updated)
+            g_list_foreach (entries, process_subsequent_entry, book);
+        else
+            g_list_foreach (entries, process_initial_entry, book);
+        g_object_unref (feed);
 
-        if (results == chunk_size) {
-            start_index += results;
-        } else {
-            GTimeVal current_time;
+        /* Move to the next page */
+        gdata_query_next_page (query);
+    } while (results == chunk_size);
+
+    /* Finish updating the cache */
+    g_get_current_time (&current_time);
+    google_book_cache_set_last_update (book, &current_time);
+    google_book_emit_sequence_complete (book, NULL);
 
-            start_index = -1;
-            g_get_current_time (&current_time);
-            google_book_cache_set_last_update (book, &current_time);
-            google_book_emit_sequence_complete (book, NULL);
-        }
-        g_object_unref (feed);
-    }
 out:
     g_free (last_updated);
     google_book_cache_thaw (book);
@@ -1093,30 +1077,30 @@ google_book_get_contact (GoogleBook *book,
 {
     GoogleBookPrivate *priv;
     EContact *contact;
+    GError *child_error = NULL;
 
     priv = GET_PRIVATE (book);
 
     __debug__ (G_STRFUNC);
     g_return_val_if_fail (IS_GOOGLE_BOOK (book), NULL);
 
-    google_book_cache_refresh_if_needed (book, error);
+    google_book_cache_refresh_if_needed (book, &child_error);
 
     contact = google_book_cache_get_contact (book, uid, NULL);
 
     if (contact) {
-        if (*error) {
+        if (child_error) {
             /* We found the contact, so forget about errors during refresh */
-            g_clear_error (error);
+            g_error_free (child_error);
         }
         return contact;
-    } else {
-        if (NULL == *error) {
-            g_set_error (error,
-                        GOOGLE_BOOK_ERROR,
-                        GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND,
-                        "Contact with uid %s not found in cache.", uid);
-        }
     }
+
+    if (!child_error)
+        g_propagate_error (error, child_error);
+    else
+        g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NOT_FOUND, "Contact with uid %s not found in cache.", uid);
+
     return NULL;
 }
 
@@ -1126,23 +1110,26 @@ google_book_get_all_contacts (GoogleBook *book,
 {
     GoogleBookPrivate *priv;
     GList *contacts;
+    GError *child_error = NULL;
 
     priv = GET_PRIVATE (book);
 
     __debug__ (G_STRFUNC);
     g_return_val_if_fail (IS_GOOGLE_BOOK (book), NULL);
 
-    google_book_cache_refresh_if_needed (book, error);
+    google_book_cache_refresh_if_needed (book, &child_error);
 
     contacts = google_book_cache_get_contacts (book);
 
     if (contacts) {
-        if (*error) {
+        if (child_error) {
             /* We found the contact, so forget about errors during refresh */
-            g_clear_error (error);
+            g_error_free (child_error);
         }
         return contacts;
     }
+
+    g_propagate_error (error, child_error);
     return NULL;
 }
 
@@ -1209,46 +1196,3 @@ google_book_set_live_mode (GoogleBook *book, gboolean live_mode)
         google_book_cache_refresh_if_needed (book, NULL);
     }
 }
-
-static void
-google_book_error_from_soup_error (GError     *soup_error,
-                                   GError    **error,
-                                   const gchar *message)
-{
-    GoogleBookError code;
-
-    g_assert (soup_error);
-
-    if (soup_error->code < 100) {
-        code = GOOGLE_BOOK_ERROR_NETWORK_ERROR;
-    } else
-    if (soup_error->code == 200) {
-        code = GOOGLE_BOOK_ERROR_NONE;
-    } else
-    if (soup_error->code == 400) {
-        code = GOOGLE_BOOK_ERROR_INVALID_CONTACT;
-    } else
-    if (soup_error->code == 401) {
-        code = GOOGLE_BOOK_ERROR_AUTH_REQUIRED;
-    } else
-    if (soup_error->code == 403) {
-        code = GOOGLE_BOOK_ERROR_AUTH_FAILED;
-    } else
-    if (soup_error->code == 404) {
-        code = GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND;
-    } else
-    if (soup_error->code == 409) {
-        code = GOOGLE_BOOK_ERROR_CONFLICT;
-    } else {
-        code = GOOGLE_BOOK_ERROR_HTTP_ERROR;
-    }
-    g_set_error (error,
-                GOOGLE_BOOK_ERROR,
-                code,
-                "%s due to '%s' (HTTP code %d)",
-                message ? message : "Action failed",
-                soup_error->message,
-                soup_error->code);
-    g_clear_error (&soup_error);
-}
-
diff --git a/addressbook/backends/google/google-book.h b/addressbook/backends/google/google-book.h
index ea1e85c..09cc9b6 100644
--- a/addressbook/backends/google/google-book.h
+++ b/addressbook/backends/google/google-book.h
@@ -45,7 +45,6 @@ G_BEGIN_DECLS
 
 typedef struct _GoogleBook      GoogleBook;
 typedef struct _GoogleBookClass GoogleBookClass;
-typedef enum   _GoogleBookError GoogleBookError;
 
 struct _GoogleBook
 {
@@ -64,20 +63,6 @@ struct _GoogleBookClass
     void (*auth_required) (void);
 };
 
-enum _GoogleBookError
-{
-    GOOGLE_BOOK_ERROR_NONE,
-    GOOGLE_BOOK_ERROR_CONTACT_NOT_FOUND,
-    GOOGLE_BOOK_ERROR_INVALID_CONTACT,
-    GOOGLE_BOOK_ERROR_CONFLICT,
-    GOOGLE_BOOK_ERROR_AUTH_FAILED,
-    GOOGLE_BOOK_ERROR_AUTH_REQUIRED,
-    GOOGLE_BOOK_ERROR_NETWORK_ERROR,
-    GOOGLE_BOOK_ERROR_HTTP_ERROR
-};
-
-#define GOOGLE_BOOK_ERROR (g_quark_from_string ("GoogleBookError"))
-
 typedef void (*GoogleBookContactRetrievedCallback) (EContact *contact, gpointer user_data);
 
 GType google_book_get_type (void);
diff --git a/addressbook/backends/google/util.c b/addressbook/backends/google/util.c
index e7569e5..626a359 100644
--- a/addressbook/backends/google/util.c
+++ b/addressbook/backends/google/util.c
@@ -1,6 +1,7 @@
 /* util.c - Google contact backend utility functions.
  *
  * Copyright (C) 2008 Joergen Scheibengruber
+ * Copyright (C) 2010 Philip Withnall
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by the
@@ -21,39 +22,24 @@
 
 #include <string.h>
 #include <libsoup/soup.h>
+#include <gdata/gdata.h>
+#include <gdata/services/contacts/gdata-contacts-contact.h>
 #include "util.h"
 
-/*#define GOOGLE_PRIMARY_PARAM "X-GOOGLE-PRIMARY"*/
 #define GOOGLE_PRIMARY_PARAM "X-EVOLUTION-UI-SLOT"
 #define GOOGLE_LABEL_PARAM "X-GOOGLE-LABEL"
+#define GDATA_ENTRY_XML_ATTR "X-GDATA-ENTRY-XML"
+#define GDATA_ENTRY_LINK_ATTR "X-GDATA-ENTRY-LINK"
 
-static EVCardAttribute*
-attribute_from_gdata_entry_email_address  (GDataEntryEmailAddress  *email);
-
-static EVCardAttribute*
-attribute_from_gdata_entry_im_address     (GDataEntryIMAddress     *im);
-
-static EVCardAttribute*
-attribute_from_gdata_entry_phone_number   (GDataEntryPhoneNumber   *number);
-
-static EVCardAttribute*
-attribute_from_gdata_entry_postal_address (GDataEntryPostalAddress *address);
-
-static GDataEntryEmailAddress*
-gdata_entry_email_address_from_attribute  (EVCardAttribute         *attr,
-                                           gboolean                *primary);
-
-static GDataEntryIMAddress*
-gdata_entry_im_address_from_attribute     (EVCardAttribute         *attr,
-                                           gboolean                *primary);
-
-static GDataEntryPhoneNumber*
-gdata_entry_phone_number_from_attribute   (EVCardAttribute         *attr,
-                                           gboolean                *primary);
+static void add_attribute_from_gdata_gd_email_address (EVCard *vcard, GDataGDEmailAddress *email);
+static void add_attribute_from_gdata_gd_im_address (EVCard *vcard, GDataGDIMAddress *im);
+static void add_attribute_from_gdata_gd_phone_number (EVCard *vcard, GDataGDPhoneNumber *number);
+static void add_attribute_from_gdata_gd_postal_address (EVCard *vcard, GDataGDPostalAddress *address);
 
-static GDataEntryPostalAddress*
-gdata_entry_postal_address_from_attribute (EVCardAttribute         *attr,
-                                           gboolean                *primary);
+static GDataGDEmailAddress *gdata_gd_email_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDIMAddress *gdata_gd_im_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDPhoneNumber *gdata_gd_phone_number_from_attribute (EVCardAttribute *attr, gboolean *primary);
+static GDataGDPostalAddress *gdata_gd_postal_address_from_attribute (EVCardAttribute *attr, gboolean *primary);
 
 static gboolean
 is_known_google_im_protocol (const gchar *protocol);
@@ -61,15 +47,7 @@ is_known_google_im_protocol (const gchar *protocol);
 GDataEntry*
 _gdata_entry_new_from_e_contact (EContact *contact)
 {
-    GDataEntry *entry;
-    GDataEntryCategory *category;
-
-    entry = gdata_entry_new ();
-
-    category = g_new0 (GDataEntryCategory, 1);
-    category->scheme = g_strdup ("http://schemas.google.com/g/2005#kind";);
-    category->term = g_strdup ("http://schemas.google.com/contact/2008#contact";);
-    gdata_entry_set_categories (entry, g_slist_append (NULL, category));
+    GDataEntry *entry = GDATA_ENTRY (gdata_contacts_contact_new (NULL));
 
     if (_gdata_entry_update_from_e_contact (entry, contact))
         return entry;
@@ -84,11 +62,7 @@ _gdata_entry_update_from_e_contact (GDataEntry *entry,
                                     EContact   *contact)
 {
     GList *attributes, *iter;
-    gchar *fullname = NULL;
-    GSList *email_addresses = NULL;
-    GSList *im_addresses = NULL;
-    GSList *phone_numbers = NULL;
-    GSList *postal_addresses = NULL;
+    EContactName *name_struct = NULL;
     gboolean have_email_primary = FALSE;
     gboolean have_im_primary = FALSE;
     gboolean have_phone_primary = FALSE;
@@ -96,14 +70,36 @@ _gdata_entry_update_from_e_contact (GDataEntry *entry,
 
     attributes = e_vcard_get_attributes (E_VCARD (contact));
 
-    fullname = g_strdup (e_contact_get (contact, E_CONTACT_FULL_NAME));
-    if (NULL == fullname) {
-        EContactName *name = e_contact_get (contact, E_CONTACT_NAME);
-
-        fullname = e_contact_name_to_string (name);
-        e_contact_name_free (name);
+    /* N and FN */
+    name_struct = e_contact_get (contact, E_CONTACT_NAME);
+    if (name_struct) {
+        GDataGDName *name;
+        const gchar *given = NULL, *family = NULL;
+
+        if (name_struct->given && *(name_struct->given) != '\0')
+            given = name_struct->given;
+        if (name_struct->family && *(name_struct->family) != '\0')
+            family = name_struct->family;
+
+        name = gdata_gd_name_new (given, family);
+        if (name_struct->additional && *(name_struct->additional) != '\0')
+            gdata_gd_name_set_additional_name (name, name_struct->additional);
+        if (name_struct->prefixes && *(name_struct->prefixes) != '\0')
+            gdata_gd_name_set_prefix (name, name_struct->prefixes);
+        if (name_struct->suffixes && *(name_struct->suffixes) != '\0')
+            gdata_gd_name_set_suffix (name, name_struct->suffixes);
+        gdata_gd_name_set_full_name (name, e_contact_get (contact, E_CONTACT_FULL_NAME));
+
+        gdata_contacts_contact_set_name (GDATA_CONTACTS_CONTACT (entry), name);
+        g_object_unref (name);
     }
 
+    /* Clear out all the old attributes */
+    gdata_contacts_contact_remove_all_email_addresses (GDATA_CONTACTS_CONTACT (entry));
+    gdata_contacts_contact_remove_all_phone_numbers (GDATA_CONTACTS_CONTACT (entry));
+    gdata_contacts_contact_remove_all_postal_addresses (GDATA_CONTACTS_CONTACT (entry));
+    gdata_contacts_contact_remove_all_im_addresses (GDATA_CONTACTS_CONTACT (entry));
+
     /* We walk them in reverse order, so we can find
      * the correct primaries */
     iter = g_list_last (attributes);
@@ -116,59 +112,67 @@ _gdata_entry_update_from_e_contact (GDataEntry *entry,
 
         /* EMAIL */
 
-        /* Ignore UID, VERSION, X-EVOLUTION-FILE-AS, N, FN */
+        /* Ignore UID, VERSION, X-EVOLUTION-FILE-AS, N, FN, LABEL */
         if (0 == g_ascii_strcasecmp (name, EVC_UID) ||
             0 == g_ascii_strcasecmp (name, EVC_N) ||
             0 == g_ascii_strcasecmp (name, EVC_FN) ||
+            0 == g_ascii_strcasecmp (name, EVC_LABEL) ||
             0 == g_ascii_strcasecmp (name, EVC_VERSION) ||
             0 == g_ascii_strcasecmp (name, EVC_X_FILE_AS)) {
         } else
         if (0 == g_ascii_strcasecmp (name, EVC_EMAIL)) {
-            GDataEntryEmailAddress *email;
+            GDataGDEmailAddress *email;
 
-            email = gdata_entry_email_address_from_attribute
+            email = gdata_gd_email_address_from_attribute
                         (attr, &have_email_primary);
             if (email) {
-                email_addresses = g_slist_append (email_addresses,
-                                                  email);
+                gdata_contacts_contact_add_email_address (GDATA_CONTACTS_CONTACT (entry), email);
+                g_object_unref (email);
             }
         } else
 
         /* TEL */
         if (0 == g_ascii_strcasecmp (name, EVC_TEL)) {
-            GDataEntryPhoneNumber *number;
+            GDataGDPhoneNumber *number;
 
-            number = gdata_entry_phone_number_from_attribute
+            number = gdata_gd_phone_number_from_attribute
                         (attr, &have_phone_primary);
             if (number) {
-                phone_numbers = g_slist_append (phone_numbers,
-                                                number);
+                gdata_contacts_contact_add_phone_number (GDATA_CONTACTS_CONTACT (entry), number);
+                g_object_unref (number);
             }
         } else
 
-        /* LABEL */
-        if (0 == g_ascii_strcasecmp (name, EVC_LABEL)) {
-            GDataEntryPostalAddress *address;
+        /* ADR (we ignore LABEL, since it should be the same as ADR, and ADR is more structured) */
+        if (0 == g_ascii_strcasecmp (name, EVC_ADR)) {
+            GDataGDPostalAddress *address;
 
-            address = gdata_entry_postal_address_from_attribute
+            address = gdata_gd_postal_address_from_attribute
                         (attr, &have_postal_primary);
             if (address) {
-                postal_addresses = g_slist_append (postal_addresses,
-                                                   address);
+                gdata_contacts_contact_add_postal_address (GDATA_CONTACTS_CONTACT (entry), address);
+                g_object_unref (address);
             }
         } else
 
         /* X-IM */
         if (0 == g_ascii_strncasecmp (name, "X-", 2) &&
             is_known_google_im_protocol (name + 2)) {
-            GDataEntryIMAddress *im;
+            GDataGDIMAddress *im;
 
-            im = gdata_entry_im_address_from_attribute
+            im = gdata_gd_im_address_from_attribute
                         (attr, &have_im_primary);
             if (im) {
-                im_addresses = g_slist_append (im_addresses,
-                                               im);
+                gdata_contacts_contact_add_im_address (GDATA_CONTACTS_CONTACT (entry), im);
+                g_object_unref (im);
             }
+        } else if (e_vcard_attribute_is_single_valued (attr)) {
+            gchar *value;
+
+            /* Add the attribute as an extended property */
+            value = e_vcard_attribute_get_value (attr);
+            gdata_contacts_contact_set_extended_property (GDATA_CONTACTS_CONTACT (entry), name, value);
+            g_free (value);
         } else {
             GList *values;
 
@@ -178,29 +182,33 @@ _gdata_entry_update_from_e_contact (GDataEntry *entry,
             }
         }
     }
-    gdata_entry_set_title (entry, fullname);
-    g_free (fullname);
-    gdata_entry_set_email_addresses (entry, email_addresses);
-    gdata_entry_set_im_addresses (entry, im_addresses);
-    gdata_entry_set_phone_numbers (entry, phone_numbers);
-    gdata_entry_set_postal_addresses (entry, postal_addresses);
 
     return TRUE;
 }
 
+static void
+foreach_extended_props_cb (const gchar *name, const gchar *value, EVCard *vcard)
+{
+    EVCardAttribute *attr;
+
+    attr = e_vcard_attribute_new (NULL, name);
+    e_vcard_add_attribute_with_value (vcard, attr, value);
+}
+
 EContact*
 _e_contact_new_from_gdata_entry (GDataEntry *entry)
 {
     EVCard *vcard;
     EVCardAttribute *attr;
-    GSList *email_addresses, *im_addresses, *phone_numbers, *postal_addresses;
-    const gchar *name;
+    GList *email_addresses, *im_addresses, *phone_numbers, *postal_addresses;
     const gchar *uid;
-    GSList *itr;
-    GDataEntryEmailAddress *email;
-    GDataEntryIMAddress *im;
-    GDataEntryPhoneNumber *phone_number;
-    GDataEntryPostalAddress *postal_address;
+    GList *itr;
+    GDataGDName *name;
+    GDataGDEmailAddress *email;
+    GDataGDIMAddress *im;
+    GDataGDPhoneNumber *phone_number;
+    GDataGDPostalAddress *postal_address;
+    GHashTable *extended_props;
 
     uid = gdata_entry_get_id (entry);
     if (NULL == uid) {
@@ -213,111 +221,126 @@ _e_contact_new_from_gdata_entry (GDataEntry *entry)
     attr = e_vcard_attribute_new (NULL, EVC_UID);
     e_vcard_add_attribute_with_value (vcard, attr, uid);
 
-    /* FN - TODO: get title */
-    name = gdata_entry_get_title (entry);
+    /* FN, N */
+    name = gdata_contacts_contact_get_name (GDATA_CONTACTS_CONTACT (entry));
     if (name) {
-        e_contact_set (E_CONTACT (vcard), E_CONTACT_FULL_NAME, (gconstpointer)name);
+        EContactName name_struct;
+
+        /* Set the full name */
+        e_contact_set (E_CONTACT (vcard), E_CONTACT_FULL_NAME, gdata_gd_name_get_full_name (name));
+
+        /* We just need to set the E_CONTACT_NAME field, and all the other name attribute values
+         * in the EContact will be populated automatically from that */
+        name_struct.family = (gchar*) gdata_gd_name_get_family_name (name);
+        name_struct.given = (gchar*) gdata_gd_name_get_given_name (name);
+        name_struct.additional = (gchar*) gdata_gd_name_get_additional_name (name);
+        name_struct.prefixes = (gchar*) gdata_gd_name_get_prefix (name);
+        name_struct.suffixes = (gchar*) gdata_gd_name_get_suffix (name);
+
+        e_contact_set (E_CONTACT (vcard), E_CONTACT_NAME, &name_struct);
     }
 
     /* EMAIL - primary first */
-    email = gdata_entry_get_primary_email_address (entry);
-    attr = attribute_from_gdata_entry_email_address (email);
-    if (attr) {
-        e_vcard_add_attribute (vcard, attr);
-    }
+    email = gdata_contacts_contact_get_primary_email_address (GDATA_CONTACTS_CONTACT (entry));
+    add_attribute_from_gdata_gd_email_address (vcard, email);
 
-    email_addresses = gdata_entry_get_email_addresses (entry);
+    email_addresses = gdata_contacts_contact_get_email_addresses (GDATA_CONTACTS_CONTACT (entry));
     for (itr = email_addresses; itr; itr = itr->next) {
         email = itr->data;
-        if (TRUE == email->primary)
+        if (gdata_gd_email_address_is_primary (email) == TRUE)
             continue;
-        attr = attribute_from_gdata_entry_email_address (email);
-        if (attr) {
-            e_vcard_add_attribute (vcard, attr);
-        }
+        add_attribute_from_gdata_gd_email_address (vcard, email);
     }
 
     /* X-IM - primary first */
-    im = gdata_entry_get_primary_im_address (entry);
-    attr = attribute_from_gdata_entry_im_address (im);
-    if (attr) {
-        e_vcard_add_attribute (vcard, attr);
-    }
-    im_addresses = gdata_entry_get_im_addresses (entry);
+    im = gdata_contacts_contact_get_primary_im_address (GDATA_CONTACTS_CONTACT (entry));
+    add_attribute_from_gdata_gd_im_address (vcard, im);
+
+    im_addresses = gdata_contacts_contact_get_im_addresses (GDATA_CONTACTS_CONTACT (entry));
     for (itr = im_addresses; itr; itr = itr->next) {
         im = itr->data;
-        if (TRUE == im->primary)
+        if (gdata_gd_im_address_is_primary (im) == TRUE)
             continue;
-        attr = attribute_from_gdata_entry_im_address (im);
-        if (attr) {
-            e_vcard_add_attribute (vcard, attr);
-        }
+        add_attribute_from_gdata_gd_im_address (vcard, im);
     }
 
     /* TEL - primary first */
-    phone_number = gdata_entry_get_primary_phone_number (entry);
-    attr = attribute_from_gdata_entry_phone_number (phone_number);
-    if (attr) {
-        e_vcard_add_attribute (vcard, attr);
-    }
-    phone_numbers = gdata_entry_get_phone_numbers (entry);
+    phone_number = gdata_contacts_contact_get_primary_phone_number (GDATA_CONTACTS_CONTACT (entry));
+    add_attribute_from_gdata_gd_phone_number (vcard, phone_number);
+
+    phone_numbers = gdata_contacts_contact_get_phone_numbers (GDATA_CONTACTS_CONTACT (entry));
     for (itr = phone_numbers; itr; itr = itr->next) {
         phone_number = itr->data;
-        if (TRUE == phone_number->primary)
+        if (gdata_gd_phone_number_is_primary (phone_number) == TRUE)
             continue;
-        attr = attribute_from_gdata_entry_phone_number (phone_number);
-        if (attr) {
-            e_vcard_add_attribute (vcard, attr);
-        }
+        add_attribute_from_gdata_gd_phone_number (vcard, phone_number);
     }
 
-    /* LABEL - primary first TODO: ADR */
-    postal_address = gdata_entry_get_primary_postal_address (entry);
-    attr = attribute_from_gdata_entry_postal_address (postal_address);
-    if (attr) {
-        e_vcard_add_attribute (vcard, attr);
-    }
-    postal_addresses = gdata_entry_get_postal_addresses (entry);
+    /* LABEL and ADR - primary first */
+    postal_address = gdata_contacts_contact_get_primary_postal_address (GDATA_CONTACTS_CONTACT (entry));
+    add_attribute_from_gdata_gd_postal_address (vcard, postal_address);
+
+    postal_addresses = gdata_contacts_contact_get_postal_addresses (GDATA_CONTACTS_CONTACT (entry));
     for (itr = postal_addresses; itr; itr = itr->next) {
         postal_address = itr->data;
-        if (TRUE == postal_address->primary)
+        if (gdata_gd_postal_address_is_primary (postal_address) == TRUE)
             continue;
-        attr = attribute_from_gdata_entry_postal_address (postal_address);
-        if (attr) {
-            e_vcard_add_attribute (vcard, attr);
-        }
+        add_attribute_from_gdata_gd_postal_address (vcard, postal_address);
     }
 
+    /* Extended properties */
+    extended_props = gdata_contacts_contact_get_extended_properties (GDATA_CONTACTS_CONTACT (entry));
+    g_hash_table_foreach (extended_props, (GHFunc) foreach_extended_props_cb, vcard);
+
     return E_CONTACT (vcard);
 }
 
-#define GDATA_ENTRY_XML_ATTR "X-GDATA-ENTRY-XML"
-
 void
 _e_contact_add_gdata_entry_xml (EContact *contact, GDataEntry *entry)
 {
     EVCardAttribute *attr;
-    const gchar * entry_xml;
-
-    entry_xml = gdata_entry_generate_xml (entry);
+    gchar *entry_xml;
+    GDataLink *link;
 
+    /* Cache the XML representing the entry */
+    entry_xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
     attr = e_vcard_attribute_new ("", GDATA_ENTRY_XML_ATTR);
     e_vcard_attribute_add_value (attr, entry_xml);
     e_vcard_add_attribute (E_VCARD (contact), attr);
+    g_free (entry_xml);
+
+    /* Also add the update URI for the entry, since that's not serialised by gdata_parsable_get_xml */
+    link = gdata_entry_look_up_link (entry, GDATA_LINK_EDIT);
+    if (link != NULL) {
+        attr = e_vcard_attribute_new ("", GDATA_ENTRY_LINK_ATTR);
+        e_vcard_attribute_add_value (attr, gdata_link_get_uri (link));
+        e_vcard_add_attribute (E_VCARD (contact), attr);
+    }
 }
 
 void
 _e_contact_remove_gdata_entry_xml (EContact *contact)
 {
     e_vcard_remove_attributes (E_VCARD (contact), NULL, GDATA_ENTRY_XML_ATTR);
+    e_vcard_remove_attributes (E_VCARD (contact), NULL, GDATA_ENTRY_LINK_ATTR);
 }
 
 const gchar *
-_e_contact_get_gdata_entry_xml (EContact *contact)
+_e_contact_get_gdata_entry_xml (EContact *contact, const gchar **edit_link)
 {
     EVCardAttribute *attr;
-    GList *values;
+    GList *values = NULL;
 
+    /* Return the edit link if asked */
+    if (edit_link != NULL) {
+        attr = e_vcard_get_attribute (E_VCARD (contact), GDATA_ENTRY_LINK_ATTR);
+        if (attr != NULL)
+            values = e_vcard_attribute_get_values (attr);
+        if (values != NULL)
+            *edit_link = values->data;
+    }
+
+    /* Return the entry's XML */
     attr = e_vcard_get_attribute (E_VCARD (contact), GDATA_ENTRY_XML_ATTR);
     values = e_vcard_attribute_get_values (attr);
 
@@ -325,35 +348,55 @@ _e_contact_get_gdata_entry_xml (EContact *contact)
 }
 
 struct RelTypeMap {
-    const gchar * rel;
-    const gchar * types[3];
+    const gchar *rel;
+    const gchar *types[2];
 };
 
+/* NOTE: These maps must be kept ordered with the one-to-many types first */
 static const struct RelTypeMap rel_type_map_phone[] = {
-    {"fax", { "FAX", NULL, NULL}},
-    {"home", { "HOME", "VOICE", NULL}},
-    {"home_fax", { "HOME", "FAX", NULL}},
-    {"mobile", { "CELL", NULL, NULL}},
-    {"other", { "VOICE", NULL, NULL}},
-    {"pager", { "PAGER", NULL, NULL}},
-    {"work", { "WORK", "VOICE", NULL}},
-    {"work_fax", { "WORK", "FAX", NULL}}
+    {"home", { "HOME", "VOICE"}},
+    {"home_fax", { "HOME", "FAX"}},
+    {"work", { "WORK", "VOICE"}},
+    {"work_fax", { "WORK", "FAX"}},
+    {"work_mobile", { "WORK", "CELL"}},
+    {"work_pager", { "WORK", "PAGER"}},
+    {"assistant", { EVC_X_ASSISTANT, NULL}},
+    {"callback", { EVC_X_CALLBACK, NULL}},
+    {"car", { "CAR", NULL}},
+    {"company_main", {EVC_X_COMPANY, NULL}},
+    {"fax", { "FAX", NULL}},
+    {"isdn", { "ISDN", NULL}},
+    {"main", { "PREF", NULL}},
+    {"mobile", { "CELL", NULL}},
+    {"other", { "VOICE", NULL}},
+    {"other_fax", { "FAX", NULL}},
+    {"pager", { "PAGER", NULL}},
+    {"radio", { EVC_X_RADIO, NULL}},
+    {"telex", { EVC_X_TELEX, NULL}},
+    {"tty_tdd", { EVC_X_TTYTDD, NULL}}
+};
+
+static const struct RelTypeMap rel_type_map_im[] = {
+    {"home", { "HOME", NULL}},
+    {"netmeeting", { "NETMEETING", NULL}},
+    {"other", { "OTHER", NULL}},
+    {"work", { "WORK", NULL}},
 };
 
 static const struct RelTypeMap rel_type_map_others[] = {
-    {"home", { "HOME", NULL, NULL}},
-    {"other", { "OTHER", NULL, NULL}},
-    {"work", { "WORK", NULL, NULL}},
+    {"home", { "HOME", NULL}},
+    {"other", { "OTHER", NULL}},
+    {"work", { "WORK", NULL}},
 };
 
 static gboolean
 _add_type_param_from_google_rel (EVCardAttribute *attr,
                                  const struct RelTypeMap rel_type_map[],
-                                 gint map_len,
+                                 guint map_len,
                                  const gchar *rel)
 {
     const gchar * field;
-    gint i;
+    guint i;
 
     field = strstr (rel ? rel : "", "#");
     if (NULL == field)
@@ -363,11 +406,10 @@ _add_type_param_from_google_rel (EVCardAttribute *attr,
     for (i = 0; i < map_len; i++) {
         if (0 == g_ascii_strcasecmp (rel_type_map[i].rel, field)) {
             EVCardAttributeParam *param;
-            const gchar * const * type;
             param = e_vcard_attribute_param_new ("TYPE");
-            for (type = rel_type_map[i].types; *type; type++) {
-                e_vcard_attribute_param_add_value (param, *type);
-            }
+            e_vcard_attribute_param_add_value (param, rel_type_map[i].types[0]);
+            if (rel_type_map[i].types[1])
+                e_vcard_attribute_param_add_value (param, rel_type_map[i].types[1]);
             e_vcard_attribute_add_param (attr, param);
             return TRUE;
         }
@@ -387,6 +429,15 @@ add_type_param_from_google_rel_phone (EVCardAttribute *attr, const gchar *rel)
 }
 
 static gboolean
+add_type_param_from_google_rel_im (EVCardAttribute *attr, const gchar *rel)
+{
+    return _add_type_param_from_google_rel (attr,
+                                            rel_type_map_im,
+                                            G_N_ELEMENTS (rel_type_map_im),
+                                            rel);
+}
+
+static gboolean
 add_type_param_from_google_rel (EVCardAttribute *attr, const gchar *rel)
 {
     return _add_type_param_from_google_rel (attr,
@@ -408,28 +459,30 @@ add_label_param (EVCardAttribute *attr, const gchar *label)
 static gchar *
 _google_rel_from_types (GList *types,
                         const struct RelTypeMap rel_type_map[],
-                        gint map_len)
+                        guint map_len)
 {
     const gchar format[] = "http://schemas.google.com/g/2005#%s";;
+    guint i;
 
-    while (types) {
-        gint i;
-        GList *cur = types;
-        types = types->next;
-
-        for (i = 0; i < map_len; i++) {
-            if (0 == g_ascii_strcasecmp (rel_type_map[i].types[0], cur->data)) {
-                while (types && rel_type_map[i].types[1]) {
-                    if (0 == g_ascii_strcasecmp (rel_type_map[i].types[1], types->data)) {
-                        return g_strdup_printf (format, rel_type_map[i].rel);
-                    }
-                    types = types->next;
-                }
+    /* For each of the entries in the map... */
+    for (i = 0; i < map_len; i++) {
+        GList *cur;
+        gboolean first_matched = FALSE, second_matched = rel_type_map[i].types[1] ? FALSE : TRUE;
+
+        /* ...iterate through all the vCard's types and see if two of them match the types in the current map entry. */
+        for (cur = types; cur != NULL; cur = cur->next) {
+            if (0 == g_ascii_strcasecmp (rel_type_map[i].types[0], cur->data))
+                first_matched = TRUE;
+            else if (!rel_type_map[i].types[1] || 0 == g_ascii_strcasecmp (rel_type_map[i].types[1], cur->data))
+                second_matched = TRUE;
+
+            /* If they do, return the rel value from that entry... */
+            if (first_matched && second_matched)
                 return g_strdup_printf (format, rel_type_map[i].rel);
-            }
         }
     }
 
+    /* ...otherwise return an "other" result. */
     return g_strdup_printf (format, "other");
 }
 
@@ -457,7 +510,7 @@ is_known_google_im_protocol (const gchar *protocol)
         "AIM", "MSN", "YAHOO", "SKYPE", "QQ",
         "GOOGLE_TALK", "ICQ", "JABBER"
     };
-    gint i;
+    guint i;
 
     if (NULL == protocol)
         return FALSE;
@@ -470,7 +523,7 @@ is_known_google_im_protocol (const gchar *protocol)
 }
 
 static gchar *
-field_name_from_google_im_protocol (const gchar * google_protocol)
+field_name_from_google_im_protocol (const gchar *google_protocol)
 {
     gchar *protocol;
     if (NULL == google_protocol)
@@ -483,7 +536,7 @@ field_name_from_google_im_protocol (const gchar * google_protocol)
 }
 
 static gchar *
-google_im_protocol_from_field_name (const gchar * field_name)
+google_im_protocol_from_field_name (const gchar *field_name)
 {
     const gchar format[] = "http://schemas.google.com/g/2005#%s";;
 
@@ -546,96 +599,132 @@ get_google_primary_type_label (EVCardAttribute *attr,
     return types;
 }
 
-static EVCardAttribute*
-attribute_from_gdata_entry_email_address (GDataEntryEmailAddress *email)
+static void
+add_attribute_from_gdata_gd_email_address (EVCard *vcard, GDataGDEmailAddress *email)
 {
     EVCardAttribute *attr;
     gboolean has_type;
 
-    if (NULL == email || NULL == email->address)
-        return NULL;;
+    if (NULL == email || NULL == gdata_gd_email_address_get_address (email))
+        return;
 
     attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
-    has_type = add_type_param_from_google_rel (attr, email->rel);
-    if (email->primary) {
+    has_type = add_type_param_from_google_rel (attr, gdata_gd_email_address_get_relation_type (email));
+    if (gdata_gd_email_address_is_primary (email) == TRUE)
         add_primary_param (attr, has_type);
-    }
-    add_label_param (attr, email->label);
-    e_vcard_attribute_add_value (attr, email->address);
-    return attr;
+    add_label_param (attr, gdata_gd_email_address_get_label (email));
+
+    e_vcard_attribute_add_value (attr, gdata_gd_email_address_get_address (email));
+
+    if (attr)
+        e_vcard_add_attribute (vcard, attr);
 }
 
-static EVCardAttribute*
-attribute_from_gdata_entry_im_address (GDataEntryIMAddress *im)
+static void
+add_attribute_from_gdata_gd_im_address (EVCard *vcard, GDataGDIMAddress *im)
 {
     EVCardAttribute *attr;
     gboolean has_type;
     gchar *field_name;
 
-    if (NULL == im || NULL == im->address)
-        return NULL;;
+    if (NULL == im || NULL == gdata_gd_im_address_get_address (im))
+        return;
 
-    field_name = field_name_from_google_im_protocol (im->protocol);
+    field_name = field_name_from_google_im_protocol (gdata_gd_im_address_get_protocol (im));
     if (NULL == field_name)
-        return NULL;
+        return;
 
     attr = e_vcard_attribute_new (NULL, field_name);
-    has_type = add_type_param_from_google_rel (attr, im->rel);
-    if (im->primary) {
+    has_type = add_type_param_from_google_rel_im (attr, gdata_gd_im_address_get_relation_type (im));
+    if (gdata_gd_im_address_is_primary (im))
         add_primary_param (attr, has_type);
-    }
-    add_label_param (attr, im->label);
-    e_vcard_attribute_add_value (attr, im->address);
-    return attr;
+    add_label_param (attr, gdata_gd_im_address_get_label (im));
+
+    e_vcard_attribute_add_value (attr, gdata_gd_im_address_get_address (im));
+
+    if (attr)
+        e_vcard_add_attribute (vcard, attr);
 }
 
-static EVCardAttribute*
-attribute_from_gdata_entry_phone_number (GDataEntryPhoneNumber *number)
+static void
+add_attribute_from_gdata_gd_phone_number (EVCard *vcard, GDataGDPhoneNumber *number)
 {
     EVCardAttribute *attr;
     gboolean has_type;
 
-    if (NULL == number || NULL == number->number)
-        return NULL;;
+    if (NULL == number || NULL == gdata_gd_phone_number_get_number (number))
+        return;
 
     attr = e_vcard_attribute_new (NULL, EVC_TEL);
-    has_type = add_type_param_from_google_rel_phone (attr, number->rel);
-    if (number->primary) {
+    has_type = add_type_param_from_google_rel_phone (attr, gdata_gd_phone_number_get_relation_type (number));
+    if (gdata_gd_phone_number_is_primary (number))
         add_primary_param (attr, has_type);
-    }
-    add_label_param (attr, number->label);
-    e_vcard_attribute_add_value (attr, number->number);
-    return attr;
+    add_label_param (attr, gdata_gd_phone_number_get_label (number));
+
+    e_vcard_attribute_add_value (attr, gdata_gd_phone_number_get_number (number));
+
+    if (attr)
+        e_vcard_add_attribute (vcard, attr);
 }
 
-static EVCardAttribute*
-attribute_from_gdata_entry_postal_address (GDataEntryPostalAddress *address)
+static void
+add_attribute_from_gdata_gd_postal_address (EVCard *vcard, GDataGDPostalAddress *address)
 {
     EVCardAttribute *attr;
     gboolean has_type;
 
-    if (NULL == address || NULL == address->address)
-        return NULL;;
+    if (NULL == address || NULL == gdata_gd_postal_address_get_address (address))
+        return;
 
+    /* Add the LABEL */
     attr = e_vcard_attribute_new (NULL, EVC_LABEL);
-    has_type = add_type_param_from_google_rel (attr, address->rel);
-    if (address->primary) {
+    has_type = add_type_param_from_google_rel (attr, gdata_gd_postal_address_get_relation_type (address));
+    if (gdata_gd_postal_address_is_primary (address))
         add_primary_param (attr, has_type);
-    }
-    add_label_param (attr, address->label);
-    e_vcard_attribute_add_value (attr, address->address);
-    return attr;
+    add_label_param (attr, gdata_gd_postal_address_get_label (address));
+
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_address (address));
+
+    if (attr)
+        e_vcard_add_attribute (vcard, attr);
+
+    /* Add the ADR */
+    attr = e_vcard_attribute_new (NULL, EVC_ADR);
+    has_type = add_type_param_from_google_rel (attr, gdata_gd_postal_address_get_relation_type (address));
+    if (gdata_gd_postal_address_is_primary (address))
+        add_primary_param (attr, has_type);
+    add_label_param (attr, gdata_gd_postal_address_get_label (address));
+
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_po_box (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_house_name (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_street (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_city (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_region (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_postcode (address));
+    e_vcard_attribute_add_value (attr, gdata_gd_postal_address_get_country (address));
+
+    /* The following bits of data provided by the Google Contacts API can't be fitted into the vCard format:
+     *   gdata_gd_postal_address_get_mail_class
+     *   gdata_gd_postal_address_get_usage
+     *   gdata_gd_postal_address_get_agent
+     *   gdata_gd_postal_address_get_neighborhood
+     *   gdata_gd_postal_address_get_subregion
+     *   gdata_gd_postal_address_get_country_code */
+
+    if (attr)
+        e_vcard_add_attribute (vcard, attr);
 }
 
-static GDataEntryEmailAddress*
-gdata_entry_email_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+static GDataGDEmailAddress*
+gdata_gd_email_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
 {
-    GDataEntryEmailAddress *email = NULL;
+    GDataGDEmailAddress *email = NULL;
     GList *values;
 
     values = e_vcard_attribute_get_values (attr);
     if (values) {
         GList *types;
+        gchar *rel;
         const gchar *label;
         gboolean primary;
 
@@ -646,25 +735,24 @@ gdata_entry_email_address_from_attribute (EVCardAttribute *attr, gboolean *have_
             primary = FALSE;
         }
 
-        email = g_new0 (GDataEntryEmailAddress, 1);
-        email->address = g_strdup (values->data);
-        email->rel = google_rel_from_types (types);
-        email->label = g_strdup (label);
-        email->primary = primary;
+        rel = google_rel_from_types (types);
+        email = gdata_gd_email_address_new (values->data, rel, label, primary);
+        g_free (rel);
+
         __debug__ ("New %semail entry %s (%s/%s)",
-                    email->primary ? "primary " : "",
-                    email->address,
-                    email->rel,
-                    email->label);
+                    gdata_gd_email_address_is_primary (email) ? "primary " : "",
+                    gdata_gd_email_address_get_address (email),
+                    gdata_gd_email_address_get_relation_type (email),
+                    gdata_gd_email_address_get_label (email));
     }
 
     return email;
 }
 
-static GDataEntryIMAddress*
-gdata_entry_im_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+static GDataGDIMAddress*
+gdata_gd_im_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
 {
-    GDataEntryIMAddress *im = NULL;
+    GDataGDIMAddress *im = NULL;
     GList *values;
     const gchar *name;
 
@@ -673,6 +761,7 @@ gdata_entry_im_address_from_attribute (EVCardAttribute *attr, gboolean *have_pri
     values = e_vcard_attribute_get_values (attr);
     if (values) {
         GList *types;
+        gchar *protocol, *rel;
         const gchar *label;
         gboolean primary;
 
@@ -683,33 +772,34 @@ gdata_entry_im_address_from_attribute (EVCardAttribute *attr, gboolean *have_pri
             primary = FALSE;
         }
 
-        im = g_new0 (GDataEntryIMAddress, 1);
-        im->address = g_strdup (values->data);
-        im->rel = google_rel_from_types (types);
-        im->label = g_strdup (label);
-        im->primary = primary;
-        im->protocol = google_im_protocol_from_field_name (name);
+        rel = google_rel_from_types (types);
+        protocol = google_im_protocol_from_field_name (name);
+        im = gdata_gd_im_address_new (values->data, protocol, rel, label, primary);
+        g_free (rel);
+        g_free (protocol);
+
         __debug__ ("New %s%s entry %s (%s/%s)",
-                    im->primary ? "primary " : "",
-                    im->protocol,
-                    im->address,
-                    im->rel,
-                    im->label);
+                    gdata_gd_im_address_is_primary (im) ? "primary " : "",
+                    gdata_gd_im_address_get_protocol (im),
+                    gdata_gd_im_address_get_address (im),
+                    gdata_gd_im_address_get_relation_type (im),
+                    gdata_gd_im_address_get_label (im));
     }
 
     return im;
 }
 
-static GDataEntryPhoneNumber*
-gdata_entry_phone_number_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+static GDataGDPhoneNumber*
+gdata_gd_phone_number_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
 {
-    GDataEntryPhoneNumber *number = NULL;
+    GDataGDPhoneNumber *number = NULL;
     GList *values;
 
     values = e_vcard_attribute_get_values (attr);
     if (values) {
         GList *types;
         gboolean primary;
+        gchar *rel;
         const gchar *label;
 
         types = get_google_primary_type_label (attr, &primary, &label);
@@ -719,30 +809,30 @@ gdata_entry_phone_number_from_attribute (EVCardAttribute *attr, gboolean *have_p
             primary = FALSE;
         }
 
-        number = g_new0 (GDataEntryPhoneNumber, 1);
-        number->number = g_strdup (values->data);
-        number->rel = google_rel_from_types_phone (types);
-        number->label = g_strdup (label);
-        number->primary = primary;
+        rel = google_rel_from_types_phone (types);
+        number = gdata_gd_phone_number_new (values->data, rel, label, NULL, primary);
+        g_free (rel);
+
         __debug__ ("New %sphone-number entry %s (%s/%s)",
-                    number->primary ? "primary " : "",
-                    number->number,
-                    number->rel,
-                    number->label);
+                    gdata_gd_phone_number_is_primary (number) ? "primary " : "",
+                    gdata_gd_phone_number_get_number (number),
+                    gdata_gd_phone_number_get_relation_type (number),
+                    gdata_gd_phone_number_get_label (number));
     }
 
     return number;
 }
 
-static GDataEntryPostalAddress*
-gdata_entry_postal_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
+static GDataGDPostalAddress*
+gdata_gd_postal_address_from_attribute (EVCardAttribute *attr, gboolean *have_primary)
 {
-    GDataEntryPostalAddress *address = NULL;
+    GDataGDPostalAddress *address = NULL;
     GList *values;
 
     values = e_vcard_attribute_get_values (attr);
     if (values) {
-        GList *types;
+        GList *types, *value;
+        gchar *rel;
         const gchar *label;
         gboolean primary;
 
@@ -753,16 +843,45 @@ gdata_entry_postal_address_from_attribute (EVCardAttribute *attr, gboolean *have
             primary = FALSE;
         }
 
-        address = g_new0 (GDataEntryPostalAddress, 1);
-        address->address = g_strdup (values->data);
-        address->rel = google_rel_from_types (types);
-        address->label = g_strdup (label);
-        address->primary = primary;
+        rel = google_rel_from_types (types);
+        address = gdata_gd_postal_address_new (rel, label, primary);
+        g_free (rel);
+
         __debug__ ("New %spostal address entry %s (%s/%s)",
-                    address->primary ? "primary " : "",
-                    address->address,
-                    address->rel,
-                    address->label);
+                   gdata_gd_postal_address_is_primary (address) ? "primary " : "",
+                   gdata_gd_postal_address_get_address (address),
+                   gdata_gd_postal_address_get_relation_type (address),
+                   gdata_gd_postal_address_get_label (address));
+
+        /* Set the components of the address from the vCard's attribute values */
+        value = values;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_po_box (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_house_name (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_street (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_city (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_region (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_postcode (address, (*((gchar*) value->data) != '\0') ? value->data : NULL);
+        value = value->next;
+        if (!value)
+            return address;
+        gdata_gd_postal_address_set_country (address, (*((gchar*) value->data) != '\0') ? value->data : NULL, NULL);
     }
 
     return address;
diff --git a/addressbook/backends/google/util.h b/addressbook/backends/google/util.h
index 54291f4..3d74b3d 100644
--- a/addressbook/backends/google/util.h
+++ b/addressbook/backends/google/util.h
@@ -1,6 +1,7 @@
 /* util.h - Google contact backend utility functions.
  *
  * Copyright (C) 2008 Joergen Scheibengruber
+ * Copyright (C) 2010 Philip Withnall
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by the
@@ -23,7 +24,7 @@
 
 #include <libebook/e-vcard.h>
 #include <libebook/e-contact.h>
-#include <servers/google/libgdata/gdata-entry.h>
+#include <gdata/gdata-entry.h>
 
 extern gboolean __e_book_backend_google_debug__;
 
@@ -40,6 +41,7 @@ EContact*   _e_contact_new_from_gdata_entry    (GDataEntry *entry);
 void        _e_contact_add_gdata_entry_xml     (EContact   *contact,
                                                 GDataEntry *entry);
 void        _e_contact_remove_gdata_entry_xml  (EContact   *contact);
-const gchar * _e_contact_get_gdata_entry_xml     (EContact *contact);
+const gchar *_e_contact_get_gdata_entry_xml    (EContact *contact,
+						const gchar **edit_link);
 
 #endif
diff --git a/calendar/backends/google/Makefile.am b/calendar/backends/google/Makefile.am
index 9cc1706..5b62ba6 100644
--- a/calendar/backends/google/Makefile.am
+++ b/calendar/backends/google/Makefile.am
@@ -7,13 +7,10 @@ libecalbackendgoogle_la_CPPFLAGS = \
 	-I$(top_builddir)				\
 	-I$(top_srcdir)/calendar			\
 	-I$(top_builddir)/calendar			\
-	-I$(top_srcdir)/servers/google/libgdata		\
-	-I$(top_builddir)/servers/google/libgdata	\
-	-I$(top_srcdir)/servers/google/libgdata-google	\
-	-I$(top_builddir)/servers/google/libgdata-google\
 	$(EVOLUTION_CALENDAR_CFLAGS)			\
 	$(SOUP_CFLAGS)					\
-	$(DEBUG_CFLAGS)					
+	$(DEBUG_CFLAGS)					\
+	$(GDATA_CFLAGS)
 
 libecalbackendgoogle_la_SOURCES =		\
 	e-cal-backend-google-factory.c		\
@@ -28,10 +25,9 @@ libecalbackendgoogle_la_LIBADD =						\
 	$(top_builddir)/calendar/libedata-cal/libedata-cal-1.2.la		\
 	$(top_builddir)/libedataserver/libedataserver-1.2.la			\
 	$(top_builddir)/libebackend/libebackend-1.2.la				\
-	$(top_builddir)/servers/google/libgdata/libgdata-1.2.la			\
-	$(top_builddir)/servers/google/libgdata-google/libgdata-google-1.2.la	\
 	$(EVOLUTION_CALENDAR_LIBS)						\
-	$(SOUP_LIBS)
+	$(SOUP_LIBS)								\
+	$(GDATA_LIBS)
 
 libecalbackendgoogle_la_LDFLAGS =		\
 	-module -avoid-version $(NO_UNDEFINED)
diff --git a/calendar/backends/google/e-cal-backend-google-utils.c b/calendar/backends/google/e-cal-backend-google-utils.c
index 1d475e3..053b6cb 100644
--- a/calendar/backends/google/e-cal-backend-google-utils.c
+++ b/calendar/backends/google/e-cal-backend-google-utils.c
@@ -2,6 +2,7 @@
 /*
  * Authors :
  *  Ebby Wiselyn <ebbyw gnome org>
+ *  Philip Withnall <philip tecnocode co uk>
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
@@ -54,28 +55,23 @@
 #include "e-cal-backend-google.h"
 #include "e-cal-backend-google-utils.h"
 
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-#define GDATA_SCHEMA "http://schemas.google.com/g/2005#";
 #define CACHE_REFRESH_INTERVAL 10000
 
 /****************************************************** Google Connection Helper Functions ***********************************************/
 
-static gboolean gd_date_to_ical (EGoItem *item, const gchar *google_time_string, struct icaltimetype *itt, ECalComponentDateTime *dt, icaltimezone *default_zone);
-static gchar * get_date (ECalComponentDateTime dt);
+static gboolean gd_timeval_to_ical (GTimeVal *timeval, struct icaltimetype *itt, ECalComponentDateTime *dt, icaltimezone *default_zone);
+static void get_timeval (ECalComponentDateTime dt, GTimeVal *timeval);
 static gint utils_compare_ids (gconstpointer cache_id, gconstpointer modified_cache_id);
 static gchar * utils_form_query (const gchar *query);
 static gboolean get_deltas_timeout (gpointer cbgo);
-static void utils_update_insertion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, EGoItem *item, GSList *cache_keys);
+static void utils_update_insertion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, GDataFeed *feed, GSList *cache_keys);
 static void utils_update_deletion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, GSList *cache_keys);
 
 /**
  *
  * e_cal_backend_google_utils_populate_cache:
  * @cbgo ECalBackendGoogle Object
- * Populates the cache with intial values
+ * Populates the cache with initial values
  *
  **/
 static void
@@ -83,21 +79,20 @@ e_cal_backend_google_utils_populate_cache (ECalBackendGoogle *cbgo)
 {
 	ECalComponent *comp=NULL;
 	ECalBackendCache *cache;
-	EGoItem *item;
+	GDataFeed *feed;
 	ECalBackendGooglePrivate *priv;
 	icalcomponent_kind kind;
-	GSList *entries = NULL, *list = NULL;
+	GList *entries = NULL, *list = NULL;
 
 	cache = e_cal_backend_google_get_cache (cbgo);
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND(cbgo));
 
-	item = e_cal_backend_google_get_item (cbgo);
-	entries = gdata_feed_get_entries (item->feed);
+	feed = e_cal_backend_google_get_feed (cbgo);
+	entries = gdata_feed_get_entries (feed);
 	priv = cbgo->priv;
 
 	for (list = entries; list != NULL; list = list->next) {
-		item->entry = (GDataEntry *)list->data;
-		comp =	e_go_item_to_cal_component (item, cbgo);
+		comp = e_gdata_event_to_cal_component (GDATA_CALENDAR_EVENT (list->data), cbgo);
 		if (comp && E_IS_CAL_COMPONENT(comp)) {
 			gchar *comp_str;
 			e_cal_component_commit_sequence (comp);
@@ -159,9 +154,9 @@ e_cal_backend_google_utils_create_cache (ECalBackendGoogle *cbgo)
  * e_cal_backend_google_utils_update:
  *
  * @handle:
- * Call this to Update changes, made to the calendar.
+ * Call this to update changes made to the calendar.
  *
- * Returns: TRUE if update is successful FALSE otherwise .
+ * Returns: %TRUE if update is successful, %FALSE otherwise 
  **/
 gpointer
 e_cal_backend_google_utils_update (gpointer handle)
@@ -169,13 +164,17 @@ e_cal_backend_google_utils_update (gpointer handle)
 	static gint max_results = -1;
 	ECalBackendGoogle *cbgo;
 	ECalBackendGooglePrivate *priv;
-	EGoItem *item;
+	GDataFeed *feed;
+	GError *error = NULL;
+
 	ECalBackendCache *cache;
-	GDataGoogleService *service;
+
+	GDataService *service;
 	static GStaticMutex updating = G_STATIC_MUTEX_INIT;
 	icalcomponent_kind kind;
-	GSList *ids_list = NULL, *cache_keys = NULL, *entries_list = NULL;
-	GSList *uid_list = NULL, *iter_list = NULL, *remove = NULL;
+
+	GList *entries_list = NULL, *iter_list = NULL, *ids_list = NULL;
+	GSList *uid_list = NULL, *cache_keys = NULL;
 	gboolean needs_to_insert = FALSE;
 	gchar *uri, *full_uri;
 
@@ -190,8 +189,7 @@ e_cal_backend_google_utils_update (gpointer handle)
 	priv = cbgo->priv;
 
 	cache = e_cal_backend_google_get_cache (cbgo);
-	item =  e_cal_backend_google_get_item (cbgo);
-	service = e_cal_backend_google_get_service (cbgo);
+	service = GDATA_SERVICE (e_cal_backend_google_get_service (cbgo));
 	uri = e_cal_backend_google_get_uri (cbgo);
 
 	if (max_results <= 0) {
@@ -205,36 +203,40 @@ e_cal_backend_google_utils_update (gpointer handle)
 	}
 
 	full_uri = g_strdup_printf ("%s?max-results=%d", uri, max_results);
-	item->feed = gdata_service_get_feed (GDATA_SERVICE(service), full_uri, NULL);
+	feed = gdata_service_query (GDATA_SERVICE(service), full_uri, NULL, GDATA_TYPE_CALENDAR_EVENT, NULL, NULL, NULL, &error);
 	g_free (full_uri);
 
-	entries_list = gdata_feed_get_entries (item->feed);
+	if (feed == NULL) {
+		g_warning ("Error querying Google Calendar %s: %s", uri, error->message);
+		g_error_free (error);
+		g_static_mutex_unlock (&updating);
+		return NULL;
+	}
+
+	e_cal_backend_google_set_feed (cbgo, feed);
+	g_object_unref (feed);
+	entries_list = gdata_feed_get_entries (feed);
 	cache_keys = e_cal_backend_cache_get_keys (cache);
 	kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbgo));
 
 	for (iter_list = entries_list; iter_list != NULL; iter_list = iter_list->next) {
-		gchar *id;
-		id = gdata_entry_get_id ((GDataEntry *)iter_list->data);
-		ids_list = g_slist_prepend (ids_list, id);
+		const gchar *id;
+		id = gdata_entry_get_id (GDATA_ENTRY (iter_list->data));
+		ids_list = g_list_prepend (ids_list, (gchar*) id);
 	}
 
 	/* Find the Removed Item */
 	iter_list = NULL;
 	for (iter_list = ids_list; iter_list != NULL; iter_list = iter_list->next) {
-		GCompareFunc func = NULL;
-		GSList *remove = NULL;
-
-		func = (GCompareFunc)utils_compare_ids;
+		GSList *remove_list = g_slist_find_custom (cache_keys, iter_list->data, (GCompareFunc) utils_compare_ids);
 
-		if (!(remove = g_slist_find_custom (cache_keys, iter_list->data, func))) {
+		if (!remove_list) {
 			uid_list = g_slist_prepend (uid_list, g_strdup ((gchar *)iter_list->data));
 			needs_to_insert = TRUE;
-		}else {
-			cache_keys = g_slist_remove_link (cache_keys, remove);
+		} else {
+			cache_keys = g_slist_remove_link (cache_keys, remove_list);
+			g_slist_free (remove_list);
 		}
-
-		if (remove)
-			g_slist_free (remove);
 	}
 
 	/* Update the deleted entries */
@@ -242,33 +244,15 @@ e_cal_backend_google_utils_update (gpointer handle)
 
 	/* Update the inserted entries */
 	if (needs_to_insert) {
-		utils_update_insertion (cbgo, cache, item,uid_list);
+		utils_update_insertion (cbgo, cache, feed, uid_list);
 		needs_to_insert = FALSE;
 	}
 
-	if (ids_list) {
-		ids_list = NULL;
-		g_slist_free (ids_list);
-	}
-
-	if (uid_list) {
-		/*FIXME could crash while freeing*/
-		uid_list = NULL;
-		g_slist_free (uid_list);
-	}
-
-	if (entries_list) {
-		/* FIXME could crash while freeing */
-		entries_list = NULL;
-		g_slist_free (entries_list);
-	}
-
-	if (remove) {
-		remove = NULL;
-		g_slist_free (remove);
-	}
+	g_list_free (ids_list);
+	g_slist_free (uid_list);
 
 	g_static_mutex_unlock (&updating);
+
 	return NULL;
 }
 
@@ -276,15 +260,13 @@ ECalBackendSyncStatus
 e_cal_backend_google_utils_connect (ECalBackendGoogle *cbgo)
 {
 	ECalBackendCache *cache;
-	EGoItem *item;
 	ESource *source;
 	GDataFeed *feed;
-	GDataGoogleService *service;
+	GDataCalendarService *service;
 
 	ECalSourceType source_type;
 	icalcomponent_kind kind;
 	icaltimezone *default_zone;
-	GSList *entries;
 	GError *error = NULL;
 	GThread *thread;
 	gchar *username, *password;
@@ -294,37 +276,34 @@ e_cal_backend_google_utils_connect (ECalBackendGoogle *cbgo)
 
 	source = e_cal_backend_get_source (E_CAL_BACKEND(cbgo));
 
-	service = gdata_google_service_new ("cl", "evolution-client-0.0.1");
+	service = gdata_calendar_service_new ("evolution-client-0.0.1");
 	e_cal_backend_google_set_service (cbgo, service);
 
+	/* Get the query URI */
+	/* TODO: Would be better as a GDataCalendarQuery */
 	suri = e_source_get_uri (source);
 	uri = utils_form_query (suri);
 	e_cal_backend_google_set_uri (cbgo, uri);
-
 	g_free (suri);
 
+	/* Authenticate with the service */
 	username = e_cal_backend_google_get_username (cbgo);
 	password = e_cal_backend_google_get_password (cbgo);
-	gdata_service_set_credentials (GDATA_SERVICE(service), username, password);
-	feed = gdata_service_get_feed (GDATA_SERVICE(service), uri, NULL);
-
-	if (!feed) {
+	if (!gdata_service_authenticate (GDATA_SERVICE(service), username, password, NULL, NULL)) {
 		g_critical ("%s, Authentication Failed \n ", G_STRLOC);
 		if (username || password)
 			return GNOME_Evolution_Calendar_AuthenticationFailed;
 		return GNOME_Evolution_Calendar_AuthenticationRequired;
 	}
 
-	entries = gdata_feed_get_entries (feed);
-
-	item = g_new0 (EGoItem, 1);
-	item->entry = e_cal_backend_google_get_entry (cbgo);
-	item->feed = feed;
+	/* Query for calendar events */
+	feed = gdata_service_query (GDATA_SERVICE(service), uri, NULL, GDATA_TYPE_CALENDAR_EVENT, NULL, NULL, NULL, NULL);
 
 	cache = e_cal_backend_google_get_cache (cbgo);
 	service = e_cal_backend_google_get_service (cbgo);
 
-	e_cal_backend_google_set_item (cbgo, item);
+	e_cal_backend_google_set_feed (cbgo, feed);
+	g_object_unref (feed);
 
 	/* For event sync */
 	if (cache && service) {
@@ -366,7 +345,7 @@ e_cal_backend_google_utils_connect (ECalBackendGoogle *cbgo)
 	}
 
 	/* Creating cache when in remote  */
-	if (GDATA_IS_GOOGLE_SERVICE (service)) {
+	if (GDATA_IS_CALENDAR_SERVICE (service)) {
 		cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (cbgo)),source_type);
 		e_cal_backend_google_set_cache (cbgo, cache);
 	}
@@ -392,28 +371,30 @@ e_cal_backend_google_utils_connect (ECalBackendGoogle *cbgo)
 
 }
 
-/*************************************************** EGoItem Functions*********************************************/
+/*************************************************** GDataCalendarEvent Functions*********************************************/
 
 /**
- * e_go_item_to_cal_component:
- * @item a EGoItem object
- * @cbgo a ECalBackendGoogle object
+ * e_gdata_event_to_cal_component:
+ * @event: a #GDataCalendarEvent
+ * @cbgo: an #ECalBackendGoogle
  *
- * Creates a EGoItem from ECalComponent
+ * Creates an #ECalComponent from a #GDataCalendarEvent
  **/
 
 ECalComponent *
-e_go_item_to_cal_component (EGoItem *item, ECalBackendGoogle *cbgo)
+e_gdata_event_to_cal_component (GDataCalendarEvent *event, ECalBackendGoogle *cbgo)
 {
 	ECalComponent *comp;
 	ECalComponentText text;
-	ECalComponentDateTime dt;
+	ECalComponentDateTime dt, dt_start;
 	ECalComponentOrganizer *org = NULL;
 	icaltimezone *default_zone;
-	const gchar *description, *uid, *temp;
+	const gchar *description, *temp, *location = NULL;
+	GTimeVal timeval, timeval2;
 	struct icaltimetype itt;
-	GSList *category_ids;
-	GSList *go_attendee_list = NULL, *l = NULL, *attendee_list = NULL;
+	GList *category_ids;
+	GList *go_attendee_list = NULL, *go_location_list = NULL, *l = NULL;
+	GSList *attendee_list = NULL;
 
 	comp = e_cal_component_new ();
 	default_zone = e_cal_backend_google_get_default_zone (cbgo);
@@ -424,47 +405,48 @@ e_go_item_to_cal_component (EGoItem *item, ECalBackendGoogle *cbgo)
 	e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
 
 	/* Description*/
-	description = gdata_entry_get_content (item->entry);
+	description = gdata_entry_get_content (GDATA_ENTRY (event));
 	if (description) {
-		GSList l;
+		GSList li;
 		text.value = description;
 		text.altrep = NULL;
-		l.data = &text;
-		l.next = NULL;
-		e_cal_component_set_description_list (comp, &l);
-
+		li.data = &text;
+		li.next = NULL;
+		e_cal_component_set_description_list (comp, &li);
 	}
 
 	/* Creation/Last update */
-	if (gd_date_to_ical (item, gdata_entry_get_custom (item->entry, "published"), &itt, &dt, default_zone))
+	gdata_entry_get_published (GDATA_ENTRY (event), &timeval);
+	if (gd_timeval_to_ical (&timeval, &itt, &dt, default_zone))
 		e_cal_component_set_created (comp, &itt);
 
-	if (gd_date_to_ical (item, gdata_entry_get_custom (item->entry, "updated"), &itt, &dt, default_zone))
+	gdata_entry_get_updated (GDATA_ENTRY (event), &timeval);
+	if (gd_timeval_to_ical (&timeval, &itt, &dt, default_zone))
 		e_cal_component_set_dtstamp (comp, &itt);
 
-	/* Start time */
-	if (gd_date_to_ical (item, gdata_entry_get_start_time (item->entry), &itt, &dt, default_zone))
-		e_cal_component_set_dtstart (comp, &dt);
-
-	/* End time */
-	if (gd_date_to_ical (item, gdata_entry_get_end_time (item->entry), &itt, &dt, default_zone))
+	/* Start/End times */
+	/* TODO: deal with multiple time periods */
+	gdata_calendar_event_get_primary_time (event, &timeval, &timeval2, NULL);
+	if (gd_timeval_to_ical (&timeval, &itt, &dt_start, default_zone))
+		e_cal_component_set_dtstart (comp, &dt_start);
+	if (gd_timeval_to_ical (&timeval2, &itt, &dt, default_zone))
 		e_cal_component_set_dtend (comp, &dt);
 
-	/* Summary of the Entry */
-	text.value = gdata_entry_get_title (item->entry);
+	/* Summary of the event */
+	text.value = gdata_entry_get_title (GDATA_ENTRY (event));
 	text.altrep = NULL;
 	if (text.value != NULL)
 		e_cal_component_set_summary (comp, &text);
 
 	/* Categories or Kinds */
 	category_ids = NULL;
-	category_ids = gdata_entry_get_categories (item->entry);
+	category_ids = gdata_entry_get_categories (GDATA_ENTRY (event));
 
 	/* Classification or Visibility */
 	temp = NULL;
-	temp = gdata_entry_get_visibility (item->entry);
+	temp = gdata_calendar_event_get_visibility (event);
 
-	if (temp)
+	if (strcmp (temp, "public") == 0)
 		e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_PUBLIC);
 	else
 		e_cal_component_set_classification (comp, E_CAL_COMPONENT_CLASS_NONE);
@@ -473,68 +455,292 @@ e_go_item_to_cal_component (EGoItem *item, ECalBackendGoogle *cbgo)
 	temp = NULL;
 
 	/* Transparency */
-	temp = gdata_entry_get_transparency (item->entry);
-	e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
+	temp = gdata_calendar_event_get_transparency (event);
+	if (strcmp (temp, "http://schemas.google.com/g/2005#event.opaque";) == 0)
+		e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
+	else if (strcmp (temp, "http://schemas.google.com/g/2005#event.transparent";) == 0)
+		e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
+	else
+		e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_UNKNOWN);
 
 	/* Attendees */
-	go_attendee_list = gdata_entry_get_attendee_list (item->entry);
+	go_attendee_list = gdata_calendar_event_get_people (event);
 
-	if (go_attendee_list != NULL) {
+	for (l = go_attendee_list; l != NULL; l = l->next) {
+		GDataGDWho *go_attendee;
+		ECalComponentAttendee *attendee;
 
-		for (l = go_attendee_list; l != NULL; l = l->next) {
-			Attendee *go_attendee;
-			ECalComponentAttendee *attendee;
+		go_attendee = (GDataGDWho *)l->data;
 
-			go_attendee = (Attendee *)l->data;
-
-			attendee = g_new0 (ECalComponentAttendee, 1);
+		attendee = g_new0 (ECalComponentAttendee, 1);
 #if 0
-			_print_attendee ((Attendee *)l->data);
+		_print_attendee ((Attendee *)l->data);
 #endif
-			attendee->value = g_strconcat ("MAILTO:", go_attendee->attendee_email, NULL);
-			attendee->cn = g_strdup (go_attendee->attendee_value);
-			attendee->role = ICAL_ROLE_OPTPARTICIPANT;
-			attendee->status = ICAL_PARTSTAT_NEEDSACTION;
-			attendee->cutype =  ICAL_CUTYPE_INDIVIDUAL;
-
-			/* Check for Organizer */
-			if (go_attendee->attendee_rel) {
-				gchar *val;
-				val = strstr ((const gchar *)go_attendee->attendee_rel, (const gchar *)"organizer");
-				if (val != NULL && !strcmp ("organizer", val)) {
-					org = g_new0 (ECalComponentOrganizer, 1);
-
-					if (go_attendee->attendee_email)
-						org->value = g_strconcat("MAILTO:", go_attendee->attendee_email, NULL);
-					if (go_attendee->attendee_value)
-						org->cn =  g_strdup (go_attendee->attendee_value);
-				}
-			}
-
-			attendee_list = g_slist_prepend (attendee_list, attendee);
+		attendee->value = g_strconcat ("MAILTO:", gdata_gd_who_get_email_address (go_attendee), NULL);
+		attendee->cn = g_strdup (gdata_gd_who_get_value_string (go_attendee));
+		/* TODO: This could be made less static once the GData API's in place */
+		attendee->role = ICAL_ROLE_OPTPARTICIPANT;
+		attendee->status = ICAL_PARTSTAT_NEEDSACTION;
+		attendee->cutype =  ICAL_CUTYPE_INDIVIDUAL;
+
+		/* Check for Organizer */
+		if (gdata_gd_who_get_relation_type (go_attendee)) {
+			gchar *val;
+			val = strstr (gdata_gd_who_get_relation_type (go_attendee), "organizer");
+			if (val != NULL && !strcmp ("organizer", val)) {
+				org = g_new0 (ECalComponentOrganizer, 1);
+
+				if (gdata_gd_who_get_email_address (go_attendee))
+					org->value = g_strconcat ("MAILTO:", gdata_gd_who_get_email_address (go_attendee), NULL);
+				if (gdata_gd_who_get_value_string (go_attendee))
+					org->cn = g_strdup (gdata_gd_who_get_value_string (go_attendee));
+			}	
 		}
-		e_cal_component_set_attendee_list (comp, attendee_list);
+		
+		attendee_list = g_slist_prepend (attendee_list, attendee);	
 	}
+	e_cal_component_set_attendee_list (comp, attendee_list);
 
 	/* Set the organizer if any */
 	if (org)
 		e_cal_component_set_organizer (comp, org);
 
 	/* Location */
-	e_cal_component_set_location (comp, gdata_entry_get_location (item->entry));
+	go_location_list = gdata_calendar_event_get_places (event);
 
-#if 0
-	/* temp hack to see how recurrence work */
-	ECalComponentRange *recur_id;
-	recur_id = g_new0 (ECalComponentRange, 1);
-	recur_id->datetime = dt;
-	recur_id->type = E_CAL_COMPONENT_RANGE_THISFUTURE;
-	e_cal_component_set_recurid (comp, recur_id);
-#endif
-	e_cal_component_set_dtend (comp, &dt);
+	for (l = go_location_list; l != NULL; l = l->next) {
+		GDataGDWhere *go_location;
+
+		go_location = (GDataGDWhere *)l->data;
+
+		if (gdata_gd_where_get_relation_type (go_location) == NULL ||
+		    strcmp (gdata_gd_where_get_relation_type (go_location), "http://schemas.google.com/g/2005#event";) == 0)
+			location = gdata_gd_where_get_value_string (go_location);
+	}
+	e_cal_component_set_location (comp, location);
+
+	/* Recurrence */
+	if (gdata_calendar_event_get_recurrence (event) != NULL) {
+		/* We have to parse something like this (http://code.google.com/apis/gdata/elements.html#gdRecurrence):
+			DTSTART;TZID=America/Los_Angeles:20060314T060000
+			DURATION:PT3600S
+			RRULE:FREQ=DAILY;UNTIL=20060321T220000Z
+			BEGIN:VTIMEZONE
+			...
+			END:VTIMEZONE
+		 * For the moment, we can ignore the vtimezone component. */
+
+		gboolean in_timezone = FALSE;
+		const gchar *recurrence = gdata_calendar_event_get_recurrence (event);
+		const gchar *i = recurrence;
+		GSList *rrule_list = NULL, *rdate_list = NULL, *exrule_list = NULL, *exdate_list = NULL;
+		guint recurrence_length = strlen (recurrence);
+
+		do {
+			icalproperty *prop;
+			const gchar *f = NULL;
+
+			if (i == NULL || *i == '\0' || i - recurrence >= recurrence_length)
+				break;
+
+			f = strchr (i, '\n');
+
+			/* Ignore the timezone component */
+			if (strncmp (i, "BEGIN:VTIMEZONE", 15) == 0) {
+				in_timezone = TRUE;
+				goto next_property;
+			} else if (strncmp (i, "END:VTIMEZONE", 13) == 0) {
+				in_timezone = FALSE;
+				goto next_property;
+			}
+
+			/* Skip any rules inside the timezone block */
+			if (in_timezone == TRUE)
+				goto next_property;
+
+			/* Parse the recurrence properties */
+			if (strncmp (i, "DTSTART", 7) == 0) {
+				struct icaltimetype recur;
+				gchar *recur_string;
+
+				/* Parse the dtstart property; this takes priority over that retrieved from gdata_calendar_event_get_primary_time */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_DTSTART_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_dtstart (prop);
+				icalproperty_free (prop);
+				itt = icaltime_convert_to_zone (recur, default_zone);
+				dt.value = &itt;
+				dt.tzid = NULL;
+				e_cal_component_set_dtstart (comp, &dt);
+			} else if (strncmp (i, "DTEND", 5) == 0) {
+				struct icaltimetype recur;
+				gchar *recur_string;
+
+				/* Parse the dtend property; this takes priority over that retrieved from gdata_calendar_event_get_primary_time */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_DTEND_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_dtstart (prop);
+				icalproperty_free (prop);
+				itt = icaltime_convert_to_zone (recur, default_zone);
+				dt.value = &itt;
+				dt.tzid = NULL;
+				e_cal_component_set_dtend (comp, &dt);
+			} else if (strncmp (i, "RRULE", 5) == 0) {
+				struct icalrecurrencetype recur, *recur2;
+				gchar *recur_string;
+
+				/* Parse the rrule property */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_RRULE_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_rrule (prop);
+				icalproperty_free (prop);
+				recur2 = g_memdup (&recur, sizeof (recur));
+				rrule_list = g_slist_prepend (rrule_list, recur2);
+			} else if (strncmp (i, "RDATE", 5) == 0) {
+				struct icaldatetimeperiodtype recur;
+				ECalComponentPeriod *period;
+				icalvalue *value;
+				gchar *recur_string;
+
+				/* Parse the rdate property */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_RDATE_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_rdate (prop);
+				value = icalproperty_get_value (prop);
+
+				period = g_new0 (ECalComponentPeriod, 1);
+				period->start = recur.period.start;
+				if (icalvalue_isa (value) == ICAL_VALUE_DATE || icalvalue_isa (value) == ICAL_VALUE_DATETIME) {
+					period->type = E_CAL_COMPONENT_PERIOD_DATETIME;
+					period->u.end = recur.period.end;
+				} else if (icalvalue_isa (value) == ICAL_VALUE_DURATION) {
+					period->type = E_CAL_COMPONENT_PERIOD_DURATION;
+					period->u.duration = recur.period.duration;
+				} else {
+					g_assert_not_reached ();
+				}
+				icalproperty_free (prop);
+
+				rdate_list = g_slist_prepend (rdate_list, period);
+			} else if (strncmp (i, "EXRULE", 6) == 0) {
+				struct icalrecurrencetype recur, *recur2;
+				gchar *recur_string;
+
+				/* Parse the exrule property */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_EXRULE_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_rrule (prop);
+				icalproperty_free (prop);
+				recur2 = g_memdup (&recur, sizeof (recur));
+				exrule_list = g_slist_prepend (exrule_list, recur2);
+			} else if (strncmp (i, "EXDATE", 6) == 0) {
+				struct icaltimetype recur;
+				ECalComponentDateTime *date_time;
+				gchar *recur_string;
+
+				/* Parse the exdate property */
+				recur_string = g_strndup (i, f - i);
+				prop = icalproperty_new_from_string (recur_string);
+				recur = icaltime_from_string (recur_string);
+				g_free (recur_string);
+
+				if (icalproperty_isa (prop) != ICAL_EXDATE_PROPERTY) {
+					icalproperty_free (prop);
+					goto next_property;
+				}
+
+				recur = icalproperty_get_exdate (prop);
+				icalproperty_free (prop);
+				itt = icaltime_convert_to_zone (recur, default_zone);
+				date_time = g_new0 (ECalComponentDateTime, 1);
+				date_time->value = g_memdup (&itt, sizeof (itt));
+				exdate_list = g_slist_prepend (exdate_list, date_time);
+			}
+
+next_property:
+			/* Advance to the next line, and hence the next property */
+			i = f + 1;
+		} while (TRUE);
+
+		rrule_list = g_slist_reverse (rrule_list);
+		e_cal_component_set_rrule_list (comp, rrule_list);
+		g_slist_foreach (rrule_list, (GFunc) g_free, NULL);
+		g_slist_free (rrule_list);
+
+		rdate_list = g_slist_reverse (rdate_list);
+		e_cal_component_set_rdate_list (comp, rdate_list);
+		g_slist_foreach (rdate_list, (GFunc) g_free, NULL);
+		g_slist_free (rdate_list);
+
+		exrule_list = g_slist_reverse (exrule_list);
+		e_cal_component_set_exrule_list (comp, exrule_list);
+		g_slist_foreach (exrule_list, (GFunc) g_free, NULL);
+		g_slist_free (exrule_list);
+
+		exdate_list = g_slist_reverse (exdate_list);
+		e_cal_component_set_exdate_list (comp, exdate_list);
+		g_slist_foreach (exdate_list, (GFunc) e_cal_component_free_datetime, NULL);
+		g_slist_foreach (exdate_list, (GFunc) g_free, NULL);
+		g_slist_free (exdate_list);
+	}
+
+	/* Recurrence exceptions */
+	if (gdata_calendar_event_is_exception (event)) {
+		ECalComponentRange *recur_id;
+		gchar *original_id = NULL;
+
+		/* Provide the ID of the original event */
+		gdata_calendar_event_get_original_event_details (event, &original_id, NULL);
+		e_cal_component_set_uid (comp, original_id);
+		g_free (original_id);
+
+		/* Set the recurrence id and X-GW-RECORDID */
+		recur_id = g_new0 (ECalComponentRange, 1);
+		recur_id->type = E_CAL_COMPONENT_RANGE_SINGLE;
+		recur_id->datetime = dt_start;
+		e_cal_component_set_recurid (comp, recur_id);
+		g_free (recur_id);
+	} else {
+		/* The event is not an exception to a recurring event */
+		const gchar *uid = gdata_entry_get_id (GDATA_ENTRY (event));
+		e_cal_component_set_uid (comp, uid);
+	}
 
-	uid = gdata_entry_get_id (item->entry);
-	e_cal_component_set_uid (comp, (const gchar *)uid);
 	e_cal_component_commit_sequence (comp);
 
 	return comp;
@@ -542,145 +748,214 @@ e_go_item_to_cal_component (EGoItem *item, ECalBackendGoogle *cbgo)
 
 /**
  *
- * e_go_item_from_cal_component:
+ * e_gdata_event_from_cal_component:
  * @cbgo a ECalBackendGoogle
  * @comp a ECalComponent object
- * Creates a ECalComponent from EGoItem
+ * Creates a #GDataCalendarEvent from an #ECalComponent
  *
  **/
-EGoItem *
-e_go_item_from_cal_component (ECalBackendGoogle *cbgo, ECalComponent *comp)
+GDataCalendarEvent *
+e_gdata_event_from_cal_component (ECalBackendGoogle *cbgo, ECalComponent *comp)
+{
+	const gchar *uid;
+	GDataCalendarEvent *event;
+
+	e_cal_component_get_uid (comp, &uid);
+	event = gdata_calendar_event_new (uid);
+
+	e_gdata_event_update_from_cal_component (cbgo, event, comp);
+
+	return event;
+}
+
+static gchar *
+comp_date_time_as_ical_string (ECalComponentDateTime *dt, icaltimezone *default_zone)
+{
+	icaltimetype itt;
+	icalproperty *prop;
+	char *buf;
+
+	itt = icaltime_convert_to_zone (*(dt->value), default_zone);
+	dt->value = &itt;
+	prop = icalproperty_new_dtend (*(dt->value));
+	buf = icalproperty_get_value_as_string_r (prop);
+	icalproperty_free (prop);
+
+	return buf;
+}
+
+void
+e_gdata_event_update_from_cal_component (ECalBackendGoogle *cbgo, GDataCalendarEvent *event, ECalComponent *comp)
 {
 	ECalBackendGooglePrivate *priv;
-	EGoItem *item;
 	ECalComponentText text;
 	ECalComponentDateTime dt;
-	gchar *temp, *term = NULL;
+	const gchar *term = NULL;
 	icaltimezone *default_zone;
 	icaltimetype itt;
-	const gchar *uid;
+	icalproperty *prop;
+	GTimeVal timeval, timeval2;
 	const gchar *location;
 	GSList *list = NULL;
-	GDataEntry *entry;
+	GDataCategory *category;
+	GDataGDWhen *when;
 	ECalComponentText *t;
 	GSList *attendee_list = NULL, *l = NULL;
+	GString *recur_string;
+	char *buf;
 
 	priv = cbgo->priv;
 
-	item = g_new0 (EGoItem, 1);
-	entry = gdata_entry_new ();
-
 	/* Summary */
 	e_cal_component_get_summary (comp, &text);
-	if (text.value!=NULL)
-		gdata_entry_set_title (entry, text.value);
+	if (text.value != NULL)
+		gdata_entry_set_title (GDATA_ENTRY (event), text.value);
 
 	default_zone = e_cal_backend_google_get_default_zone (cbgo);
 
-	/* Start time */
+	/* Start/End times */
 	e_cal_component_get_dtstart (comp, &dt);
 	itt = icaltime_convert_to_zone (*dt.value, default_zone);
 	dt.value = &itt;
-	temp = get_date (dt);
-	gdata_entry_set_start_time (entry, temp);
+	get_timeval (dt, &timeval);
 
-	/* End Time */
 	e_cal_component_get_dtend (comp, &dt);
 	itt = icaltime_convert_to_zone (*dt.value, default_zone);
 	dt.value = &itt;
-	temp = get_date (dt);
-	gdata_entry_set_end_time (entry, temp);
+	get_timeval (dt, &timeval2);
+
+	/* TODO: deal with pure dates */
+	when = gdata_gd_when_new (&timeval, &timeval2, FALSE);
+	gdata_calendar_event_add_time (event, when);
 
 	/* Content / Description */
 	e_cal_component_get_description_list (comp, &list);
 	if (list != NULL) {
 		t = (ECalComponentText *)list->data;
-		gdata_entry_set_content (entry, t->value);
-	}
-	else
-		gdata_entry_set_content (entry, "");
-
-	e_cal_component_get_uid (comp, &uid);
-	gdata_entry_set_id (entry, g_strdup(uid));
+		gdata_entry_set_content (GDATA_ENTRY (event), t->value);
+	} else
+		gdata_entry_set_content (GDATA_ENTRY (event), "");
 
 	/* Location */
 	e_cal_component_get_location (comp, &location);
-	if (location)
-		gdata_entry_set_location (entry , location);
+	if (location) {
+		GDataGDWhere *where;
+
+		where = gdata_gd_where_new (NULL, location, NULL);
+		gdata_calendar_event_add_place (event, where);
+	}
 
 	if (e_cal_backend_get_kind (E_CAL_BACKEND(cbgo)) == ICAL_VEVENT_COMPONENT)
-		term = g_strconcat (GDATA_SCHEMA, "event", NULL);
+		term = "http://schemas.google.com/g/2005#event";;
+
+	category = gdata_category_new (term, "http://schemas.google.com/g/2005#kind";, "label");
+	gdata_entry_add_category (GDATA_ENTRY (event), category);
 
-	gdata_entry_create_categories (entry, g_strconcat (GDATA_SCHEMA, "kind", NULL),
-			"label",
-			term);
 	/* Attendee */
 	e_cal_component_get_attendee_list (comp, &attendee_list);
 
-	for (l = attendee_list; l!=NULL; l=l->next) {
+	for (l = attendee_list; l != NULL; l = l->next) {
 		ECalComponentAttendee *ecal_att;
-		ecal_att = (ECalComponentAttendee *)l->data;
-		/* TODO Convert ECalComponentAttendee to Attendee, and change during parsing to store the types */
+		GDataGDWho *who;
+		gchar *email;
+		const gchar *rel;
 
-	}
+		ecal_att = (ECalComponentAttendee *)l->data;
 
-	/* FIXME For transparency and status */
-	item->entry = entry;
-	return item;
-}
+		/* Extract the attendee's e-mail address from att->value, which should be in the form:
+		 * MAILTO:john foobar com
+		 */
+		email = strstr (ecal_att->value, "MAILTO:");
+		if (!email)
+			continue;
+		email += 7; /* length of MAILTO: */
+
+		rel = "http://schemas.google.com/g/2005#event.attendee";;
+		if (e_cal_component_has_organizer (comp)) {
+			ECalComponentOrganizer org;
+
+			e_cal_component_get_organizer (comp, &org);
+			if (strcmp (org.value, ecal_att->value) == 0)
+				rel = "http://schemas.google.com/g/2005#event.organizer";;
+		}
 
-/**
- *
- * e_go_item_get_entry:
- * @item a EGoItem
- * Returns the GDataEntry object
- *
- **/
+		who = gdata_gd_who_new (rel, ecal_att->cn, email);
+		gdata_calendar_event_add_person (event, who);
+	}
 
-GDataEntry *
-e_go_item_get_entry (EGoItem *item)
-{
-	g_return_val_if_fail (item != NULL, NULL);
-	return item->entry;
-}
+	/* Recurrence support */
+	recur_string = g_string_new (NULL);
 
-/**
- *
- * e_go_item_set_entry:
- * @item  a EGoItem
- * @entry a GDataEntry
- * Sets the GDataEntry of EGoItem to entry
- *
- **/
-void
-e_go_item_set_entry (EGoItem *item, GDataEntry *entry)
-{
-	g_return_if_fail (item != NULL);
-	g_return_if_fail (entry != NULL);
+	e_cal_component_get_dtstart (comp, &dt);
+	buf = comp_date_time_as_ical_string (&dt, default_zone);
+	g_string_append_printf (recur_string, "DTSTART:%s\r\n", buf);
+	icalmemory_free_buffer (buf);
 
-	item->entry = entry;
-}
+	e_cal_component_get_dtend (comp, &dt);
+	buf = comp_date_time_as_ical_string (&dt, default_zone);
+	g_string_append_printf (recur_string, "DTEND:%s\r\n", buf);
+	icalmemory_free_buffer (buf);
+
+	e_cal_component_get_rrule_list (comp, &list);
+	for (l = list; l != NULL; l = l->next) {
+		/* Append each rrule to recur_string */
+		buf = icalrecurrencetype_as_string_r ((struct icalrecurrencetype*) l->data);
+		g_string_append_printf (recur_string, "RRULE:%s\r\n", buf);
+		icalmemory_free_buffer (buf);
+	}
+	e_cal_component_free_recur_list (list);
+
+	e_cal_component_get_rdate_list (comp, &list);
+	for (l = list; l != NULL; l = l->next) {
+		/* Append each rdate to recur_string */
+		struct icaldatetimeperiodtype date_time_period = { { 0, }, };
+		ECalComponentPeriod *period = l->data;
+
+		/* Build a struct icaldatetimeperiodtypeâ?¦ */
+		date_time_period.time = period->start;
+		date_time_period.period.start = period->start;
+		if (period->type == E_CAL_COMPONENT_PERIOD_DATETIME)
+			date_time_period.period.end = period->u.end;
+		else if (period->type == E_CAL_COMPONENT_PERIOD_DURATION)
+			date_time_period.period.duration = period->u.duration;
+		else
+			g_assert_not_reached ();
+
+		/* â?¦allowing us to build an icalproperty and get it in string form */
+		prop = icalproperty_new_rdate (date_time_period);
+
+		buf = icalproperty_get_value_as_string_r (prop);
+		g_string_append_printf (recur_string, "RDATE:%s\r\n", buf);
+		icalmemory_free_buffer (buf);
+		icalproperty_free (prop);
+	}
+	e_cal_component_free_period_list (list);
+
+	e_cal_component_get_exrule_list (comp, &list);
+	for (l = list; l != NULL; l = l->next) {
+		/* Append each exrule to recur_string */
+		buf = icalrecurrencetype_as_string_r ((struct icalrecurrencetype*) l->data);
+		g_string_append_printf (recur_string, "EXRULE:%s\r\n", buf);
+		icalmemory_free_buffer (buf);
+	}
+	e_cal_component_free_recur_list (list);
 
-/**
- *
- * gdata_entry_get_entry_by_id:
- * @entries List of entries
- * @id id to retreive
- * Gets the specified entry
- *
- **/
-GDataEntry *
-gdata_entry_get_entry_by_id (GSList *entries, const gchar *id)
-{
-	GSList *l = NULL;
+	e_cal_component_get_exdate_list (comp, &list);
+	for (l = list; l != NULL; l = l->next) {
+		/* Append each exdate to recur_string */
+		ECalComponentDateTime *date_time = l->data;
 
-	for (l = entries; l != NULL;l = l->next) {
-		if (!strcmp (gdata_entry_get_id ((GDataEntry *)l->data), id)) {
-			return l->data;
-		}
+		/* Build an icalproperty and get the exdate in string form */
+		buf = comp_date_time_as_ical_string (date_time, default_zone);
+		g_string_append_printf (recur_string, "EXDATE:%s\r\n", buf);
+		icalmemory_free_buffer (buf);
 	}
+	e_cal_component_free_exdate_list (list);
 
-	return NULL;
+	/* Set the recurrence data on the event */
+	gdata_calendar_event_set_recurrence (event, g_string_free (recur_string, FALSE));
+
+	/* FIXME For transparency and status */
 }
 
 /***************************************************************** Utility Functions *********************************************/
@@ -701,23 +976,18 @@ utils_form_query (const gchar *query)
 }
 
 static void
-utils_update_insertion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, EGoItem *item, GSList *uid_list)
+utils_update_insertion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, GDataFeed *feed, GSList *uid_list)
 {
-	EGoItem *item_t;
 	ECalComponent *comp;
-	GSList *list = NULL, *entries_list = NULL;
-	GDataEntry *entry;
+	GSList *list = NULL;
+	GDataCalendarEvent *event;
 	gchar *temp;
 
 	comp = e_cal_component_new ();
-	item_t = g_new0 (EGoItem, 1);
-	item_t->feed = item->feed;
-	entries_list = gdata_feed_get_entries (item->feed);
 
 	for (list = uid_list; list != NULL; list = list->next) {
-		entry = gdata_entry_get_entry_by_id (entries_list, list->data);
-		item_t->entry = entry;
-		comp = e_go_item_to_cal_component (item_t, cbgo);
+		event = GDATA_CALENDAR_EVENT (gdata_feed_look_up_entry (feed, list->data));
+		comp = e_gdata_event_to_cal_component (event, cbgo);
 
 		if (comp) {
 			e_cal_component_commit_sequence (comp);
@@ -731,12 +1001,6 @@ utils_update_insertion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, EGoIte
 			g_object_unref (comp);
 		}
 	}
-
-	g_free (item_t);
-	if (list)
-		g_slist_free (list);
-	if (entries_list)
-		g_slist_free (entries_list);
 }
 
 static void
@@ -768,47 +1032,20 @@ utils_update_deletion (ECalBackendGoogle *cbgo, ECalBackendCache *cache, GSList
 }
 
 /**
- * get_date: Returns date in gdata format '2006-04-17T17:00:00.000Z'
+ * get_timeval: Returns date in a GTimeVal
  * @dt a #ECalComponentDateTime value
+ * @timeval a #GTimeVal
  **/
-/* FIXME use proper functions to manipulate the dates */
-static gchar *
-get_date (ECalComponentDateTime dt)
+static void
+get_timeval (ECalComponentDateTime dt, GTimeVal *timeval)
 {
-	gchar *temp;
-	struct icaltimetype itt;
-	struct icaltimetype *itt_u;
-	gchar *month;
-	gchar *day, *minute, *hour, *second;
-
-	itt_u = dt.value;
-	itt.year = itt_u->year;
-	itt.month = itt_u->month;
-	itt.day = itt_u->day;
-	itt.hour = itt_u->hour;
-	itt.minute = itt_u->minute;
-	itt.second = itt_u->second;
-	itt.is_utc = itt_u->is_utc;
-	itt.is_date = itt_u->is_date;
-	itt.is_daylight = itt_u->is_daylight;
-	itt.zone = itt_u->zone;
-
-	month = (itt.month<10) ? g_strdup_printf("0%d", itt.month):g_strdup_printf ("%d", itt.month);
-	day = (itt.day < 10) ? g_strdup_printf("0%d", itt.day):g_strdup_printf ("%d", itt.day);
-
-	hour = (itt.hour<10) ? g_strdup_printf("0%d", itt.hour):g_strdup_printf ("%d", itt.hour);
-	minute = (itt.minute<10) ? g_strdup_printf("0%d", itt.minute):g_strdup_printf ("%d", itt.minute);
-	second = (itt.second<10) ? g_strdup_printf ("0%d", itt.second):g_strdup_printf ("%d", itt.second);
-
-	/* FIXME not the best way to do this */
-	temp =  g_strdup_printf ("%d-%s-%sT%s:%s:%s.000", itt.year, month, day, hour, minute, second);
-	g_free (month);
-	g_free (day);
-	g_free (hour);
-	g_free (minute);
-	g_free (second);
-
-	return temp;
+	time_t tt;
+
+	/* GTimeVals are always in UTC */
+	tt = icaltime_as_timet_with_zone (*(dt.value), icaltimezone_get_utc_timezone ());
+
+	timeval->tv_sec = (glong) tt;
+	timeval->tv_usec = 0;
 }
 
 static gboolean
@@ -830,10 +1067,10 @@ get_deltas_timeout (gpointer cbgo)
 
 /**
  *
- * gd_date_to_ical:
+ * gd_timeval_to_ical:
  * Helper Function to convert a gdata format date to ical date
- * @item item from which the time comes. It's used to get to the feed's timezone
- * @google_time_string date in gdata format eg: '2006-04-17T17:00:00.000Z' or '2006-04-17T17:00:00.000+07:00'
+ * @event event from which the time comes. It's used to get to the event's timezone
+ * @timeval date as a #GTimeVal
  * @iit Resulting icaltimetype.
  * @dt Resulting ECalComponentDateTime.
  * @default_zone Default time zone for the backend. If set, then the time will be converted to that timezone.
@@ -841,59 +1078,16 @@ get_deltas_timeout (gpointer cbgo)
  * @note Do not free itt or dt values, those come from buildin structures held by libical
  **/
 static gboolean
-gd_date_to_ical (EGoItem *item, const gchar *google_time_string, struct icaltimetype *itt, ECalComponentDateTime *dt, icaltimezone *default_zone)
+gd_timeval_to_ical (GTimeVal *timeval, struct icaltimetype *itt, ECalComponentDateTime *dt, icaltimezone *default_zone)
 {
-	gchar *s, *string, *dup;
-	gint count = 0;
-	gboolean is_utc = TRUE;
-
+	/* TODO: Event's timezone? */
 	g_return_val_if_fail (itt != NULL, FALSE);
 	g_return_val_if_fail (dt != NULL, FALSE);
 
-	if (!google_time_string || !*google_time_string)
+	if (!timeval)
 		return FALSE;
 
-	dup = g_strdup (google_time_string);
-	s = dup;
-	string = dup;
-
-	/* Strip of the string to the gdata format */
-	while (s[0] != '\0') {
-		if ((s[0] != '-') && (s[0] != '+') && (s[0] != ':') && (s[0] != '.')) {
-			*string = *s;
-			string = string + 1;
-			s = s + 1;
-			count = count + 1;
-		}else
-			s = s + 1;
-
-		if (count == 15) {
-			if (strlen (s) >= 5) {
-				is_utc = s [4] == 'Z';
-			}
-
-			string[0] = '\0';
-			break;
-		}
-		if (s[1] == '\0')
-			string[0] = '\0';
-	}
-
-	*itt = icaltime_from_string (dup);
-
-	if (!is_utc) {
-		const gchar *zone_name = item->feed ? gdata_feed_get_timezone (item->feed) : NULL;
-
-		if (zone_name) {
-			icaltimezone *zone = icaltimezone_get_builtin_timezone (zone_name);
-
-			if (zone)
-				icaltime_set_timezone (itt, zone);
-		}
-	}
-
-	if (!icaltime_get_timezone (*itt))
-		icaltime_set_timezone (itt, icaltimezone_get_utc_timezone ());
+	*itt = icaltime_from_timet_with_zone (timeval->tv_sec, 0, icaltimezone_get_utc_timezone ());
 
 	if (default_zone)
 		*itt = icaltime_convert_to_zone (*itt, default_zone);
@@ -901,7 +1095,5 @@ gd_date_to_ical (EGoItem *item, const gchar *google_time_string, struct icaltime
 	dt->value = itt;
 	dt->tzid = icaltimezone_get_tzid ((icaltimezone *) icaltime_get_timezone (*itt));
 
-	g_free (dup);
-
 	return TRUE;
 }
diff --git a/calendar/backends/google/e-cal-backend-google-utils.h b/calendar/backends/google/e-cal-backend-google-utils.h
index 0ecdb97..5023f90 100644
--- a/calendar/backends/google/e-cal-backend-google-utils.h
+++ b/calendar/backends/google/e-cal-backend-google-utils.h
@@ -2,6 +2,7 @@
 /*
  * Authors :
  *  Ebby Wiselyn <ebbywiselyn gmail com>
+ *  Philip Withnall <philip tecnocode co uk>
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
@@ -25,29 +26,20 @@
 #endif
 #include <e-cal-backend-google.h>
 #include <libecal/e-cal-component.h>
-#include <servers/google/libgdata/gdata-entry.h>
-#include <servers/google/libgdata/gdata-feed.h>
-#include <servers/google/libgdata-google/gdata-google-service.h>
-#include <servers/google/libgdata/gdata-service-iface.h>
+#include <gdata/services/calendar/gdata-calendar-event.h>
 
 ECalComponent *
-e_go_item_to_cal_component (EGoItem *item, ECalBackendGoogle *cbgo);
+e_gdata_event_to_cal_component (GDataCalendarEvent *event, ECalBackendGoogle *cbgo);
 
-void
-e_go_item_set_entry (EGoItem *item, GDataEntry *entry);
-
-GDataEntry *
-e_go_item_get_entry (EGoItem *item);
+GDataCalendarEvent *
+e_gdata_event_from_cal_component (ECalBackendGoogle *cbgo, ECalComponent *comp);
 
-EGoItem *
-e_go_item_from_cal_component (ECalBackendGoogle *cbgo, ECalComponent *comp);
+void
+e_gdata_event_update_from_cal_component (ECalBackendGoogle *cbgo, GDataCalendarEvent *event, ECalComponent *comp);
 
 gpointer
 e_cal_backend_google_utils_update (gpointer handle);
 
-GDataEntry *
-gdata_entry_get_entry_by_id (GSList *entries, const gchar *id);
-
 ECalBackendSyncStatus
 e_cal_backend_google_utils_connect (ECalBackendGoogle *cbgo);
 
diff --git a/calendar/backends/google/e-cal-backend-google.c b/calendar/backends/google/e-cal-backend-google.c
index 21a4b06..049dbec 100644
--- a/calendar/backends/google/e-cal-backend-google.c
+++ b/calendar/backends/google/e-cal-backend-google.c
@@ -2,6 +2,7 @@
 /*
  * Authors :
  *  Ebby Wiselyn <ebbyw gnome org>
+ *  Philip Withnall <philip tecnocode co uk>
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
@@ -45,10 +46,9 @@
 #include <libecal/e-cal-time-util.h>
 #include <libecal/e-cal-util.h>
 
-#include <servers/google/libgdata/gdata-entry.h>
-#include <servers/google/libgdata/gdata-feed.h>
-#include <servers/google/libgdata-google/gdata-google-service.h>
-#include <servers/google/libgdata/gdata-service-iface.h>
+#include <gdata/gdata-entry.h>
+#include <gdata/gdata-feed.h>
+#include <gdata/services/calendar/gdata-calendar-service.h>
 #include "e-cal-backend-google-utils.h"
 #include "e-cal-backend-google.h"
 
@@ -63,20 +63,17 @@ struct _ECalBackendGooglePrivate {
 	ECalBackendCache *cache;
 	ESource *source;
 
-	GDataGoogleService *service;
+	GDataCalendarService *service;
+	GDataFeed *feed;
 	GMutex *mutex;
-	GDataEntry *entry;
-	GSList *entries;
 	icaltimezone *default_zone;
 	CalMode	mode;
-	EGoItem *item;
 
 	guint timeout_id;
 	gchar *username;
 	gchar *password;
 	gchar *uri;
-	gchar *feed;
-	gchar *local_attachments_store;
+	gchar *local_attachments_store;	
 
 	gboolean read_only;
 	gboolean mode_changed;
@@ -84,15 +81,6 @@ struct _ECalBackendGooglePrivate {
 	EProxy *proxy;
 };
 
-gint compare_ids (gconstpointer cache_id, gconstpointer modified_cache_id);
-gchar * form_query (const gchar *query);
-
-gint
-compare_ids (gconstpointer cache_id, gconstpointer modified_cache_id)
-{
-	return strcmp (cache_id, modified_cache_id);
-}
-
 /************************************************** Calendar Backend Methods **********************************/
 
 static ECalBackendSyncStatus
@@ -376,7 +364,7 @@ e_cal_backend_google_set_mode (ECalBackend *backend, CalMode mode)
 	cbgo = E_CAL_BACKEND_GOOGLE (backend);
 	priv = cbgo->priv;
 
-	if (!priv->mode && priv->mode == mode) {
+	if (priv->mode == mode) {
 		e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET,
 					   cal_mode_to_corba (mode));
 		return;
@@ -492,7 +480,6 @@ static ECalBackendSyncStatus
 receive_object (ECalBackendGoogle *cbgo, EDataCal *cal, icalcomponent *icalcomp)
 {
 	ECalBackendGooglePrivate *priv;
-	EGoItem *item = NULL;
 	GDataEntry *entry = NULL, *updated_entry = NULL;
 	ECalComponent *comp, *modif_comp;
 	GSList *comps = NULL, *l = NULL;
@@ -526,13 +513,13 @@ receive_object (ECalBackendGoogle *cbgo, EDataCal *cal, icalcomponent *icalcomp)
 		fetch_attachments (cbgo, comp);
 
 	/* Sent to Server */
-	item = e_go_item_from_cal_component (cbgo, comp);
-	entry =	e_go_item_get_entry (item);
+	entry =	GDATA_ENTRY (e_gdata_event_from_cal_component (cbgo, comp));
 
-	if (!GDATA_IS_ENTRY(entry))
-		return GNOME_Evolution_Calendar_InvalidObject;
+	if (!GDATA_IS_ENTRY (entry))
+		return GNOME_Evolution_Calendar_InvalidObject;	
 
-	updated_entry = gdata_service_insert_entry (GDATA_SERVICE(priv->service), priv->uri, entry, NULL);
+	updated_entry = gdata_service_insert_entry (GDATA_SERVICE (priv->service), priv->uri, entry, NULL, NULL);
+	g_object_unref (entry);
 
 	if (updated_entry) {
 		/* FIXME */
@@ -540,7 +527,6 @@ receive_object (ECalBackendGoogle *cbgo, EDataCal *cal, icalcomponent *icalcomp)
 	}
 
 	/* Update the Cache */
-
 	modif_comp = g_object_ref (comp);
 	if (instances) {
 		const gchar *uid;
@@ -804,9 +790,7 @@ e_cal_backend_google_get_changes (ECalBackendSync *backend, EDataCal *cal, const
 static ECalBackendSyncStatus
 e_cal_backend_google_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only)
 {
-	/* FIXME */
-	*read_only = FALSE;
-
+	*read_only = E_CAL_BACKEND_GOOGLE (backend)->priv->read_only;
 	return GNOME_Evolution_Calendar_Success;
 }
 
@@ -842,11 +826,9 @@ e_cal_backend_google_modify_object (ECalBackendSync *backend, EDataCal *cal, con
 	ECalBackendGooglePrivate *priv;
 	icalcomponent *icalcomp;
 	ECalComponent *comp = NULL, *cache_comp = NULL;
-	EGoItem *item;
-	const gchar *uid=NULL, *rid=NULL;
-	GDataEntry *entry, *entry_from_server=NULL, *updated_entry=NULL;
-	gchar *edit_link;
-	GSList *l;
+	const gchar *uid = NULL, *rid = NULL;
+	GDataFeed *feed;
+	GDataEntry *entry, *updated_entry = NULL;
 
 	*old_object = NULL;
 	cbgo = E_CAL_BACKEND_GOOGLE (backend);
@@ -880,35 +862,37 @@ e_cal_backend_google_modify_object (ECalBackendSync *backend, EDataCal *cal, con
 				return GNOME_Evolution_Calendar_ObjectNotFound;
 			}
 
-			item = e_go_item_from_cal_component (cbgo, comp);
-			item->feed = gdata_service_get_feed (GDATA_SERVICE(priv->service), priv->uri, NULL);
-			entry = item->entry;
+			feed = gdata_service_query (GDATA_SERVICE(priv->service), priv->uri, NULL, GDATA_TYPE_CALENDAR_EVENT,
+						    NULL, NULL, NULL, NULL);
 
-			if (!item->feed) {
-				g_message ("CRITICAL: Could not find feed in EGoItem %s", G_STRLOC);
+			if (!feed) {
+				g_message ("CRITICAL: Could not find feed %s", G_STRLOC);
 				g_object_unref (comp);
 				return GNOME_Evolution_Calendar_OtherError;
 			}
 
-			l = gdata_feed_get_entries (item->feed);
-			entry_from_server = gdata_entry_get_entry_by_id (l, uid);
+			e_cal_backend_google_set_feed (cbgo, feed);
+			g_object_unref (feed);
+
+			entry = gdata_feed_look_up_entry (feed, uid);
 
-			if (!GDATA_IS_ENTRY(entry_from_server)) {
+			if (!GDATA_IS_ENTRY (entry)) {
 				g_object_unref (comp);
 				return GNOME_Evolution_Calendar_OtherError;
 			}
 
-			edit_link = gdata_entry_get_edit_link (entry_from_server);
-			updated_entry = gdata_service_update_entry_with_link (GDATA_SERVICE (priv->service),
-					entry, edit_link, NULL);
+			/* Send the update to the server */
+			e_gdata_event_update_from_cal_component (cbgo, GDATA_CALENDAR_EVENT (entry), comp);
+			updated_entry = gdata_service_update_entry (GDATA_SERVICE (priv->service), entry, NULL, NULL);
 
 			if (updated_entry) {
-				/* FIXME Response from server contains, additional info about GDataEntry
+				/* FIXME Response from server contains additional info about GDataEntry 
 				 * Store and use them later
 				 */
+				g_object_unref (updated_entry);
 			}
 
-			break;
+			/* If successful, update the cache instead of breaking out of the switch */
 		case CAL_MODE_LOCAL:
 			e_cal_backend_cache_put_component (priv->cache, comp);
 			break;
@@ -933,32 +917,24 @@ e_cal_backend_google_remove_object (ECalBackendSync *backend, EDataCal *cal,
 	GDataEntry *entry;
 	ECalBackendGooglePrivate *priv;
 	ECalComponent *comp = NULL;
-	gchar *calobj = NULL;
-	GSList *entries = NULL;
-	EGoItem *item;
+	char *calobj = NULL;
 
 	cbgo = E_CAL_BACKEND_GOOGLE (backend);
 	priv = cbgo->priv;
-	item = priv->item;
 
 	*old_object = *object = NULL;
-	/* FIXME */
-	item->feed = gdata_service_get_feed (GDATA_SERVICE(priv->service), priv->uri, NULL);
-
-	entries = gdata_feed_get_entries (item->feed);
 
 	if (priv->mode == CAL_MODE_REMOTE) {
 		ECalBackendSyncStatus status;
 		icalcomponent *icalcomp;
 		ECalComponentId *id;
-		gchar *comp_str;
+		char *comp_str;
+		GDataFeed *feed;
 
 		status = e_cal_backend_google_get_object (backend, cal, uid, rid, &calobj);
 
 		if (status != GNOME_Evolution_Calendar_Success) {
 			g_free (calobj);
-			if (entries)
-				g_slist_free (entries);
 			return status;
 		}
 
@@ -969,8 +945,6 @@ e_cal_backend_google_remove_object (ECalBackendSync *backend, EDataCal *cal,
 
 		if (!icalcomp) {
 			g_free (calobj);
-			if (entries)
-				g_slist_free (entries);
 			return GNOME_Evolution_Calendar_InvalidObject;
 		}
 
@@ -979,24 +953,25 @@ e_cal_backend_google_remove_object (ECalBackendSync *backend, EDataCal *cal,
 		e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbgo), id, comp_str, NULL);
 		g_free (comp_str);
 
-		entry = gdata_entry_get_entry_by_id (entries, uid);
+		/* FIXME */
+		feed = gdata_service_query (GDATA_SERVICE(priv->service), priv->uri, NULL, GDATA_TYPE_CALENDAR_EVENT, NULL, NULL, NULL, NULL);
+		e_cal_backend_google_set_feed (cbgo, feed);
+		g_object_unref (feed);
+
+		entry = gdata_feed_look_up_entry (feed, uid);
 
 		if (!entry) {
 			g_free (calobj);
-			if (entries)
-				g_slist_free (entries);
 			return GNOME_Evolution_Calendar_InvalidObject;
 		}
 
-		gdata_service_delete_entry (GDATA_SERVICE(priv->service), entry, NULL);
+		gdata_service_delete_entry (GDATA_SERVICE(priv->service), entry, NULL, NULL);
 		*object = NULL;
 		*old_object = strdup (calobj);
 	}
 
 	if (calobj)
 		g_free (calobj);
-	if (entries)
-		g_slist_free (entries);
 
 	return GNOME_Evolution_Calendar_Success;
 }
@@ -1008,14 +983,12 @@ e_cal_backend_google_create_object (ECalBackendSync *backend, EDataCal *cal, gch
 	ECalBackendGooglePrivate *priv;
 	icalcomponent *icalcomp;
 	ECalComponent *comp;
-	EGoItem *item;
 	GDataEntry *entry;
-	const gchar *id;
 
 	cbgo = E_CAL_BACKEND_GOOGLE (backend);
 
 	g_return_val_if_fail (E_IS_CAL_BACKEND_GOOGLE(cbgo), GNOME_Evolution_Calendar_InvalidObject);
-	g_return_val_if_fail (calobj != NULL && *calobj!=NULL,GNOME_Evolution_Calendar_InvalidObject);
+	g_return_val_if_fail (calobj != NULL && *calobj!=NULL, GNOME_Evolution_Calendar_InvalidObject);
 	priv = cbgo->priv;
 	if (priv->mode == CAL_MODE_LOCAL) {
 		/*FIXME call offline method */
@@ -1023,9 +996,8 @@ e_cal_backend_google_create_object (ECalBackendSync *backend, EDataCal *cal, gch
 	}
 
 	icalcomp = icalparser_parse_string (*calobj);
-	if (!icalcomp)	{
+	if (!icalcomp)
 		return GNOME_Evolution_Calendar_InvalidObject;
-	}
 
 	if (e_cal_backend_get_kind(E_CAL_BACKEND(backend)) != icalcomponent_isa (icalcomp)) {
 		icalcomponent_free (icalcomp);
@@ -1042,18 +1014,22 @@ e_cal_backend_google_create_object (ECalBackendSync *backend, EDataCal *cal, gch
 		case CAL_MODE_REMOTE: {
 			/* Create an appointment */
 			GDataEntry *updated_entry;
+			const gchar *id;
+			GError *error = NULL;
 
-			item = e_go_item_from_cal_component (cbgo, comp);
-			entry = e_go_item_get_entry (item);
+			entry = GDATA_ENTRY (e_gdata_event_from_cal_component (cbgo, comp));
+			updated_entry = gdata_service_insert_entry (GDATA_SERVICE (priv->service), priv->uri, entry, NULL, &error);
+			g_object_unref (entry);
 
-			updated_entry = gdata_service_insert_entry (GDATA_SERVICE(priv->service),
-					priv->uri, entry, NULL);
-			if (!GDATA_IS_ENTRY (updated_entry)) {
-				g_message ("\n Entry Insertion Failed %s \n", G_STRLOC);
+			if (!updated_entry) {
+				g_message ("\n Entry Insertion Failed %s: %s \n", G_STRLOC, error->message);
+				g_error_free (error);
+				return GNOME_Evolution_Calendar_InvalidObject;
 			}
 
 			id = gdata_entry_get_id (updated_entry);
 			e_cal_component_set_uid (comp, id);
+			g_object_unref (updated_entry);
 
 			break; }
 		default:
@@ -1191,6 +1167,10 @@ e_cal_backend_google_dispose (GObject *object)
 	cbgo = E_CAL_BACKEND_GOOGLE (object);
 	priv = cbgo->priv;
 
+	if (priv->feed)
+		g_object_unref (priv->feed);
+	priv->feed = NULL;
+
 	if (G_OBJECT_CLASS (parent_class)->dispose)
 		(* G_OBJECT_CLASS (parent_class)->dispose) (object);
 }
@@ -1271,7 +1251,7 @@ proxy_settings_changed (EProxy *proxy, gpointer user_data)
 	if (e_proxy_require_proxy_for_uri (proxy, priv->uri)) {
 		proxy_uri = e_proxy_peek_uri_for (proxy, priv->uri);
 	}
-	gdata_service_set_proxy (GDATA_SERVICE (priv->service), proxy_uri);
+	gdata_service_set_proxy_uri (GDATA_SERVICE (priv->service), proxy_uri);
 }
 
 /* Object initialisation function for google backend */
@@ -1283,9 +1263,9 @@ e_cal_backend_google_init (ECalBackendGoogle *cbgo)
 	priv = g_new0 (ECalBackendGooglePrivate, 1);
 
 	priv->mutex = g_mutex_new ();
+	priv->read_only = FALSE;
 	priv->username = NULL;
 	priv->password = NULL;
-	priv->entry = NULL;
 	priv->service = NULL;
 	priv->timeout_id = 0;
 	cbgo->priv = priv;
@@ -1372,32 +1352,32 @@ e_cal_backend_google_set_cache (ECalBackendGoogle *cbgo, ECalBackendCache *cache
 }
 
 /**
- * e_cal_backend_google_set_item:
+ * e_cal_backend_google_set_feed:
  * @cbgo a #ECalBackendGoogle object
- * @cache a #EGoItem *item
+ * @feed a #GDataFeed
  *
  **/
 void
-e_cal_backend_google_set_item (ECalBackendGoogle *cbgo, EGoItem *item)
+e_cal_backend_google_set_feed (ECalBackendGoogle *cbgo, GDataFeed *feed)
 {
-	ECalBackendGooglePrivate *priv;
-
 	g_return_if_fail (cbgo != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND_GOOGLE(cbgo));
+	g_return_if_fail (GDATA_IS_FEED (feed));
 
-	priv = cbgo->priv;
-	priv->item = item;
+	if (cbgo->priv->feed)
+		g_object_unref (cbgo->priv->feed);
+	cbgo->priv->feed = g_object_ref (feed);
 }
 
 /**
- * e_cal_backend_google_set_item:
+ * e_cal_backend_google_set_service:
  * @cbgo a #ECalBackendGoogle object
- * @cache a #EGoItem *item
- * Sets the #EGoItem item on object
+ * @service a #GDataCalendarService
+ * Sets the #GDataCalendarService service on object
  *
  **/
 void
-e_cal_backend_google_set_service (ECalBackendGoogle *cbgo, GDataGoogleService *service)
+e_cal_backend_google_set_service (ECalBackendGoogle *cbgo, GDataCalendarService *service)
 {
 	ECalBackendGooglePrivate *priv;
 
@@ -1432,26 +1412,7 @@ e_cal_backend_google_set_uri (ECalBackendGoogle *cbgo, gchar *uri)
 		proxy_uri = e_proxy_peek_uri_for (priv->proxy, priv->uri);
 	}
 
-	gdata_service_set_proxy (GDATA_SERVICE (priv->service), proxy_uri);
-}
-
-/**
- * e_cal_backend_google_set_entry:
- * @cbgo a #ECalBackendGoogle object
- * @entry a #GDataEntry entry
- * Sets the entry on object
- *
- **/
-void
-e_cal_backend_google_set_entry (ECalBackendGoogle *cbgo, GDataEntry *entry)
-{
-	ECalBackendGooglePrivate *priv;
-
-	g_return_if_fail (cbgo != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND_GOOGLE(cbgo));
-
-	priv = cbgo->priv;
-	priv->entry = entry;
+	gdata_service_set_proxy_uri (GDATA_SERVICE (priv->service), proxy_uri);
 }
 
 /**
@@ -1495,13 +1456,13 @@ e_cal_backend_google_set_username (ECalBackendGoogle *cbgo,gchar *username)
 /**
  * e_cal_backend_google_set_password:
  * @cbgo a #ECalBackendGoogle object
- * @cache a #EGoItem *item
- * Sets the #EGoItem item on object
+ * @password a password
+ * Sets the password on object
  *
  **/
 
 void
-e_cal_backend_google_set_password (ECalBackendGoogle *cbgo,gchar *password)
+e_cal_backend_google_set_password (ECalBackendGoogle *cbgo, gchar *password)
 {
 	ECalBackendGooglePrivate *priv;
 	priv = cbgo->priv;
@@ -1531,29 +1492,26 @@ e_cal_backend_google_get_cache (ECalBackendGoogle *cbgo)
 }
 
 /**
- * e_cal_backend_google_get_item:
+ * e_cal_backend_google_get_feed:
  * @cbgo a #ECalBackendGoogle object
- * Gets the #EGoItem . from cbgo
+ * Gets the #GDataFeed from cbgo
  **/
-EGoItem *
-e_cal_backend_google_get_item (ECalBackendGoogle *cbgo)
+GDataFeed *
+e_cal_backend_google_get_feed (ECalBackendGoogle *cbgo)
 {
-	ECalBackendGooglePrivate *priv;
-
 	g_return_val_if_fail (cbgo != NULL, NULL);
 	g_return_val_if_fail (E_IS_CAL_BACKEND_GOOGLE(cbgo), NULL);
 
-	priv = cbgo->priv;
-	return priv->item;
+	return cbgo->priv->feed;
 }
 
 /**
  * e_cal_backend_google_get_service:
  * @cbgo a #ECalBackendGoogle object
- * Gets the #GDataGoogleService service object .
+ * Gets the #GDataCalendarService service object .
  *
  **/
-GDataGoogleService *
+GDataCalendarService *
 e_cal_backend_google_get_service (ECalBackendGoogle *cbgo)
 {
 	ECalBackendGooglePrivate *priv;
@@ -1566,7 +1524,7 @@ e_cal_backend_google_get_service (ECalBackendGoogle *cbgo)
 }
 
 /**
- * e_cal_backend_google_set_item:
+ * e_cal_backend_google_get_uri:
  * @cbgo a #ECalBackendGoogle object
  * Gets the uri
  **/
@@ -1583,24 +1541,6 @@ e_cal_backend_google_get_uri (ECalBackendGoogle *cbgo)
 }
 
 /**
- * e_cal_backend_google_get_entry:
- * @cbgo a #ECalBackendGoogle object
- * Gets the #GDataEntry object.
- *
- **/
-GDataEntry *
-e_cal_backend_google_get_entry (ECalBackendGoogle *cbgo)
-{
-	ECalBackendGooglePrivate *priv;
-
-	g_return_val_if_fail (cbgo != NULL, NULL);
-	g_return_val_if_fail (E_IS_CAL_BACKEND_GOOGLE(cbgo), NULL);
-
-	priv = cbgo->priv;
-	return priv->entry;
-}
-
-/**
  * e_cal_backend_google_get_timeout_id:
  * @cbgo a #ECalBackendGoogle object
  * Gets the timeout id.
diff --git a/calendar/backends/google/e-cal-backend-google.h b/calendar/backends/google/e-cal-backend-google.h
index c3de6af..c2f0d90 100644
--- a/calendar/backends/google/e-cal-backend-google.h
+++ b/calendar/backends/google/e-cal-backend-google.h
@@ -2,6 +2,7 @@
 /*
  * Authors :
  *  Ebby Wiselyn <ebbywiselyn gmail com>
+ *  Philip Withnall <philip tecnocode co uk>
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
@@ -27,10 +28,8 @@
 #include <libedata-cal/e-cal-backend-sync.h>
 #include <libedata-cal/e-cal-backend-cache.h>
 
-#include <servers/google/libgdata/gdata-entry.h>
-#include <servers/google/libgdata/gdata-feed.h>
-#include <servers/google/libgdata-google/gdata-google-service.h>
-#include <servers/google/libgdata/gdata-service-iface.h>
+#include <gdata/gdata-feed.h>
+#include <gdata/services/calendar/gdata-calendar-service.h>
 
 G_BEGIN_DECLS
 
@@ -56,17 +55,10 @@ struct _ECalBackendGoogleClass {
 	ECalBackendSyncClass parent_class;
 };
 
-struct _EGoItem {
-	GDataEntry *entry;
-	GDataFeed *feed;
-};
-typedef struct _EGoItem EGoItem;
-
 GType e_cal_backend_google_get_type (void);
-EGoItem * e_cal_backend_google_get_item (ECalBackendGoogle *cbgo);
-GDataEntry * e_cal_backend_google_get_entry (ECalBackendGoogle *cbgo);
+GDataFeed * e_cal_backend_google_get_feed (ECalBackendGoogle *cbgo);
 ECalBackendCache * e_cal_backend_google_get_cache (ECalBackendGoogle *cbgo);
-GDataGoogleService * e_cal_backend_google_get_service (ECalBackendGoogle *cbgo);
+GDataCalendarService * e_cal_backend_google_get_service (ECalBackendGoogle *cbgo);
 gchar * e_cal_backend_google_get_uri (ECalBackendGoogle *cbgo);
 icaltimezone * e_cal_backend_google_get_default_zone (ECalBackendGoogle *cbgo);
 gboolean e_cal_backend_google_get_mode_changed (ECalBackendGoogle *cbgo);
@@ -75,10 +67,9 @@ gchar * e_cal_backend_google_get_password (ECalBackendGoogle *cbgo);
 gchar * e_cal_backend_google_get_local_attachments_store (ECalBackendGoogle *cbgo);
 guint e_cal_backend_google_get_timeout_id (ECalBackendGoogle *cbgo);
 
-void e_cal_backend_google_set_entry (ECalBackendGoogle *cbgo, GDataEntry *entry);
 void e_cal_backend_google_set_cache (ECalBackendGoogle *cbgo, ECalBackendCache *cache);
-void e_cal_backend_google_set_item (ECalBackendGoogle *cbgo, EGoItem *item);
-void e_cal_backend_google_set_service (ECalBackendGoogle *cbgo, GDataGoogleService *service);
+void e_cal_backend_google_set_feed (ECalBackendGoogle *cbgo, GDataFeed *feed);
+void e_cal_backend_google_set_service (ECalBackendGoogle *cbgo, GDataCalendarService *service);
 void e_cal_backend_google_set_uri (ECalBackendGoogle *cbgo, gchar *uri);
 void e_cal_backend_google_set_mode_changed (ECalBackendGoogle *cbgo, gboolean mode_changed);
 void e_cal_backend_google_set_username (ECalBackendGoogle *cbgo, gchar *username);
diff --git a/configure.ac b/configure.ac
index 898c0f4..d7ac3bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,7 @@ m4_define([gtk_minimum_version], [2.20.0])
 m4_define([gconf_minimum_version], [2.0.0])		dnl XXX Just a Guess
 m4_define([libxml_minimum_version], [2.0.0])		dnl XXX Just a Guess
 m4_define([libsoup_minimum_version], [2.3.0])
+m4_define([libgdata_minimum_version], [0.6.3])
 m4_define([gnome_keyring_minimum_version], [2.20.1])
 m4_define([sqlite_minimum_version], [3.5])
 m4_define([gweather_minimum_version], [2.25.4])
@@ -87,14 +88,6 @@ LIBCAMEL_CURRENT=15
 LIBCAMEL_REVISION=0
 LIBCAMEL_AGE=0
 
-LIBGDATA_CURRENT=1
-LIBGDATA_REVISION=0
-LIBGDATA_AGE=0
-
-LIBGDATA_GOOGLE_CURRENT=1
-LIBGDATA_GOOGLE_REVISION=0
-LIBGDATA_GOOGLE_AGE=0
-
 LIBEBACKEND_CURRENT=0
 LIBEBACKEND_REVISION=1
 LIBEBACKEND_AGE=0
@@ -126,12 +119,6 @@ AC_SUBST(LIBEGROUPWISE_AGE)
 AC_SUBST(LIBCAMEL_CURRENT)
 AC_SUBST(LIBCAMEL_REVISION)
 AC_SUBST(LIBCAMEL_AGE)
-AC_SUBST(LIBGDATA_CURRENT)
-AC_SUBST(LIBGDATA_REVISION)
-AC_SUBST(LIBGDATA_AGE)
-AC_SUBST(LIBGDATA_GOOGLE_CURRENT)
-AC_SUBST(LIBGDATA_GOOGLE_REVISION)
-AC_SUBST(LIBGDATA_GOOGLE_AGE)
 AC_SUBST(LIBEBACKEND_CURRENT)
 AC_SUBST(LIBEBACKEND_REVISION)
 AC_SUBST(LIBEBACKEND_AGE)
@@ -295,7 +282,8 @@ PKG_CHECK_MODULES(GNOME_PLATFORM,
 	gtk+-2.0 >= gtk_minimum_version
 	gconf-2.0 >= gconf_minimum_version
 	libxml-2.0 >= libxml_minimum_version
-	libsoup-2.4 >= libsoup_minimum_version])
+	libsoup-2.4 >= libsoup_minimum_version
+	libgdata >= libgdata_minimum_version])
 
 LIBICAL_REQUIRED=libical_minimum_version
 AC_SUBST(LIBICAL_REQUIRED)
@@ -1223,8 +1211,10 @@ fi
 dnl ******************************
 dnl Google flags
 dnl ******************************
-GDATA_DEPS="libsoup-2.4 libxml-2.0"
-EVO_SET_COMPILE_FLAGS(GDATA, $GDATA_DEPS)
+LIBGDATA_REQUIRED=libgdata_minimum_version
+AC_SUBST(LIBGDATA_REQUIRED)
+
+EVO_SET_COMPILE_FLAGS(GDATA, libgdata)
 AC_SUBST(GDATA_CFLAGS)
 AC_SUBST(GDATA_LIBS)
 
@@ -1450,11 +1440,6 @@ libedataserverui/libedataserverui.pc
 servers/Makefile
 servers/groupwise/Makefile
 servers/groupwise/libegroupwise.pc
-servers/google/Makefile
-servers/google/libgdata/Makefile
-servers/google/libgdata/libgdata.pc
-servers/google/libgdata-google/Makefile
-servers/google/libgdata-google/libgdata-google.pc
 docs/Makefile
 docs/reference/Makefile
 docs/reference/addressbook/Makefile
diff --git a/servers/Makefile.am b/servers/Makefile.am
index 6d5f0c1..ae2e183 100644
--- a/servers/Makefile.am
+++ b/servers/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = groupwise google
+SUBDIRS = groupwise
 
 -include $(top_srcdir)/git.mk



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