[evolution-data-server] Introduce EWebDAVCollectionBackend to be used for WebDAV-discovered collections
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Introduce EWebDAVCollectionBackend to be used for WebDAV-discovered collections
- Date: Fri, 21 Jul 2017 10:58:49 +0000 (UTC)
commit 884adf3eca8a94dbcf3101b45c81b8218274e0f0
Author: Milan Crha <mcrha redhat com>
Date: Fri Jul 21 12:56:24 2017 +0200
Introduce EWebDAVCollectionBackend to be used for WebDAV-discovered collections
Any server providing CalDAV/CardDAV interfaces to access the calendars,
memo lists, task lists and address books may derive from this new object
and avoid code duplication.
src/libebackend/CMakeLists.txt | 2 +
src/libebackend/e-webdav-collection-backend.c | 544 ++++++++++++++++++++
src/libebackend/e-webdav-collection-backend.h | 98 ++++
src/libebackend/libebackend.h | 1 +
src/modules/google-backend/module-google-backend.c | 292 ++---------
.../owncloud-backend/module-owncloud-backend.c | 372 +-------------
src/modules/yahoo-backend/module-yahoo-backend.c | 215 +-------
7 files changed, 729 insertions(+), 795 deletions(-)
---
diff --git a/src/libebackend/CMakeLists.txt b/src/libebackend/CMakeLists.txt
index 844bcbc..fbf2023 100644
--- a/src/libebackend/CMakeLists.txt
+++ b/src/libebackend/CMakeLists.txt
@@ -29,6 +29,7 @@ set(SOURCES
e-user-prompter.c
e-user-prompter-server.c
e-user-prompter-server-extension.c
+ e-webdav-collection-backend.c
${CMAKE_CURRENT_BINARY_DIR}/e-backend-enumtypes.c
)
@@ -54,6 +55,7 @@ set(HEADERS
e-user-prompter.h
e-user-prompter-server.h
e-user-prompter-server-extension.h
+ e-webdav-collection-backend.h
${CMAKE_CURRENT_BINARY_DIR}/e-backend-enumtypes.h
)
diff --git a/src/libebackend/e-webdav-collection-backend.c b/src/libebackend/e-webdav-collection-backend.c
new file mode 100644
index 0000000..0073bdd
--- /dev/null
+++ b/src/libebackend/e-webdav-collection-backend.c
@@ -0,0 +1,544 @@
+/* -*- 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/>.
+ *
+ */
+
+#include "evolution-data-server-config.h"
+
+#include <libebackend/libebackend.h>
+#include <libedataserver/libedataserver.h>
+
+#include "e-webdav-collection-backend.h"
+
+struct _EWebDAVCollectionBackendPrivate {
+ gboolean dummy;
+};
+
+G_DEFINE_TYPE (EWebDAVCollectionBackend, e_webdav_collection_backend, E_TYPE_COLLECTION_BACKEND)
+
+static void
+webdav_collection_add_uid_to_hashtable (gpointer source,
+ gpointer known_sources)
+{
+ ESourceResource *resource;
+ gchar *uid, *rid;
+
+ if (!e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE))
+ return;
+
+ resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
+
+ uid = e_source_dup_uid (source);
+ if (!uid || !*uid) {
+ g_free (uid);
+ return;
+ }
+
+ rid = e_source_resource_dup_identity (resource);
+ if (!rid || !*rid) {
+ g_free (rid);
+ g_free (uid);
+ return;
+ }
+
+ g_hash_table_insert (known_sources, rid, uid);
+}
+
+typedef struct _RemoveSourcesData {
+ ESourceRegistryServer *server;
+ EWebDAVCollectionBackend *webdav_backend;
+} RemoveSourcesData;
+
+static void
+webdav_collection_remove_unknown_sources_cb (gpointer resource_id,
+ gpointer uid,
+ gpointer user_data)
+{
+ RemoveSourcesData *rsd = user_data;
+ ESource *source;
+
+ g_return_if_fail (rsd != NULL);
+
+ source = e_source_registry_server_ref_source (rsd->server, uid);
+
+ if (source) {
+ if (!e_webdav_collection_backend_is_custom_source (rsd->webdav_backend, source))
+ e_source_remove_sync (source, NULL, NULL);
+
+ g_object_unref (source);
+ }
+}
+
+static void
+webdav_collection_add_found_source (ECollectionBackend *collection,
+ EWebDAVDiscoverSupports source_type,
+ SoupURI *uri,
+ const gchar *display_name,
+ const gchar *color,
+ GHashTable *known_sources)
+{
+ ESourceRegistryServer *server;
+ ESourceBackend *backend;
+ ESource *source = NULL;
+ const gchar *backend_name = NULL;
+ const gchar *provider = NULL;
+ const gchar *identity_prefix = NULL;
+ const gchar *source_uid;
+ gboolean is_new;
+ gchar *url;
+ gchar *identity;
+
+ g_return_if_fail (collection != NULL);
+ g_return_if_fail (uri != NULL);
+ g_return_if_fail (display_name != NULL);
+ g_return_if_fail (known_sources != NULL);
+
+ switch (source_type) {
+ case E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS:
+ backend_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ provider = "webdav";
+ identity_prefix = "contacts";
+ break;
+ case E_WEBDAV_DISCOVER_SUPPORTS_EVENTS:
+ backend_name = E_SOURCE_EXTENSION_CALENDAR;
+ provider = "caldav";
+ identity_prefix = "events";
+ break;
+ case E_WEBDAV_DISCOVER_SUPPORTS_MEMOS:
+ backend_name = E_SOURCE_EXTENSION_MEMO_LIST;
+ provider = "caldav";
+ identity_prefix = "memos";
+ break;
+ case E_WEBDAV_DISCOVER_SUPPORTS_TASKS:
+ backend_name = E_SOURCE_EXTENSION_TASK_LIST;
+ provider = "caldav";
+ identity_prefix = "tasks";
+ break;
+ default:
+ g_warn_if_reached ();
+ return;
+ }
+
+ g_return_if_fail (backend_name != NULL);
+
+ server = e_collection_backend_ref_server (collection);
+ if (!server)
+ return;
+
+ url = soup_uri_to_string (uri, FALSE);
+ identity = g_strconcat (identity_prefix, "::", url, NULL);
+ source_uid = g_hash_table_lookup (known_sources, identity);
+ is_new = !source_uid;
+ if (is_new) {
+ source = e_collection_backend_new_child (collection, identity);
+ g_warn_if_fail (source != NULL);
+ } else {
+ source = e_source_registry_server_ref_source (server, source_uid);
+ g_warn_if_fail (source != NULL);
+
+ g_hash_table_remove (known_sources, identity);
+ }
+
+ if (source) {
+ ESource *master_source;
+ ESourceCollection *collection_extension;
+ ESourceAuthentication *child_auth;
+ ESourceResource *resource;
+ ESourceWebdav *master_webdav, *child_webdav;
+
+ master_source = e_backend_get_source (E_BACKEND (collection));
+ master_webdav = e_source_get_extension (master_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+ collection_extension = e_source_get_extension (master_source, E_SOURCE_EXTENSION_COLLECTION);
+ child_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+ child_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+ resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
+
+ e_source_authentication_set_user (child_auth, e_source_collection_get_identity
(collection_extension));
+ e_source_webdav_set_soup_uri (child_webdav, uri);
+ e_source_resource_set_identity (resource, identity);
+
+ if (is_new) {
+ /* inherit ssl trust options */
+ e_source_webdav_set_ssl_trust (child_webdav, e_source_webdav_get_ssl_trust
(master_webdav));
+ }
+ }
+
+ g_free (identity);
+ g_free (url);
+
+ /* these properties are synchronized always */
+ if (source) {
+ gint rr, gg, bb;
+
+ backend = e_source_get_extension (source, backend_name);
+ e_source_backend_set_backend_name (backend, provider);
+
+ e_source_set_display_name (source, display_name);
+ e_source_set_enabled (source, TRUE);
+
+ /* Also check whether the color format is as expected; it cannot
+ be used gdk_rgba_parse here, because it required gdk/gtk. */
+ if (is_new && source_type != E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS && color &&
+ sscanf (color, "#%02x%02x%02x", &rr, &gg, &bb) == 3) {
+ gchar *safe_color;
+
+ /* In case an #RRGGBBAA is returned */
+ safe_color = g_strdup_printf ("#%02x%02x%02x", rr, gg, bb);
+
+ e_source_selectable_set_color (E_SOURCE_SELECTABLE (backend), safe_color);
+
+ g_free (safe_color);
+ }
+
+ if (is_new)
+ e_source_registry_server_add_source (server, source);
+
+ g_object_unref (source);
+ }
+
+ g_object_unref (server);
+}
+
+static void
+webdav_collection_process_discovered_sources (ECollectionBackend *collection,
+ GSList *discovered_sources,
+ GHashTable *known_sources,
+ const EWebDAVDiscoverSupports *source_types,
+ gint n_source_types)
+{
+ GSList *link;
+ gint ii;
+
+ for (link = discovered_sources; link; link = g_slist_next (link)) {
+ EWebDAVDiscoveredSource *discovered_source = link->data;
+ SoupURI *soup_uri;
+
+ if (!discovered_source || !discovered_source->href || !discovered_source->display_name)
+ continue;
+
+ soup_uri = soup_uri_new (discovered_source->href);
+ if (!soup_uri)
+ continue;
+
+ for (ii = 0; ii < n_source_types; ii++) {
+ if ((discovered_source->supports & source_types[ii]) == source_types[ii])
+ webdav_collection_add_found_source (collection, source_types[ii], soup_uri,
+ discovered_source->display_name, discovered_source->color,
known_sources);
+ }
+
+ soup_uri_free (soup_uri);
+ }
+}
+
+static gchar *
+webdav_collection_backend_get_resource_id (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+ if (e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE)) {
+ ESourceResource *resource;
+
+ resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
+ return e_source_resource_dup_identity (resource);
+ }
+
+ return NULL;
+}
+
+static gboolean
+webdav_collection_backend_is_custom_source (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+ return FALSE;
+}
+
+static void
+webdav_collection_backend_populate (ECollectionBackend *collection)
+{
+ EWebDAVCollectionBackend *webdav_backend = E_WEBDAV_COLLECTION_BACKEND (collection);
+ ESourceRegistryServer *server;
+ ESourceCollection *collection_extension;
+ ESource *source;
+ GList *list, *liter;
+
+ /* Chain up to parent's method. */
+ E_COLLECTION_BACKEND_CLASS (e_webdav_collection_backend_parent_class)->populate (collection);
+
+ server = e_collection_backend_ref_server (collection);
+ list = e_collection_backend_claim_all_resources (collection);
+
+ for (liter = list; liter; liter = g_list_next (liter)) {
+ ESource *source = liter->data;
+ gchar *resource_id;
+
+ resource_id = webdav_collection_backend_get_resource_id (webdav_backend, source);
+ if (resource_id) {
+ ESource *child;
+
+ child = e_collection_backend_new_child (collection, resource_id);
+ if (child) {
+ e_source_registry_server_add_source (server, source);
+ g_object_unref (child);
+ }
+
+ g_free (resource_id);
+ }
+
+ }
+
+ g_list_free_full (list, g_object_unref);
+ g_object_unref (server);
+
+ source = e_backend_get_source (E_BACKEND (collection));
+ collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
+
+ if (e_source_get_enabled (source) && (
+ e_source_collection_get_calendar_enabled (collection_extension) ||
+ e_source_collection_get_contacts_enabled (collection_extension))) {
+ e_backend_schedule_credentials_required (E_BACKEND (collection),
+ E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL, NULL, G_STRFUNC);
+ }
+}
+
+static void
+e_webdav_collection_backend_class_init (EWebDAVCollectionBackendClass *klass)
+{
+ ECollectionBackendClass *collection_backend_class;
+
+ g_type_class_add_private (klass, sizeof (EWebDAVCollectionBackendPrivate));
+
+ klass->get_resource_id = webdav_collection_backend_get_resource_id;
+ klass->is_custom_source = webdav_collection_backend_is_custom_source;
+
+ collection_backend_class = E_COLLECTION_BACKEND_CLASS (klass);
+ collection_backend_class->populate = webdav_collection_backend_populate;
+}
+
+static void
+e_webdav_collection_backend_init (EWebDAVCollectionBackend *webdav_backend)
+{
+ webdav_backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (webdav_backend, E_TYPE_WEBDAV_COLLECTION_BACKEND,
EWebDAVCollectionBackendPrivate);
+}
+
+/**
+ * e_webdav_collection_backend_get_resource_id:
+ * @webdav_backend: an #EWebDAVCollectionBackend
+ * @source: an #ESource
+ *
+ * Verifies that the @source is expected here and returns its resource ID,
+ * which is used in call to e_collection_backend_new_child(). It returns %NULL,
+ * when the @source is not part of the backend and should be removed instead.
+ * The default implementation allows all sources, which has %ESourceResource
+ * extension defined.
+ *
+ * Returns: (transfer full) (nullable): a resource ID corresponding to @source,
+ * or %NULL, when the @source should be removed.
+ *
+ * Since: 3.26
+ **/
+gchar *
+e_webdav_collection_backend_get_resource_id (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ EWebDAVCollectionBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_WEBDAV_COLLECTION_BACKEND (webdav_backend), NULL);
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+ klass = E_WEBDAV_COLLECTION_BACKEND_GET_CLASS (webdav_backend);
+ g_return_val_if_fail (klass != NULL, NULL);
+ g_return_val_if_fail (klass->get_resource_id != NULL, NULL);
+
+ return klass->get_resource_id (webdav_backend, source);
+}
+
+/**
+ * e_webdav_collection_backend_is_custom_source:
+ * @webdav_backend: an #EWebDAVCollectionBackend
+ * @source: an #ESource
+ *
+ * Returns: %TRUE, when the @source is a custom source, thus it
+ * should not be removed as an obsolete source; %FALSE to not
+ * force to keep it. It still can be left, when it's one of
+ * the WebDAV-discovered sources.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_webdav_collection_backend_is_custom_source (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ EWebDAVCollectionBackendClass *klass;
+
+ g_return_val_if_fail (E_IS_WEBDAV_COLLECTION_BACKEND (webdav_backend), FALSE);
+ g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+ klass = E_WEBDAV_COLLECTION_BACKEND_GET_CLASS (webdav_backend);
+ g_return_val_if_fail (klass != NULL, FALSE);
+
+ if (!klass->is_custom_source)
+ return FALSE;
+
+ return klass->is_custom_source (webdav_backend, source);
+}
+
+/**
+ * e_webdav_collection_backend_discover_sync:
+ * @webdav_backend: an #EWebDAVCollectionBackend
+ * @calendar_url: (nullable): a URL to search calendars at, or %NULL
+ * @contacts_url: (nullable): a URL to search contacts at, or %NULL
+ * @credentials: credentials to use when running the discovery
+ * @out_certificate_pem: (out) (nullable): optional return location
+ * for a server SSL certificate in PEM format, when the operation failed
+ * with an SSL error
+ * @out_certificate_errors: (out) (nullable): optional #GTlsCertificateFlags,
+ * with certificate error flags when the operation failed with SSL error
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * This function is usually called in EBackend::authenticate_sync() implementation
+ * of the descendant, causing discovery of CalDAV and CardDAV sources on given URLs.
+ * If either of @calendar_url and @contacts_url is %NULL, that that part is skipped.
+ * The @calendar_url covers all calendars, memo lists and task lists.
+ *
+ * The function also takes care of e_collection_backend_authenticate_children() on success.
+ *
+ * Returns: an #ESourceAuthenticationResult describing whether discovery on given
+ * addresses succeeded.
+ *
+ * Since: 3.26
+ **/
+ESourceAuthenticationResult
+e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_backend,
+ const gchar *calendar_url,
+ const gchar *contacts_url,
+ const ENamedParameters *credentials,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
+{
+ ECollectionBackend *collection;
+ ESourceCollection *collection_extension;
+ ESource *source;
+ ESourceAuthenticationResult result;
+ GHashTable *known_sources; /* resource-id ~> source's UID */
+ GList *sources;
+ GSList *discovered_sources = NULL;
+ ENamedParameters *credentials_copy = NULL;
+ gboolean any_success = FALSE;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_WEBDAV_COLLECTION_BACKEND (webdav_backend), E_SOURCE_AUTHENTICATION_ERROR);
+
+ collection = E_COLLECTION_BACKEND (webdav_backend);
+ source = e_backend_get_source (E_BACKEND (webdav_backend));
+ collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
+
+ if (!e_source_collection_get_calendar_enabled (collection_extension) &&
+ !e_source_collection_get_contacts_enabled (collection_extension))
+ return E_SOURCE_AUTHENTICATION_ACCEPTED;
+
+ if (credentials && !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME)) {
+ credentials_copy = e_named_parameters_new_clone (credentials);
+ e_named_parameters_set (credentials_copy, E_SOURCE_CREDENTIAL_USERNAME,
e_source_collection_get_identity (collection_extension));
+ credentials = credentials_copy;
+ }
+
+ known_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ sources = e_collection_backend_list_calendar_sources (collection);
+ g_list_foreach (sources, webdav_collection_add_uid_to_hashtable, known_sources);
+ g_list_free_full (sources, g_object_unref);
+
+ sources = e_collection_backend_list_contacts_sources (collection);
+ g_list_foreach (sources, webdav_collection_add_uid_to_hashtable, known_sources);
+ g_list_free_full (sources, g_object_unref);
+
+ if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url &&
+ e_webdav_discover_sources_sync (source, calendar_url,
+ E_WEBDAV_DISCOVER_SUPPORTS_EVENTS | E_WEBDAV_DISCOVER_SUPPORTS_MEMOS |
E_WEBDAV_DISCOVER_SUPPORTS_TASKS,
+ credentials, out_certificate_pem, out_certificate_errors,
+ &discovered_sources, NULL, cancellable, &local_error)) {
+ EWebDAVDiscoverSupports source_types[] = {
+ E_WEBDAV_DISCOVER_SUPPORTS_EVENTS,
+ E_WEBDAV_DISCOVER_SUPPORTS_MEMOS,
+ E_WEBDAV_DISCOVER_SUPPORTS_TASKS
+ };
+
+ webdav_collection_process_discovered_sources (collection, discovered_sources, known_sources,
source_types, G_N_ELEMENTS (source_types));
+
+ e_webdav_discover_free_discovered_sources (discovered_sources);
+ discovered_sources = NULL;
+ any_success = TRUE;
+ }
+
+ if (!local_error && e_source_collection_get_contacts_enabled (collection_extension) && contacts_url &&
+ e_webdav_discover_sources_sync (source, contacts_url, E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS,
+ credentials, out_certificate_pem, out_certificate_errors,
+ &discovered_sources, NULL, cancellable, &local_error)) {
+ EWebDAVDiscoverSupports source_types[] = {
+ E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS
+ };
+
+ webdav_collection_process_discovered_sources (collection, discovered_sources, known_sources,
source_types, G_N_ELEMENTS (source_types));
+
+ e_webdav_discover_free_discovered_sources (discovered_sources);
+ discovered_sources = NULL;
+ any_success = TRUE;
+ }
+
+ if (any_success) {
+ ESourceRegistryServer *server;
+
+ server = e_collection_backend_ref_server (collection);
+
+ if (server) {
+ RemoveSourcesData rsd;
+
+ rsd.server = server;
+ rsd.webdav_backend = webdav_backend;
+
+ g_hash_table_foreach (known_sources, webdav_collection_remove_unknown_sources_cb,
&rsd);
+ g_object_unref (server);
+ }
+
+ g_clear_error (&local_error);
+ }
+
+ if (local_error == NULL) {
+ result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+ e_collection_backend_authenticate_children (collection, credentials);
+ } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+ g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+ result = E_SOURCE_AUTHENTICATION_REJECTED;
+ g_clear_error (&local_error);
+ } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+ result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
+ g_propagate_error (error, local_error);
+ } else {
+ result = E_SOURCE_AUTHENTICATION_ERROR;
+ g_propagate_error (error, local_error);
+ }
+
+ g_hash_table_destroy (known_sources);
+ e_named_parameters_free (credentials_copy);
+
+ return result;
+}
diff --git a/src/libebackend/e-webdav-collection-backend.h b/src/libebackend/e-webdav-collection-backend.h
new file mode 100644
index 0000000..949e234
--- /dev/null
+++ b/src/libebackend/e-webdav-collection-backend.h
@@ -0,0 +1,98 @@
+/* -*- 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 (__LIBEBACKEND_H_INSIDE__) && !defined (LIBEBACKEND_COMPILATION)
+#error "Only <libebackend/libebackend.h> should be included directly."
+#endif
+
+#ifndef E_WEBDAV_COLLECTION_BACKEND_H
+#define E_WEBDAV_COLLECTION_BACKEND_H
+
+#include <libebackend/e-collection-backend.h>
+#include <libedataserver/libedataserver.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEBDAV_COLLECTION_BACKEND \
+ (e_webdav_collection_backend_get_type ())
+#define E_WEBDAV_COLLECTION_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEBDAV_COLLECTION_BACKEND, EWebDAVCollectionBackend))
+#define E_WEBDAV_COLLECTION_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_WEBDAV_COLLECTION_BACKEND, EWebDAVCollectionBackendClass))
+#define E_IS_WEBDAV_COLLECTION_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_WEBDAV_COLLECTION_BACKEND))
+#define E_IS_WEBDAV_COLLECTION_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_WEBDAV_COLLECTION_BACKEND))
+#define E_WEBDAV_COLLECTION_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_WEBDAV_COLLECTION_BACKEND, EWebDAVCollectionBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EWebDAVCollectionBackend EWebDAVCollectionBackend;
+typedef struct _EWebDAVCollectionBackendClass EWebDAVCollectionBackendClass;
+typedef struct _EWebDAVCollectionBackendPrivate EWebDAVCollectionBackendPrivate;
+
+/**
+ * EWebDAVCollectionBackend:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.26
+ **/
+struct _EWebDAVCollectionBackend {
+ /*< private >*/
+ ECollectionBackend parent;
+ EWebDAVCollectionBackendPrivate *priv;
+};
+
+struct _EWebDAVCollectionBackendClass {
+ ECollectionBackendClass parent_class;
+
+ gchar * (* get_resource_id) (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source);
+ gboolean (* is_custom_source) (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source);
+};
+
+GType e_webdav_collection_backend_get_type (void);
+
+gchar * e_webdav_collection_backend_get_resource_id
+ (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source);
+gboolean e_webdav_collection_backend_is_custom_source
+ (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source);
+ESourceAuthenticationResult
+ e_webdav_collection_backend_discover_sync
+ (EWebDAVCollectionBackend *webdav_backend,
+ const gchar *calendar_url,
+ const gchar *contacts_url,
+ const ENamedParameters *credentials,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_WEBDAV_COLLECTION_BACKEND_H */
diff --git a/src/libebackend/libebackend.h b/src/libebackend/libebackend.h
index d1559fd..9a7c8c2 100644
--- a/src/libebackend/libebackend.h
+++ b/src/libebackend/libebackend.h
@@ -42,6 +42,7 @@
#include <libebackend/e-user-prompter.h>
#include <libebackend/e-user-prompter-server.h>
#include <libebackend/e-user-prompter-server-extension.h>
+#include <libebackend/e-webdav-collection-backend.h>
#undef __LIBEBACKEND_H_INSIDE__
diff --git a/src/modules/google-backend/module-google-backend.c
b/src/modules/google-backend/module-google-backend.c
index 0f4887f..c33e869 100644
--- a/src/modules/google-backend/module-google-backend.c
+++ b/src/modules/google-backend/module-google-backend.c
@@ -72,11 +72,11 @@ typedef struct _EGoogleBackendFactory EGoogleBackendFactory;
typedef struct _EGoogleBackendFactoryClass EGoogleBackendFactoryClass;
struct _EGoogleBackend {
- ECollectionBackend parent;
+ EWebDAVCollectionBackend parent;
};
struct _EGoogleBackendClass {
- ECollectionBackendClass parent_class;
+ EWebDAVCollectionBackendClass parent_class;
};
struct _EGoogleBackendFactory {
@@ -98,7 +98,7 @@ GType e_google_backend_factory_get_type (void);
G_DEFINE_DYNAMIC_TYPE (
EGoogleBackend,
e_google_backend,
- E_TYPE_COLLECTION_BACKEND)
+ E_TYPE_WEBDAV_COLLECTION_BACKEND)
G_DEFINE_DYNAMIC_TYPE (
EGoogleBackendFactory,
@@ -272,13 +272,14 @@ google_backend_contacts_update_auth_method_cb (ESource *child_source,
}
static void
-google_add_uid_to_hashtable (gpointer source,
- gpointer known_sources)
+google_add_task_list_uid_to_hashtable (gpointer source,
+ gpointer known_sources)
{
ESourceResource *resource;
gchar *uid, *rid;
- if (!e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE))
+ if (!e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE) ||
+ !e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
return;
resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
@@ -315,138 +316,6 @@ google_remove_unknown_sources_cb (gpointer resource_id,
}
}
-static void
-google_add_found_source (ECollectionBackend *collection,
- EWebDAVDiscoverSupports source_type,
- SoupURI *uri,
- const gchar *display_name,
- const gchar *color,
- GHashTable *known_sources)
-{
- ESourceRegistryServer *server;
- ESourceBackend *backend;
- ESource *source = NULL;
- const gchar *backend_name = NULL;
- const gchar *provider = NULL;
- const gchar *identity_prefix = NULL;
- const gchar *source_uid;
- gboolean is_new;
- gchar *url;
- gchar *identity;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (uri != NULL);
- g_return_if_fail (display_name != NULL);
- g_return_if_fail (known_sources != NULL);
-
- switch (source_type) {
- case E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS:
- backend_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
- provider = "webdav";
- identity_prefix = "contacts";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_EVENTS:
- backend_name = E_SOURCE_EXTENSION_CALENDAR;
- provider = "caldav";
- identity_prefix = "events";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_MEMOS:
- backend_name = E_SOURCE_EXTENSION_MEMO_LIST;
- provider = "caldav";
- identity_prefix = "memos";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_TASKS:
- backend_name = E_SOURCE_EXTENSION_TASK_LIST;
- provider = "caldav";
- identity_prefix = "tasks";
- break;
- default:
- g_warn_if_reached ();
- return;
- }
-
- g_return_if_fail (backend_name != NULL);
-
- server = e_collection_backend_ref_server (collection);
- if (!server)
- return;
-
- url = soup_uri_to_string (uri, FALSE);
- identity = g_strconcat (identity_prefix, "::", url, NULL);
- source_uid = g_hash_table_lookup (known_sources, identity);
- is_new = !source_uid;
- if (is_new) {
- source = e_collection_backend_new_child (collection, identity);
- g_warn_if_fail (source != NULL);
- } else {
- source = e_source_registry_server_ref_source (server, source_uid);
- g_warn_if_fail (source != NULL);
-
- g_hash_table_remove (known_sources, identity);
- }
-
- if (source) {
- ESource *master_source;
- ESourceCollection *collection_extension;
- ESourceAuthentication *child_auth;
- ESourceResource *resource;
- ESourceWebdav *master_webdav, *child_webdav;
-
- master_source = e_backend_get_source (E_BACKEND (collection));
- master_webdav = e_source_get_extension (master_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
- collection_extension = e_source_get_extension (master_source, E_SOURCE_EXTENSION_COLLECTION);
- child_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
- child_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
-
- google_backend_calendar_update_auth_method (source, master_source);
-
- e_source_authentication_set_user (child_auth, e_source_collection_get_identity
(collection_extension));
- e_source_webdav_set_soup_uri (child_webdav, uri);
- e_source_resource_set_identity (resource, identity);
-
- if (is_new) {
- /* inherit ssl trust options */
- e_source_webdav_set_ssl_trust (child_webdav, e_source_webdav_get_ssl_trust
(master_webdav));
- }
- }
-
- g_free (identity);
- g_free (url);
-
- /* these properties are synchronized always */
- if (source) {
- gint rr, gg, bb;
-
- backend = e_source_get_extension (source, backend_name);
- e_source_backend_set_backend_name (backend, provider);
-
- e_source_set_display_name (source, display_name);
- e_source_set_enabled (source, TRUE);
-
- /* Also check whether the color format is as expected; it cannot
- be used gdk_rgba_parse here, because it required gdk/gtk. */
- if (is_new && source_type != E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS && color &&
- sscanf (color, "#%02x%02x%02x", &rr, &gg, &bb) == 3) {
- gchar *safe_color;
-
- /* In case an #RRGGBBAA is returned */
- safe_color = g_strdup_printf ("#%02x%02x%02x", rr, gg, bb);
-
- e_source_selectable_set_color (E_SOURCE_SELECTABLE (backend), safe_color);
-
- g_free (safe_color);
- }
-
- if (is_new)
- e_source_registry_server_add_source (server, source);
-
- g_object_unref (source);
- }
-
- g_object_unref (server);
-}
-
#if GDATA_CHECK_VERSION(0,15,1)
static void
google_add_task_list (ECollectionBackend *collection,
@@ -541,13 +410,11 @@ google_backend_authenticate_sync (EBackend *backend,
ESourceCollection *collection_extension;
ESourceGoa *goa_extension = NULL;
ESource *source;
- ESourceAuthenticationResult result;
+ ESourceAuthenticationResult result = E_SOURCE_AUTHENTICATION_ERROR;
GHashTable *known_sources;
GList *sources;
- GSList *discovered_sources = NULL;
ENamedParameters *credentials_copy = NULL;
const gchar *calendar_url;
- gboolean any_success = FALSE;
GError *local_error = NULL;
g_return_val_if_fail (collection != NULL, E_SOURCE_AUTHENTICATION_ERROR);
@@ -572,7 +439,7 @@ google_backend_authenticate_sync (EBackend *backend,
known_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
sources = e_collection_backend_list_calendar_sources (collection);
- g_list_foreach (sources, google_add_uid_to_hashtable, known_sources);
+ g_list_foreach (sources, google_add_task_list_uid_to_hashtable, known_sources);
g_list_free_full (sources, g_object_unref);
/* When the WebDAV extension is created, the auth method can be reset, thus ensure
@@ -596,57 +463,9 @@ google_backend_authenticate_sync (EBackend *backend,
}
}
- if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url &&
- e_webdav_discover_sources_sync (source, calendar_url, E_WEBDAV_DISCOVER_SUPPORTS_NONE,
- credentials, out_certificate_pem, out_certificate_errors,
- &discovered_sources, NULL, cancellable, &local_error)) {
- EWebDAVDiscoverSupports source_types[] = {
- E_WEBDAV_DISCOVER_SUPPORTS_EVENTS,
- E_WEBDAV_DISCOVER_SUPPORTS_MEMOS,
- E_WEBDAV_DISCOVER_SUPPORTS_TASKS
- };
- GSList *link;
- gint ii;
-
- for (link = discovered_sources; link; link = g_slist_next (link)) {
- EWebDAVDiscoveredSource *discovered_source = link->data;
- SoupURI *soup_uri;
-
- if (!discovered_source || !discovered_source->href ||
!discovered_source->display_name)
- continue;
-
- soup_uri = soup_uri_new (discovered_source->href);
- if (!soup_uri)
- continue;
-
- for (ii = 0; ii < G_N_ELEMENTS (source_types); ii++) {
- if ((discovered_source->supports & source_types[ii]) == source_types[ii])
- google_add_found_source (collection, source_types[ii], soup_uri,
- discovered_source->display_name, discovered_source->color,
known_sources);
- }
-
- soup_uri_free (soup_uri);
- }
-
- any_success = TRUE;
- }
-
- if (any_success)
- g_clear_error (&local_error);
-
- if (local_error == NULL) {
- result = E_SOURCE_AUTHENTICATION_ACCEPTED;
- e_collection_backend_authenticate_children (collection, credentials);
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
- g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
- result = E_SOURCE_AUTHENTICATION_REJECTED;
- g_clear_error (&local_error);
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
- result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
- g_propagate_error (error, local_error);
- } else {
- result = E_SOURCE_AUTHENTICATION_ERROR;
- g_propagate_error (error, local_error);
+ if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url) {
+ result = e_webdav_collection_backend_discover_sync (E_WEBDAV_COLLECTION_BACKEND (backend),
calendar_url, NULL,
+ credentials, out_certificate_pem, out_certificate_errors, cancellable, error);
}
#if GDATA_CHECK_VERSION(0,15,1)
@@ -700,7 +519,7 @@ google_backend_authenticate_sync (EBackend *backend,
}
#endif /* GDATA_CHECK_VERSION(0,15,1) */
- if (any_success) {
+ if (result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
ESourceRegistryServer *server;
server = e_collection_backend_ref_server (collection);
@@ -768,76 +587,66 @@ google_backend_add_contacts (ECollectionBackend *backend)
g_object_unref (source);
}
+static gchar *
+google_backend_get_resource_id (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+ if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
+ return g_strdup (GOOGLE_CONTACTS_RESOURCE_ID);
+
+ /* Chain up to parent's method. */
+ return E_WEBDAV_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->get_resource_id
(webdav_backend, source);
+}
+
+static gboolean
+google_backend_is_custom_source (EWebDAVCollectionBackend *webdav_backend,
+ ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+ if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK) ||
+ e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
+ return TRUE;
+
+ /* Chain up to parent's method. */
+ return E_WEBDAV_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->is_custom_source
(webdav_backend, source);
+}
+
static void
google_backend_populate (ECollectionBackend *backend)
{
- GList *list, *link;
- ESourceRegistryServer *server;
ESourceCollection *collection_extension;
ESource *source;
- server = e_collection_backend_ref_server (backend);
- list = e_collection_backend_claim_all_resources (backend);
- for (link = list; link; link = g_list_next (link)) {
- ESource *source = link->data;
- ESource *child = NULL;
-
- if (e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE)) {
- ESourceResource *resource;
-
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
- child = e_collection_backend_new_child (backend, e_source_resource_get_identity
(resource));
- } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
- child = e_collection_backend_new_child (backend, GOOGLE_CONTACTS_RESOURCE_ID);
- }
-
- if (child) {
- e_source_registry_server_add_source (server, source);
- g_object_unref (child);
- }
- }
-
- g_list_free_full (list, g_object_unref);
- g_object_unref (server);
+ /* Chain up to parent's method. */
+ E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->populate (backend);
source = e_backend_get_source (E_BACKEND (backend));
collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
if (e_source_collection_get_contacts_enabled (collection_extension)) {
+ GList *list;
+
list = e_collection_backend_list_contacts_sources (backend);
if (list == NULL)
google_backend_add_contacts (backend);
g_list_free_full (list, (GDestroyNotify) g_object_unref);
}
- /* Chain up to parent's populate() method. */
- E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->populate (backend);
-
- if (e_source_get_enabled (source) && e_source_collection_get_calendar_enabled (collection_extension))
{
- e_backend_schedule_credentials_required (E_BACKEND (backend),
- E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL, NULL, G_STRFUNC);
- }
}
static gchar *
google_backend_dup_resource_id (ECollectionBackend *backend,
ESource *child_source)
{
- const gchar *extension_name;
-
- /* XXX This is trivial for now since we only
- * add one calendar and one address book. */
-
- extension_name = E_SOURCE_EXTENSION_CALENDAR;
- if (e_source_has_extension (child_source, extension_name))
- return E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->dup_resource_id (backend,
child_source);
-
- extension_name = E_SOURCE_EXTENSION_TASK_LIST;
- if (e_source_has_extension (child_source, extension_name))
+ if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_CALENDAR) ||
+ e_source_has_extension (child_source, E_SOURCE_EXTENSION_MEMO_LIST) ||
+ e_source_has_extension (child_source, E_SOURCE_EXTENSION_TASK_LIST))
return E_COLLECTION_BACKEND_CLASS (e_google_backend_parent_class)->dup_resource_id (backend,
child_source);
- extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
- if (e_source_has_extension (child_source, extension_name))
+ if (e_source_has_extension (child_source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
return g_strdup (GOOGLE_CONTACTS_RESOURCE_ID);
return NULL;
@@ -996,6 +805,7 @@ e_google_backend_class_init (EGoogleBackendClass *class)
{
EBackendClass *backend_class;
ECollectionBackendClass *collection_backend_class;
+ EWebDAVCollectionBackendClass *webdav_collection_backend_class;
backend_class = E_BACKEND_CLASS (class);
backend_class->authenticate_sync = google_backend_authenticate_sync;
@@ -1006,6 +816,10 @@ e_google_backend_class_init (EGoogleBackendClass *class)
collection_backend_class->dup_resource_id = google_backend_dup_resource_id;
collection_backend_class->child_added = google_backend_child_added;
collection_backend_class->child_removed = google_backend_child_removed;
+
+ webdav_collection_backend_class = E_WEBDAV_COLLECTION_BACKEND_CLASS (class);
+ webdav_collection_backend_class->get_resource_id = google_backend_get_resource_id;
+ webdav_collection_backend_class->is_custom_source = google_backend_is_custom_source;
}
static void
diff --git a/src/modules/owncloud-backend/module-owncloud-backend.c
b/src/modules/owncloud-backend/module-owncloud-backend.c
index 27b6980..0768959 100644
--- a/src/modules/owncloud-backend/module-owncloud-backend.c
+++ b/src/modules/owncloud-backend/module-owncloud-backend.c
@@ -37,11 +37,11 @@ typedef struct _EOwncloudBackendFactory EOwncloudBackendFactory;
typedef struct _EOwncloudBackendFactoryClass EOwncloudBackendFactoryClass;
struct _EOwncloudBackend {
- ECollectionBackend parent;
+ EWebDAVCollectionBackend parent;
};
struct _EOwncloudBackendClass {
- ECollectionBackendClass parent_class;
+ EWebDAVCollectionBackendClass parent_class;
};
struct _EOwncloudBackendFactory {
@@ -63,218 +63,13 @@ GType e_owncloud_backend_factory_get_type (void);
G_DEFINE_DYNAMIC_TYPE (
EOwncloudBackend,
e_owncloud_backend,
- E_TYPE_COLLECTION_BACKEND)
+ E_TYPE_WEBDAV_COLLECTION_BACKEND)
G_DEFINE_DYNAMIC_TYPE (
EOwncloudBackendFactory,
e_owncloud_backend_factory,
E_TYPE_COLLECTION_BACKEND_FACTORY)
-static void
-owncloud_add_uid_to_hashtable (gpointer source,
- gpointer known_sources)
-{
- ESourceResource *resource;
- gchar *uid, *rid;
-
- if (!e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE))
- return;
-
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
-
- uid = e_source_dup_uid (source);
- if (!uid || !*uid) {
- g_free (uid);
- return;
- }
-
- rid = e_source_resource_dup_identity (resource);
- if (!rid || !*rid) {
- g_free (rid);
- g_free (uid);
- return;
- }
-
- g_hash_table_insert (known_sources, rid, uid);
-}
-
-static void
-owncloud_remove_unknown_sources_cb (gpointer resource_id,
- gpointer uid,
- gpointer user_data)
-{
- ESourceRegistryServer *server = user_data;
- ESource *source;
-
- source = e_source_registry_server_ref_source (server, uid);
-
- if (source) {
- e_source_remove_sync (source, NULL, NULL);
- g_object_unref (source);
- }
-}
-
-static void
-owncloud_add_found_source (ECollectionBackend *collection,
- EWebDAVDiscoverSupports source_type,
- SoupURI *uri,
- const gchar *display_name,
- const gchar *color,
- GHashTable *known_sources)
-{
- ESourceRegistryServer *server;
- ESourceBackend *backend;
- ESource *source = NULL;
- const gchar *backend_name = NULL;
- const gchar *provider = NULL;
- const gchar *identity_prefix = NULL;
- const gchar *source_uid;
- gboolean is_new;
- gchar *url;
- gchar *identity;
-
- g_return_if_fail (collection != NULL);
- g_return_if_fail (uri != NULL);
- g_return_if_fail (display_name != NULL);
- g_return_if_fail (known_sources != NULL);
-
- switch (source_type) {
- case E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS:
- backend_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
- provider = "webdav";
- identity_prefix = "contacts";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_EVENTS:
- backend_name = E_SOURCE_EXTENSION_CALENDAR;
- provider = "caldav";
- identity_prefix = "events";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_MEMOS:
- backend_name = E_SOURCE_EXTENSION_MEMO_LIST;
- provider = "caldav";
- identity_prefix = "memos";
- break;
- case E_WEBDAV_DISCOVER_SUPPORTS_TASKS:
- backend_name = E_SOURCE_EXTENSION_TASK_LIST;
- provider = "caldav";
- identity_prefix = "tasks";
- break;
- default:
- g_warn_if_reached ();
- return;
- }
-
- g_return_if_fail (backend_name != NULL);
-
- server = e_collection_backend_ref_server (collection);
- if (!server)
- return;
-
- url = soup_uri_to_string (uri, FALSE);
- identity = g_strconcat (identity_prefix, "::", url, NULL);
- source_uid = g_hash_table_lookup (known_sources, identity);
- is_new = !source_uid;
- if (is_new) {
- source = e_collection_backend_new_child (collection, identity);
- g_warn_if_fail (source != NULL);
- } else {
- source = e_source_registry_server_ref_source (server, source_uid);
- g_warn_if_fail (source != NULL);
-
- g_hash_table_remove (known_sources, identity);
- }
-
- if (source) {
- ESource *master_source;
- ESourceCollection *collection_extension;
- ESourceAuthentication *child_auth;
- ESourceResource *resource;
- ESourceWebdav *master_webdav, *child_webdav;
-
- master_source = e_backend_get_source (E_BACKEND (collection));
- master_webdav = e_source_get_extension (master_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
- collection_extension = e_source_get_extension (master_source, E_SOURCE_EXTENSION_COLLECTION);
- child_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
- child_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
-
- e_source_authentication_set_user (child_auth, e_source_collection_get_identity
(collection_extension));
- e_source_webdav_set_soup_uri (child_webdav, uri);
- e_source_resource_set_identity (resource, identity);
-
- if (is_new) {
- /* inherit ssl trust options */
- e_source_webdav_set_ssl_trust (child_webdav, e_source_webdav_get_ssl_trust
(master_webdav));
- }
- }
-
- g_free (identity);
- g_free (url);
-
- /* these properties are synchronized always */
- if (source) {
- gint rr, gg, bb;
-
- backend = e_source_get_extension (source, backend_name);
- e_source_backend_set_backend_name (backend, provider);
-
- e_source_set_display_name (source, display_name);
- e_source_set_enabled (source, TRUE);
-
- /* Also check whether the color format is as expected; it cannot
- be used gdk_rgba_parse here, because it required gdk/gtk. */
- if (is_new && source_type != E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS && color &&
- sscanf (color, "#%02x%02x%02x", &rr, &gg, &bb) == 3) {
- gchar *safe_color;
-
- /* In case an #RRGGBBAA is returned */
- safe_color = g_strdup_printf ("#%02x%02x%02x", rr, gg, bb);
-
- e_source_selectable_set_color (E_SOURCE_SELECTABLE (backend), safe_color);
-
- g_free (safe_color);
- }
-
- if (is_new)
- e_source_registry_server_add_source (server, source);
-
- g_object_unref (source);
- }
-
- g_object_unref (server);
-}
-
-static void
-owncloud_process_discovered_sources (ECollectionBackend *collection,
- GSList *discovered_sources,
- GHashTable *known_sources,
- const EWebDAVDiscoverSupports *source_types,
- gint n_source_types)
-{
- GSList *link;
- gint ii;
-
- for (link = discovered_sources; link; link = g_slist_next (link)) {
- EWebDAVDiscoveredSource *discovered_source = link->data;
- SoupURI *soup_uri;
-
- if (!discovered_source || !discovered_source->href || !discovered_source->display_name)
- continue;
-
- soup_uri = soup_uri_new (discovered_source->href);
- if (!soup_uri)
- continue;
-
- for (ii = 0; ii < n_source_types; ii++) {
- if ((discovered_source->supports & source_types[ii]) == source_types[ii])
- owncloud_add_found_source (collection, source_types[ii], soup_uri,
- discovered_source->display_name, discovered_source->color,
known_sources);
- }
-
- soup_uri_free (soup_uri);
- }
-}
-
static ESourceAuthenticationResult
owncloud_backend_authenticate_sync (EBackend *backend,
const ENamedParameters *credentials,
@@ -283,22 +78,12 @@ owncloud_backend_authenticate_sync (EBackend *backend,
GCancellable *cancellable,
GError **error)
{
- ECollectionBackend *collection = E_COLLECTION_BACKEND (backend);
- ESourceCollection *collection_extension;
ESourceGoa *goa_extension;
ESource *source;
- ESourceAuthenticationResult result;
- GHashTable *known_sources;
- GList *sources;
- GSList *discovered_sources = NULL;
- ENamedParameters *credentials_copy = NULL;
- gboolean any_success = FALSE, contacts_found = FALSE;
- GError *local_error = NULL;
- g_return_val_if_fail (collection != NULL, E_SOURCE_AUTHENTICATION_ERROR);
+ g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), E_SOURCE_AUTHENTICATION_ERROR);
source = e_backend_get_source (backend);
- collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
/* Ignore the request for non-GOA ownCloud sources by pretending success */
if (!e_source_has_extension (source, E_SOURCE_EXTENSION_GOA))
@@ -306,160 +91,19 @@ owncloud_backend_authenticate_sync (EBackend *backend,
goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA);
- if (!e_source_collection_get_calendar_enabled (collection_extension) &&
- !e_source_collection_get_contacts_enabled (collection_extension))
- return E_SOURCE_AUTHENTICATION_ACCEPTED;
-
- if (credentials && !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME)) {
- credentials_copy = e_named_parameters_new_clone (credentials);
- e_named_parameters_set (credentials_copy, E_SOURCE_CREDENTIAL_USERNAME,
e_source_collection_get_identity (collection_extension));
- credentials = credentials_copy;
- }
-
- /* resource-id => source's UID */
- known_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- sources = e_collection_backend_list_calendar_sources (collection);
- g_list_foreach (sources, owncloud_add_uid_to_hashtable, known_sources);
- g_list_free_full (sources, g_object_unref);
-
- sources = e_collection_backend_list_contacts_sources (collection);
- g_list_foreach (sources, owncloud_add_uid_to_hashtable, known_sources);
- g_list_free_full (sources, g_object_unref);
-
- if (e_source_collection_get_calendar_enabled (collection_extension) && e_source_goa_get_calendar_url
(goa_extension) &&
- e_webdav_discover_sources_sync (source, e_source_goa_get_calendar_url (goa_extension),
E_WEBDAV_DISCOVER_SUPPORTS_NONE,
- credentials, out_certificate_pem, out_certificate_errors,
- &discovered_sources, NULL, cancellable, &local_error)) {
- GSList *link;
- EWebDAVDiscoverSupports source_types[] = {
- E_WEBDAV_DISCOVER_SUPPORTS_EVENTS,
- E_WEBDAV_DISCOVER_SUPPORTS_MEMOS,
- E_WEBDAV_DISCOVER_SUPPORTS_TASKS,
- E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS
- };
-
- for (link = discovered_sources; link && !contacts_found; link = g_slist_next (link)) {
- EWebDAVDiscoveredSource *discovered_source = link->data;
-
- if (discovered_source)
- contacts_found = contacts_found || (discovered_source->supports &
E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS) != 0;
- }
-
- owncloud_process_discovered_sources (collection, discovered_sources, known_sources,
source_types,
- G_N_ELEMENTS (source_types) - (contacts_found ? 0 : 1));
-
- e_webdav_discover_free_discovered_sources (discovered_sources);
- discovered_sources = NULL;
- any_success = TRUE;
- }
-
- /* Skip search in this URL, if the previous one returned also contacts - it's quite likely it did */
- if (!contacts_found && !local_error && e_source_collection_get_contacts_enabled
(collection_extension) &&
- e_source_goa_get_contacts_url (goa_extension) &&
- e_webdav_discover_sources_sync (source, e_source_goa_get_contacts_url (goa_extension),
E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS,
- credentials, out_certificate_pem, out_certificate_errors,
- &discovered_sources, NULL, cancellable, &local_error)) {
- EWebDAVDiscoverSupports source_types[] = {
- E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS
- };
-
- owncloud_process_discovered_sources (collection, discovered_sources, known_sources,
source_types, G_N_ELEMENTS (source_types));
-
- e_webdav_discover_free_discovered_sources (discovered_sources);
- discovered_sources = NULL;
- any_success = TRUE;
- }
-
- if (any_success) {
- ESourceRegistryServer *server;
-
- server = e_collection_backend_ref_server (collection);
-
- if (server) {
- g_hash_table_foreach (known_sources, owncloud_remove_unknown_sources_cb, server);
- g_object_unref (server);
- }
-
- g_clear_error (&local_error);
- }
-
- if (local_error == NULL) {
- result = E_SOURCE_AUTHENTICATION_ACCEPTED;
- e_collection_backend_authenticate_children (collection, credentials);
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
- g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
- result = E_SOURCE_AUTHENTICATION_REJECTED;
- g_clear_error (&local_error);
- } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
- result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
- g_propagate_error (error, local_error);
- } else {
- result = E_SOURCE_AUTHENTICATION_ERROR;
- g_propagate_error (error, local_error);
- }
-
- g_hash_table_destroy (known_sources);
- e_named_parameters_free (credentials_copy);
-
- return result;
-}
-
-static void
-owncloud_backend_populate (ECollectionBackend *collection)
-{
- GList *list, *liter;
- ESourceRegistryServer *server;
- ESourceCollection *collection_extension;
- ESource *source;
-
- /* Chain up to parent's populate() method. */
- E_COLLECTION_BACKEND_CLASS (e_owncloud_backend_parent_class)->populate (collection);
-
- server = e_collection_backend_ref_server (collection);
- list = e_collection_backend_claim_all_resources (collection);
-
- for (liter = list; liter; liter = g_list_next (liter)) {
- ESource *source = liter->data;
-
- if (e_source_has_extension (source, E_SOURCE_EXTENSION_RESOURCE)) {
- ESourceResource *resource;
- ESource *child;
-
- resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
- child = e_collection_backend_new_child (collection, e_source_resource_get_identity
(resource));
- if (child) {
- e_source_registry_server_add_source (server, source);
- g_object_unref (child);
- }
- }
- }
-
- g_list_free_full (list, g_object_unref);
- g_object_unref (server);
-
- source = e_backend_get_source (E_BACKEND (collection));
- collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
-
- if (e_source_get_enabled (source) && (
- e_source_collection_get_calendar_enabled (collection_extension) ||
- e_source_collection_get_contacts_enabled (collection_extension))) {
- e_backend_schedule_credentials_required (E_BACKEND (collection),
- E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL, NULL, G_STRFUNC);
- }
+ return e_webdav_collection_backend_discover_sync (E_WEBDAV_COLLECTION_BACKEND (backend),
+ e_source_goa_get_calendar_url (goa_extension),
+ e_source_goa_get_contacts_url (goa_extension),
+ credentials, out_certificate_pem, out_certificate_errors, cancellable, error);
}
static void
e_owncloud_backend_class_init (EOwncloudBackendClass *class)
{
EBackendClass *backend_class;
- ECollectionBackendClass *collection_backend_class;
backend_class = E_BACKEND_CLASS (class);
backend_class->authenticate_sync = owncloud_backend_authenticate_sync;
-
- collection_backend_class = E_COLLECTION_BACKEND_CLASS (class);
- collection_backend_class->populate = owncloud_backend_populate;
}
static void
diff --git a/src/modules/yahoo-backend/module-yahoo-backend.c
b/src/modules/yahoo-backend/module-yahoo-backend.c
index 0a34236..2d98870 100644
--- a/src/modules/yahoo-backend/module-yahoo-backend.c
+++ b/src/modules/yahoo-backend/module-yahoo-backend.c
@@ -43,15 +43,9 @@
#define YAHOO_SMTP_PORT 465
#define YAHOO_SMTP_SECURITY_METHOD METHOD (SSL_ON_ALTERNATE_PORT)
-/* Calendar Configuration Details */
-#define YAHOO_CALENDAR_BACKEND_NAME "caldav"
-#define YAHOO_CALENDAR_HOST "caldav.calendar.yahoo.com"
-#define YAHOO_CALENDAR_CALDAV_PATH "/dav/%s/Calendar/%s"
-#define YAHOO_CALENDAR_RESOURCE_ID "Calendar"
+/* WebDAV Configuration Details */
+#define YAHOO_WEBDAV_URL "https://caldav.calendar.yahoo.com/dav/"
-/* Tasks Configuration Details
- * (mostly the same as calendar) */
-#define YAHOO_TASKS_RESOURCE_ID "Tasks"
typedef struct _EYahooBackend EYahooBackend;
typedef struct _EYahooBackendClass EYahooBackendClass;
@@ -60,12 +54,12 @@ typedef struct _EYahooBackendFactory EYahooBackendFactory;
typedef struct _EYahooBackendFactoryClass EYahooBackendFactoryClass;
struct _EYahooBackend {
- ECollectionBackend parent;
+ EWebDAVCollectionBackend parent;
GWeakRef mail_identity_source;
};
struct _EYahooBackendClass {
- ECollectionBackendClass parent_class;
+ EWebDAVCollectionBackendClass parent_class;
};
struct _EYahooBackendFactory {
@@ -87,191 +81,26 @@ GType e_yahoo_backend_factory_get_type (void);
G_DEFINE_DYNAMIC_TYPE (
EYahooBackend,
e_yahoo_backend,
- E_TYPE_COLLECTION_BACKEND)
+ E_TYPE_WEBDAV_COLLECTION_BACKEND)
G_DEFINE_DYNAMIC_TYPE (
EYahooBackendFactory,
e_yahoo_backend_factory,
E_TYPE_COLLECTION_BACKEND_FACTORY)
-static void
-yahoo_backend_config_calendar_child (ECollectionBackend *backend,
- ESource *source)
+static ESourceAuthenticationResult
+yahoo_backend_authenticate_sync (EBackend *backend,
+ const ENamedParameters *credentials,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors,
+ GCancellable *cancellable,
+ GError **error)
{
- EYahooBackend *yahoo_backend;
- ESource *collection_source;
- ESource *mail_identity_source;
- ESourceExtension *extension;
- ESourceCollection *collection_extension;
- const gchar *extension_name;
- const gchar *identity;
- gchar *display_name = NULL;
-
- /* FIXME As a future enhancement, we should query Yahoo!
- * for a list of user calendars and add them to the
- * collection with matching display names and colors. */
-
- yahoo_backend = E_YAHOO_BACKEND (backend);
-
- collection_source = e_backend_get_source (E_BACKEND (backend));
-
- collection_extension = e_source_get_extension (
- collection_source, E_SOURCE_EXTENSION_COLLECTION);
-
- identity = e_source_collection_get_identity (collection_extension);
-
- /* XXX Assume the calendar's display name can be derived from
- * the user's mail identity. As mentioned above, we should
- * really just query Yahoo! for a list of user calendars. */
- mail_identity_source =
- g_weak_ref_get (&yahoo_backend->mail_identity_source);
- if (mail_identity_source != NULL) {
- extension = e_source_get_extension (
- mail_identity_source,
- E_SOURCE_EXTENSION_MAIL_IDENTITY);
- display_name = e_source_mail_identity_dup_name (
- E_SOURCE_MAIL_IDENTITY (extension));
- if (display_name != NULL)
- g_strdelimit (display_name, " ", '_');
- g_object_unref (mail_identity_source);
- }
-
- extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
- extension = e_source_get_extension (source, extension_name);
-
- e_source_authentication_set_host (
- E_SOURCE_AUTHENTICATION (extension),
- YAHOO_CALENDAR_HOST);
-
- e_binding_bind_property (
- collection_extension, "identity",
- extension, "user",
- G_BINDING_SYNC_CREATE);
+ g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), E_SOURCE_AUTHENTICATION_ERROR);
- extension_name = E_SOURCE_EXTENSION_SECURITY;
- extension = e_source_get_extension (source, extension_name);
-
- e_source_security_set_secure (
- E_SOURCE_SECURITY (extension), TRUE);
-
- extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
- extension = e_source_get_extension (source, extension_name);
-
- e_source_webdav_set_display_name (
- E_SOURCE_WEBDAV (extension), display_name);
-
- if (identity != NULL && display_name != NULL) {
- gchar *resource_path;
-
- resource_path = g_strdup_printf (
- YAHOO_CALENDAR_CALDAV_PATH, identity, display_name);
- e_source_webdav_set_resource_path (
- E_SOURCE_WEBDAV (extension), resource_path);
- g_free (resource_path);
- }
-
- g_free (display_name);
-}
-
-static void
-yahoo_backend_add_calendar (ECollectionBackend *backend)
-{
- ESource *source;
- ESourceBackend *extension;
- ESourceRegistryServer *server;
- const gchar *backend_name;
- const gchar *extension_name;
- const gchar *resource_id;
-
- /* XXX We could just stick a [Calendar] and [Task List] extension
- * into the same ESource since all other settings are exactly
- * the same. But it might be confusing if tweaking a setting
- * in your Yahoo! Calendar also gets applied to your Yahoo!
- * Task List in Evolution. */
-
- backend_name = YAHOO_CALENDAR_BACKEND_NAME;
-
- server = e_collection_backend_ref_server (backend);
-
- /* Add Yahoo! Calendar */
-
- resource_id = YAHOO_CALENDAR_RESOURCE_ID;
- source = e_collection_backend_new_child (backend, resource_id);
- e_source_set_display_name (source, _("Calendar"));
-
- extension_name = E_SOURCE_EXTENSION_CALENDAR;
- extension = e_source_get_extension (source, extension_name);
- e_source_backend_set_backend_name (extension, backend_name);
-
- extension_name = E_SOURCE_EXTENSION_ALARMS;
- extension = e_source_get_extension (source, extension_name);
- if (!e_source_alarms_get_last_notified (E_SOURCE_ALARMS (extension))) {
- GTimeVal today_tv;
- gchar *today;
-
- g_get_current_time (&today_tv);
- today = g_time_val_to_iso8601 (&today_tv);
- e_source_alarms_set_last_notified (E_SOURCE_ALARMS (extension), today);
- g_free (today);
- }
-
- yahoo_backend_config_calendar_child (backend, source);
- e_source_registry_server_add_source (server, source);
-
- g_object_unref (source);
-
- /* Add Yahoo! Tasks */
-
- resource_id = YAHOO_TASKS_RESOURCE_ID;
- source = e_collection_backend_new_child (backend, resource_id);
- e_source_set_display_name (source, _("Tasks"));
-
- extension_name = E_SOURCE_EXTENSION_TASK_LIST;
- extension = e_source_get_extension (source, extension_name);
- e_source_backend_set_backend_name (extension, backend_name);
-
- yahoo_backend_config_calendar_child (backend, source);
- e_source_registry_server_add_source (server, source);
-
- g_object_unref (source);
-
- g_object_unref (server);
-}
-
-static void
-yahoo_backend_populate (ECollectionBackend *backend)
-{
- GList *list;
-
- /* Chain up to parent's populate() method. */
- E_COLLECTION_BACKEND_CLASS (e_yahoo_backend_parent_class)->
- populate (backend);
-
- /* Chain up first so we pick up the mail identity source. */
- list = e_collection_backend_list_calendar_sources (backend);
- if (list == NULL)
- yahoo_backend_add_calendar (backend);
- g_list_free_full (list, (GDestroyNotify) g_object_unref);
-}
-
-static gchar *
-yahoo_backend_dup_resource_id (ECollectionBackend *backend,
- ESource *child_source)
-{
- const gchar *extension_name;
-
- /* XXX This is trival for now since we only
- * add one calendar and one task list. */
-
- extension_name = E_SOURCE_EXTENSION_CALENDAR;
- if (e_source_has_extension (child_source, extension_name))
- return g_strdup (YAHOO_CALENDAR_RESOURCE_ID);
-
- extension_name = E_SOURCE_EXTENSION_TASK_LIST;
- if (e_source_has_extension (child_source, extension_name))
- return g_strdup (YAHOO_TASKS_RESOURCE_ID);
-
- return NULL;
+ return e_webdav_collection_backend_discover_sync (E_WEBDAV_COLLECTION_BACKEND (backend),
+ YAHOO_WEBDAV_URL, YAHOO_WEBDAV_URL, credentials,
+ out_certificate_pem, out_certificate_errors, cancellable, error);
}
static void
@@ -351,15 +180,17 @@ static void
e_yahoo_backend_class_init (EYahooBackendClass *class)
{
GObjectClass *object_class;
- ECollectionBackendClass *backend_class;
+ EBackendClass *backend_class;
+ ECollectionBackendClass *collection_backend_class;
object_class = G_OBJECT_CLASS (class);
object_class->finalize = yahoo_backend_finalize;
- backend_class = E_COLLECTION_BACKEND_CLASS (class);
- backend_class->populate = yahoo_backend_populate;
- backend_class->dup_resource_id = yahoo_backend_dup_resource_id;
- backend_class->child_added = yahoo_backend_child_added;
+ backend_class = E_BACKEND_CLASS (class);
+ backend_class->authenticate_sync = yahoo_backend_authenticate_sync;
+
+ collection_backend_class = E_COLLECTION_BACKEND_CLASS (class);
+ collection_backend_class->child_added = yahoo_backend_child_added;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]