[evolution-data-server/wip/offline-cache] Make GTasks backend derive from ECalMetaBackend
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/offline-cache] Make GTasks backend derive from ECalMetaBackend
- Date: Tue, 21 Mar 2017 22:27:18 +0000 (UTC)
commit 1c034ab74721f7b1d8c44678d96306ad9080349d
Author: Milan Crha <mcrha redhat com>
Date: Tue Mar 21 23:26:32 2017 +0100
Make GTasks backend derive from ECalMetaBackend
.../backends/gtasks/e-cal-backend-gtasks.c | 1649 +++++++-------------
.../backends/gtasks/e-cal-backend-gtasks.h | 4 +-
src/calendar/libedata-cal/e-cal-meta-backend.c | 70 +-
3 files changed, 591 insertions(+), 1132 deletions(-)
---
diff --git a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 5076f58..2d5dc2f 100644
--- a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -26,234 +26,50 @@
#define d(x)
-#define E_CAL_BACKEND_GTASKS_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_CAL_BACKEND_GTASKS, ECalBackendGTasksPrivate))
-
#define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
#define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
-#define GTASKS_KEY_LAST_UPDATED "last-updated"
-#define GTASKS_KEY_VERSION "version"
+#define GTASKS_DEFAULT_TASKLIST_NAME "@default"
#define X_EVO_GTASKS_SELF_LINK "X-EVOLUTION-GTASKS-SELF-LINK"
/* Current data version; when doesn't match with the stored,
then fetches everything again. */
-#define GTASKS_DATA_VERSION "1"
-
-#define PROPERTY_LOCK(_gtasks) g_mutex_lock (&(_gtasks)->priv->property_mutex)
-#define PROPERTY_UNLOCK(_gtasks) g_mutex_unlock (&(_gtasks)->priv->property_mutex)
+#define GTASKS_DATA_VERSION 1
+#define GTASKS_DATA_VERSION_KEY "gtasks-data-version"
struct _ECalBackendGTasksPrivate {
GDataAuthorizer *authorizer;
GDataTasksService *service;
GDataTasksTasklist *tasklist;
-
- ECalBackendStore *store;
- GCancellable *cancellable;
- GMutex property_mutex;
-
- guint refresh_id;
+ GHashTable *preloaded; /* gchar *uid ~> ECalComponent * */
};
-G_DEFINE_TYPE (ECalBackendGTasks, e_cal_backend_gtasks, E_TYPE_CAL_BACKEND)
+G_DEFINE_TYPE (ECalBackendGTasks, e_cal_backend_gtasks, E_TYPE_CAL_META_BACKEND)
static gboolean
-ecb_gtasks_check_data_version_locked (ECalBackendGTasks *gtasks)
+ecb_gtasks_check_data_version (ECalCache *cal_cache)
{
#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
- const gchar *key;
- gboolean data_version_correct;
-
- g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks), FALSE);
-
- key = e_cal_backend_store_get_key_value (gtasks->priv->store, GTASKS_KEY_VERSION);
- data_version_correct = g_strcmp0 (key, GTASKS_DATA_VERSION) == 0;
+ g_return_val_if_fail (E_IS_CAL_CACHE (cal_cache), FALSE);
- return data_version_correct;
+ return GTASKS_DATA_VERSION == e_cache_get_key_int (E_CACHE (cal_cache), GTASKS_DATA_VERSION_KEY,
NULL);
#else
return TRUE;
#endif
}
static void
-ecb_gtasks_store_data_version_locked (ECalBackendGTasks *gtasks)
+ecb_gtasks_store_data_version (ECalCache *cal_cache)
{
#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
- e_cal_backend_store_put_key_value (gtasks->priv->store, GTASKS_KEY_VERSION, GTASKS_DATA_VERSION);
-#endif
-}
-
-static GCancellable *
-ecb_gtasks_ref_cancellable (ECalBackendGTasks *gtasks)
-{
- GCancellable *cancellable = NULL;
-
- g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks), NULL);
-
- PROPERTY_LOCK (gtasks);
-
- if (gtasks->priv->cancellable)
- cancellable = g_object_ref (gtasks->priv->cancellable);
-
- PROPERTY_UNLOCK (gtasks);
-
- return cancellable;
-}
-
-static void
-ecb_gtasks_take_cancellable (ECalBackendGTasks *gtasks,
- GCancellable *cancellable)
-{
- GCancellable *old_cancellable;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks));
-
- PROPERTY_LOCK (gtasks);
-
- old_cancellable = gtasks->priv->cancellable;
- gtasks->priv->cancellable = cancellable;
-
- PROPERTY_UNLOCK (gtasks);
-
- if (old_cancellable) {
- g_cancellable_cancel (old_cancellable);
- g_clear_object (&old_cancellable);
- }
-}
-
-static void
-ecb_gtasks_icomp_x_prop_set (icalcomponent *comp,
- const gchar *key,
- const gchar *value)
-{
- icalproperty *xprop;
-
- /* Find the old one first */
- xprop = icalcomponent_get_first_property (comp, ICAL_X_PROPERTY);
-
- while (xprop) {
- const gchar *str = icalproperty_get_x_name (xprop);
-
- if (!strcmp (str, key)) {
- if (value) {
- icalproperty_set_value_from_string (xprop, value, "NO");
- } else {
- icalcomponent_remove_property (comp, xprop);
- icalproperty_free (xprop);
- }
- break;
- }
-
- xprop = icalcomponent_get_next_property (comp, ICAL_X_PROPERTY);
- }
-
- if (!xprop && value) {
- xprop = icalproperty_new_x (value);
- icalproperty_set_x_name (xprop, key);
- icalcomponent_add_property (comp, xprop);
- }
-}
-
-static gchar *
-ecb_gtasks_icomp_x_prop_get (icalcomponent *comp,
- const gchar *key)
-{
- icalproperty *xprop;
-
- /* Find the old one first */
- xprop = icalcomponent_get_first_property (comp, ICAL_X_PROPERTY);
-
- while (xprop) {
- const gchar *str = icalproperty_get_x_name (xprop);
-
- if (!strcmp (str, key)) {
- break;
- }
-
- xprop = icalcomponent_get_next_property (comp, ICAL_X_PROPERTY);
- }
-
- if (xprop) {
- return icalproperty_get_value_as_string_r (xprop);
- }
-
- return NULL;
-}
-
-/* May hold PROPERTY_LOCK() when calling this */
-static ECalComponent *
-ecb_gtasks_get_cached_comp (ECalBackendGTasks *gtasks,
- const gchar *uid)
-{
- g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks), NULL);
- g_return_val_if_fail (uid != NULL, NULL);
-
- return e_cal_backend_store_get_component (gtasks->priv->store, uid, NULL);
-}
-
-static gboolean
-ecb_gtasks_is_authorized (ECalBackend *backend)
-{
- ECalBackendGTasks *gtasks = E_CAL_BACKEND_GTASKS (backend);
-
- if (!gtasks->priv->service ||
- !gtasks->priv->tasklist)
- return FALSE;
-
- return gdata_service_is_authorized (GDATA_SERVICE (gtasks->priv->service));
-}
-
-static void
-ecb_gtasks_prepare_tasklist (ECalBackendGTasks *gtasks,
- GCancellable *cancellable,
- GError **error)
-{
- ESourceResource *resource;
- ESource *source;
- GDataFeed *feed;
- GDataQuery *query;
- gchar *id;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks));
- g_return_if_fail (gtasks->priv->service != NULL);
- g_return_if_fail (gdata_service_is_authorized (GDATA_SERVICE (gtasks->priv->service)));
-
- source = e_backend_get_source (E_BACKEND (gtasks));
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
- id = e_source_resource_dup_identity (resource);
-
- query = gdata_query_new_with_limits (NULL, 0, 1);
- /* This also verifies that the service can connect to the server with given credentials */
- feed = gdata_tasks_service_query_all_tasklists (gtasks->priv->service, query, cancellable, NULL,
NULL, error);
- if (feed) {
- /* If the tasklist ID is not set, then pick the first from the list, most likely the "Default
List" */
- if (!id || !*id) {
- GList *entries;
+ GError *local_error = NULL;
- entries = gdata_feed_get_entries (feed);
- if (entries) {
- GDataEntry *entry = entries->data;
- if (entry) {
- g_free (id);
- id = g_strdup (gdata_entry_get_id (entry));
- }
- }
- }
- }
- g_clear_object (&feed);
- g_object_unref (query);
+ g_return_if_fail (E_IS_CAL_CACHE (cal_cache));
- if (!id || !*id) {
- /* But the tests for change will not work */
- g_free (id);
- id = g_strdup ("@default");
+ if (!e_cache_set_key_int (E_CACHE (cal_cache), GTASKS_DATA_VERSION_KEY, GTASKS_DATA_VERSION,
&local_error)) {
+ g_warning ("%s: Failed to store data version: %s\n", G_STRFUNC, local_error ?
local_error->message : "Unknown error");
}
-
- g_clear_object (>asks->priv->tasklist);
- gtasks->priv->tasklist = gdata_tasks_tasklist_new (id);
-
- g_free (id);
+#endif
}
static void
@@ -344,7 +160,7 @@ ecb_gtasks_gdata_to_comp (GDataTasksTask *task)
data_link = gdata_entry_look_up_link (entry, GDATA_LINK_SELF);
if (data_link)
- ecb_gtasks_icomp_x_prop_set (icomp, X_EVO_GTASKS_SELF_LINK, gdata_link_get_uri (data_link));
+ e_cal_util_set_x_property (icomp, X_EVO_GTASKS_SELF_LINK, gdata_link_get_uri (data_link));
comp = e_cal_component_new_from_icalcomponent (icomp);
g_warn_if_fail (comp != NULL);
@@ -354,7 +170,8 @@ ecb_gtasks_gdata_to_comp (GDataTasksTask *task)
static GDataTasksTask *
ecb_gtasks_comp_to_gdata (ECalComponent *comp,
- ECalComponent *cached_comp)
+ ECalComponent *cached_comp,
+ gboolean ignore_uid)
{
GDataEntry *entry;
GDataTasksTask *task;
@@ -370,7 +187,7 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
g_return_val_if_fail (icomp != NULL, NULL);
text = icalcomponent_get_uid (icomp);
- task = gdata_tasks_task_new (text && *text ? text : NULL);
+ task = gdata_tasks_task_new ((!ignore_uid && text && *text) ? text : NULL);
entry = GDATA_ENTRY (task);
tt = icalcomponent_get_due (icomp);
@@ -408,7 +225,7 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
else if (icalcomponent_get_status (icomp) == ICAL_STATUS_NEEDSACTION)
gdata_tasks_task_set_status (task, "needsAction");
- tmp = ecb_gtasks_icomp_x_prop_get (icomp, X_EVO_GTASKS_SELF_LINK);
+ tmp = e_cal_util_dup_x_property (icomp, X_EVO_GTASKS_SELF_LINK);
if (!tmp || !*tmp) {
g_free (tmp);
tmp = NULL;
@@ -416,7 +233,7 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
/* If the passed-in component doesn't contain the libgdata self link,
then get it from the cached comp */
if (cached_comp) {
- tmp = ecb_gtasks_icomp_x_prop_get (
+ tmp = e_cal_util_dup_x_property (
e_cal_component_get_icalcomponent (cached_comp),
X_EVO_GTASKS_SELF_LINK);
}
@@ -435,351 +252,146 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
return task;
}
-struct EGTasksUpdateData
-{
- ECalBackendGTasks *gtasks;
- gint64 taskslist_time;
-};
-
-static gpointer
-ecb_gtasks_update_thread (gpointer user_data)
+static gboolean
+ecb_gtasks_is_authorized (ECalBackendGTasks *cbgtasks)
{
- struct EGTasksUpdateData *update_data = user_data;
- ECalBackendGTasks *gtasks;
- GTimeVal last_updated;
- GDataFeed *feed;
- GDataTasksQuery *tasks_query;
- const gchar *key;
- GCancellable *cancellable;
- GError *local_error = NULL;
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cbgtasks), FALSE);
- g_return_val_if_fail (update_data != NULL, NULL);
+ if (!cbgtasks->priv->service ||
+ !cbgtasks->priv->tasklist)
+ return FALSE;
- gtasks = update_data->gtasks;
+ return gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service));
+}
- g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks), NULL);
+static gboolean
+ecb_gtasks_request_authorization (ECalBackendGTasks *cbgtasks,
+ const ENamedParameters *credentials,
+ GCancellable *cancellable,
+ GError **error)
+{
+ /* Make sure we have the GDataService configured
+ * before requesting authorization. */
- if (!ecb_gtasks_is_authorized (E_CAL_BACKEND (gtasks))) {
- g_clear_object (>asks);
- g_free (update_data);
- return NULL;
- }
+ if (!cbgtasks->priv->authorizer) {
+ ESource *source;
+ EGDataOAuth2Authorizer *authorizer;
- PROPERTY_LOCK (gtasks);
+ source = e_backend_get_source (E_BACKEND (cbgtasks));
- if (ecb_gtasks_check_data_version_locked (gtasks)) {
- key = e_cal_backend_store_get_key_value (gtasks->priv->store, GTASKS_KEY_LAST_UPDATED);
- if (!key || !g_time_val_from_iso8601 (key, &last_updated))
- last_updated.tv_sec = 0;
- } else {
- last_updated.tv_sec = 0;
+ /* Only OAuth2 is supported with Google Tasks */
+ authorizer = e_gdata_oauth2_authorizer_new (source);
+ cbgtasks->priv->authorizer = GDATA_AUTHORIZER (authorizer);
}
- PROPERTY_UNLOCK (gtasks);
-
- cancellable = ecb_gtasks_ref_cancellable (gtasks);
-
- tasks_query = gdata_tasks_query_new (NULL);
- gdata_query_set_max_results (GDATA_QUERY (tasks_query), 100);
- gdata_tasks_query_set_show_completed (tasks_query, TRUE);
- gdata_tasks_query_set_show_hidden (tasks_query, TRUE);
-
- if (last_updated.tv_sec > 0) {
- gdata_query_set_updated_min (GDATA_QUERY (tasks_query), last_updated.tv_sec);
- gdata_tasks_query_set_show_deleted (tasks_query, TRUE);
+ if (E_IS_GDATA_OAUTH2_AUTHORIZER (cbgtasks->priv->authorizer)) {
+ e_gdata_oauth2_authorizer_set_credentials (E_GDATA_OAUTH2_AUTHORIZER
(cbgtasks->priv->authorizer), credentials);
}
- feed = gdata_tasks_service_query_tasks (gtasks->priv->service, gtasks->priv->tasklist,
- GDATA_QUERY (tasks_query), cancellable, NULL, NULL, &local_error);
-
- if (!local_error)
- e_backend_ensure_source_status_connected (E_BACKEND (gtasks));
-
-#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
- while (feed && !g_cancellable_is_cancelled (cancellable) && !local_error) {
-#else
- if (feed) {
-#endif
- GList *link;
- const gchar *uid;
-
- PROPERTY_LOCK (gtasks);
-
- e_cal_backend_store_freeze_changes (gtasks->priv->store);
-
- for (link = gdata_feed_get_entries (feed); link; link = g_list_next (link)) {
- GDataTasksTask *task = link->data;
- ECalComponent *cached_comp;
-
- if (!GDATA_IS_TASKS_TASK (task))
- continue;
-
- uid = gdata_entry_get_id (GDATA_ENTRY (task));
- if (!uid || !*uid)
- continue;
-
- cached_comp = ecb_gtasks_get_cached_comp (gtasks, uid);
-
- if (gdata_tasks_task_is_deleted (task)) {
- ECalComponentId id;
-
- id.uid = (gchar *) uid;
- id.rid = NULL;
-
- e_cal_backend_notify_component_removed ((ECalBackend *) gtasks, &id,
cached_comp, NULL);
- if (cached_comp)
- e_cal_backend_store_remove_component (gtasks->priv->store, uid, NULL);
- } else {
- ECalComponent *new_comp;
-
- new_comp = ecb_gtasks_gdata_to_comp (task);
- if (new_comp) {
- if (cached_comp) {
- struct icaltimetype *cached_tt = NULL, *new_tt = NULL;
-
- e_cal_component_get_last_modified (cached_comp, &cached_tt);
- e_cal_component_get_last_modified (new_comp, &new_tt);
-
- if (!cached_tt || !new_tt ||
- icaltime_compare (*cached_tt, *new_tt) != 0) {
- /* Google doesn't store/provide 'created', thus use
'created,
- as first seen by the backend' */
- if (cached_tt)
- e_cal_component_set_created (new_comp,
cached_tt);
-
- e_cal_backend_store_put_component
(gtasks->priv->store, new_comp);
- e_cal_backend_notify_component_modified ((ECalBackend
*) gtasks, cached_comp, new_comp);
- }
-
- if (cached_tt)
- e_cal_component_free_icaltimetype (cached_tt);
- if (new_tt)
- e_cal_component_free_icaltimetype (new_tt);
- } else {
- e_cal_backend_store_put_component (gtasks->priv->store,
new_comp);
- e_cal_backend_notify_component_created ((ECalBackend *)
gtasks, new_comp);
- }
- }
-
- g_clear_object (&new_comp);
- }
-
- g_clear_object (&cached_comp);
- }
-
- e_cal_backend_store_thaw_changes (gtasks->priv->store);
-
- PROPERTY_UNLOCK (gtasks);
-
-#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
- if (!gdata_feed_get_entries (feed))
- break;
-
- gdata_query_next_page (GDATA_QUERY (tasks_query));
-
- g_clear_object (&feed);
-
- feed = gdata_tasks_service_query_tasks (gtasks->priv->service, gtasks->priv->tasklist,
- GDATA_QUERY (tasks_query), cancellable, NULL, NULL, &local_error);
-#endif
- }
-
- g_clear_object (&tasks_query);
- g_clear_object (&feed);
-
- if (!g_cancellable_is_cancelled (cancellable) && !local_error) {
- gchar *strtm;
-
- PROPERTY_LOCK (gtasks);
-
- last_updated.tv_sec = update_data->taskslist_time;
- last_updated.tv_usec = 0;
-
- strtm = g_time_val_to_iso8601 (&last_updated);
- e_cal_backend_store_put_key_value (gtasks->priv->store, GTASKS_KEY_LAST_UPDATED, strtm);
- g_free (strtm);
+ if (!cbgtasks->priv->service) {
+ GDataTasksService *tasks_service;
- ecb_gtasks_store_data_version_locked (gtasks);
+ tasks_service = gdata_tasks_service_new (cbgtasks->priv->authorizer);
+ cbgtasks->priv->service = tasks_service;
- PROPERTY_UNLOCK (gtasks);
+ e_binding_bind_property (
+ cbgtasks, "proxy-resolver",
+ cbgtasks->priv->service, "proxy-resolver",
+ G_BINDING_SYNC_CREATE);
}
- g_clear_object (&cancellable);
- g_clear_object (>asks);
- g_clear_error (&local_error);
- g_free (update_data);
+ /* If we're using OAuth tokens, then as far as the backend
+ * is concerned it's always authorized. The GDataAuthorizer
+ * will take care of everything in the background. */
+ if (!GDATA_IS_CLIENT_LOGIN_AUTHORIZER (cbgtasks->priv->authorizer))
+ return TRUE;
- return NULL;
+ /* Otherwise it's up to us to obtain a login secret, but
+ there is currently no way to do it, thus simply fail. */
+ return FALSE;
}
-static void
-ecb_gtasks_start_update (ECalBackendGTasks *gtasks)
+static gboolean
+ecb_gtasks_prepare_tasklist (ECalBackendGTasks *cbgtasks,
+ GCancellable *cancellable,
+ GError **error)
{
+ ESourceResource *resource;
+ ESource *source;
GDataFeed *feed;
- GCancellable *cancellable;
+ GDataQuery *query;
+ gchar *id;
GError *local_error = NULL;
- gchar *id = NULL;
- gint64 taskslist_time = 0;
- gboolean changed = TRUE;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks));
-
- if (!ecb_gtasks_is_authorized ((ECalBackend *) gtasks))
- return;
- cancellable = ecb_gtasks_ref_cancellable (gtasks);
- g_return_if_fail (cancellable != NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cbgtasks), FALSE);
+ g_return_val_if_fail (cbgtasks->priv->service != NULL, FALSE);
+ g_return_val_if_fail (gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service)), FALSE);
- g_object_get (gtasks->priv->tasklist, "id", &id, NULL);
- g_return_if_fail (id != NULL);
-
- /* Check whether the tasklist changed */
- feed = gdata_tasks_service_query_all_tasklists (gtasks->priv->service, NULL, cancellable, NULL, NULL,
&local_error);
+ source = e_backend_get_source (E_BACKEND (cbgtasks));
+ resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
+ id = e_source_resource_dup_identity (resource);
- if (!local_error)
- e_backend_ensure_source_status_connected (E_BACKEND (gtasks));
+ query = gdata_query_new_with_limits (NULL, 0, 1);
+ /* This also verifies that the service can connect to the server with given credentials */
+ feed = gdata_tasks_service_query_all_tasklists (cbgtasks->priv->service, query, cancellable, NULL,
NULL, &local_error);
if (feed) {
- GList *link;
-
- for (link = gdata_feed_get_entries (feed); link; link = g_list_next (link)) {
- GDataEntry *entry = link->data;
-
- if (entry && g_strcmp0 (id, gdata_entry_get_id (entry)) == 0) {
- taskslist_time = gdata_entry_get_updated (entry);
-
- if (taskslist_time > 0) {
- PROPERTY_LOCK (gtasks);
-
- if (ecb_gtasks_check_data_version_locked (gtasks)) {
- GTimeVal stored;
- const gchar *key;
-
- key = e_cal_backend_store_get_key_value (gtasks->priv->store,
GTASKS_KEY_LAST_UPDATED);
- if (key && g_time_val_from_iso8601 (key, &stored))
- changed = taskslist_time != stored.tv_sec;
- }
+ /* If the tasklist ID is not set, then pick the first from the list, most likely the "Default
List" */
+ if (!id || !*id) {
+ GList *entries;
- PROPERTY_UNLOCK (gtasks);
+ entries = gdata_feed_get_entries (feed);
+ if (entries) {
+ GDataEntry *entry = entries->data;
+ if (entry) {
+ g_free (id);
+ id = g_strdup (gdata_entry_get_id (entry));
}
-
- break;
}
}
-
- g_clear_object (&feed);
}
+ g_clear_object (&feed);
+ g_object_unref (query);
- if (changed && !g_cancellable_is_cancelled (cancellable)) {
- GThread *thread;
- struct EGTasksUpdateData *data;
-
- data = g_new0 (struct EGTasksUpdateData, 1);
- data->gtasks = g_object_ref (gtasks);
- data->taskslist_time = taskslist_time;
-
- thread = g_thread_new (NULL, ecb_gtasks_update_thread, data);
- g_thread_unref (thread);
+ if (!id || !*id) {
+ /* But the tests for change will not work */
+ g_free (id);
+ id = g_strdup (GTASKS_DEFAULT_TASKLIST_NAME);
}
- if (local_error) {
- g_debug ("%s: Failed to get all tasklists: %s", G_STRFUNC, local_error->message);
- g_clear_error (&local_error);
- }
+ g_clear_object (&cbgtasks->priv->tasklist);
+ cbgtasks->priv->tasklist = gdata_tasks_tasklist_new (id);
- g_clear_object (&cancellable);
g_free (id);
-}
-
-static void
-ecb_gtasks_time_to_refresh_data_cb (ESource *source,
- gpointer user_data)
-{
- ECalBackendGTasks *gtasks = user_data;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks));
-
- if (!ecb_gtasks_is_authorized (E_CAL_BACKEND (gtasks)) ||
- !e_backend_get_online (E_BACKEND (gtasks))) {
- return;
- }
-
- ecb_gtasks_start_update (gtasks);
-}
-static gboolean
-ecb_gtasks_request_authorization (ECalBackend *backend,
- const ENamedParameters *credentials,
- GCancellable *cancellable,
- GError **error)
-{
- ECalBackendGTasks *gtasks = E_CAL_BACKEND_GTASKS (backend);
-
- /* Make sure we have the GDataService configured
- * before requesting authorization. */
-
- if (!gtasks->priv->authorizer) {
- ESource *source;
- EGDataOAuth2Authorizer *authorizer;
-
- source = e_backend_get_source (E_BACKEND (backend));
-
- /* Only OAuth2 is supported with Google Tasks */
- authorizer = e_gdata_oauth2_authorizer_new (source);
- gtasks->priv->authorizer = GDATA_AUTHORIZER (authorizer);
- }
-
- if (E_IS_GDATA_OAUTH2_AUTHORIZER (gtasks->priv->authorizer)) {
- e_gdata_oauth2_authorizer_set_credentials (E_GDATA_OAUTH2_AUTHORIZER
(gtasks->priv->authorizer), credentials);
- }
-
- if (!gtasks->priv->service) {
- GDataTasksService *tasks_service;
-
- tasks_service = gdata_tasks_service_new (gtasks->priv->authorizer);
- gtasks->priv->service = tasks_service;
-
- e_binding_bind_property (
- backend, "proxy-resolver",
- gtasks->priv->service, "proxy-resolver",
- G_BINDING_SYNC_CREATE);
+ if (local_error) {
+ g_propagate_error (error, local_error);
+ return FALSE;
}
- /* If we're using OAuth tokens, then as far as the backend
- * is concerned it's always authorized. The GDataAuthorizer
- * will take care of everything in the background. */
- if (!GDATA_IS_CLIENT_LOGIN_AUTHORIZER (gtasks->priv->authorizer))
- return TRUE;
-
- /* Otherwise it's up to us to obtain a login secret, but
- there is currently no way to do it, thus simply fail. */
- return FALSE;
+ return TRUE;
}
static gchar *
-ecb_gtasks_get_backend_property (ECalBackend *backend,
+ecb_gtasks_get_backend_property (ECalBackend *cal_backend,
const gchar *prop_name)
{
- g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (backend), NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cal_backend), NULL);
g_return_val_if_fail (prop_name != NULL, NULL);
if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
- GString *caps;
-
- caps = g_string_new (
- CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
- CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
- CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
-
- return g_string_free (caps, FALSE);
-
+ return g_strjoin (",",
+ CAL_STATIC_CAPABILITY_NO_THISANDFUTURE,
+ CAL_STATIC_CAPABILITY_NO_THISANDPRIOR,
+ e_cal_meta_backend_get_capabilities (E_CAL_META_BACKEND (cal_backend)),
+ NULL);
} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
ESourceAuthentication *authentication;
ESource *source;
const gchar *user;
- source = e_backend_get_source (E_BACKEND (backend));
+ source = e_backend_get_source (E_BACKEND (cal_backend));
authentication = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
user = e_source_authentication_get_user (authentication);
@@ -787,821 +399,626 @@ ecb_gtasks_get_backend_property (ECalBackend *backend,
return NULL;
return g_strdup (user);
-
- } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
- ECalComponent *comp;
- gchar *prop_value;
-
- comp = e_cal_component_new ();
- e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
-
- prop_value = e_cal_component_get_as_string (comp);
-
- g_object_unref (comp);
-
- return prop_value;
}
/* Chain up to parent's method. */
- return E_CAL_BACKEND_CLASS (e_cal_backend_gtasks_parent_class)->get_backend_property (backend,
prop_name);
+ return E_CAL_BACKEND_CLASS (e_cal_backend_gtasks_parent_class)->get_backend_property (cal_backend,
prop_name);
}
-static void
-ecb_gtasks_update_connection_sync (ECalBackendGTasks *gtasks,
- const ENamedParameters *credentials,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+ecb_gtasks_connect_sync (ECalMetaBackend *meta_backend,
+ const ENamedParameters *credentials,
+ ESourceAuthenticationResult *out_auth_result,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackend *backend;
+ ECalBackendGTasks *cbgtasks;
gboolean success;
GError *local_error = NULL;
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (gtasks));
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
+ g_return_val_if_fail (out_auth_result != NULL, FALSE);
+
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
+
+ *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
- backend = E_CAL_BACKEND (gtasks);
+ if (ecb_gtasks_is_authorized (cbgtasks))
+ return TRUE;
- success = ecb_gtasks_request_authorization (backend, credentials, cancellable, &local_error);
+ success = ecb_gtasks_request_authorization (cbgtasks, credentials, cancellable, &local_error);
+ if (success)
+ success = gdata_authorizer_refresh_authorization (cbgtasks->priv->authorizer, cancellable,
&local_error);
if (success)
- success = gdata_authorizer_refresh_authorization (gtasks->priv->authorizer, cancellable,
&local_error);
+ success = ecb_gtasks_prepare_tasklist (cbgtasks, cancellable, &local_error);
if (success) {
- e_cal_backend_set_writable (backend, TRUE);
-
- ecb_gtasks_prepare_tasklist (gtasks, cancellable, &local_error);
- if (!local_error)
- ecb_gtasks_start_update (gtasks);
+ e_cal_backend_set_writable (E_CAL_BACKEND (cbgtasks), TRUE);
} else {
- e_cal_backend_set_writable (backend, FALSE);
+ e_cal_backend_set_writable (E_CAL_BACKEND (cbgtasks), FALSE);
+
+ if (g_error_matches (local_error, GDATA_SERVICE_ERROR,
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
+ if (!e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD))
+ *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
+ else
+ *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
+ g_clear_error (&local_error);
+ } else {
+ *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
+ g_propagate_error (error, local_error);
+ }
}
- if (local_error)
- g_propagate_error (error, local_error);
+ return success;
}
-static ESourceAuthenticationResult
-ecb_gtasks_authenticate_sync (EBackend *backend,
- const ENamedParameters *credentials,
- gchar **out_certificate_pem,
- GTlsCertificateFlags *out_certificate_errors,
- GCancellable *cancellable,
- GError **error)
+static gboolean
+ecb_gtasks_disconnect_sync (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackendGTasks *gtasks;
- ESourceAuthenticationResult result;
- GError *local_error = NULL;
-
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ ECalBackendGTasks *cbgtasks;
- ecb_gtasks_update_connection_sync (gtasks, credentials, cancellable, &local_error);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
- if (local_error == NULL) {
- result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- } else if (g_error_matches (local_error, GDATA_SERVICE_ERROR,
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
- if (!e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD))
- result = E_SOURCE_AUTHENTICATION_REQUIRED;
- else
- result = E_SOURCE_AUTHENTICATION_REJECTED;
- g_clear_error (&local_error);
- } else {
- result = E_SOURCE_AUTHENTICATION_ERROR;
- g_propagate_error (error, local_error);
- }
+ g_clear_object (&cbgtasks->priv->service);
+ g_clear_object (&cbgtasks->priv->authorizer);
+ g_clear_object (&cbgtasks->priv->tasklist);
- return result;
+ return TRUE;
}
-static void
-ecb_gtasks_open (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- gboolean only_if_exists)
+static gboolean
+ecb_gtasks_check_tasklist_changed_sync (ECalBackendGTasks *cbgtasks,
+ const gchar *last_sync_tag,
+ gboolean *out_changed,
+ gint64 *out_taskslist_time,
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackendGTasks *gtasks;
+ GDataFeed *feed;
+ gchar *id = NULL;
+ gint64 taskslist_time = 0;
GError *local_error = NULL;
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cbgtasks), FALSE);
+ g_return_val_if_fail (out_changed != NULL, FALSE);
+ g_return_val_if_fail (out_taskslist_time != NULL, FALSE);
- if (ecb_gtasks_is_authorized (backend)) {
- e_data_cal_respond_open (cal, opid, NULL);
- return;
- }
+ *out_changed = TRUE;
+ *out_taskslist_time = 0;
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ g_object_get (cbgtasks->priv->tasklist, "id", &id, NULL);
+ g_return_val_if_fail (id != NULL, FALSE);
- e_cal_backend_set_writable (backend, FALSE);
+ /* Check whether the tasklist changed */
+ feed = gdata_tasks_service_query_all_tasklists (cbgtasks->priv->service, NULL, cancellable, NULL,
NULL, &local_error);
- ecb_gtasks_take_cancellable (gtasks, g_cancellable_new ());
+ if (local_error) {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
- if (e_backend_get_online (E_BACKEND (backend))) {
- ESource *source;
- gchar *auth_method = NULL;
+ if (feed) {
+ GList *link;
- source = e_backend_get_source (E_BACKEND (backend));
+ for (link = gdata_feed_get_entries (feed); link; link = g_list_next (link)) {
+ GDataEntry *entry = link->data;
- if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
- ESourceAuthentication *auth_extension;
+ if (entry && g_strcmp0 (id, gdata_entry_get_id (entry)) == 0) {
+ ECalCache *cal_cache;
- auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
- auth_method = e_source_authentication_dup_method (auth_extension);
- }
+ cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbgtasks));
+ taskslist_time = gdata_entry_get_updated (entry);
- if (g_strcmp0 (auth_method, "Google") == 0) {
- e_backend_credentials_required_sync (
- E_BACKEND (backend), E_SOURCE_CREDENTIALS_REASON_REQUIRED,
- NULL, 0, NULL, cancellable, &local_error);
- } else {
- ecb_gtasks_update_connection_sync (gtasks, NULL, cancellable, &local_error);
- }
+ if (taskslist_time > 0 && last_sync_tag && ecb_gtasks_check_data_version
(cal_cache)) {
+ GTimeVal stored;
- g_free (auth_method);
- }
+ if (g_time_val_from_iso8601 (last_sync_tag, &stored))
+ *out_changed = taskslist_time != stored.tv_sec;
+ }
- e_data_cal_respond_open (cal, opid, local_error);
-}
+ g_clear_object (&cal_cache);
-static void
-ecb_gtasks_refresh (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ break;
+ }
+ }
- if (!ecb_gtasks_is_authorized (backend) ||
- !e_backend_get_online (E_BACKEND (backend))) {
- e_data_cal_respond_refresh (cal, opid, EDC_ERROR (RepositoryOffline));
- return;
+ g_clear_object (&feed);
}
- ecb_gtasks_start_update (E_CAL_BACKEND_GTASKS (backend));
+ g_free (id);
- e_data_cal_respond_refresh (cal, opid, NULL);
+ *out_taskslist_time = taskslist_time;
+
+ return TRUE;
}
-static void
-ecb_gtasks_get_object (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *uid,
- const gchar *rid)
+static gboolean
+ecb_gtasks_get_changes_sync (ECalMetaBackend *meta_backend,
+ const gchar *last_sync_tag,
+ gchar **out_new_sync_tag,
+ gboolean *out_repeat,
+ GSList **out_created_objects, /* ECalMetaBackendInfo * */
+ GSList **out_modified_objects, /* ECalMetaBackendInfo * */
+ GSList **out_removed_objects, /* ECalMetaBackendInfo * */
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackendGTasks *gtasks;
- ECalComponent *cached_comp;
- gchar *comp_str = NULL;
+ ECalBackendGTasks *cbgtasks;
+ ECalCache *cal_cache;
+ gint64 taskslist_time = 0;
+ GTimeVal last_updated;
+ GDataFeed *feed;
+ GDataTasksQuery *tasks_query;
+ gboolean changed = TRUE;
GError *local_error = NULL;
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
-
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
+ g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+ g_return_val_if_fail (out_created_objects != NULL, FALSE);
+ g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+ g_return_val_if_fail (out_removed_objects != NULL, FALSE);
- PROPERTY_LOCK (gtasks);
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- cached_comp = ecb_gtasks_get_cached_comp (gtasks, uid);
- if (cached_comp)
- comp_str = e_cal_component_get_as_string (cached_comp);
- else
- local_error = EDC_ERROR (ObjectNotFound);
+ *out_created_objects = NULL;
+ *out_modified_objects = NULL;
+ *out_removed_objects = NULL;
- PROPERTY_UNLOCK (gtasks);
+ if (!ecb_gtasks_check_tasklist_changed_sync (cbgtasks, last_sync_tag, &changed, &taskslist_time,
cancellable, error))
+ return FALSE;
- e_data_cal_respond_get_object (cal, opid, local_error, comp_str);
+ if (!changed)
+ return TRUE;
- g_clear_object (&cached_comp);
- g_free (comp_str);
-}
+ cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
-static void
-ecb_gtasks_get_object_list (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *sexp_str)
-{
- ECalBackendGTasks *gtasks;
- ECalBackendSExp *sexp;
- ETimezoneCache *cache;
- gboolean do_search;
- GSList *list, *iter, *calobjs = NULL;
- time_t occur_start = -1, occur_end = -1;
- gboolean prunning_by_time;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
-
- gtasks = E_CAL_BACKEND_GTASKS (backend);
-
- sexp = e_cal_backend_sexp_new (sexp_str);
- if (sexp == NULL) {
- e_data_cal_respond_get_object_list (cal, opid, EDC_ERROR (InvalidQuery), NULL);
- return;
+ if (!ecb_gtasks_check_data_version (cal_cache) ||
+ !last_sync_tag ||
+ !g_time_val_from_iso8601 (last_sync_tag, &last_updated)) {
+ last_updated.tv_sec = 0;
}
- do_search = !g_str_equal (sexp_str, "#t");
- prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp, &occur_start, &occur_end);
-
- cache = E_TIMEZONE_CACHE (backend);
-
- PROPERTY_LOCK (gtasks);
-
- list = prunning_by_time ?
- e_cal_backend_store_get_components_occuring_in_range (gtasks->priv->store, occur_start,
occur_end)
- : e_cal_backend_store_get_components (gtasks->priv->store);
-
- PROPERTY_UNLOCK (gtasks);
-
- for (iter = list; iter; iter = g_slist_next (iter)) {
- ECalComponent *comp = E_CAL_COMPONENT (iter->data);
-
- if (!do_search || e_cal_backend_sexp_match_comp (sexp, comp, cache)) {
- calobjs = g_slist_prepend (calobjs, e_cal_component_get_as_string (comp));
- }
+ tasks_query = gdata_tasks_query_new (NULL);
+ gdata_query_set_max_results (GDATA_QUERY (tasks_query), 100);
+ gdata_tasks_query_set_show_completed (tasks_query, TRUE);
+ gdata_tasks_query_set_show_hidden (tasks_query, TRUE);
- g_object_unref (comp);
+ if (last_updated.tv_sec > 0) {
+ gdata_query_set_updated_min (GDATA_QUERY (tasks_query), last_updated.tv_sec);
+ gdata_tasks_query_set_show_deleted (tasks_query, TRUE);
}
- g_object_unref (sexp);
- g_slist_free (list);
-
- e_data_cal_respond_get_object_list (cal, opid, NULL, calobjs);
+ feed = gdata_tasks_service_query_tasks (cbgtasks->priv->service, cbgtasks->priv->tasklist,
+ GDATA_QUERY (tasks_query), cancellable, NULL, NULL, &local_error);
- g_slist_foreach (calobjs, (GFunc) g_free, NULL);
- g_slist_free (calobjs);
-}
+#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
+ while (feed && !g_cancellable_is_cancelled (cancellable) && !local_error) {
+#else
+ if (feed) {
+#endif
+ GList *link;
-static void
-ecb_gtasks_get_free_busy (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *users,
- time_t start,
- time_t end)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ for (link = gdata_feed_get_entries (feed); link && !g_cancellable_is_cancelled (cancellable);
link = g_list_next (link)) {
+ GDataTasksTask *task = link->data;
+ ECalComponent *cached_comp = NULL;
+ gchar *uid;
- e_data_cal_respond_get_free_busy (cal, opid, EDC_ERROR (NotSupported), NULL);
-}
+ if (!GDATA_IS_TASKS_TASK (task))
+ continue;
-static void
-ecb_gtasks_create_objects (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *calobjs)
-{
- ECalBackendGTasks *gtasks;
- GSList *new_uids = NULL, *new_calcomps = NULL;
- const GSList *link;
- GError *local_error = NULL;
+ uid = g_strdup (gdata_entry_get_id (GDATA_ENTRY (task)));
+ if (!uid || !*uid) {
+ g_free (uid);
+ continue;
+ }
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ if (!e_cal_cache_get_component (cal_cache, uid, NULL, &cached_comp, cancellable,
NULL))
+ cached_comp = NULL;
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ if (gdata_tasks_task_is_deleted (task)) {
+ *out_removed_objects = g_slist_prepend (*out_removed_objects,
+ e_cal_meta_backend_info_new (uid, NULL, NULL, NULL));
+ } else {
+ ECalComponent *new_comp;
- if (!ecb_gtasks_is_authorized (backend) ||
- !e_backend_get_online (E_BACKEND (backend))) {
- e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (RepositoryOffline), NULL, NULL);
- return;
- }
+ new_comp = ecb_gtasks_gdata_to_comp (task);
+ if (new_comp) {
+ gchar *revision, *object;
- for (link = calobjs; link && !local_error; link = link->next) {
- const gchar *icalstr = link->data;
- ECalComponent *comp;
- icalcomponent *icomp;
- const gchar *uid;
- GDataTasksTask *new_task, *comp_task;
+ revision = e_cal_cache_dup_component_revision (cal_cache,
e_cal_component_get_icalcomponent (new_comp));
+ object = e_cal_component_get_as_string (new_comp);
- if (!icalstr) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ if (cached_comp) {
+ struct icaltimetype *cached_tt = NULL, *new_tt = NULL;
- comp = e_cal_component_new_from_string (icalstr);
- if (comp == NULL) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ e_cal_component_get_last_modified (cached_comp, &cached_tt);
+ e_cal_component_get_last_modified (new_comp, &new_tt);
- icomp = e_cal_component_get_icalcomponent (comp);
- if (!icomp) {
- g_object_unref (comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ if (!cached_tt || !new_tt ||
+ icaltime_compare (*cached_tt, *new_tt) != 0) {
+ /* Google doesn't store/provide 'created', thus use
'created,
+ as first seen by the backend' */
+ if (cached_tt)
+ e_cal_component_set_created (new_comp,
cached_tt);
- uid = icalcomponent_get_uid (icomp);
- if (uid) {
- PROPERTY_LOCK (gtasks);
+ *out_modified_objects = g_slist_prepend
(*out_modified_objects,
+ e_cal_meta_backend_info_new (uid, NULL,
revision, object));
+ }
- if (e_cal_backend_store_has_component (gtasks->priv->store, uid, NULL)) {
- PROPERTY_UNLOCK (gtasks);
- g_object_unref (comp);
- local_error = EDC_ERROR (ObjectIdAlreadyExists);
- break;
- }
+ if (cached_tt)
+ e_cal_component_free_icaltimetype (cached_tt);
+ if (new_tt)
+ e_cal_component_free_icaltimetype (new_tt);
+ } else {
+ *out_created_objects = g_slist_prepend (*out_created_objects,
+ e_cal_meta_backend_info_new (uid, NULL, revision,
object));
+ }
- PROPERTY_UNLOCK (gtasks);
+ g_free (revision);
+ g_free (object);
+ }
- icalcomponent_set_uid (icomp, "");
- }
+ g_clear_object (&new_comp);
+ }
- comp_task = ecb_gtasks_comp_to_gdata (comp, NULL);
- if (!comp_task) {
- g_object_unref (comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
+ g_clear_object (&cached_comp);
+ g_free (uid);
}
- new_task = gdata_tasks_service_insert_task (gtasks->priv->service, comp_task,
gtasks->priv->tasklist, cancellable, &local_error);
-
- g_object_unref (comp_task);
- g_object_unref (comp);
-
- if (!new_task)
+#ifdef HAVE_LIBGDATA_TASKS_PAGINATION_FUNCTIONS
+ if (!gdata_feed_get_entries (feed))
break;
- comp = ecb_gtasks_gdata_to_comp (new_task);
- g_object_unref (new_task);
+ gdata_query_next_page (GDATA_QUERY (tasks_query));
- if (!comp) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ g_clear_object (&feed);
- icomp = e_cal_component_get_icalcomponent (comp);
- uid = icalcomponent_get_uid (icomp);
+ feed = gdata_tasks_service_query_tasks (cbgtasks->priv->service, cbgtasks->priv->tasklist,
+ GDATA_QUERY (tasks_query), cancellable, NULL, NULL, &local_error);
+#endif
+ }
- if (!uid) {
- g_object_unref (comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ g_clear_object (&tasks_query);
+ g_clear_object (&feed);
- PROPERTY_LOCK (gtasks);
- e_cal_backend_store_put_component (gtasks->priv->store, comp);
- PROPERTY_UNLOCK (gtasks);
+ if (!g_cancellable_is_cancelled (cancellable) && !local_error) {
+ last_updated.tv_sec = taskslist_time;
+ last_updated.tv_usec = 0;
- e_cal_backend_notify_component_created (backend, comp);
+ *out_new_sync_tag = g_time_val_to_iso8601 (&last_updated);
- new_uids = g_slist_prepend (new_uids, g_strdup (uid));
- new_calcomps = g_slist_prepend (new_calcomps, comp);
+ ecb_gtasks_store_data_version (cal_cache);
}
- new_uids = g_slist_reverse (new_uids);
- new_calcomps = g_slist_reverse (new_calcomps);
+ g_clear_object (&cal_cache);
- e_data_cal_respond_create_objects (cal, opid, local_error, new_uids, new_calcomps);
+ if (local_error) {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
- g_slist_free_full (new_uids, g_free);
- e_util_free_nullable_object_slist (new_calcomps);
+ return TRUE;
}
-static void
-ecb_gtasks_modify_objects (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *calobjs,
- ECalObjModType mod)
+static gboolean
+ecb_gtasks_load_component_sync (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ icalcomponent **out_instances,
+ gchar **out_extra,
+ GCancellable *cancellable,
+ GError **error)
{
- ECalBackendGTasks *gtasks;
- GSList *old_calcomps = NULL, *new_calcomps = NULL;
- const GSList *link;
- GError *local_error = NULL;
+ ECalBackendGTasks *cbgtasks;
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (out_instances != NULL, FALSE);
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- if (!ecb_gtasks_is_authorized (backend) ||
- !e_backend_get_online (E_BACKEND (backend))) {
- e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (RepositoryOffline), NULL, NULL);
- return;
- }
+ /* Only "load" preloaded during save, otherwise fail with an error,
+ because the backend provides objects within get_changes_sync() */
- for (link = calobjs; link && !local_error; link = link->next) {
- const gchar *icalstr = link->data;
- ECalComponent *comp, *cached_comp;
- icalcomponent *icomp;
- const gchar *uid;
- GDataTasksTask *new_task, *comp_task;
+ if (cbgtasks->priv->preloaded) {
+ ECalComponent *comp;
- if (!icalstr) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ comp = g_hash_table_lookup (cbgtasks->priv->preloaded, uid);
+ if (comp) {
+ icalcomponent *icalcomp;
- comp = e_cal_component_new_from_string (icalstr);
- if (comp == NULL) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ icalcomp = e_cal_component_get_icalcomponent (comp);
+ if (icalcomp)
+ *out_instances = icalcomponent_new_clone (icalcomp);
- icomp = e_cal_component_get_icalcomponent (comp);
- if (!icomp) {
- g_object_unref (comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ g_hash_table_remove (cbgtasks->priv->preloaded, uid);
- uid = icalcomponent_get_uid (icomp);
- if (!uid) {
- g_object_unref (comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
+ if (icalcomp)
+ return TRUE;
}
+ }
- PROPERTY_LOCK (gtasks);
+ g_propagate_error (error, EDC_ERROR (ObjectNotFound));
- cached_comp = ecb_gtasks_get_cached_comp (gtasks, uid);
+ return FALSE;
+}
- PROPERTY_UNLOCK (gtasks);
+static gboolean
+ecb_gtasks_save_component_sync (ECalMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ const GSList *instances, /* ECalComponent * */
+ const gchar *extra,
+ gchar **out_new_uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendGTasks *cbgtasks;
+ ECalCache *cal_cache;
+ GDataTasksTask *new_task, *comp_task;
+ ECalComponent *comp, *cached_comp = NULL;
+ icalcomponent *icalcomp;
+ const gchar *uid;
- if (!cached_comp) {
- g_object_unref (comp);
- local_error = EDC_ERROR (ObjectNotFound);
- break;
- }
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
+ g_return_val_if_fail (out_new_uid != NULL, FALSE);
- comp_task = ecb_gtasks_comp_to_gdata (comp, cached_comp);
- g_object_unref (comp);
+ cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+ g_return_val_if_fail (cal_cache != NULL, FALSE);
- if (!comp_task) {
- g_object_unref (cached_comp);
- local_error = EDC_ERROR (ObjectNotFound);
- break;
- }
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- new_task = gdata_tasks_service_update_task (gtasks->priv->service, comp_task, cancellable,
&local_error);
- g_object_unref (comp_task);
+ if (g_slist_length ((GSList *) instances) != 1) {
+ g_propagate_error (error, EDC_ERROR (InvalidArg));
+ g_clear_object (&cal_cache);
+ return FALSE;
+ }
- if (!local_error)
- e_backend_ensure_source_status_connected (E_BACKEND (backend));
+ comp = instances->data;
- if (!new_task) {
- g_object_unref (cached_comp);
- break;
- }
+ if (!comp) {
+ g_propagate_error (error, EDC_ERROR (InvalidObject));
+ g_clear_object (&cal_cache);
+ return FALSE;
+ }
- comp = ecb_gtasks_gdata_to_comp (new_task);
- g_object_unref (new_task);
+ if (!overwrite_existing || !e_cal_cache_get_component (cal_cache,
+ icalcomponent_get_uid (e_cal_component_get_icalcomponent (comp)),
+ NULL, &cached_comp, cancellable, NULL)) {
+ cached_comp = NULL;
+ }
- PROPERTY_LOCK (gtasks);
- e_cal_backend_store_put_component (gtasks->priv->store, comp);
- PROPERTY_UNLOCK (gtasks);
+ comp_task = ecb_gtasks_comp_to_gdata (comp, cached_comp, !overwrite_existing);
- e_cal_backend_notify_component_modified (backend, cached_comp, comp);
+ g_clear_object (&cached_comp);
+ g_clear_object (&cal_cache);
- old_calcomps = g_slist_prepend (old_calcomps, cached_comp);
- new_calcomps = g_slist_prepend (new_calcomps, comp);
+ if (!comp_task) {
+ g_propagate_error (error, EDC_ERROR (InvalidObject));
+ return FALSE;
}
- old_calcomps = g_slist_reverse (old_calcomps);
- new_calcomps = g_slist_reverse (new_calcomps);
+ if (overwrite_existing)
+ new_task = gdata_tasks_service_update_task (cbgtasks->priv->service, comp_task, cancellable,
error);
+ else
+ new_task = gdata_tasks_service_insert_task (cbgtasks->priv->service, comp_task,
cbgtasks->priv->tasklist, cancellable, error);
- e_data_cal_respond_modify_objects (cal, opid, local_error, old_calcomps, new_calcomps);
+ g_object_unref (comp_task);
- e_util_free_nullable_object_slist (old_calcomps);
- e_util_free_nullable_object_slist (new_calcomps);
-}
+ if (!new_task)
+ return FALSE;
-static void
-ecb_gtasks_remove_objects (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *ids,
- ECalObjModType mod)
-{
- ECalBackendGTasks *gtasks;
- GSList *old_calcomps = NULL, *removed_ids = NULL;
- const GSList *link;
- GError *local_error = NULL;
+ comp = ecb_gtasks_gdata_to_comp (new_task);
+ g_object_unref (new_task);
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ if (!comp) {
+ g_propagate_error (error, EDC_ERROR (InvalidObject));
+ return FALSE;
+ }
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ icalcomp = e_cal_component_get_icalcomponent (comp);
+ uid = icalcomp ? icalcomponent_get_uid (icalcomp) : NULL;
- if (!ecb_gtasks_is_authorized (backend) ||
- !e_backend_get_online (E_BACKEND (backend))) {
- e_data_cal_respond_remove_objects (cal, opid, EDC_ERROR (RepositoryOffline), NULL, NULL,
NULL);
- return;
+ if (!icalcomp || !uid) {
+ g_object_unref (comp);
+ g_propagate_error (error, EDC_ERROR (InvalidObject));
+ return FALSE;
}
- for (link = ids; link; link = link->next) {
- const ECalComponentId *id = link->data;
- ECalComponentId *tmp_id;
- ECalComponent *cached_comp;
- GDataTasksTask *task;
+ if (cbgtasks->priv->preloaded) {
+ *out_new_uid = g_strdup (uid);
+ g_hash_table_insert (cbgtasks->priv->preloaded, g_strdup (uid), comp);
+ } else {
+ g_object_unref (comp);
+ }
- if (!id || !id->uid) {
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ return TRUE;
+}
- PROPERTY_LOCK (gtasks);
- cached_comp = ecb_gtasks_get_cached_comp (gtasks, id->uid);
- PROPERTY_UNLOCK (gtasks);
+static gboolean
+ecb_gtasks_remove_component_sync (ECalMetaBackend *meta_backend,
+ EConflictResolution conflict_resolution,
+ const gchar *uid,
+ const gchar *extra,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalBackendGTasks *cbgtasks;
+ ECalCache *cal_cache;
+ GDataTasksTask *task;
+ ECalComponent *cached_comp = NULL;
+ GError *local_error = NULL;
- if (!cached_comp) {
- local_error = EDC_ERROR (ObjectNotFound);
- break;
- }
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
- task = ecb_gtasks_comp_to_gdata (cached_comp, NULL);
- if (!task) {
- g_object_unref (cached_comp);
- local_error = EDC_ERROR (InvalidObject);
- break;
- }
+ cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+ g_return_val_if_fail (cal_cache != NULL, FALSE);
- /* Ignore protocol errors here, libgdata 0.15.1 results with "Error code 204 when deleting an
entry: No Content",
- while the delete succeeded */
- if (!gdata_tasks_service_delete_task (gtasks->priv->service, task, cancellable, &local_error)
&&
- !g_error_matches (local_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR)) {
- g_object_unref (cached_comp);
- g_object_unref (task);
- break;
+ if (!e_cal_cache_get_component (cal_cache, uid, NULL, &cached_comp, cancellable, &local_error)) {
+ if (g_error_matches (local_error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND)) {
+ g_clear_error (&local_error);
+ g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+ } else if (local_error) {
+ g_propagate_error (error, local_error);
}
- if (!local_error)
- e_backend_ensure_source_status_connected (E_BACKEND (backend));
-
- g_clear_error (&local_error);
-
- g_object_unref (task);
-
- PROPERTY_LOCK (gtasks);
- e_cal_backend_store_remove_component (gtasks->priv->store, id->uid, NULL);
- PROPERTY_UNLOCK (gtasks);
+ g_object_unref (cal_cache);
- tmp_id = e_cal_component_id_new (id->uid, NULL);
- e_cal_backend_notify_component_removed (backend, tmp_id, cached_comp, NULL);
-
- old_calcomps = g_slist_prepend (old_calcomps, cached_comp);
- removed_ids = g_slist_prepend (removed_ids, tmp_id);
+ return FALSE;
}
- old_calcomps = g_slist_reverse (old_calcomps);
- removed_ids = g_slist_reverse (removed_ids);
+ g_object_unref (cal_cache);
- e_data_cal_respond_remove_objects (cal, opid, local_error, removed_ids, old_calcomps, NULL);
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
- g_slist_free_full (removed_ids, (GDestroyNotify) e_cal_component_free_id);
- e_util_free_nullable_object_slist (old_calcomps);
-}
+ if (!cached_comp) {
+ g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-static void
-ecb_gtasks_receive_objects (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *calobj)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ return FALSE;
+ }
- e_data_cal_respond_receive_objects (cal, opid, EDC_ERROR (NotSupported));
-}
+ task = ecb_gtasks_comp_to_gdata (cached_comp, NULL, FALSE);
+ if (!task) {
+ g_object_unref (cached_comp);
+ g_propagate_error (error, EDC_ERROR (InvalidObject));
-static void
-ecb_gtasks_send_objects (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *calobj)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
-
- e_data_cal_respond_send_objects (cal, opid, EDC_ERROR (NotSupported), NULL, NULL);
-}
+ return FALSE;
+ }
-static void
-ecb_gtasks_get_attachment_uris (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *uid,
- const gchar *rid)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ /* Ignore protocol errors here, libgdata 0.15.1 results with "Error code 204 when deleting an entry:
No Content",
+ while the delete succeeded */
+ if (!gdata_tasks_service_delete_task (cbgtasks->priv->service, task, cancellable, &local_error) &&
+ !g_error_matches (local_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR)) {
+ g_object_unref (cached_comp);
+ g_object_unref (task);
+ g_propagate_error (error, local_error);
- e_data_cal_respond_get_attachment_uris (cal, opid, EDC_ERROR (NotSupported), NULL);
-}
+ return FALSE;
+ } else {
+ g_clear_error (&local_error);
+ }
-static void
-ecb_gtasks_discard_alarm (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *uid,
- const gchar *rid,
- const gchar *auid)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL (cal));
+ g_object_unref (cached_comp);
+ g_object_unref (task);
- e_data_cal_respond_discard_alarm (cal, opid, EDC_ERROR (NotSupported));
+ return TRUE;
}
-static void
-ecb_gtasks_start_view (ECalBackend *backend,
- EDataCalView *view)
+static gboolean
+ecb_gtasks_requires_reconnect (ECalMetaBackend *meta_backend)
{
- ECalBackendGTasks *gtasks;
- ECalBackendSExp *sexp;
- ETimezoneCache *cache;
- const gchar *sexp_str;
- gboolean do_search;
- GSList *list, *iter;
- time_t occur_start = -1, occur_end = -1;
- gboolean prunning_by_time;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL_VIEW (view));
-
- g_object_ref (view);
-
- gtasks = E_CAL_BACKEND_GTASKS (backend);
- sexp = e_data_cal_view_get_sexp (view);
- sexp_str = e_cal_backend_sexp_text (sexp);
- do_search = !g_str_equal (sexp_str, "#t");
- prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp, &occur_start, &occur_end);
-
- cache = E_TIMEZONE_CACHE (backend);
-
- list = prunning_by_time ?
- e_cal_backend_store_get_components_occuring_in_range (gtasks->priv->store, occur_start,
occur_end)
- : e_cal_backend_store_get_components (gtasks->priv->store);
-
- for (iter = list; iter; iter = g_slist_next (iter)) {
- ECalComponent *comp = E_CAL_COMPONENT (iter->data);
-
- if (!do_search || e_cal_backend_sexp_match_comp (sexp, comp, cache)) {
- e_data_cal_view_notify_components_added_1 (view, comp);
- }
+ ESource *source;
+ ESourceResource *resource;
+ gchar *id;
+ ECalBackendGTasks *cbgtasks;
+ gboolean changed;
- g_object_unref (comp);
- }
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
- g_slist_free (list);
+ cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
+ if (!cbgtasks->priv->tasklist)
+ return TRUE;
- e_data_cal_view_notify_complete (view, NULL /* Success */);
+ source = e_backend_get_source (E_BACKEND (cbgtasks));
+ resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
+ id = e_source_resource_dup_identity (resource);
- g_object_unref (view);
-}
+ changed = id && *id && g_strcmp0 (id, gdata_entry_get_id (GDATA_ENTRY (cbgtasks->priv->tasklist))) !=
0 &&
+ g_strcmp0 (GTASKS_DEFAULT_TASKLIST_NAME, gdata_entry_get_id (GDATA_ENTRY
(cbgtasks->priv->tasklist))) != 0;
-static void
-ecb_gtasks_stop_view (ECalBackend *backend,
- EDataCalView *view)
-{
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
- g_return_if_fail (E_IS_DATA_CAL_VIEW (view));
-}
+ g_free (id);
-static void
-ecb_gtasks_add_timezone (ECalBackend *backend,
- EDataCal *cal,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *tzobject)
-{
- /* Nothing to do, times are in UTC */
- e_data_cal_respond_add_timezone (cal, opid, NULL);
+ return changed;
}
-static void
-ecb_gtasks_shutdown (ECalBackend *backend)
+static gchar *
+ecb_gtasks_dup_component_revision (ECalCache *cal_cache,
+ icalcomponent *icalcomp,
+ gpointer user_data)
{
- ECalBackendGTasks *gtasks;
-
- g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
-
- gtasks = E_CAL_BACKEND_GTASKS (backend);
+ icalproperty *prop;
+ gchar *revision = NULL;
- ecb_gtasks_take_cancellable (gtasks, NULL);
+ g_return_val_if_fail (icalcomp != NULL, NULL);
- if (gtasks->priv->refresh_id) {
- ESource *source = e_backend_get_source (E_BACKEND (backend));
- if (source)
- e_source_refresh_remove_timeout (source, gtasks->priv->refresh_id);
+ prop = icalcomponent_get_first_property (icalcomp, ICAL_LASTMODIFIED_PROPERTY);
+ if (prop) {
+ struct icaltimetype itt;
- gtasks->priv->refresh_id = 0;
+ itt = icalproperty_get_lastmodified (prop);
+ revision = icaltime_as_ical_string_r (itt);
}
- /* Chain up to parent's method. */
- E_CAL_BACKEND_CLASS (e_cal_backend_gtasks_parent_class)->shutdown (backend);
+ return revision;
}
static void
-e_cal_backend_gtasks_init (ECalBackendGTasks *gtasks)
+e_cal_backend_gtasks_init (ECalBackendGTasks *cbgtasks)
{
- gtasks->priv = E_CAL_BACKEND_GTASKS_GET_PRIVATE (gtasks);
- gtasks->priv->cancellable = NULL;
-
- g_mutex_init (>asks->priv->property_mutex);
+ cbgtasks->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbgtasks, E_TYPE_CAL_BACKEND_GTASKS,
ECalBackendGTasksPrivate);
+ cbgtasks->priv->preloaded = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
static void
ecb_gtasks_constructed (GObject *object)
{
- ECalBackendGTasks *gtasks = E_CAL_BACKEND_GTASKS (object);
- ESource *source;
+ ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
+ ECalCache *cal_cache;
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->constructed (object);
- gtasks->priv->store = e_cal_backend_store_new (
- e_cal_backend_get_cache_dir (E_CAL_BACKEND (gtasks)),
- E_TIMEZONE_CACHE (gtasks));
- e_cal_backend_store_load (gtasks->priv->store);
+ cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cbgtasks));
+ g_return_if_fail (cal_cache != NULL);
- source = e_backend_get_source (E_BACKEND (gtasks));
- gtasks->priv->refresh_id = e_source_refresh_add_timeout (
- source, NULL, ecb_gtasks_time_to_refresh_data_cb, gtasks, NULL);
+ g_signal_connect (cal_cache, "dup-component-revision", G_CALLBACK
(ecb_gtasks_dup_component_revision), NULL);
+
+ g_clear_object (&cal_cache);
}
static void
ecb_gtasks_dispose (GObject *object)
{
- ECalBackendGTasks *gtasks = E_CAL_BACKEND_GTASKS (object);
-
- ecb_gtasks_take_cancellable (gtasks, NULL);
+ ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
- g_clear_object (>asks->priv->cancellable);
- g_clear_object (>asks->priv->service);
- g_clear_object (>asks->priv->authorizer);
- g_clear_object (>asks->priv->tasklist);
- g_clear_object (>asks->priv->store);
+ g_clear_object (&cbgtasks->priv->service);
+ g_clear_object (&cbgtasks->priv->authorizer);
+ g_clear_object (&cbgtasks->priv->tasklist);
- if (gtasks->priv->refresh_id) {
- ESource *source = e_backend_get_source (E_BACKEND (object));
- if (source)
- e_source_refresh_remove_timeout (source, gtasks->priv->refresh_id);
-
- gtasks->priv->refresh_id = 0;
- }
+ g_hash_table_destroy (cbgtasks->priv->preloaded);
+ cbgtasks->priv->preloaded = NULL;
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->dispose (object);
}
static void
-ecb_gtasks_finalize (GObject *object)
-{
- ECalBackendGTasks *gtasks = E_CAL_BACKEND_GTASKS (object);
-
- g_mutex_clear (>asks->priv->property_mutex);
-
- /* Chain up to parent's method. */
- G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->finalize (object);
-}
-
-static void
-e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *class)
+e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *klass)
{
GObjectClass *object_class;
- EBackendClass *backend_class;
ECalBackendClass *cal_backend_class;
+ ECalMetaBackendClass *cal_meta_backend_class;
- g_type_class_add_private (class, sizeof (ECalBackendGTasksPrivate));
-
- object_class = (GObjectClass *) class;
- object_class->constructed = ecb_gtasks_constructed;
- object_class->dispose = ecb_gtasks_dispose;
- object_class->finalize = ecb_gtasks_finalize;
+ g_type_class_add_private (klass, sizeof (ECalBackendGTasksPrivate));
- backend_class = (EBackendClass *) class;
- backend_class->authenticate_sync = ecb_gtasks_authenticate_sync;
+ cal_meta_backend_class = E_CAL_META_BACKEND_CLASS (klass);
+ cal_meta_backend_class->connect_sync = ecb_gtasks_connect_sync;
+ cal_meta_backend_class->disconnect_sync = ecb_gtasks_disconnect_sync;
+ cal_meta_backend_class->get_changes_sync = ecb_gtasks_get_changes_sync;
+ cal_meta_backend_class->load_component_sync = ecb_gtasks_load_component_sync;
+ cal_meta_backend_class->save_component_sync = ecb_gtasks_save_component_sync;
+ cal_meta_backend_class->remove_component_sync = ecb_gtasks_remove_component_sync;
+ cal_meta_backend_class->requires_reconnect = ecb_gtasks_requires_reconnect;
- cal_backend_class = (ECalBackendClass *) class;
+ cal_backend_class = E_CAL_BACKEND_CLASS (klass);
cal_backend_class->get_backend_property = ecb_gtasks_get_backend_property;
- cal_backend_class->open = ecb_gtasks_open;
- cal_backend_class->refresh = ecb_gtasks_refresh;
- cal_backend_class->get_object = ecb_gtasks_get_object;
- cal_backend_class->get_object_list = ecb_gtasks_get_object_list;
- cal_backend_class->get_free_busy = ecb_gtasks_get_free_busy;
- cal_backend_class->create_objects = ecb_gtasks_create_objects;
- cal_backend_class->modify_objects = ecb_gtasks_modify_objects;
- cal_backend_class->remove_objects = ecb_gtasks_remove_objects;
- cal_backend_class->receive_objects = ecb_gtasks_receive_objects;
- cal_backend_class->send_objects = ecb_gtasks_send_objects;
- cal_backend_class->get_attachment_uris = ecb_gtasks_get_attachment_uris;
- cal_backend_class->discard_alarm = ecb_gtasks_discard_alarm;
- cal_backend_class->start_view = ecb_gtasks_start_view;
- cal_backend_class->stop_view = ecb_gtasks_stop_view;
- cal_backend_class->add_timezone = ecb_gtasks_add_timezone;
- cal_backend_class->shutdown = ecb_gtasks_shutdown;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->constructed = ecb_gtasks_constructed;
+ object_class->dispose = ecb_gtasks_dispose;
}
diff --git a/src/calendar/backends/gtasks/e-cal-backend-gtasks.h
b/src/calendar/backends/gtasks/e-cal-backend-gtasks.h
index 6823a98..747d044 100644
--- a/src/calendar/backends/gtasks/e-cal-backend-gtasks.h
+++ b/src/calendar/backends/gtasks/e-cal-backend-gtasks.h
@@ -47,12 +47,12 @@ typedef struct _ECalBackendGTasksClass ECalBackendGTasksClass;
typedef struct _ECalBackendGTasksPrivate ECalBackendGTasksPrivate;
struct _ECalBackendGTasks {
- ECalBackend parent;
+ ECalMetaBackend parent;
ECalBackendGTasksPrivate *priv;
};
struct _ECalBackendGTasksClass {
- ECalBackendClass parent_class;
+ ECalMetaBackendClass parent_class;
};
GType e_cal_backend_gtasks_get_type (void);
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index 7bb8cec..aa06272 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -108,7 +108,8 @@ static gboolean ecmb_save_component_wrapper_sync (ECalMetaBackend *meta_backend,
const GSList *in_instances,
const gchar *extra,
const gchar *orig_uid,
- gboolean *requires_put,
+ gboolean *out_requires_put,
+ gchar **out_new_uid,
GCancellable *cancellable,
GError **error);
@@ -538,6 +539,7 @@ ecmb_start_view_thread_func (ECalBackend *cal_backend,
ECalCache *cal_cache;
GSList *components = NULL;
const gchar *expr = NULL;
+ GError *local_error = NULL;
g_return_if_fail (E_IS_CAL_META_BACKEND (cal_backend));
g_return_if_fail (E_IS_DATA_CAL_VIEW (view));
@@ -553,13 +555,16 @@ ecmb_start_view_thread_func (ECalBackend *cal_backend,
cal_cache = e_cal_meta_backend_ref_cache (E_CAL_META_BACKEND (cal_backend));
g_return_if_fail (cal_cache != NULL);
- if (e_cal_cache_search_components (cal_cache, expr, &components, cancellable, error) && components) {
+ if (e_cal_cache_search_components (cal_cache, expr, &components, cancellable, &local_error) &&
components) {
if (!g_cancellable_is_cancelled (cancellable))
e_data_cal_view_notify_components_added (view, components);
g_slist_free_full (components, g_object_unref);
}
+ e_data_cal_view_notify_complete (view, local_error);
+
+ g_clear_error (&local_error);
g_object_unref (cal_cache);
}
@@ -606,7 +611,7 @@ ecmb_upload_local_changes_sync (ECalMetaBackend *meta_backend,
if (success) {
success = ecmb_save_component_wrapper_sync (meta_backend, cal_cache,
change->state == E_OFFLINE_STATE_LOCALLY_MODIFIED,
- conflict_resolution, instances, extra, change->uid, NULL,
cancellable, error);
+ conflict_resolution, instances, extra, change->uid, NULL, NULL,
cancellable, error);
}
g_slist_free_full (instances, g_object_unref);
@@ -1154,6 +1159,7 @@ ecmb_save_component_wrapper_sync (ECalMetaBackend *meta_backend,
const gchar *extra,
const gchar *orig_uid,
gboolean *out_requires_put,
+ gchar **out_new_uid,
GCancellable *cancellable,
GError **error)
{
@@ -1161,6 +1167,12 @@ ecmb_save_component_wrapper_sync (ECalMetaBackend *meta_backend,
gchar *new_uid = NULL;
gboolean has_attachments = FALSE, success = TRUE;
+ if (out_requires_put)
+ *out_requires_put = TRUE;
+
+ if (out_new_uid)
+ *out_new_uid = NULL;
+
for (link = (GSList *) in_instances; link && !has_attachments; link = g_slist_next (link)) {
has_attachments = e_cal_component_has_attachments (link->data);
}
@@ -1191,9 +1203,12 @@ ecmb_save_component_wrapper_sync (ECalMetaBackend *meta_backend,
success = ecmb_load_component_wrapper_sync (meta_backend, cal_cache, new_uid, NULL,
cancellable, error);
if (success && g_strcmp0 (new_uid, orig_uid) != 0)
- success = ecmb_maybe_remove_from_cache (meta_backend, cal_cache, E_CACHE_IS_ONLINE,
orig_uid, cancellable, error);
+ success = ecmb_maybe_remove_from_cache (meta_backend, cal_cache, E_CACHE_IS_ONLINE,
orig_uid, cancellable, error);
- g_free (new_uid);
+ if (success && out_new_uid)
+ *out_new_uid = new_uid;
+ else
+ g_free (new_uid);
if (out_requires_put)
*out_requires_put = FALSE;
@@ -1516,6 +1531,7 @@ ecmb_create_object_sync (ECalMetaBackend *meta_backend,
icalcomponent *icalcomp;
struct icaltimetype itt;
const gchar *uid;
+ gchar *new_uid = NULL;
gboolean success, requires_put = TRUE;
g_return_val_if_fail (comp != NULL, FALSE);
@@ -1566,7 +1582,7 @@ ecmb_create_object_sync (ECalMetaBackend *meta_backend,
instances = g_slist_prepend (NULL, comp);
- if (!ecmb_save_component_wrapper_sync (meta_backend, cal_cache, FALSE, conflict_resolution,
instances, NULL, uid, &requires_put, cancellable, error)) {
+ if (!ecmb_save_component_wrapper_sync (meta_backend, cal_cache, FALSE, conflict_resolution,
instances, NULL, uid, &requires_put, &new_uid, cancellable, error)) {
g_slist_free (instances);
return FALSE;
}
@@ -1585,11 +1601,19 @@ ecmb_create_object_sync (ECalMetaBackend *meta_backend,
if (success) {
if (out_new_uid)
- *out_new_uid = g_strdup (icalcomponent_get_uid (e_cal_component_get_icalcomponent
(comp)));
- if (out_new_comp)
- *out_new_comp = g_object_ref (comp);
+ *out_new_uid = g_strdup (new_uid ? new_uid : icalcomponent_get_uid
(e_cal_component_get_icalcomponent (comp)));
+ if (out_new_comp) {
+ if (new_uid) {
+ if (!e_cal_cache_get_component (cal_cache, new_uid, NULL, out_new_comp,
cancellable, NULL))
+ *out_new_comp = NULL;
+ } else {
+ *out_new_comp = g_object_ref (comp);
+ }
+ }
}
+ g_free (new_uid);
+
return success;
}
@@ -1676,7 +1700,7 @@ ecmb_modify_object_sync (ECalMetaBackend *meta_backend,
ECalComponentId *id;
ECalComponent *old_comp = NULL, *new_comp = NULL, *master_comp, *existing_comp = NULL;
GSList *instances = NULL;
- gchar *extra = NULL;
+ gchar *extra = NULL, *new_uid = NULL;
gboolean success = TRUE, requires_put = TRUE;
GError *local_error = NULL;
@@ -1852,7 +1876,7 @@ ecmb_modify_object_sync (ECalMetaBackend *meta_backend,
if (success && *offline_flag == E_CACHE_IS_ONLINE) {
success = ecmb_save_component_wrapper_sync (meta_backend, cal_cache, TRUE,
conflict_resolution,
- instances, extra, id->uid, &requires_put, cancellable, error);
+ instances, extra, id->uid, &requires_put, &new_uid, cancellable, error);
}
if (success && requires_put)
@@ -1865,11 +1889,19 @@ ecmb_modify_object_sync (ECalMetaBackend *meta_backend,
if (out_old_comp)
*out_old_comp = old_comp;
- if (out_new_comp)
- *out_new_comp = new_comp;
+ if (out_new_comp) {
+ if (new_uid) {
+ if (!e_cal_cache_get_component (cal_cache, new_uid, NULL, out_new_comp, cancellable,
NULL))
+ *out_new_comp = NULL;
+ } else {
+ *out_new_comp = new_comp ? g_object_ref (new_comp) : NULL;
+ }
+ }
g_slist_free_full (instances, g_object_unref);
e_cal_component_free_id (id);
+ g_clear_object (&new_comp);
+ g_free (new_uid);
g_free (extra);
return success;
@@ -2125,6 +2157,7 @@ ecmb_remove_object_sync (ECalMetaBackend *meta_backend,
success = success && ecmb_maybe_remove_from_cache (meta_backend, cal_cache,
*offline_flag, uid, cancellable, error);
} else {
gboolean requires_put = TRUE;
+ gchar *new_uid = NULL;
if (master_comp) {
icalcomponent *icalcomp = e_cal_component_get_icalcomponent (master_comp);
@@ -2140,11 +2173,20 @@ ecmb_remove_object_sync (ECalMetaBackend *meta_backend,
if (*offline_flag == E_CACHE_IS_ONLINE) {
success = ecmb_save_component_wrapper_sync (meta_backend, cal_cache, TRUE,
conflict_resolution,
- instances, extra, uid, &requires_put, cancellable, error);
+ instances, extra, uid, &requires_put, &new_uid, cancellable, error);
}
if (success && requires_put)
success = ecmb_put_instances (meta_backend, cal_cache, uid, *offline_flag,
instances, extra, cancellable, error);
+
+ if (success && new_uid && !requires_put) {
+ g_clear_object (&new_comp);
+
+ if (!e_cal_cache_get_component (cal_cache, new_uid, NULL, &new_comp,
cancellable, NULL))
+ new_comp = NULL;
+ }
+
+ g_free (new_uid);
}
g_free (extra);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]