[evolution-data-server/wip/offline-cache] Begin prototype of ECalMetaBackend
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/offline-cache] Begin prototype of ECalMetaBackend
- Date: Tue, 21 Mar 2017 17:32:49 +0000 (UTC)
commit dfc48abe331f841c35b69dedcfdf8ded3996ef19
Author: Milan Crha <mcrha redhat com>
Date: Wed Feb 22 19:41:44 2017 +0100
Begin prototype of ECalMetaBackend
po/POTFILES.in | 1 +
src/calendar/libedata-cal/CMakeLists.txt | 4 +-
src/calendar/libedata-cal/e-cal-cache.c | 8 +-
src/calendar/libedata-cal/e-cal-meta-backend.c | 978 ++++++++++++++++++++++++
src/calendar/libedata-cal/e-cal-meta-backend.h | 223 ++++++
src/calendar/libedata-cal/libedata-cal.h | 1 +
6 files changed, 1210 insertions(+), 5 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 483e797..5826587 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -40,6 +40,7 @@ src/calendar/libedata-cal/e-cal-backend-sexp.c
src/calendar/libedata-cal/e-cal-backend-sync.c
src/calendar/libedata-cal/e-cal-backend-util.c
src/calendar/libedata-cal/e-cal-cache.c
+src/calendar/libedata-cal/e-cal-meta-backend.c
src/calendar/libedata-cal/e-data-cal.c
src/calendar/libedata-cal/e-data-cal-factory.c
src/camel/camel-address.c
diff --git a/src/calendar/libedata-cal/CMakeLists.txt b/src/calendar/libedata-cal/CMakeLists.txt
index 86109af..15df5d2 100644
--- a/src/calendar/libedata-cal/CMakeLists.txt
+++ b/src/calendar/libedata-cal/CMakeLists.txt
@@ -18,6 +18,7 @@ set(SOURCES
e-cal-backend-util.c
e-cal-backend-store.c
e-cal-cache.c
+ e-cal-meta-backend.c
e-data-cal.c
e-data-cal-factory.c
e-data-cal-view.c
@@ -33,10 +34,11 @@ set(HEADERS
e-cal-backend-sync.h
e-cal-backend-util.h
e-cal-backend-sexp.h
+ e-cal-backend-store.h
e-cal-cache.h
+ e-cal-meta-backend.h
e-data-cal.h
e-data-cal-factory.h
- e-cal-backend-store.h
e-data-cal-view.h
e-subprocess-cal-factory.h
)
diff --git a/src/calendar/libedata-cal/e-cal-cache.c b/src/calendar/libedata-cal/e-cal-cache.c
index d9b57b6..6b9933b 100644
--- a/src/calendar/libedata-cal/e-cal-cache.c
+++ b/src/calendar/libedata-cal/e-cal-cache.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -97,7 +97,7 @@ G_DEFINE_BOXED_TYPE (ECalCacheSearchData, e_cal_cache_search_data, e_cal_cache_s
* @object: the component as an iCal string; cannot be %NULL
* @extra: (nullable): any extra data stored with the component, or %NULL
*
- * Creates a new ECalCacheSearchData prefilled with the given values.
+ * Creates a new #ECalCacheSearchData prefilled with the given values.
*
* Returns: (transfer full): A new #ECalCacheSearchData. Free it with
* e_cal_cache_search_data_free() when no longer needed.
@@ -145,9 +145,9 @@ e_cal_cache_search_data_copy (const ECalCacheSearchData *data)
/**
* e_cal_cache_search_data_free:
- * @data: (nullable): an #ECalCacheSearchData
+ * @ptr: (nullable): an #ECalCacheSearchData
*
- * Frees the @data structure, previously allocated with e_cal_cache_search_data_new()
+ * Frees the @ptr structure, previously allocated with e_cal_cache_search_data_new()
* or e_cal_cache_search_data_copy().
*
* Since: 3.26
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
new file mode 100644
index 0000000..504b9e5
--- /dev/null
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -0,0 +1,978 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-cal-meta-backend
+ * @include: libedata-cal/libedata-cal.h
+ * @short_description: An #ECalBackend descendant for calendar backends
+ *
+ * The #ECalMetaBackend is an abstract #ECalBackend descendant which
+ * aims to implement all evolution-data-server internals for the backend
+ * itself and lefts the backend do as minimum work as possible, like
+ * loading and saving components, listing available components and so on,
+ * thus the backend implementation can focus on things like converting
+ * (possibly) remote data into iCalendar objects and back.
+ *
+ * As the #ECalMetaBackend uses an #ECalCache, the offline support
+ * is provided by default.
+ *
+ * The structure is thread safe.
+ **/
+
+#include "evolution-data-server-config.h"
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-cal-backend.h"
+#include "e-cal-meta-backend.h"
+
+#define LOCAL_PREFIX "file://"
+
+struct _ECalMetaBackendPrivate {
+ GMutex property_lock;
+ ECalCache *cache;
+};
+
+enum {
+ PROP_0,
+ PROP_CACHE
+};
+
+G_DEFINE_ABSTRACT_TYPE (ECalMetaBackend, e_cal_meta_backend, E_TYPE_CAL_BACKEND)
+
+G_DEFINE_BOXED_TYPE (ECalMetaBackendInfo, e_cal_meta_backend_info, e_cal_meta_backend_info_copy,
e_cal_meta_backend_info_free)
+
+/**
+ * e_cal_cache_search_data_new:
+ * @uid: a component UID; cannot be %NULL
+ * @rid: (nullable): a component Recurrence-ID; can be %NULL
+ * @revision: (nullable): the component revision; can be %NULL
+ *
+ * Creates a new #ECalMetaBackendInfo prefilled with the given values.
+ *
+ * Returns: (transfer full): A new #ECalMetaBackendInfo. Free it with
+ * e_cal_meta_backend_info_new() when no longer needed.
+ *
+ * Since: 3.26
+ **/
+ECalMetaBackendInfo *
+e_cal_meta_backend_info_new (const gchar *uid,
+ const gchar *rid,
+ const gchar *revision)
+{
+ ECalMetaBackendInfo *info;
+
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ info = g_new0 (ECalMetaBackendInfo, 1);
+ info->uid = g_strdup (uid);
+ info->rid = g_strdup (rid && *rid ? rid : NULL);
+ info->revision = g_strdup (revision);
+
+ return info;
+}
+
+/**
+ * e_cal_meta_backend_info_copy:
+ * @src: (nullable): a source ECalMetaBackendInfo to copy, or %NULL
+ *
+ * Returns: (transfer full): Copy of the given @src. Free it with
+ * e_cal_meta_backend_info_free() when no longer needed.
+ * If the @src is %NULL, then returns %NULL as well.
+ *
+ * Since: 3.26
+ **/
+ECalMetaBackendInfo *
+e_cal_meta_backend_info_copy (const ECalMetaBackendInfo *src)
+{
+ if (src)
+ return NULL;
+
+ return e_cal_meta_backend_info_new (src->uid, src->rid, src->revision);
+}
+
+/**
+ * e_cal_meta_backend_info_free:
+ * @ptr: (nullable): an #ECalMetaBackendInfo
+ *
+ * Frees the @ptr structure, previously allocated with e_cal_meta_backend_info_new()
+ * or e_cal_meta_backend_info_copy().
+ *
+ * Since: 3.26
+ **/
+void
+e_cal_meta_backend_info_free (gpointer ptr)
+{
+ ECalMetaBackendInfo *info = ptr;
+
+ if (info) {
+ g_free (info->uid);
+ g_free (info->rid);
+ g_free (info->revision);
+ g_free (info);
+ }
+}
+
+static void
+e_cal_meta_backend_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CACHE:
+ e_cal_meta_backend_set_cache (
+ E_CAL_META_BACKEND (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_cal_meta_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CACHE:
+ g_value_take_object (
+ value,
+ e_cal_meta_backend_ref_cache (
+ E_CAL_META_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_cal_meta_backend_dispose (GObject *object)
+{
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_meta_backend_parent_class)->dispose (object);
+}
+
+static void
+e_cal_meta_backend_finalize (GObject *object)
+{
+ ECalMetaBackend *meta_backend = E_CAL_META_BACKEND (object);
+
+ g_clear_object (&meta_backend->priv->cache);
+
+ g_mutex_clear (&meta_backend->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_meta_backend_parent_class)->finalize (object);
+}
+
+static void
+e_cal_meta_backend_class_init (ECalMetaBackendClass *klass)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (klass, sizeof (ECalMetaBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = e_cal_meta_backend_set_property;
+ object_class->get_property = e_cal_meta_backend_get_property;
+ object_class->dispose = e_cal_meta_backend_dispose;
+ object_class->finalize = e_cal_meta_backend_finalize;
+
+ /**
+ * ECalMetaBackend:cache:
+ *
+ * The #ECalCache being used for this meta backend.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_CACHE,
+ g_param_spec_object (
+ "cache",
+ "Cache",
+ "Calendar Cache",
+ E_TYPE_CAL_CACHE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_cal_meta_backend_init (ECalMetaBackend *meta_backend)
+{
+ meta_backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (meta_backend, E_TYPE_CAL_META_BACKEND,
ECalMetaBackendPrivate);
+
+ g_mutex_init (&meta_backend->priv->property_lock);
+}
+
+/**
+ * e_cal_meta_backend_set_cache:
+ * @meta_backend: an #ECalMetaBackend
+ * @cache: an #ECalCache to use
+ *
+ * Sets the @cache as the cache to be used by the @meta_backend.
+ * This should be done as soon as possible, like at the end
+ * of the constructed() method, thus the other places can
+ * safely use it.
+ *
+ * Note the @meta_backend adds its own reference to the @cache.
+ *
+ * Since: 3.26
+ **/
+void
+e_cal_meta_backend_set_cache (ECalMetaBackend *meta_backend,
+ ECalCache *cache)
+{
+ g_return_if_fail (E_IS_CAL_META_BACKEND (meta_backend));
+ g_return_if_fail (E_IS_CAL_CACHE (cache));
+
+ g_mutex_lock (&meta_backend->priv->property_lock);
+
+ if (meta_backend->priv->cache == cache) {
+ g_mutex_unlock (&meta_backend->priv->property_lock);
+ return;
+ }
+
+ g_clear_object (&meta_backend->priv->cache);
+ meta_backend->priv->cache = g_object_ref (cache);
+
+ g_mutex_unlock (&meta_backend->priv->property_lock);
+
+ g_object_notify (G_OBJECT (meta_backend), "cache");
+}
+
+/**
+ * e_cal_meta_backend_ref_cache:
+ * @meta_backend: an #ECalMetaBackend
+ *
+ * Returns: (transfer full): Referenced #ECalCache, which is used by @meta_backend.
+ * Unref it with g_object_unref() when no longer needed.
+ *
+ * Since: 3.26
+ **/
+ECalCache *
+e_cal_meta_backend_ref_cache (ECalMetaBackend *meta_backend)
+{
+ ECalCache *cache;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), NULL);
+
+ g_mutex_lock (&meta_backend->priv->property_lock);
+
+ if (meta_backend->priv->cache)
+ cache = g_object_ref (meta_backend->priv->cache);
+ else
+ cache = NULL;
+
+ g_mutex_unlock (&meta_backend->priv->property_lock);
+
+ return cache;
+}
+
+static gint
+sort_master_first_cb (gconstpointer a,
+ gconstpointer b)
+{
+ icalcomponent *ca, *cb;
+
+ ca = e_cal_component_get_icalcomponent ((ECalComponent *) a);
+ cb = e_cal_component_get_icalcomponent ((ECalComponent *) b);
+
+ if (!ca) {
+ if (!cb)
+ return 0;
+ else
+ return -1;
+ } else if (!cb) {
+ return 1;
+ }
+
+ return icaltime_compare (icalcomponent_get_recurrenceid (ca), icalcomponent_get_recurrenceid (cb));
+}
+
+typedef struct {
+ ECalCache *cache;
+ gboolean replace_tzid_with_location;
+ icalcomponent *vcalendar;
+ icalcomponent *icalcomp;
+} ForeachTzidData;
+
+static void
+add_timezone_cb (icalparameter *param,
+ gpointer data)
+{
+ icaltimezone *tz;
+ const gchar *tzid;
+ icalcomponent *vtz_comp;
+ ForeachTzidData *f_data = (ForeachTzidData *) data;
+
+ tzid = icalparameter_get_tzid (param);
+ if (!tzid)
+ return;
+
+ tz = icalcomponent_get_timezone (f_data->vcalendar, tzid);
+ if (tz)
+ return;
+
+ tz = icalcomponent_get_timezone (f_data->icalcomp, tzid);
+ if (!tz)
+ tz = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+ if (!tz && f_data->cache)
+ tz = e_timezone_cache_get_timezone (E_TIMEZONE_CACHE (f_data->cache), tzid);
+ if (!tz)
+ return;
+
+ if (f_data->replace_tzid_with_location) {
+ const gchar *location;
+
+ location = icaltimezone_get_location (tz);
+ if (location && *location) {
+ icalparameter_set_tzid (param, location);
+ tzid = location;
+
+ if (icalcomponent_get_timezone (f_data->vcalendar, tzid))
+ return;
+ }
+ }
+
+ vtz_comp = icaltimezone_get_component (tz);
+
+ if (vtz_comp) {
+ icalcomponent *clone = icalcomponent_new_clone (vtz_comp);
+
+ if (f_data->replace_tzid_with_location) {
+ icalproperty *prop;
+
+ prop = icalcomponent_get_first_property (clone, ICAL_TZID_PROPERTY);
+ if (prop) {
+ icalproperty_set_tzid (prop, tzid);
+ }
+ }
+
+ icalcomponent_add_component (f_data->vcalendar, clone);
+ }
+}
+
+/**
+ * e_cal_meta_backend_merge_instances:
+ * @meta_backend: an #ECalMetaBackend
+ * @instances: (element-type ECalComponent): component instances to merge
+ * @replace_tzid_with_location: whether to replace TZID-s with locations
+ *
+ * Merges all the instances provided in @instances list into one VCALENDAR
+ * object, which would eventually contain also all the used timezones.
+ * The @instances list should contain the master object and eventually all
+ * the detached instances for one component (they all have the same UID).
+ *
+ * Any TZID property parameters can be replaced with corresponding timezone
+ * location, which will not influence the timezone itself.
+ *
+ * Returns: (transfer full): an #icalcomponent containing a VCALENDAR
+ * component which consists of all the given instances. Free
+ * the returned pointer with icalcomponent_free() when no longer needed.
+ *
+ * See: e_cal_meta_backend_save_component_sync()
+ *
+ * Since: 3.26
+ **/
+icalcomponent *
+e_cal_meta_backend_merge_instances (ECalMetaBackend *meta_backend,
+ const GSList *instances,
+ gboolean replace_tzid_with_location)
+{
+ ForeachTzidData f_data;
+ icalcomponent *vcalendar;
+ GSList *link, *sorted;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), NULL);
+ g_return_val_if_fail (instances != NULL, NULL);
+
+ sorted = g_slist_sort (g_slist_copy ((GSList *) instances), sort_master_first_cb);
+
+ vcalendar = e_cal_util_new_top_level ();
+
+ f_data.cache = e_cal_meta_backend_ref_cache (meta_backend);
+ f_data.replace_tzid_with_location = replace_tzid_with_location;
+ f_data.vcalendar = vcalendar;
+
+ for (link = sorted; link; link = g_slist_next (link)) {
+ ECalComponent *comp = link->data;
+ icalcomponent *icalcomp;
+ ForeachTzidData f_data;
+
+ if (!E_IS_CAL_COMPONENT (comp)) {
+ g_warn_if_reached ();
+ continue;
+ }
+
+ icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+ icalcomponent_add_component (vcalendar, icalcomp);
+
+ f_data.icalcomp = icalcomp;
+
+ icalcomponent_foreach_tzid (icalcomp, add_timezone_cb, &f_data);
+ }
+
+ g_clear_object (&f_data.cache);
+ g_slist_free (sorted);
+
+ return vcalendar;
+}
+
+/**
+ * e_cal_meta_backend_inline_local_attachments_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @component: an icalcomponent to work with
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Changes all URL attachments which point to a local file in @component
+ * to inline attachments, aka adds the file content into the @component.
+ * It also populates FILENAME parameter on the attachment.
+ * This is called automatically before e_cal_meta_backend_save_component_sync().
+ *
+ * The reverse operation is e_cal_meta_backend_store_inline_attachments_sync().
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_inline_local_attachments_sync (ECalMetaBackend *meta_backend,
+ icalcomponent *component,
+ GCancellable *cancellable,
+ GError **error)
+{
+ icalproperty *prop;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (component != NULL, FALSE);
+
+ for (prop = icalcomponent_get_first_property (component, ICAL_ATTACH_PROPERTY);
+ prop && success;
+ prop = icalcomponent_get_next_property (component, ICAL_ATTACH_PROPERTY)) {
+ icalattach *attach;
+
+ attach = icalproperty_get_attach (prop);
+ if (icalattach_get_is_url (attach)) {
+ const gchar *url;
+
+ url = icalattach_get_url (attach);
+ if (g_str_has_prefix (url, LOCAL_PREFIX)) {
+ GFile *file;
+ gchar *basename;
+ gchar *content;
+ gsize len;
+
+ file = g_file_new_for_uri (url);
+ basename = g_file_get_basename (file);
+ if (g_file_load_contents (file, cancellable, &content, &len, NULL, error)) {
+ icalattach *new_attach;
+ icalparameter *param;
+ gchar *base64;
+
+ base64 = g_base64_encode ((const guchar *) content, len);
+ new_attach = icalattach_new_from_data (base64, NULL, NULL);
+ g_free (content);
+ g_free (base64);
+
+ while (param = icalproperty_get_first_parameter (prop,
ICAL_ANY_PARAMETER), param) {
+ icalproperty_remove_parameter_by_ref (prop, param);
+ }
+
+ icalproperty_set_attach (prop, new_attach);
+ icalattach_unref (new_attach);
+
+ param = icalparameter_new_value (ICAL_VALUE_BINARY);
+ icalproperty_add_parameter (prop, param);
+
+ param = icalparameter_new_encoding (ICAL_ENCODING_BASE64);
+ icalproperty_add_parameter (prop, param);
+
+ param = icalparameter_new_filename (basename);
+ icalproperty_add_parameter (prop, param);
+ } else {
+ success = FALSE;
+ }
+
+ g_object_unref (file);
+ g_free (basename);
+ }
+ }
+ }
+
+ return success;
+}
+
+/**
+ * e_cal_meta_backend_store_inline_attachments_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @component: an icalcomponent to work with
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Changes all inline attachments to URL attachments in @component, which
+ * will point to a local file instead. The function expects FILENAME parameter
+ * to be set on the attachment as the file name of it.
+ * This is called automatically after e_cal_meta_backend_load_component_sync().
+ *
+ * The reverse operation is e_cal_meta_backend_inline_local_attachments_sync().
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_store_inline_attachments_sync (ECalMetaBackend *meta_backend,
+ icalcomponent *component,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gint fileindex;
+ icalproperty *prop;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (component != NULL, FALSE);
+
+ for (prop = icalcomponent_get_first_property (component, ICAL_ATTACH_PROPERTY), fileindex = 0;
+ prop && success;
+ prop = icalcomponent_get_next_property (component, ICAL_ATTACH_PROPERTY), fileindex++) {
+ icalattach *attach;
+
+ attach = icalproperty_get_attach (prop);
+ if (!icalattach_get_is_url (attach)) {
+ icalparameter *param;
+ const gchar *basename;
+ gsize len = -1;
+ gchar *decoded = NULL;
+ gchar *local_filename;
+
+ param = icalproperty_get_first_parameter (prop, ICAL_FILENAME_PARAMETER);
+ basename = param ? icalparameter_get_filename (param) : NULL;
+ if (!basename || !*basename)
+ basename = _("attachment.dat");
+
+ local_filename = e_cal_backend_create_cache_filename (E_CAL_BACKEND (meta_backend),
icalcomponent_get_uid (component), basename, fileindex);
+
+ if (local_filename) {
+ const gchar *content;
+
+ content = (const gchar *) icalattach_get_data (attach);
+ decoded = (gchar *) g_base64_decode (content, &len);
+
+ if (g_file_set_contents (local_filename, decoded, len, error)) {
+ icalattach *new_attach;
+ gchar *url;
+
+ url = g_filename_to_uri (local_filename, NULL, NULL);
+ new_attach = icalattach_new_from_url (url);
+
+ icalproperty_set_attach (prop, new_attach);
+
+ icalattach_unref (new_attach);
+ g_free (url);
+ } else {
+ success = FALSE;
+ }
+ }
+
+ g_free (local_filename);
+ }
+ }
+
+ return success;
+}
+
+/**
+ * e_cal_meta_backend_connect_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * This is called always before any operations which requires
+ * a connection to the remote side. It can fail with
+ * an #E_CLIENT_ERROR_REPOSITORY_OFFLINE error to indicate
+ * that the remote side cannot be currently reached. Other
+ * errors are propagated to the caller/client side.
+ * This method is not called when the backend is not online.
+ *
+ * It is mandatory to implement this virtual method by the descendant.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_connect_sync (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->connect_sync != NULL, FALSE);
+
+ return klass->connect_sync (meta_backend, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_disconnect_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * This is called when the backend goes into offline mode or
+ * when the disconnect is required. The implementation should
+ * not report any error when it is called and the @meta_backend
+ * is not connected.
+ *
+ * It is mandatory to implement this virtual method by the descendant.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_disconnect_sync (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->disconnect_sync != NULL, FALSE);
+
+ return klass->disconnect_sync (meta_backend, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_get_changes_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @out_created_objects: (out) (element-type ECalMetaBackendInfo) (transfer full):
+ * a #GSList of #ECalMetaBackendInfo object infos which had been created since
+ * the last check
+ * @out_modified_objects: (out) (element-type ECalMetaBackendInfo) (transfer full):
+ * a #GSList of #ECalMetaBackendInfo object infos which had been modified since
+ * the last check
+ * @out_removed_objects: (out) (element-type ECalMetaBackendInfo) (transfer full):
+ * a #GSList of #ECalMetaBackendInfo object infos which had been removed since
+ * the last check
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gathers the changes since the last check which had been done
+ * on the remote side.
+ *
+ * It is optional to implement this virtual method by the descendant.
+ * The default implementation calls e_cal_meta_backend_list_existing_sync()
+ * and then compares the list with the current content of the local cache
+ * and populates the respective lists appropriately.
+ *
+ * Each output #GSList should be freed with
+ * g_slist_free_full (objects, e_cal_meta_backend_info_free);
+ * when no longer needed.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_get_changes_sync (ECalMetaBackend *meta_backend,
+ GSList **out_created_objects,
+ GSList **out_modified_objects,
+ GSList **out_removed_objects,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), 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);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->get_changes_sync != NULL, FALSE);
+
+ return klass->get_changes_sync (meta_backend, out_created_objects, out_modified_objects,
out_removed_objects, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_list_existing_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @out_existing_objects: (out) (element-type ECalMetaBackendInfo) (transfer full):
+ * a #GSList of #ECalMetaBackendInfo object infos which are stored on the remote side
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Used to get list of all existing objects on the remote side.
+ *
+ * It is mandatory to implement this virtual method by the descendant.
+ *
+ * The @out_existing_objects #GSList should be freed with
+ * g_slist_free_full (objects, e_cal_meta_backend_info_free);
+ * when no longer needed.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_list_existing_sync (ECalMetaBackend *meta_backend,
+ GSList **out_existing_objects,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (out_existing_objects != NULL, FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->list_existing_sync != NULL, FALSE);
+
+ return klass->list_existing_sync (meta_backend, out_existing_objects, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_save_component_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @overwrite_existing: %TRUE when can overwrite existing components, %FALSE otherwise
+ * @conflict_resolution: one of #EConflictResolution, what to do on conflicts
+ * @instances: (element-type ECalComponent): instances of the component to save
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Saves one component into the remote side. The @instances contain the master
+ * object and all the detached instances of the same component (all have the same UID).
+ * When the @overwrite_existing is %TRUE, then the descendant can overwrite an object
+ * with the same UID on the remote side (usually used for modify). The @conflict_resolution
+ * defines what to do when the remote side had made any changes to the object since
+ * the last update.
+ *
+ * The descendant can use e_cal_meta_backend_merge_instances() to merge
+ * the instances into one VCALENDAR component, which will contain also
+ * used time zones.
+ *
+ * The components in @instances have already converted locally stored attachments
+ * into inline attachments, thus it's not needed to call
+ * e_cal_meta_backend_inline_local_attachments_sync() by the descendant.
+ *
+ * The descendant can use an #E_CLIENT_ERROR_OUT_OF_SYNC error to indicate that
+ * the save failed due to made changes on the remote side, and let the @meta_backend
+ * to resolve this conflict based on the @conflict_resolution on its own.
+ * The #E_CLIENT_ERROR_OUT_OF_SYNC error should not be used when the descendant
+ * is able to resolve the conflicts itself.
+ *
+ * It is mandatory to implement this virtual method by the descendant.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_save_component_sync (ECalMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ const GSList *instances,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (instances != NULL, FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->save_component_sync != NULL, FALSE);
+
+ return klass->save_component_sync (meta_backend, overwrite_existing, conflict_resolution, instances,
cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_load_component_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @uid: a component UID
+ * @rid: (nullable): optional component Recurrence-ID, or %NULL
+ * @out_component: (out) (transfer full): a loaded component, as icalcomponent
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Loads one component from the remote side. In case the descendant's storage
+ * doesn't allow to store detached instances separately it can ignore the @rid
+ * and return whole component. The @out_component can be either
+ * a VCALENDAR component, which would contain the master object and all of
+ * its detached instances, eventually also used time zones, or the requested
+ * component of type VEVENT, VJOURNAL or VTODO.
+ *
+ * It is mandatory to implement this virtual method by the descendant.
+ *
+ * The returned @out_component should be freed with icalcomponent_free()
+ * when no longer needed.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_load_component_sync (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ icalcomponent **out_component,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (out_component != NULL, FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->load_component_sync != NULL, FALSE);
+
+ return klass->load_component_sync (meta_backend, uid, rid, out_component, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_get_free_busy_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @users: (element-type utf8): a #GSList of user mail addresses
+ * @start: time range start
+ * @end: time range end
+ * @out_freebusy: (out) (element-type utf8): a #GSList of iCalendar strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets Free/Busy information for all the mail addresses specified
+ * in the @users list for the given time range. The descendant can
+ * use e_cal_meta_backend_notify_free_busy() to let the client side
+ * know about Free/Busy information asynchronously, but it should
+ * also report all found Free/Busy data in @out_freebusy #GSList.
+ *
+ * It is optional to implement this virtual method by the descendant.
+ * The default implementation checks whether any of the users
+ * equals to #CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS and if so, then
+ * it returns the Free/Busy information for this user according to
+ * the information in the local cache.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_get_free_busy_sync (ECalMetaBackend *meta_backend,
+ const GSList *users,
+ time_t start,
+ time_t end,
+ GSList **out_freebusy,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (users != NULL, FALSE);
+ g_return_val_if_fail (out_freebusy != NULL, FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->get_free_busy_sync != NULL, FALSE);
+
+ return klass->get_free_busy_sync (meta_backend, users, start, end, out_freebusy, cancellable, error);
+}
+
+/**
+ * e_cal_meta_backend_notify_free_busy:
+ * @meta_backend: an #ECalMetaBackend
+ * @freebusy: (element-type utf8): a #GSList of iCalendar strings
+ *
+ * Notifies the client side about Free/Busy information asynchronously.
+ * This is usually used within e_cal_meta_backend_get_free_busy_sync().
+ *
+ * Since: 3.26
+ **/
+void
+e_cal_meta_backend_notify_free_busy (ECalMetaBackend *meta_backend,
+ const GSList *freebusy)
+{
+ g_return_if_fail (E_IS_CAL_META_BACKEND (meta_backend));
+
+ if (freebusy) {
+ EDataCal *data_cal;
+
+ data_cal = e_cal_backend_ref_data_cal (E_CAL_BACKEND (meta_backend));
+ if (data_cal) {
+ e_data_cal_report_free_busy_data (data_cal, freebusy);
+ g_object_unref (data_cal);
+ }
+ }
+}
+
+/**
+ * e_cal_meta_backend_discard_alarm_sync:
+ * @meta_backend: an #ECalMetaBackend
+ * @uid: a component UID
+ * @rid: (nullable): optional component Recurrence-ID, or %NULL
+ * @auid: alarm UID to discard
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Discards alarm identified by @auid for component identified
+ * by @uid and eventually @rid.
+ *
+ * It is optional to implement this virtual method by the descendant.
+ * The default implementation does nothing.
+ *
+ * Returns: Whether succeeded.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cal_meta_backend_discard_alarm_sync (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ const gchar *auid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECalMetaBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (auid != NULL, FALSE);
+
+ klass = E_CAL_META_BACKEND_GET_CLASS (meta_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+ g_return_val_if_fail (klass->discard_alarm_sync != NULL, FALSE);
+
+ return klass->discard_alarm_sync (meta_backend, uid, rid, auid, cancellable, error);
+}
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.h b/src/calendar/libedata-cal/e-cal-meta-backend.h
new file mode 100644
index 0000000..6d1103b
--- /dev/null
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.h
@@ -0,0 +1,223 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__LIBEDATA_CAL_H_INSIDE__) && !defined (LIBEDATA_CAL_COMPILATION)
+#error "Only <libedata-cal/libedata-cal.h> should be included directly."
+#endif
+
+#ifndef E_CAL_META_BACKEND_H
+#define E_CAL_META_BACKEND_H
+
+#include <libebackend/libebackend.h>
+#include <libedata-cal/e-cal-backend.h>
+#include <libedata-cal/e-cal-cache.h>
+#include <libecal/libecal.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_META_BACKEND \
+ (e_cal_meta_backend_get_type ())
+#define E_CAL_META_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_META_BACKEND, ECalMetaBackend))
+#define E_CAL_META_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_META_BACKEND, ECalMetaBackendClass))
+#define E_IS_CAL_META_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_META_BACKEND))
+#define E_IS_CAL_META_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_META_BACKEND))
+#define E_CAL_META_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_META_BACKEND, ECalMetaBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalMetaBackendInfo {
+ gchar *uid;
+ gchar *rid;
+ gchar *revision;
+} ECalMetaBackendInfo;
+
+#define E_TYPE_CAL_META_BACKEND_INFO (e_cal_meta_backend_info_get_type ())
+
+GType e_cal_meta_backend_info_get_type
+ (void) G_GNUC_CONST;
+ECalMetaBackendInfo *
+ e_cal_meta_backend_info_new (const gchar *uid,
+ const gchar *rid,
+ const gchar *revision);
+ECalMetaBackendInfo *
+ e_cal_meta_backend_info_copy (const ECalMetaBackendInfo *src);
+void e_cal_meta_backend_info_free (gpointer ptr /* ECalMetaBackendInfo * */);
+
+typedef struct _ECalMetaBackend ECalMetaBackend;
+typedef struct _ECalMetaBackendClass ECalMetaBackendClass;
+typedef struct _ECalMetaBackendPrivate ECalMetaBackendPrivate;
+
+/**
+ * ECalMetaBackend:
+ *
+ * Contains only private data that should be read and manipulated using
+ * the functions below.
+ *
+ * Since: 3.26
+ **/
+struct _ECalMetaBackend {
+ /*< private >*/
+ ECache parent;
+ ECalMetaBackendPrivate *priv;
+};
+
+/**
+ * ECalMetaBackendClass:
+ *
+ * Class structure for the #ECalMetaBackend class.
+ *
+ * Since: 3.26
+ */
+struct _ECalMetaBackendClass {
+ /*< private >*/
+ ECacheClass parent_class;
+
+ /* Virtual methods */
+ gboolean (* connect_sync) (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error);
+ gboolean (* disconnect_sync) (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error);
+
+ gboolean (* get_changes_sync) (ECalMetaBackend *meta_backend,
+ GSList **out_created_objects, /* ECalMetaBackendInfo * */
+ GSList **out_modified_objects, /* ECalMetaBackendInfo * */
+ GSList **out_removed_objects, /* ECalMetaBackendInfo * */
+ GCancellable *cancellable,
+ GError **error);
+ gboolean (* list_existing_sync) (ECalMetaBackend *meta_backend,
+ GSList **out_existing_objects, /* ECalMetaBackendInfo * */
+ GCancellable *cancellable,
+ GError **error);
+
+ gboolean (* save_component_sync) (ECalMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ const GSList *instances, /* ECalComponent * */
+ GCancellable *cancellable,
+ GError **error);
+ gboolean (* load_component_sync) (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ icalcomponent **out_instances,
+ GCancellable *cancellable,
+ GError **error);
+
+ /* Optional methods from ECalBackend */
+ gboolean (* get_free_busy_sync) (ECalMetaBackend *meta_backend,
+ const GSList *users,
+ time_t start,
+ time_t end,
+ GSList **out_freebusy, /* gchar * (iCal strings) */
+ GCancellable *cancellable,
+ GError **error);
+ gboolean (* discard_alarm_sync) (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ const gchar *auid,
+ GCancellable *cancellable,
+ GError **error);
+
+ /* Padding for future expansion */
+ gpointer reserved[10];
+};
+
+GType e_cal_meta_backend_get_type (void) G_GNUC_CONST;
+
+void e_cal_meta_backend_set_cache (ECalMetaBackend *meta_backend,
+ ECalCache *cache);
+ECalCache * e_cal_meta_backend_ref_cache (ECalMetaBackend *meta_backend);
+icalcomponent * e_cal_meta_backend_merge_instances
+ (ECalMetaBackend *meta_backend,
+ const GSList *instances, /* ECalComponent * */
+ gboolean replace_tzid_with_location);
+gboolean e_cal_meta_backend_inline_local_attachments_sync
+ (ECalMetaBackend *meta_backend,
+ icalcomponent *component,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_store_inline_attachments_sync
+ (ECalMetaBackend *meta_backend,
+ icalcomponent *component,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_connect_sync (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_disconnect_sync
+ (ECalMetaBackend *meta_backend,
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_get_changes_sync
+ (ECalMetaBackend *meta_backend,
+ GSList **out_created_objects, /* ECalMetaBackendInfo * */
+ GSList **out_modified_objects, /* ECalMetaBackendInfo * */
+ GSList **out_removed_objects, /* ECalMetaBackendInfo * */
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_list_existing_sync
+ (ECalMetaBackend *meta_backend,
+ GSList **out_existing_objects, /* ECalMetaBackendInfo * */
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_save_component_sync
+ (ECalMetaBackend *meta_backend,
+ gboolean overwrite_existing,
+ EConflictResolution conflict_resolution,
+ const GSList *instances, /* ECalComponent * */
+ GCancellable *cancellable,
+ GError **error);
+gboolean e_cal_meta_backend_load_component_sync
+ (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ icalcomponent **out_component,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean e_cal_meta_backend_get_free_busy_sync
+ (ECalMetaBackend *meta_backend,
+ const GSList *users,
+ time_t start,
+ time_t end,
+ GSList **out_freebusy, /* gchar * */
+ GCancellable *cancellable,
+ GError **error);
+void e_cal_meta_backend_notify_free_busy
+ (ECalMetaBackend *meta_backend,
+ const GSList *freebusy); /* gchar * */
+gboolean e_cal_meta_backend_discard_alarm_sync
+ (ECalMetaBackend *meta_backend,
+ const gchar *uid,
+ const gchar *rid,
+ const gchar *auid,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_META_BACKEND_H */
diff --git a/src/calendar/libedata-cal/libedata-cal.h b/src/calendar/libedata-cal/libedata-cal.h
index c93fdac..a754d70 100644
--- a/src/calendar/libedata-cal/libedata-cal.h
+++ b/src/calendar/libedata-cal/libedata-cal.h
@@ -32,6 +32,7 @@
#include <libedata-cal/e-cal-backend-sync.h>
#include <libedata-cal/e-cal-backend-util.h>
#include <libedata-cal/e-cal-cache.h>
+#include <libedata-cal/e-cal-meta-backend.h>
#include <libedata-cal/e-data-cal-factory.h>
#include <libedata-cal/e-data-cal.h>
#include <libedata-cal/e-data-cal-view.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]