[evolution-data-server] Clean up the Google Contacts addressbook backend
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Clean up the Google Contacts addressbook backend
- Date: Tue, 20 Apr 2010 19:37:56 +0000 (UTC)
commit 42d8a30a497df386955a198538a80eb780ec2386
Author: Philip Withnall <philip tecnocode co uk>
Date: Tue Apr 20 00:31:55 2010 +0100
Clean up the Google Contacts addressbook backend
Merge the entirely redundant GoogleBook into EBookBackendGoogle and simplify
things a bit.
addressbook/backends/google/Makefile.am | 34 +-
.../backends/google/e-book-backend-google.c | 1000 +++++++++++++++---
addressbook/backends/google/google-book.c | 1138 --------------------
addressbook/backends/google/google-book.h | 75 --
po/POTFILES.in | 1 -
5 files changed, 880 insertions(+), 1368 deletions(-)
---
diff --git a/addressbook/backends/google/Makefile.am b/addressbook/backends/google/Makefile.am
index a54ceb9..c7912de 100644
--- a/addressbook/backends/google/Makefile.am
+++ b/addressbook/backends/google/Makefile.am
@@ -2,31 +2,29 @@ extension_LTLIBRARIES = libebookbackendgoogle.la
libebookbackendgoogle_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
- -DG_LOG_DOMAIN=\"libebookbackendgoogle\" \
- -I$(top_srcdir) \
- -I$(top_builddir) \
- -I$(top_srcdir)/addressbook \
- -I$(top_builddir)/addressbook \
- $(SOUP_CFLAGS) \
+ -DG_LOG_DOMAIN=\"libebookbackendgoogle\" \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/addressbook \
+ -I$(top_builddir)/addressbook \
+ $(SOUP_CFLAGS) \
$(EVOLUTION_ADDRESSBOOK_CFLAGS) \
$(GDATA_CFLAGS)
libebookbackendgoogle_la_SOURCES = \
- util.h \
- util.c \
- google-book.h \
- google-book.c \
- e-book-backend-google-factory.c \
- e-book-backend-google.h \
+ util.h \
+ util.c \
+ e-book-backend-google-factory.c \
+ e-book-backend-google.h \
e-book-backend-google.c
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)/libebackend/libebackend-1.2.la \
- $(SOUP_LIBS) \
- $(EVOLUTION_ADDRESSBOOK_LIBS) \
+ $(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)/libebackend/libebackend-1.2.la \
+ $(SOUP_LIBS) \
+ $(EVOLUTION_ADDRESSBOOK_LIBS) \
$(GDATA_LIBS)
libebookbackendgoogle_la_LDFLAGS = \
diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c
index 6f498a1..a5d5442 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -24,40 +24,603 @@
#include <string.h>
#include <errno.h>
+#include <libedataserver/e-proxy.h>
#include <libebook/e-contact.h>
#include <libedata-book/e-data-book.h>
#include <libedata-book/e-data-book-view.h>
#include <libedata-book/e-book-backend-sexp.h>
+#include <libedata-book/e-book-backend-cache.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 "e-book-backend-google.h"
-#include "google-book.h"
#include "util.h"
+#define URI_GET_CONTACTS "://www.google.com/m8/feeds/contacts/default/full"
+
G_DEFINE_TYPE (EBookBackendGoogle, e_book_backend_google, E_TYPE_BOOK_BACKEND_SYNC)
+typedef enum {
+ NO_CACHE,
+ ON_DISK_CACHE,
+ IN_MEMORY_CACHE
+} CacheType;
+
struct _EBookBackendGooglePrivate {
GNOME_Evolution_Addressbook_BookMode mode;
- GoogleBook *book;
GList *bookviews;
-};
-#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), E_TYPE_BOOK_BACKEND_GOOGLE, EBookBackendGooglePrivate))
+ gchar *username;
+ CacheType cache_type;
+ union {
+ EBookBackendCache *on_disk;
+ struct {
+ GHashTable *contacts;
+ GHashTable *gdata_entries;
+ GTimeVal last_updated;
+ } in_memory;
+ } cache;
+
+ gboolean offline;
+ GDataService *service;
+ EProxy *proxy;
+ guint refresh_interval;
+ gboolean use_ssl;
+
+ /* Whether the backend is being used by a view at the moment; if it isn't, we don't need to do updates or send out notifications */
+ gboolean live_mode;
+
+ /* In live mode we will send out signals in an idle_handler */
+ guint idle_id;
+
+ guint refresh_id;
+};
gboolean __e_book_backend_google_debug__;
-static EBookBackendSyncStatus e_book_backend_status_from_google_book_error (GError *error);
+static EBookBackendSyncStatus e_book_backend_status_from_gdata_error (GError *error);
+
+static void
+cache_init (EBookBackend *backend, gboolean on_disk)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ if (on_disk) {
+ priv->cache_type = ON_DISK_CACHE;
+ priv->cache.on_disk = e_book_backend_cache_new (priv->username);
+ } else {
+ priv->cache_type = IN_MEMORY_CACHE;
+ priv->cache.in_memory.contacts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ priv->cache.in_memory.gdata_entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ memset (&priv->cache.in_memory.last_updated, 0, sizeof (GTimeVal));
+ }
+}
+
+static EContact *
+cache_add_contact (EBookBackend *backend, GDataEntry *entry)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ EContact *contact;
+ const gchar *uid;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ contact = _e_contact_new_from_gdata_entry (entry);
+ _e_contact_add_gdata_entry_xml (contact, entry);
+ e_book_backend_cache_add_contact (priv->cache.on_disk, contact);
+ _e_contact_remove_gdata_entry_xml (contact);
+ return contact;
+ case IN_MEMORY_CACHE:
+ contact = _e_contact_new_from_gdata_entry (entry);
+ uid = e_contact_get_const (contact, E_CONTACT_UID);
+ g_hash_table_insert (priv->cache.in_memory.contacts, g_strdup (uid), g_object_ref (contact));
+ g_hash_table_insert (priv->cache.in_memory.gdata_entries, g_strdup (uid), g_object_ref (entry));
+ return contact;
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static gboolean
+cache_remove_contact (EBookBackend *backend, const gchar *uid)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ gboolean success = TRUE;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ return e_book_backend_cache_remove_contact (priv->cache.on_disk, uid);
+ case IN_MEMORY_CACHE:
+ 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:
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+cache_has_contact (EBookBackend *backend, const gchar *uid)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ 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;
+}
+
+static EContact *
+cache_get_contact (EBookBackend *backend, const gchar *uid, GDataEntry **entry)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ EContact *contact;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ contact = e_book_backend_cache_get_contact (priv->cache.on_disk, uid);
+ if (contact) {
+ if (entry) {
+ 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) {
+ 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);
+ }
+ return contact;
+ case IN_MEMORY_CACHE:
+ contact = g_hash_table_lookup (priv->cache.in_memory.contacts, uid);
+ if (entry) {
+ *entry = g_hash_table_lookup (priv->cache.in_memory.gdata_entries, uid);
+ if (*entry)
+ g_object_ref (*entry);
+ }
+
+ if (contact)
+ g_object_ref (contact);
+
+ return contact;
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static GList *
+_g_hash_table_to_list (GHashTable *ht)
+{
+ GList *l = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, ht);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ l = g_list_prepend (l, g_object_ref (G_OBJECT (value)));
+
+ l = g_list_reverse (l);
+
+ return l;
+}
+
+static GList *
+cache_get_contacts (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GList *contacts, *iter;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ contacts = e_book_backend_cache_get_contacts (priv->cache.on_disk, "(contains \"x-evolution-any-field\" \"\")");
+ for (iter = contacts; iter; iter = iter->next)
+ _e_contact_remove_gdata_entry_xml (iter->data);
+
+ return contacts;
+ case IN_MEMORY_CACHE:
+ return _g_hash_table_to_list (priv->cache.in_memory.contacts);
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static void
+cache_freeze (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ if (priv->cache_type == ON_DISK_CACHE)
+ e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache.on_disk));
+}
+
+static void
+cache_thaw (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ if (priv->cache_type == ON_DISK_CACHE)
+ e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache.on_disk));
+}
+
+static gchar *
+cache_get_last_update (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ switch (priv->cache_type) {
+ 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)
+ return g_time_val_to_iso8601 (&priv->cache.in_memory.last_updated);
+ break;
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static gboolean
+cache_get_last_update_tv (EBookBackend *backend, GTimeVal *tv)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ gchar *last_update;
+ gint rv;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ last_update = e_book_backend_cache_get_time (priv->cache.on_disk);
+ rv = last_update ? g_time_val_from_iso8601 (last_update, tv) : FALSE;
+ g_free (last_update);
+ return rv;
+ case IN_MEMORY_CACHE:
+ memcpy (tv, &priv->cache.in_memory.last_updated, sizeof (GTimeVal));
+ return priv->cache.in_memory.contacts != NULL;
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+cache_set_last_update (EBookBackend *backend, GTimeVal *tv)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ gchar *_time;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ _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);
+ return;
+ case IN_MEMORY_CACHE:
+ memcpy (&priv->cache.in_memory.last_updated, tv, sizeof (GTimeVal));
+ case NO_CACHE:
+ default:
+ break;
+ }
+}
+
+static gboolean
+cache_needs_update (EBookBackend *backend, guint *remaining_secs)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GTimeVal last, current;
+ guint diff;
+ gboolean rv;
+
+ if (remaining_secs)
+ *remaining_secs = G_MAXUINT;
+
+ /* We never want to update in offline mode */
+ if (priv->offline)
+ return FALSE;
+
+ rv = cache_get_last_update_tv (backend, &last);
+
+ if (!rv)
+ return TRUE;
+
+ g_get_current_time (¤t);
+ if (last.tv_sec > current.tv_sec) {
+ g_warning ("last update is in the feature?");
+
+ /* Do an update so we can fix this */
+ return TRUE;
+ }
+ diff = current.tv_sec - last.tv_sec;
+
+ if (diff >= priv->refresh_interval)
+ return TRUE;
+
+ if (remaining_secs)
+ *remaining_secs = priv->refresh_interval - diff;
+
+ __debug__ ("No update needed. Next update needed in %d secs", priv->refresh_interval - diff);
+
+ return FALSE;
+}
+
+static void
+on_contact_added (EBookBackend *backend, EContact *contact)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GList *iter;
+
+ if (!priv->live_mode)
+ return;
+
+ for (iter = priv->bookviews; iter; iter = iter->next)
+ e_data_book_view_notify_update (E_DATA_BOOK_VIEW (iter->data), g_object_ref (contact));
+}
+
+static void
+on_contact_removed (EBookBackend *backend, const gchar *uid)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GList *iter;
+
+ if (!priv->live_mode)
+ return;
+
+ for (iter = priv->bookviews; iter; iter = iter->next)
+ e_data_book_view_notify_remove (E_DATA_BOOK_VIEW (iter->data), g_strdup (uid));
+}
+
+static void
+on_contact_changed (EBookBackend *backend, EContact *contact)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GList *iter;
+
+ if (!priv->live_mode)
+ return;
+
+ for (iter = priv->bookviews; iter; iter = iter->next)
+ e_data_book_view_notify_update (E_DATA_BOOK_VIEW (iter->data), g_object_ref (contact));
+}
+
+static void
+on_sequence_complete (EBookBackend *backend, GError *error)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_Success;
+ GList *iter;
+
+ if (!priv->live_mode)
+ return;
+
+ if (error) {
+ status = e_book_backend_status_from_gdata_error (error);
+ __debug__ ("Book-view query failed: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ for (iter = priv->bookviews; iter; iter = iter->next)
+ e_data_book_view_notify_complete (E_DATA_BOOK_VIEW (iter->data), GNOME_Evolution_Addressbook_Success);
+}
+
+static void
+process_subsequent_entry (GDataEntry *entry, EBookBackend *backend)
+{
+ gboolean is_deleted, is_cached;
+ const gchar *uid;
+
+ __debug__ (G_STRFUNC);
+ uid = gdata_entry_get_id (entry);
+ is_deleted = gdata_contacts_contact_is_deleted (GDATA_CONTACTS_CONTACT (entry));
+
+ is_cached = cache_has_contact (backend, uid);
+ if (is_deleted) {
+ /* Do we have this item in our cache? */
+ if (is_cached) {
+ cache_remove_contact (backend, uid);
+ on_contact_removed (backend, uid);
+ }
+ } else {
+ EContact *contact = cache_add_contact (backend, entry);
+
+ if (is_cached)
+ on_contact_changed (backend, contact);
+ else
+ on_contact_added (backend, contact);
+
+ g_object_unref (contact);
+ }
+}
+
+static void
+process_initial_entry (GDataEntry *entry, EBookBackend *backend)
+{
+ EContact *contact;
+
+ __debug__ (G_STRFUNC);
+
+ contact = cache_add_contact (backend, entry);
+ on_contact_added (backend, contact);
+ g_object_unref (contact);
+}
+
+static gboolean
+get_new_contacts_in_chunks (EBookBackend *backend, gint chunk_size, GError **error)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ GDataFeed *feed;
+ GDataQuery *query;
+ gchar *last_updated;
+ GError *our_error = NULL;
+ gboolean rv = TRUE;
+ GTimeVal current_time;
+ int results;
+
+ __debug__ (G_STRFUNC);
+ g_return_val_if_fail (priv->service, FALSE);
+
+ last_updated = cache_get_last_update (backend);
+ cache_freeze (backend);
+
+ /* 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);
+ }
+
+ /* Get the paginated results */
+ do {
+ GList *entries;
+
+ /* Run the query */
+ feed = gdata_contacts_service_query_contacts (GDATA_CONTACTS_SERVICE (priv->service), query, NULL, NULL, NULL, &our_error);
+
+ if (our_error) {
+ on_sequence_complete (backend, our_error);
+ g_propagate_error (error, our_error);
+
+ rv = FALSE;
+ goto out;
+ }
+
+ entries = gdata_feed_get_entries (feed);
+ results = entries ? g_list_length (entries) : 0;
+ __debug__ ("Feed has %d entries", results);
+
+ /* Process the entries from this page */
+ if (last_updated)
+ g_list_foreach (entries, (GFunc) process_subsequent_entry, backend);
+ else
+ g_list_foreach (entries, (GFunc) process_initial_entry, backend);
+ g_object_unref (feed);
+
+ /* Move to the next page */
+ gdata_query_next_page (query);
+ } while (results == chunk_size);
+
+ /* Finish updating the cache */
+ g_get_current_time (¤t_time);
+ cache_set_last_update (backend, ¤t_time);
+ on_sequence_complete (backend, NULL);
+
+out:
+ g_free (last_updated);
+ cache_thaw (backend);
+
+ return rv;
+}
+
+static gboolean cache_refresh_if_needed (EBookBackend *backend, GError **error);
+
+static gboolean
+on_refresh_timeout (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ __debug__ (G_STRFUNC);
+
+ priv->refresh_id = 0;
+ if (priv->live_mode)
+ cache_refresh_if_needed (backend, NULL);
+
+ return FALSE;
+}
+
+static gboolean
+cache_refresh_if_needed (EBookBackend *backend, GError **error)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ guint remaining_secs;
+ gint rv = TRUE;
+ gboolean install_timeout;
+
+ __debug__ (G_STRFUNC);
+
+ if (priv->offline || !priv->service) {
+ __debug__ ("We are not connected to Google%s.", priv->offline ? " (offline mode)" : "");
+ return TRUE;
+ }
+
+ install_timeout = (priv->live_mode && priv->refresh_interval > 0 && 0 == priv->refresh_id);
+
+ if (cache_needs_update (backend, &remaining_secs)) {
+ rv = get_new_contacts_in_chunks (backend, 32, error);
+ if (install_timeout)
+ priv->refresh_id = g_timeout_add_seconds (priv->refresh_interval, (GSourceFunc) on_refresh_timeout, backend);
+ } else {
+ if (install_timeout) {
+ __debug__ ("Installing timeout with %d seconds", remaining_secs);
+ priv->refresh_id = g_timeout_add_seconds (remaining_secs, (GSourceFunc) on_refresh_timeout, backend);
+ }
+ }
+ return rv;
+}
+
+static void
+cache_destroy (EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
+ switch (priv->cache_type) {
+ case ON_DISK_CACHE:
+ g_object_unref (priv->cache.on_disk);
+ break;
+ case IN_MEMORY_CACHE:
+ g_hash_table_destroy (priv->cache.in_memory.contacts);
+ g_hash_table_destroy (priv->cache.in_memory.gdata_entries);
+ break;
+ case NO_CACHE:
+ default:
+ break;
+ }
+
+ priv->cache_type = NO_CACHE;
+}
static EBookBackendSyncStatus
e_book_backend_google_create_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard_str, EContact **out_contact)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_OtherError;
EContact *contact;
GError *error = NULL;
+ GDataEntry *entry, *new_entry;
+ gchar *xml;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
__debug__ ("Creating: %s", vcard_str);
*out_contact = NULL;
@@ -65,53 +628,92 @@ e_book_backend_google_create_contact (EBookBackendSync *backend, EDataBook *book
if (priv->mode != GNOME_Evolution_Addressbook_MODE_REMOTE)
return GNOME_Evolution_Addressbook_OfflineUnavailable;
+ g_return_val_if_fail (priv->service, status);
+
+ /* Build the GDataEntry from the vCard */
contact = e_contact_new_from_vcard (vcard_str);
- google_book_add_contact (priv->book, contact, out_contact, &error);
+ entry = _gdata_entry_new_from_e_contact (contact);
g_object_unref (contact);
- if (error) {
- status = e_book_backend_status_from_google_book_error (error);
+ /* Debug XML output */
+ xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
+ __debug__ ("new entry with xml: %s", xml);
+ g_free (xml);
+
+ /* Insert the entry on the server */
+ 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 (!new_entry) {
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Creating contact failed: %s", error->message);
- g_clear_error (&error);
- *out_contact = NULL;
+ g_error_free (error);
+
return status;
}
+ /* Add the new contact to the cache */
+ *out_contact = cache_add_contact (E_BOOK_BACKEND (backend), new_entry);
+ g_object_unref (new_entry);
+
return GNOME_Evolution_Addressbook_Success;
}
static EBookBackendSyncStatus
e_book_backend_google_remove_contacts (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList *id_list, GList **ids)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_OtherError;
GList *id_iter;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
*ids = NULL;
if (priv->mode != GNOME_Evolution_Addressbook_MODE_REMOTE)
return GNOME_Evolution_Addressbook_OfflineUnavailable;
+ g_return_val_if_fail (priv->service, status);
+
for (id_iter = id_list; id_iter; id_iter = id_iter->next) {
GError *error = NULL;
const gchar *uid;
+ GDataEntry *entry = NULL;
+ EContact *cached_contact;
+ /* Get the contact and associated GDataEntry from the cache */
uid = id_iter->data;
- google_book_remove_contact (priv->book, uid, &error);
+ cached_contact = cache_get_contact (E_BOOK_BACKEND (backend), uid, &entry);
- if (error) {
+ if (!cached_contact) {
+ /* Only the last error will be reported */
+ status = GNOME_Evolution_Addressbook_ContactNotFound;
+ __debug__ ("Deleting contact %s failed: Contact not found in cache.", uid);
+
+ continue;
+ }
+
+ g_object_unref (cached_contact);
+
+ /* Remove the contact from the cache */
+ cache_remove_contact (E_BOOK_BACKEND (backend), uid);
+
+ /* Delete the contact from the server */
+ if (!gdata_service_delete_entry (GDATA_SERVICE (priv->service), entry, NULL, &error)) {
/* Only last error will be reported */
- status = e_book_backend_status_from_google_book_error (error);
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Deleting contact %s failed: %s", uid, error->message);
- g_clear_error (&error);
+ g_error_free (error);
} else {
+ /* Success! */
*ids = g_list_append (*ids, g_strdup (uid));
}
+
+ g_object_unref (entry);
}
+ /* On error, return the status of the last error */
if (!*ids)
return status;
@@ -121,13 +723,15 @@ e_book_backend_google_remove_contacts (EBookBackendSync *backend, EDataBook *boo
static EBookBackendSyncStatus
e_book_backend_google_modify_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard_str, EContact **out_contact)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_OtherError;
- EContact *contact;
+ EContact *contact, *cached_contact;
GError *error = NULL;
+ GDataEntry *entry = NULL, *new_entry;
+ gchar *xml;
+ const gchar *uid;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
__debug__ ("Updating: %s", vcard_str);
*out_contact = NULL;
@@ -135,41 +739,89 @@ e_book_backend_google_modify_contact (EBookBackendSync *backend, EDataBook *book
if (priv->mode != GNOME_Evolution_Addressbook_MODE_REMOTE)
return GNOME_Evolution_Addressbook_OfflineUnavailable;
+ g_return_val_if_fail (priv->service, status);
+
+ /* Get the new contact and its UID */
contact = e_contact_new_from_vcard (vcard_str);
- google_book_update_contact (priv->book, contact, out_contact, &error);
+ uid = e_contact_get (contact, E_CONTACT_UID);
+
+ /* Get the old cached contact with the same UID and its associated GDataEntry */
+ cached_contact = cache_get_contact (E_BOOK_BACKEND (backend), uid, &entry);
+
+ if (!cached_contact) {
+ __debug__ ("Modifying contact failed: Contact with uid %s not found in cache.", uid);
+ g_object_unref (contact);
+
+ return GNOME_Evolution_Addressbook_ContactNotFound;
+ }
+
+ g_object_unref (cached_contact);
+
+ /* Update the old GDataEntry from the new contact */
+ _gdata_entry_update_from_e_contact (entry, contact);
g_object_unref (contact);
- if (error) {
- status = e_book_backend_status_from_google_book_error (error);
+ /* Output debug XML */
+ xml = gdata_parsable_get_xml (GDATA_PARSABLE (entry));
+ __debug__ ("Before:\n%s", xml);
+ g_free (xml);
+
+ /* Update the contact on the server */
+ 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 (!new_entry) {
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Modifying contact failed: %s", error->message);
- g_clear_error (&error);
- *out_contact = NULL;
+ g_error_free (error);
+
return status;
}
+ /* Output debug XML */
+ xml = NULL;
+ if (new_entry)
+ xml = gdata_parsable_get_xml (GDATA_PARSABLE (new_entry));
+ __debug__ ("After:\n%s", xml);
+ g_free (xml);
+
+ /* Add the new entry to the cache */
+ *out_contact = cache_add_contact (E_BOOK_BACKEND (backend), new_entry);
+ g_object_unref (new_entry);
+
return GNOME_Evolution_Addressbook_Success;
}
static EBookBackendSyncStatus
e_book_backend_google_get_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *uid, gchar **vcard_str)
{
- EBookBackendGooglePrivate *priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_OtherError;
EContact *contact;
GError *error = NULL;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
- contact = google_book_get_contact (priv->book, uid, &error);
+ /* Refresh the cache */
+ cache_refresh_if_needed (E_BOOK_BACKEND (backend), &error);
if (error) {
- status = e_book_backend_status_from_google_book_error (error);
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Getting contact with uid %s failed: %s", uid, error->message);
- g_clear_error (&error);
+ g_error_free (error);
+
return status;
}
+ /* Get the contact */
+ contact = cache_get_contact (E_BOOK_BACKEND (backend), uid, NULL);
+
+ if (!contact) {
+ __debug__ ("Getting contact with uid %s failed: Contact not found in cache.", uid);
+ return GNOME_Evolution_Addressbook_ContactNotFound;
+ }
+
+ /* Success! Build and return a vCard of the contacts */
*vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
g_object_unref (contact);
@@ -179,188 +831,230 @@ e_book_backend_google_get_contact (EBookBackendSync *backend, EDataBook *book, g
static EBookBackendSyncStatus
e_book_backend_google_get_contact_list (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *query, GList **contacts)
{
- EBookBackendGooglePrivate *priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_OtherError;
EBookBackendSExp *sexp;
GError *error = NULL;
GList *all_contacts;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
*contacts = NULL;
- all_contacts = google_book_get_all_contacts (priv->book, &error);
+ /* Refresh the cache */
+ cache_refresh_if_needed (E_BOOK_BACKEND (backend), &error);
if (error) {
- status = e_book_backend_status_from_google_book_error (error);
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Getting all contacts failed: %s", error->message);
g_clear_error (&error);
+
return status;
}
+ /* Get all contacts */
sexp = e_book_backend_sexp_new (query);
- while (all_contacts) {
- EContact *contact;
+ all_contacts = cache_get_contacts (E_BOOK_BACKEND (backend));
- contact = all_contacts->data;
+ for (; all_contacts; all_contacts = g_list_delete_link (all_contacts, all_contacts)) {
+ EContact *contact = all_contacts->data;
+
+ /* If the search expression matches the contact, include it in the search results */
if (e_book_backend_sexp_match_contact (sexp, contact)) {
gchar *vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
*contacts = g_list_append (*contacts, vcard_str);
}
- g_object_unref (contact);
- all_contacts = g_list_delete_link (all_contacts, all_contacts);
+ g_object_unref (contact);
}
+
g_object_unref (sexp);
return GNOME_Evolution_Addressbook_Success;
}
-static void
-on_google_book_contact_added (GoogleBook *book, EContact *contact, gpointer user_data)
+static gboolean
+on_refresh_idle (EBookBackend *backend)
{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (user_data);
- GList *iter;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
- for (iter = priv->bookviews; iter; iter = iter->next) {
- g_object_ref (contact);
- e_data_book_view_notify_update (E_DATA_BOOK_VIEW (iter->data), contact);
- }
-}
+ priv->idle_id = 0;
+ cache_refresh_if_needed (backend, NULL);
-static void
-on_google_book_contact_removed (GoogleBook *book, const gchar *uid, gpointer user_data)
-{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (user_data);
- GList *iter;
-
- for (iter = priv->bookviews; iter; iter = iter->next)
- e_data_book_view_notify_remove (E_DATA_BOOK_VIEW (iter->data), g_strdup (uid));
+ return FALSE;
}
static void
-on_google_book_contact_changed (GoogleBook *book, EContact *contact, gpointer user_data)
+set_live_mode (EBookBackend *backend, gboolean live_mode)
{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (user_data);
- GList *iter;
-
- for (iter = priv->bookviews; iter; iter = iter->next) {
- g_object_ref (contact);
- e_data_book_view_notify_update (E_DATA_BOOK_VIEW (iter->data), contact);
- }
-}
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
-static void
-on_google_book_sequence_complete (GoogleBook *book, GError *error, gpointer user_data)
-{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (user_data);
- EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_Success;
- GList *iter;
+ __debug__ (G_STRFUNC);
+ priv->live_mode = live_mode;
- if (error) {
- status = e_book_backend_status_from_google_book_error (error);
- __debug__ ("Book-view query failed: %s", error->message);
- g_clear_error (&error);
+ if (!live_mode && priv->refresh_id > 0) {
+ g_source_remove (priv->refresh_id);
+ priv->refresh_id = 0;
}
- for (iter = priv->bookviews; iter; iter = iter->next)
- e_data_book_view_notify_complete (E_DATA_BOOK_VIEW (iter->data), GNOME_Evolution_Addressbook_Success);
+ if (priv->live_mode)
+ cache_refresh_if_needed (backend, NULL);
}
static void
e_book_backend_google_start_book_view (EBookBackend *backend, EDataBookView *bookview)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
GList *cached_contacts;
g_return_if_fail (E_IS_BOOK_BACKEND_GOOGLE (backend));
g_return_if_fail (E_IS_DATA_BOOK_VIEW (bookview));
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
priv->bookviews = g_list_append (priv->bookviews, bookview);
e_data_book_view_ref (bookview);
e_data_book_view_notify_status_message (bookview, "Loading...");
- google_book_set_live_mode (priv->book, TRUE);
- cached_contacts = google_book_get_all_contacts_in_live_mode (priv->book);
- while (cached_contacts) {
- EContact *contact = cached_contacts->data;
+ /* Ensure that we're ready to support a view */
+ set_live_mode (backend, TRUE);
+
+ /* Update the cache if necessary */
+ if (cache_needs_update (backend, NULL)) {
+ if (!priv->service) {
+ /* We need authorization first */
+ e_book_backend_notify_auth_required (backend);
+ } else {
+ /* Update in an idle function, so that this call doesn't block */
+ priv->idle_id = g_idle_add ((GSourceFunc) on_refresh_idle, backend);
+ }
+ }
+ /* Get the contacts */
+ cached_contacts = cache_get_contacts (backend);
+ __debug__ ("%d contacts found in cache", g_list_length (cached_contacts));
+
+ /* Notify the view that all the contacts have changed (i.e. been added) */
+ for (; cached_contacts; cached_contacts = g_list_delete_link (cached_contacts, cached_contacts)) {
+ EContact *contact = cached_contacts->data;
e_data_book_view_notify_update (bookview, contact);
g_object_unref (contact);
- cached_contacts = g_list_delete_link (cached_contacts, cached_contacts);
}
+
e_data_book_view_notify_complete (bookview, GNOME_Evolution_Addressbook_Success);
}
static void
e_book_backend_google_stop_book_view (EBookBackend *backend, EDataBookView *bookview)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
+ /* Remove the view from the list of active views */
priv->bookviews = g_list_remove (priv->bookviews, bookview);
e_data_book_view_unref (bookview);
+ /* If there are no book views left, we can stop doing certain things, like refreshes */
if (!priv->bookviews)
- google_book_set_live_mode (priv->book, FALSE);
+ set_live_mode (backend, FALSE);
+}
+
+static void
+proxy_settings_changed (EProxy *proxy, EBookBackend *backend)
+{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+ SoupURI *proxy_uri = NULL;
+ gchar *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, uri))
+ proxy_uri = e_proxy_peek_uri_for (proxy, uri);
+ gdata_service_set_proxy_uri (GDATA_SERVICE (priv->service), proxy_uri);
+
+ g_free (uri);
}
static EBookBackendSyncStatus
e_book_backend_google_authenticate_user (EBookBackendSync *backend, EDataBook *book, guint32 opid,
const gchar *username, const gchar *password, const gchar *auth_method)
{
- EBookBackendGooglePrivate *priv;
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
EBookBackendSyncStatus status = GNOME_Evolution_Addressbook_Success;
GError *error = NULL;
- gchar *book_username;
gboolean match;
__debug__ (G_STRFUNC);
- priv = GET_PRIVATE (backend);
if (priv->mode != GNOME_Evolution_Addressbook_MODE_REMOTE)
return GNOME_Evolution_Addressbook_Success;
- if (!username || username[0] == 0)
- return GNOME_Evolution_Addressbook_AuthenticationFailed;
+ if (priv->service) {
+ g_warning ("Connection to Google already established.");
+ e_book_backend_notify_writable (E_BOOK_BACKEND (backend), TRUE);
+ return GNOME_Evolution_Addressbook_Success;
+ }
- g_object_get (G_OBJECT (priv->book), "username", &book_username, NULL);
+ if (!username || username[0] == 0 || !password || password[0] == 0)
+ return GNOME_Evolution_Addressbook_AuthenticationFailed;
- match = (0 == strcmp (username, book_username));
- g_free (book_username);
- if (FALSE == match) {
+ match = (strcmp (username, priv->username) == 0);
+ if (!match) {
g_warning ("Username given when loading source and on authentication did not match!");
return GNOME_Evolution_Addressbook_AuthenticationRequired;
}
- google_book_connect_to_google (priv->book, password, &error);
+ /* Set up the service and proxy */
+ priv->service = GDATA_SERVICE (gdata_contacts_service_new ("evolution-client-0.1.0"));
+
+ priv->proxy = e_proxy_new ();
+ e_proxy_setup_proxy (priv->proxy);
+
+ proxy_settings_changed (priv->proxy, E_BOOK_BACKEND (backend));
+ g_signal_connect (priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), backend);
+
+ /* Authenticate with the server */
+ 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;
+
+ status = e_book_backend_status_from_gdata_error (error);
+ __debug__ ("Authentication failed: %s", error->message);
+ g_error_free (error);
+
+ return status;
+ }
+
+ /* Update the cache if neccessary */
+ cache_refresh_if_needed (E_BOOK_BACKEND (backend), &error);
+
if (error) {
- status = e_book_backend_status_from_google_book_error (error);
+ status = e_book_backend_status_from_gdata_error (error);
__debug__ ("Authentication failed: %s", error->message);
- g_clear_error (&error);
- } else {
- e_book_backend_notify_writable (E_BOOK_BACKEND (backend), TRUE);
+ g_error_free (error);
+
+ return status;
}
- return status;
+ e_book_backend_notify_writable (E_BOOK_BACKEND (backend), TRUE);
+
+ return GNOME_Evolution_Addressbook_Success;
}
static EBookBackendSyncStatus
e_book_backend_google_get_supported_auth_methods (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList **methods)
{
- gchar *auth_method;
-
__debug__ (G_STRFUNC);
- auth_method = g_strdup_printf ("plain/password");
- *methods = g_list_append (NULL, auth_method);
+ *methods = g_list_prepend (NULL, g_strdup ("plain/password"));
return GNOME_Evolution_Addressbook_Success;
}
@@ -476,9 +1170,10 @@ e_book_backend_google_get_supported_fields (EBookBackendSync *backend, EDataBook
__debug__ (G_STRFUNC);
+ /* Add all the fields above to the list */
for (i = 0; i < G_N_ELEMENTS (supported_fields); i++) {
const gchar *field_name = e_contact_field_name (supported_fields[i]);
- fields = g_list_append (fields, g_strdup (field_name));
+ fields = g_list_prepend (fields, g_strdup (field_name));
}
*fields_out = fields;
@@ -500,26 +1195,47 @@ e_book_backend_google_remove (EBookBackendSync *backend, EDataBook *book, guint3
}
static void
-on_google_book_auth_required (GoogleBook *book, gpointer user_data)
+set_offline_mode (EBookBackend *backend, gboolean offline)
{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
+
__debug__ (G_STRFUNC);
- e_book_backend_notify_auth_required (E_BOOK_BACKEND (user_data));
+
+ priv->offline = offline;
+
+ if (offline) {
+ /* Going offline, so we can free our service and proxy */
+ if (priv->service)
+ g_object_unref (priv->service);
+ priv->service = NULL;
+
+ if (priv->proxy)
+ g_object_unref (priv->proxy);
+ priv->proxy = NULL;
+ } else {
+ /* Going online, so we need to re-authenticate and re-create the service and proxy.
+ * This is done in e_book_backend_google_authenticate_user() when it gets the authentication data. */
+ e_book_backend_notify_auth_required (backend);
+ }
}
static GNOME_Evolution_Addressbook_CallStatus
e_book_backend_google_load_source (EBookBackend *backend, ESource *source, gboolean only_if_exists)
{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (backend);
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
const gchar *refresh_interval_str, *use_ssl_str, *use_cache_str;
guint refresh_interval;
gboolean use_ssl, use_cache;
const gchar *username;
- if (priv->book) {
+ __debug__ (G_STRFUNC);
+
+ if (priv->username) {
g_warning ("Source already loaded!");
return GNOME_Evolution_Addressbook_OtherError;
}
+ /* Parse the username property */
username = e_source_get_property (source, "username");
if (!username || username[0] == '\0') {
@@ -527,6 +1243,7 @@ e_book_backend_google_load_source (EBookBackend *backend, ESource *source, gbool
return GNOME_Evolution_Addressbook_OtherError;
}
+ /* Parse various other properties */
refresh_interval_str = e_source_get_property (source, "refresh-interval");
use_ssl_str = e_source_get_property (source, "ssl");
use_cache_str = e_source_get_property (source, "offline_sync");
@@ -544,26 +1261,23 @@ e_book_backend_google_load_source (EBookBackend *backend, ESource *source, gbool
if (use_cache_str && (g_ascii_strcasecmp (use_cache_str, "false") == 0 || strcmp (use_cache_str, "0") == 0))
use_cache = FALSE;
- priv->book = google_book_new (username, use_cache);
-
- g_object_set (G_OBJECT (priv->book),
- "refresh-interval", refresh_interval,
- "use-ssl", use_ssl,
- NULL);
- g_object_connect (G_OBJECT (priv->book),
- "signal::contact-added", G_CALLBACK (on_google_book_contact_added), backend,
- "signal::contact-changed", G_CALLBACK (on_google_book_contact_changed), backend,
- "signal::contact-removed", G_CALLBACK (on_google_book_contact_removed), backend,
- "signal::sequence-complete", G_CALLBACK (on_google_book_sequence_complete), backend,
- "signal::auth-required", G_CALLBACK (on_google_book_auth_required), backend,
- NULL);
+ /* Set up our object */
+ priv->username = g_strdup (username);
+ cache_init (backend, use_cache);
+ priv->use_ssl = use_ssl;
+ priv->refresh_interval = refresh_interval;
- __debug__ (G_STRFUNC);
+ /* 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, (GSourceFunc) on_refresh_timeout, backend);
+ }
+ /* Set up ready to be interacted with */
e_book_backend_set_is_loaded (backend, TRUE);
e_book_backend_notify_connection_status (backend, TRUE);
e_book_backend_set_is_writable (backend, FALSE);
- google_book_set_offline_mode (priv->book, (priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL));
+ set_offline_mode (backend, (priv->mode == GNOME_Evolution_Addressbook_MODE_LOCAL));
return GNOME_Evolution_Addressbook_Success;
}
@@ -572,7 +1286,7 @@ static gchar *
e_book_backend_google_get_static_capabilities (EBookBackend *backend)
{
__debug__ (G_STRFUNC);
- return g_strdup("net,do-initial-query,contact-lists");
+ return g_strdup ("net,do-initial-query,contact-lists");
}
static GNOME_Evolution_Addressbook_CallStatus
@@ -585,7 +1299,7 @@ e_book_backend_google_cancel_operation (EBookBackend *backend, EDataBook *book)
static void
e_book_backend_google_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbook_BookMode mode)
{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (backend);
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
gboolean online = (mode == GNOME_Evolution_Addressbook_MODE_REMOTE);
__debug__ (G_STRFUNC);
@@ -595,8 +1309,7 @@ e_book_backend_google_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbo
priv->mode = mode;
- if (priv->book)
- google_book_set_offline_mode (priv->book, !online);
+ set_offline_mode (backend, !online);
e_book_backend_notify_connection_status (backend, online);
/* Mark the book as unwriteable if we're going offline, but don't do the inverse when we go online;
@@ -608,7 +1321,7 @@ e_book_backend_google_set_mode (EBookBackend *backend, GNOME_Evolution_Addressbo
static void
e_book_backend_google_dispose (GObject *object)
{
- EBookBackendGooglePrivate *priv = GET_PRIVATE (object);
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (object)->priv;
__debug__ (G_STRFUNC);
@@ -617,19 +1330,33 @@ e_book_backend_google_dispose (GObject *object)
priv->bookviews = g_list_delete_link (priv->bookviews, priv->bookviews);
}
- if (priv->book) {
- g_object_unref (priv->book);
- priv->book = NULL;
+ if (priv->idle_id) {
+ g_source_remove (priv->idle_id);
+ priv->idle_id = 0;
}
+ if (priv->service)
+ g_object_unref (priv->service);
+ priv->service = NULL;
+
+ if (priv->proxy)
+ g_object_unref (priv->proxy);
+ priv->proxy = NULL;
+
+ cache_destroy (E_BOOK_BACKEND (object));
+
G_OBJECT_CLASS (e_book_backend_google_parent_class)->dispose (object);
}
static void
e_book_backend_google_finalize (GObject *object)
{
+ EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (object)->priv;
+
__debug__ (G_STRFUNC);
+ g_free (priv->username);
+
G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object);
}
@@ -673,6 +1400,7 @@ static void
e_book_backend_google_init (EBookBackendGoogle *backend)
{
__debug__ (G_STRFUNC);
+ backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, E_TYPE_BOOK_BACKEND_GOOGLE, EBookBackendGooglePrivate);
}
EBookBackend *
@@ -687,7 +1415,7 @@ e_book_backend_google_new (void)
}
static EBookBackendSyncStatus
-e_book_backend_status_from_google_book_error (GError *error)
+e_book_backend_status_from_gdata_error (GError *error)
{
if (!error)
return GNOME_Evolution_Addressbook_Success;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 360c5aa..b97c86b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,7 +3,6 @@
[encoding: UTF-8]
addressbook/backends/file/e-book-backend-file.c
addressbook/backends/google/e-book-backend-google.c
-addressbook/backends/google/google-book.c
addressbook/backends/google/util.c
addressbook/backends/groupwise/e-book-backend-groupwise.c
addressbook/backends/ldap/e-book-backend-ldap.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]