From 00740be9b52cce08611062a4b3e5b5e75e7b8c86 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Tue, 12 Feb 2013 13:21:06 +0100 Subject: [PATCH] Bug #686528 - Pickup ownCloud accounts from GOA --- configure.ac | 1 + libedataserver/e-source-goa.c | 231 ++++++++- libedataserver/e-source-goa.h | 8 + libedataserver/e-source-webdav.c | 84 +++- libedataserver/e-source-webdav.h | 6 + modules/Makefile.am | 1 + .../module-gnome-online-accounts.c | 116 +++-- modules/owncloud-backend/Makefile.am | 31 ++ modules/owncloud-backend/module-owncloud-backend.c | 344 +++++++++++++ modules/owncloud-backend/owncloud-utils.c | 558 +++++++++++++++++++++ modules/owncloud-backend/owncloud-utils.h | 47 ++ 11 files changed, 1367 insertions(+), 60 deletions(-) create mode 100644 modules/owncloud-backend/Makefile.am create mode 100644 modules/owncloud-backend/module-owncloud-backend.c create mode 100644 modules/owncloud-backend/owncloud-utils.c create mode 100644 modules/owncloud-backend/owncloud-utils.h diff --git a/configure.ac b/configure.ac index 77d035d..710fa98 100644 --- a/configure.ac +++ b/configure.ac @@ -1701,6 +1701,7 @@ modules/Makefile modules/cache-reaper/Makefile modules/gnome-online-accounts/Makefile modules/google-backend/Makefile +modules/owncloud-backend/Makefile modules/ubuntu-online-accounts/Makefile modules/ubuntu-online-accounts/calendar.service-type.in modules/ubuntu-online-accounts/contacts.service-type.in diff --git a/libedataserver/e-source-goa.c b/libedataserver/e-source-goa.c index 5cff646..2856ab8 100644 --- a/libedataserver/e-source-goa.c +++ b/libedataserver/e-source-goa.c @@ -47,11 +47,15 @@ struct _ESourceGoaPrivate { GMutex property_lock; gchar *account_id; + gchar *calendar_url; + gchar *contacts_url; }; enum { PROP_0, - PROP_ACCOUNT_ID + PROP_ACCOUNT_ID, + PROP_CALENDAR_URL, + PROP_CONTACTS_URL }; G_DEFINE_TYPE ( @@ -71,6 +75,18 @@ source_goa_set_property (GObject *object, E_SOURCE_GOA (object), g_value_get_string (value)); return; + + case PROP_CALENDAR_URL: + e_source_goa_set_calendar_url ( + E_SOURCE_GOA (object), + g_value_get_string (value)); + return; + + case PROP_CONTACTS_URL: + e_source_goa_set_contacts_url ( + E_SOURCE_GOA (object), + g_value_get_string (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -89,6 +105,20 @@ source_goa_get_property (GObject *object, e_source_goa_dup_account_id ( E_SOURCE_GOA (object))); return; + + case PROP_CALENDAR_URL: + g_value_take_string ( + value, + e_source_goa_dup_calendar_url ( + E_SOURCE_GOA (object))); + return; + + case PROP_CONTACTS_URL: + g_value_take_string ( + value, + e_source_goa_dup_contacts_url ( + E_SOURCE_GOA (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -104,6 +134,8 @@ source_goa_finalize (GObject *object) g_mutex_clear (&priv->property_lock); g_free (priv->account_id); + g_free (priv->calendar_url); + g_free (priv->contacts_url); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_source_goa_parent_class)->finalize (object); @@ -137,6 +169,32 @@ e_source_goa_class_init (ESourceGoaClass *class) G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_CALENDAR_URL, + g_param_spec_string ( + "calendar-url", + "Calendar URL", + "GNOME Online Calendar URL", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_CONTACTS_URL, + g_param_spec_string ( + "contacts-url", + "Contacts URL", + "GNOME Online Contacts URL", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS | + E_SOURCE_PARAM_SETTING)); } static void @@ -231,3 +289,174 @@ e_source_goa_set_account_id (ESourceGoa *extension, g_object_notify (G_OBJECT (extension), "account-id"); } +/** + * e_source_goa_get_calendar_url: + * @extension: an #ESourceGoa + * + * Returns the calendar URL string of the GNOME Online Account associated + * with the #ESource to which @extension belongs. Can be %NULL or an empty + * string for accounts not supporting this property. + * + * Returns: the associated GNOME Online Account calendar URL + * + * Since: 3.8 + **/ +const gchar * +e_source_goa_get_calendar_url (ESourceGoa *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_GOA (extension), NULL); + + return extension->priv->calendar_url; +} + +/** + * e_source_goa_dup_calendar_url: + * @extension: an #ESourceGoa + * + * Thread-safe variation of e_source_goa_get_calendar_url(). + * Use this function when accessing @extension from multiple threads. + * + * The returned string should be freed with g_free() when no longer needed. + * + * Returns: a newly-allocated copy of #ESourceGoa:calendar-url + * + * Since: 3.8 + **/ +gchar * +e_source_goa_dup_calendar_url (ESourceGoa *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_GOA (extension), NULL); + + g_mutex_lock (&extension->priv->property_lock); + + protected = e_source_goa_get_calendar_url (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (&extension->priv->property_lock); + + return duplicate; +} + +/** + * e_source_goa_set_calendar_url: + * @extension: an #ESourceGoa + * @calendar_url: (allow-none): the associated GNOME Online Account calendar URL, or %NULL + * + * Sets the calendar URL of the GNOME Online Account associated + * with the #ESource to which @extension belongs. + * + * The internal copy of @calendar_url is automatically stripped of leading + * and trailing whitespace. If the resulting string is empty, %NULL is set + * instead. + * + * Since: 3.8 + **/ +void +e_source_goa_set_calendar_url (ESourceGoa *extension, + const gchar *calendar_url) +{ + g_return_if_fail (E_IS_SOURCE_GOA (extension)); + + g_mutex_lock (&extension->priv->property_lock); + + if (g_strcmp0 (extension->priv->calendar_url, calendar_url) == 0) { + g_mutex_unlock (&extension->priv->property_lock); + return; + } + + g_free (extension->priv->calendar_url); + extension->priv->calendar_url = e_util_strdup_strip (calendar_url); + + g_mutex_unlock (&extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "calendar-url"); +} + +/** + * e_source_goa_get_contacts_url: + * @extension: an #ESourceGoa + * + * Returns the contacts URL string of the GNOME Online Account associated + * with the #ESource to which @extension belongs. Can be %NULL or an empty + * string for accounts not supporting this property. + * + * Returns: the associated GNOME Online Account contacts URL + * + * Since: 3.8 + **/ +const gchar * +e_source_goa_get_contacts_url (ESourceGoa *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_GOA (extension), NULL); + + return extension->priv->contacts_url; +} + +/** + * e_source_goa_dup_contacts_url: + * @extension: an #ESourceGoa + * + * Thread-safe variation of e_source_goa_get_contacts_url(). + * Use this function when accessing @extension from multiple threads. + * + * The returned string should be freed with g_free() when no longer needed. + * + * Returns: a newly-allocated copy of #ESourceGoa:contacts-url + * + * Since: 3.8 + **/ +gchar * +e_source_goa_dup_contacts_url (ESourceGoa *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_GOA (extension), NULL); + + g_mutex_lock (&extension->priv->property_lock); + + protected = e_source_goa_get_contacts_url (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (&extension->priv->property_lock); + + return duplicate; +} + +/** + * e_source_goa_set_contacts_url: + * @extension: an #ESourceGoa + * @contacts_url: (allow-none): the associated GNOME Online Account contacts URL, or %NULL + * + * Sets the contacts URL of the GNOME Online Account associated + * with the #ESource to which @extension belongs. + * + * The internal copy of @contacts_url is automatically stripped of leading + * and trailing whitespace. If the resulting string is empty, %NULL is set + * instead. + * + * Since: 3.8 + **/ +void +e_source_goa_set_contacts_url (ESourceGoa *extension, + const gchar *contacts_url) +{ + g_return_if_fail (E_IS_SOURCE_GOA (extension)); + + g_mutex_lock (&extension->priv->property_lock); + + if (g_strcmp0 (extension->priv->contacts_url, contacts_url) == 0) { + g_mutex_unlock (&extension->priv->property_lock); + return; + } + + g_free (extension->priv->contacts_url); + extension->priv->contacts_url = e_util_strdup_strip (contacts_url); + + g_mutex_unlock (&extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "contacts-url"); +} diff --git a/libedataserver/e-source-goa.h b/libedataserver/e-source-goa.h index bbbbb67..02fa321 100644 --- a/libedataserver/e-source-goa.h +++ b/libedataserver/e-source-goa.h @@ -82,6 +82,14 @@ const gchar * e_source_goa_get_account_id (ESourceGoa *extension); gchar * e_source_goa_dup_account_id (ESourceGoa *extension); void e_source_goa_set_account_id (ESourceGoa *extension, const gchar *account_id); +const gchar * e_source_goa_get_calendar_url (ESourceGoa *extension); +gchar * e_source_goa_dup_calendar_url (ESourceGoa *extension); +void e_source_goa_set_calendar_url (ESourceGoa *extension, + const gchar *calendar_url); +const gchar * e_source_goa_get_contacts_url (ESourceGoa *extension); +gchar * e_source_goa_dup_contacts_url (ESourceGoa *extension); +void e_source_goa_set_contacts_url (ESourceGoa *extension, + const gchar *contacts_url); G_END_DECLS diff --git a/libedataserver/e-source-webdav.c b/libedataserver/e-source-webdav.c index d396860..482d5e4 100644 --- a/libedataserver/e-source-webdav.c +++ b/libedataserver/e-source-webdav.c @@ -1369,6 +1369,61 @@ e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension, ESourceRegistry *registry, ENamedParameters *parameters) { + ESource *source, *parent_source = NULL; + ETrustPromptResponse res; + + g_return_val_if_fail ( + E_IS_SOURCE_WEBDAV (extension), + E_TRUST_PROMPT_RESPONSE_REJECT); + g_return_val_if_fail ( + SOUP_IS_MESSAGE (message), + E_TRUST_PROMPT_RESPONSE_REJECT); + g_return_val_if_fail ( + E_IS_SOURCE_REGISTRY (registry), + E_TRUST_PROMPT_RESPONSE_REJECT); + g_return_val_if_fail ( + parameters != NULL, + E_TRUST_PROMPT_RESPONSE_REJECT); + + source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension)); + if (source != NULL) { + const gchar *parent_uid; + + parent_uid = e_source_get_parent (source); + + if (parent_uid != NULL) + parent_source = e_source_registry_ref_source (registry, parent_uid); + + g_object_unref (source); + } + + res = e_source_webdav_prepare_ssl_trust_prompt_with_parent (extension, message, parent_source, parameters); + + if (parent_source) + g_object_unref (parent_source); + + return res; +} + +/** + * e_source_webdav_prepare_ssl_trust_prompt_with_parent: + * @extension: an #ESourceWebdav + * @message: a #SoupMessage with #SOUP_STATUS_SSL_FAILED status code + * @parent_source: an #ESource, parent of the @extension's source + * @parameters: an #ENamedParameters to be populated + * + * The same as e_source_webdav_prepare_ssl_trust_prompt(), only takes @parent_source + * directly, instead of an #ESourceRegistry. See e_source_webdav_prepare_ssl_trust_prompt() + * for more details. + * + * Since: 3.8 + **/ +ETrustPromptResponse +e_source_webdav_prepare_ssl_trust_prompt_with_parent (ESourceWebdav *extension, + SoupMessage *message, + ESource *parent_source, + ENamedParameters *parameters) +{ ETrustPromptResponse response; ESource *source; GTlsCertificate *cert = NULL; @@ -1385,9 +1440,10 @@ e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension, g_return_val_if_fail ( SOUP_IS_MESSAGE (message), E_TRUST_PROMPT_RESPONSE_REJECT); - g_return_val_if_fail ( - E_IS_SOURCE_REGISTRY (registry), - E_TRUST_PROMPT_RESPONSE_REJECT); + if (parent_source) + g_return_val_if_fail ( + E_IS_SOURCE (parent_source), + E_TRUST_PROMPT_RESPONSE_REJECT); g_return_val_if_fail ( parameters != NULL, E_TRUST_PROMPT_RESPONSE_REJECT); @@ -1439,30 +1495,16 @@ e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension, source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension)); if (source != NULL) { const gchar *display_name; - const gchar *parent_uid; gchar *bhost = g_strconcat ("", host, "", NULL); gchar *bname = NULL; display_name = e_source_get_display_name (source); - parent_uid = e_source_get_parent (source); - - if (parent_uid != NULL) { - ESource *parent = NULL; - parent = e_source_registry_ref_source ( - registry, parent_uid); + if (parent_source != NULL) { + const gchar *parent_display_name; - if (parent != NULL) { - const gchar *parent_display_name; - - parent_display_name = - e_source_get_display_name (parent); - bname = g_strdup_printf ( - "%s: %s", - parent_display_name, - display_name); - g_object_unref (parent); - } + parent_display_name = e_source_get_display_name (parent_source); + bname = g_strdup_printf ("%s: %s", parent_display_name, display_name); } if (bname == NULL) diff --git a/libedataserver/e-source-webdav.h b/libedataserver/e-source-webdav.h index 93cd8c5..d6a4957 100644 --- a/libedataserver/e-source-webdav.h +++ b/libedataserver/e-source-webdav.h @@ -135,6 +135,12 @@ ETrustPromptResponse SoupMessage *message, struct _ESourceRegistry *registry, struct _ENamedParameters *parameters); +ETrustPromptResponse + e_source_webdav_prepare_ssl_trust_prompt_with_parent + (ESourceWebdav *extension, + SoupMessage *message, + ESource *parent_source, + struct _ENamedParameters *parameters); void e_source_webdav_store_ssl_trust_prompt (ESourceWebdav *extension, SoupMessage *message, diff --git a/modules/Makefile.am b/modules/Makefile.am index a9014e1..19d96b2 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -15,6 +15,7 @@ endif SUBDIRS = \ cache-reaper \ google-backend \ + owncloud-backend \ yahoo-backend \ $(TRUST_PROMPT_DIR) \ $(GNOME_ONLINE_ACCOUNTS_DIR) \ diff --git a/modules/gnome-online-accounts/module-gnome-online-accounts.c b/modules/gnome-online-accounts/module-gnome-online-accounts.c index 16a96be..62c06e5 100644 --- a/modules/gnome-online-accounts/module-gnome-online-accounts.c +++ b/modules/gnome-online-accounts/module-gnome-online-accounts.c @@ -117,6 +117,9 @@ gnome_online_accounts_get_backend_name (const gchar *goa_provider_type) if (g_str_equal (goa_provider_type, "yahoo")) eds_backend_name = "yahoo"; + if (g_str_equal (goa_provider_type, "owncloud")) + eds_backend_name = "owncloud"; + return eds_backend_name; } @@ -500,8 +503,12 @@ gnome_online_accounts_config_collection (EGnomeOnlineAccounts *extension, GoaAccount *goa_account; ESourceExtension *source_extension; const gchar *extension_name; + const gchar *provider_type; + const gchar *backend_name; goa_account = goa_object_get_account (goa_object); + provider_type = goa_account_get_provider_type (goa_account); + backend_name = gnome_online_accounts_get_backend_name (provider_type); g_object_bind_property ( goa_account, "presentation-identity", @@ -516,6 +523,33 @@ gnome_online_accounts_config_collection (EGnomeOnlineAccounts *extension, source_extension, "account-id", G_BINDING_SYNC_CREATE); + /* requires more properties from ownCould, but these are not + available before ownCloud was introduced, thus workaround + it with the backend_name check + */ + if (g_strcmp0 (backend_name, "owncloud") == 0) { + GoaCalendar *goa_calendar; + GoaContacts *goa_contacts; + + goa_calendar = goa_object_get_calendar (goa_object); + if (goa_calendar) { + g_object_bind_property ( + goa_calendar, "uri", + source_extension, "calendar-url", + G_BINDING_SYNC_CREATE); + g_object_unref (goa_calendar); + } + + goa_contacts = goa_object_get_contacts (goa_object); + if (goa_contacts) { + g_object_bind_property ( + goa_contacts, "uri", + source_extension, "contacts-url", + G_BINDING_SYNC_CREATE); + g_object_unref (goa_contacts); + } + } + extension_name = E_SOURCE_EXTENSION_COLLECTION; source_extension = e_source_get_extension (source, extension_name); @@ -705,9 +739,9 @@ gnome_online_accounts_create_collection (EGnomeOnlineAccounts *extension, GoaAccount *goa_account; ESourceRegistryServer *server; ESource *collection_source; - ESource *mail_account_source; - ESource *mail_identity_source; - ESource *mail_transport_source; + ESource *mail_account_source = NULL; + ESource *mail_identity_source = NULL; + ESource *mail_transport_source = NULL; const gchar *account_id; const gchar *parent_uid; @@ -716,43 +750,53 @@ gnome_online_accounts_create_collection (EGnomeOnlineAccounts *extension, collection_source = gnome_online_accounts_new_source (extension); g_return_if_fail (E_IS_SOURCE (collection_source)); - mail_account_source = gnome_online_accounts_new_source (extension); - g_return_if_fail (E_IS_SOURCE (mail_account_source)); + gnome_online_accounts_config_collection (extension, collection_source, goa_object); + parent_uid = e_source_get_uid (collection_source); - mail_identity_source = gnome_online_accounts_new_source (extension); - g_return_if_fail (E_IS_SOURCE (mail_identity_source)); + if (goa_object_peek_mail (goa_object)) { + mail_account_source = gnome_online_accounts_new_source (extension); + g_return_if_fail (E_IS_SOURCE (mail_account_source)); - mail_transport_source = gnome_online_accounts_new_source (extension); - g_return_if_fail (E_IS_SOURCE (mail_transport_source)); + mail_identity_source = gnome_online_accounts_new_source (extension); + g_return_if_fail (E_IS_SOURCE (mail_identity_source)); - /* Configure parent/child relationships. */ - parent_uid = e_source_get_uid (collection_source); - e_source_set_parent (mail_account_source, parent_uid); - e_source_set_parent (mail_identity_source, parent_uid); - e_source_set_parent (mail_transport_source, parent_uid); - - /* Give the factory first crack at mail configuration. */ - e_collection_backend_factory_prepare_mail ( - E_COLLECTION_BACKEND_FACTORY (backend_factory), - mail_account_source, - mail_identity_source, - mail_transport_source); - - /* Now it's our turn. */ - gnome_online_accounts_config_collection ( - extension, collection_source, goa_object); - gnome_online_accounts_config_mail_account ( - extension, mail_account_source, goa_object); - gnome_online_accounts_config_mail_identity ( - extension, mail_identity_source, goa_object); - gnome_online_accounts_config_mail_transport ( - extension, mail_transport_source, goa_object); + mail_transport_source = gnome_online_accounts_new_source (extension); + g_return_if_fail (E_IS_SOURCE (mail_transport_source)); + + /* Configure parent/child relationships. */ + e_source_set_parent (mail_account_source, parent_uid); + e_source_set_parent (mail_identity_source, parent_uid); + e_source_set_parent (mail_transport_source, parent_uid); + + /* Give the factory first crack at mail configuration. */ + e_collection_backend_factory_prepare_mail ( + E_COLLECTION_BACKEND_FACTORY (backend_factory), + mail_account_source, + mail_identity_source, + mail_transport_source); + + gnome_online_accounts_config_mail_account (extension, mail_account_source, goa_object); + gnome_online_accounts_config_mail_identity (extension, mail_identity_source, goa_object); + gnome_online_accounts_config_mail_transport (extension, mail_transport_source, goa_object); + } /* Export the new source collection. */ e_source_registry_server_add_source (server, collection_source); - e_source_registry_server_add_source (server, mail_account_source); - e_source_registry_server_add_source (server, mail_identity_source); - e_source_registry_server_add_source (server, mail_transport_source); + + if (mail_account_source) { + e_source_registry_server_add_source (server, mail_account_source); + g_object_unref (mail_account_source); + } + + if (mail_identity_source) { + e_source_registry_server_add_source (server, mail_identity_source); + g_object_unref (mail_identity_source); + } + + if (mail_transport_source) { + e_source_registry_server_add_source (server, mail_transport_source); + g_object_unref (mail_transport_source); + } goa_account = goa_object_get_account (goa_object); account_id = goa_account_get_id (goa_account); @@ -763,11 +807,7 @@ gnome_online_accounts_create_collection (EGnomeOnlineAccounts *extension, g_strdup (parent_uid)); g_object_unref (goa_account); - g_object_unref (collection_source); - g_object_unref (mail_account_source); - g_object_unref (mail_identity_source); - g_object_unref (mail_transport_source); } static void diff --git a/modules/owncloud-backend/Makefile.am b/modules/owncloud-backend/Makefile.am new file mode 100644 index 0000000..14bf232 --- /dev/null +++ b/modules/owncloud-backend/Makefile.am @@ -0,0 +1,31 @@ +NULL = + +module_LTLIBRARIES = module-owncloud-backend.la + +module_owncloud_backend_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -DG_LOG_DOMAIN=\"module-owncloud-backend\" \ + $(E_BACKEND_CFLAGS) \ + $(E_DATA_SERVER_CFLAGS) \ + $(NULL) + +module_owncloud_backend_la_SOURCES = \ + module-owncloud-backend.c \ + owncloud-utils.c \ + owncloud-utils.h \ + $(NULL) + +module_owncloud_backend_la_LIBADD = \ + $(top_builddir)/libebackend/libebackend-1.2.la \ + $(top_builddir)/libedataserver/libedataserver-1.2.la \ + $(top_builddir)/camel/libcamel-1.2.la \ + $(E_BACKEND_LIBS) \ + $(E_DATA_SERVER_LIBS) \ + $(NULL) + +module_owncloud_backend_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/modules/owncloud-backend/module-owncloud-backend.c b/modules/owncloud-backend/module-owncloud-backend.c new file mode 100644 index 0000000..2c04bd3 --- /dev/null +++ b/modules/owncloud-backend/module-owncloud-backend.c @@ -0,0 +1,344 @@ +/* + * module-owncloud-backend.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program 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 the program; if not, see + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "owncloud-utils.h" + +/* Standard GObject macros */ +#define E_TYPE_OWNCLOUD_BACKEND \ + (e_owncloud_backend_get_type ()) +#define E_OWNCLOUD_BACKEND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_OWNCLOUD_BACKEND, EOwncloudBackend)) + +typedef struct _EOwncloudBackend EOwncloudBackend; +typedef struct _EOwncloudBackendClass EOwncloudBackendClass; + +typedef struct _EOwncloudBackendFactory EOwncloudBackendFactory; +typedef struct _EOwncloudBackendFactoryClass EOwncloudBackendFactoryClass; + +struct _EOwncloudBackend { + ECollectionBackend parent; +}; + +struct _EOwncloudBackendClass { + ECollectionBackendClass parent_class; +}; + +struct _EOwncloudBackendFactory { + ECollectionBackendFactory parent; +}; + +struct _EOwncloudBackendFactoryClass { + ECollectionBackendFactoryClass parent_class; +}; + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +/* Forward Declarations */ +GType e_owncloud_backend_get_type (void); +GType e_owncloud_backend_factory_get_type (void); + +G_DEFINE_DYNAMIC_TYPE ( + EOwncloudBackend, + e_owncloud_backend, + E_TYPE_COLLECTION_BACKEND) + +G_DEFINE_DYNAMIC_TYPE ( + EOwncloudBackendFactory, + e_owncloud_backend_factory, + E_TYPE_COLLECTION_BACKEND_FACTORY) + +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_registry_server_remove_source (server, source); + g_object_unref (source); + } +} + +static void +owncloud_source_found_cb (ECollectionBackend *collection, + OwnCloudSourceType source_type, + SoupURI *uri, + const gchar *display_name, + const gchar *color, + gpointer user_data) +{ + GHashTable *known_sources = user_data; + 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 OwnCloud_Source_Contacts: + backend_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; + provider = "webdav"; + identity_prefix = "contacts"; + break; + case OwnCloud_Source_Events: + backend_name = E_SOURCE_EXTENSION_CALENDAR; + provider = "caldav"; + identity_prefix = "events"; + break; + case OwnCloud_Source_Memos: + backend_name = E_SOURCE_EXTENSION_MEMO_LIST; + provider = "caldav"; + identity_prefix = "memos"; + break; + case OwnCloud_Source_Tasks: + backend_name = E_SOURCE_EXTENSION_TASK_LIST; + provider = "caldav"; + identity_prefix = "tasks"; + break; + } + + g_return_if_fail (backend_name != NULL); + + server = e_collection_backend_ref_server (collection); + + 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) { + ESource *master_source; + + source = e_collection_backend_new_child (collection, identity); + g_warn_if_fail (source != NULL); + + if (source) { + 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); + child_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE); + + e_source_webdav_set_soup_uri (child_webdav, uri); + e_source_resource_set_identity (resource, identity); + + /* inherit ssl trust options */ + e_source_webdav_set_ssl_trust (child_webdav, e_source_webdav_get_ssl_trust (master_webdav)); + } + } else { + source = e_source_registry_server_ref_source (server, source_uid); + g_warn_if_fail (source != NULL); + + g_hash_table_remove (known_sources, identity); + } + + g_free (identity); + g_free (url); + + /* these properties are synchronized always */ + if (source) { + backend = e_source_get_extension (source, backend_name); + e_source_backend_set_backend_name (backend, provider); + + e_source_set_display_name (source, display_name); + if (source_type != OwnCloud_Source_Contacts && color) + e_source_selectable_set_color (E_SOURCE_SELECTABLE (backend), color); + + if (is_new) + e_source_registry_server_add_source (server, source); + + g_object_unref (source); + } + + g_object_unref (server); +} + +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 gpointer +owncloud_populate_thread (gpointer data) +{ + ECollectionBackend *collection = data; + GHashTable *known_sources; + GList *sources; + + g_return_val_if_fail (collection != NULL, NULL); + + /* 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 (owncloud_utils_search_server (collection, owncloud_source_found_cb, known_sources)) { + ESourceRegistryServer *server; + + server = e_collection_backend_ref_server (collection); + + g_hash_table_foreach (known_sources, owncloud_remove_unknown_sources_cb, server); + + g_object_unref (server); + } + + g_hash_table_destroy (known_sources); + g_object_unref (collection); + + return NULL; +} + +static void +owncloud_backend_populate (ECollectionBackend *collection) +{ + GList *list, *liter; + ESourceRegistryServer *server; + GThread *thread; + + /* 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); + + thread = g_thread_new (NULL, owncloud_populate_thread, g_object_ref (collection)); + g_thread_unref (thread); +} + +static void +e_owncloud_backend_class_init (EOwncloudBackendClass *class) +{ + ECollectionBackendClass *backend_class; + + backend_class = E_COLLECTION_BACKEND_CLASS (class); + backend_class->populate = owncloud_backend_populate; +} + +static void +e_owncloud_backend_class_finalize (EOwncloudBackendClass *class) +{ +} + +static void +e_owncloud_backend_init (EOwncloudBackend *backend) +{ +} + +static void +e_owncloud_backend_factory_class_init (EOwncloudBackendFactoryClass *class) +{ + ECollectionBackendFactoryClass *factory_class; + + factory_class = E_COLLECTION_BACKEND_FACTORY_CLASS (class); + factory_class->factory_name = "owncloud"; + factory_class->backend_type = E_TYPE_OWNCLOUD_BACKEND; +} + +static void +e_owncloud_backend_factory_class_finalize (EOwncloudBackendFactoryClass *class) +{ +} + +static void +e_owncloud_backend_factory_init (EOwncloudBackendFactory *factory) +{ +} + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + e_owncloud_backend_register_type (type_module); + e_owncloud_backend_factory_register_type (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/modules/owncloud-backend/owncloud-utils.c b/modules/owncloud-backend/owncloud-utils.c new file mode 100644 index 0000000..8b652c5 --- /dev/null +++ b/modules/owncloud-backend/owncloud-utils.c @@ -0,0 +1,558 @@ +/* + * owncloud-utils.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program 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 the program; if not, see + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +#include "owncloud-utils.h" + +typedef struct _EOwncloudAuthenticator EOwncloudAuthenticator; +typedef struct _EOwncloudAuthenticatorClass EOwncloudAuthenticatorClass; + +struct _EOwncloudAuthenticator { + GObject parent; + + ECollectionBackend *collection; + gchar *username; + GString *password; +}; + +struct _EOwncloudAuthenticatorClass { + GObjectClass parent_class; +}; + +static ESourceAuthenticationResult +owncloud_authenticator_try_password_sync (ESourceAuthenticator *auth, + const GString *password, + GCancellable *cancellable, + GError **error) +{ + EOwncloudAuthenticator *authenticator = (EOwncloudAuthenticator *) auth; + + if (authenticator->password) + g_string_free (authenticator->password, TRUE); + authenticator->password = g_string_new (password->str); + + return E_SOURCE_AUTHENTICATION_ACCEPTED; +} + +#define E_TYPE_OWNCLOUD_AUTHENTICATOR (e_owncloud_authenticator_get_type ()) + +GType e_owncloud_authenticator_get_type (void) G_GNUC_CONST; + +static void e_owncloud_authenticator_authenticator_init (ESourceAuthenticatorInterface *interface); + +G_DEFINE_TYPE_EXTENDED (EOwncloudAuthenticator, e_owncloud_authenticator, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (E_TYPE_SOURCE_AUTHENTICATOR, e_owncloud_authenticator_authenticator_init)) + +static void +owncloud_authenticator_finalize (GObject *object) +{ + EOwncloudAuthenticator *authenticator = (EOwncloudAuthenticator *) object; + + g_free (authenticator->username); + if (authenticator->password) + g_string_free (authenticator->password, TRUE); + + G_OBJECT_CLASS (e_owncloud_authenticator_parent_class)->finalize (object); +} + +static void +e_owncloud_authenticator_class_init (EOwncloudAuthenticatorClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = owncloud_authenticator_finalize; +} + +static void +e_owncloud_authenticator_authenticator_init (ESourceAuthenticatorInterface *interface) +{ + interface->try_password_sync = owncloud_authenticator_try_password_sync; +} + +static void +e_owncloud_authenticator_init (EOwncloudAuthenticator *authenticator) +{ +} + +#define XPATH_STATUS "string(/D:multistatus/D:response[%d]/D:propstat/D:status)" +#define XPATH_HREF "string(/D:multistatus/D:response[%d]/D:href)" +#define XPATH_DISPLAY_NAME "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/D:displayname)" +#define XPATH_CALENDAR_COLOR "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/APL:calendar-color)" +#define XPATH_RESOURCE_TYPE_ADDRESSBOOK "/D:multistatus/D:response[%d]/D:propstat/D:prop/D:resourcetype/B:addressbook" +#define XPATH_RESOURCE_TYPE_CALENDAR "/D:multistatus/D:response[%d]/D:propstat/D:prop/D:resourcetype/C:calendar" +#define XPATH_SUPPORTED_CALENDAR_COMPONENT_SET "/D:multistatus/D:response[%d]/D:propstat/D:prop/C:supported-calendar-component-set/C:comp" +#define XPATH_CALENDAR_COMP_TYPE "string(" XPATH_SUPPORTED_CALENDAR_COMPONENT_SET "[%d]/@name)" + +static xmlXPathObjectPtr +xpath_eval (xmlXPathContextPtr ctx, + const gchar *format, + ...) +{ + xmlXPathObjectPtr xpres; + va_list args; + gchar *expr; + + if (ctx == NULL) + return NULL; + + va_start (args, format); + expr = g_strdup_vprintf (format, args); + va_end (args); + + xpres = xmlXPathEvalExpression ((xmlChar *) expr, ctx); + g_free (expr); + + if (xpres == NULL) + return NULL; + + if (xpres->type == XPATH_NODESET && + xmlXPathNodeSetIsEmpty (xpres->nodesetval)) { + xmlXPathFreeObject (xpres); + return NULL; + } + + return xpres; +} + +static guint +xp_object_get_status (xmlXPathObjectPtr xpres) +{ + gboolean res; + guint ret = 0; + + if (xpres == NULL) + return ret; + + if (xpres->type == XPATH_STRING) { + res = soup_headers_parse_status_line ( + (const gchar *) xpres->stringval, + NULL, + &ret, + NULL); + + if (!res) + ret = 0; + } + + xmlXPathFreeObject (xpres); + + return ret; +} + +static gchar * +xp_object_get_string (xmlXPathObjectPtr xpres) +{ + gchar *ret = NULL; + + if (xpres == NULL) + return ret; + + if (xpres->type == XPATH_STRING) { + ret = g_strdup ((gchar *) xpres->stringval); + } + + xmlXPathFreeObject (xpres); + + return ret; +} + +static void +add_source (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data, + OwnCloudSourceType source_type, + SoupURI *base_uri, + const gchar *href, + const gchar *display_name, + const gchar *color) +{ + SoupURI *uri = NULL; + + if (!href || !display_name) + return; + + if (!strstr (href, "://")) { + soup_uri_set_path (base_uri, href); + } else { + uri = soup_uri_new (href); + } + + found_cb (collection, source_type, uri ? uri : base_uri, display_name, color, user_data); + + if (uri) + soup_uri_free (uri); +} + +static void +enum_calendars (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data, + /* const */ xmlXPathContextPtr xpctx, + /* const */ xmlXPathObjectPtr xpathobj, + gint response_index, + SoupURI *base_uri, + const gchar *href, + const gchar *display_name, + const gchar *color) +{ + gint ii, nn; + + if (!href || !display_name || !xpctx || !xpathobj || xpathobj->type != XPATH_NODESET) + return; + + nn = xmlXPathNodeSetGetLength (xpathobj->nodesetval); + for (ii = 0; ii < nn; ii++) { + xmlXPathObjectPtr xpres; + gchar *comp_type; + + xpres = xpath_eval (xpctx, XPATH_CALENDAR_COMP_TYPE, response_index, ii + 1); + comp_type = xp_object_get_string (xpres); + + if (g_strcmp0 (comp_type, "VEVENT") == 0) { + add_source (collection, found_cb, user_data, OwnCloud_Source_Events, base_uri, href, display_name, color); + } else if (g_strcmp0 (comp_type, "VTODO") == 0) { + add_source (collection, found_cb, user_data, OwnCloud_Source_Tasks, base_uri, href, display_name, color); + } else if (g_strcmp0 (comp_type, "VJOURNAL") == 0) { + add_source (collection, found_cb, user_data, OwnCloud_Source_Memos, base_uri, href, display_name, color); + } + + g_free (comp_type); + } +} + +static void +parse_propfind_response (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data, + SoupURI *base_uri, + const gchar *body_str, + glong body_len) +{ + xmlXPathContextPtr xpctx; + xmlXPathObjectPtr xpathobj; + xmlDocPtr doc; + + if (!body_str || !body_len || !base_uri) + return; + + doc = xmlReadMemory (body_str, body_len, "response.xml", NULL, 0); + if (!doc) + return; + + xpctx = xmlXPathNewContext (doc); + xmlXPathRegisterNs (xpctx, (xmlChar *) "D", (xmlChar *) "DAV:"); + xmlXPathRegisterNs (xpctx, (xmlChar *) "B", (xmlChar *) "urn:ietf:params:xml:ns:carddav"); + xmlXPathRegisterNs (xpctx, (xmlChar *) "C", (xmlChar *) "urn:ietf:params:xml:ns:caldav"); + xmlXPathRegisterNs (xpctx, (xmlChar *) "CS", (xmlChar *) "http://calendarserver.org/ns/"); + xmlXPathRegisterNs (xpctx, (xmlChar *) "APL", (xmlChar *) "http://apple.com/ns/ical/"); + + xpathobj = xpath_eval (xpctx, "/D:multistatus/D:response"); + if (xpathobj && xpathobj->type == XPATH_NODESET) { + gint ii, nn; + gchar *href, *display_name, *color; + + nn = xmlXPathNodeSetGetLength (xpathobj->nodesetval); + for (ii = 0; ii < nn; ii++) { + xmlXPathObjectPtr xpres; + + xpres = xpath_eval (xpctx, XPATH_STATUS, ii + 1); + if (xp_object_get_status (xpres) != 200) + continue; + + xpres = xpath_eval (xpctx, XPATH_HREF, ii + 1); + href = xp_object_get_string (xpres); + + if (!href) + continue; + + xpres = xpath_eval (xpctx, XPATH_DISPLAY_NAME, ii + 1); + display_name = xp_object_get_string (xpres); + + xpres = xpath_eval (xpctx, XPATH_CALENDAR_COLOR, ii + 1); + color = xp_object_get_string (xpres); + + if (display_name && *display_name) { + xpres = xpath_eval (xpctx, XPATH_RESOURCE_TYPE_ADDRESSBOOK, ii + 1); + if (xpres) { + add_source (collection, found_cb, user_data, OwnCloud_Source_Contacts, base_uri, href, display_name, NULL); + xmlXPathFreeObject (xpres); + } + + xpres = xpath_eval (xpctx, XPATH_RESOURCE_TYPE_CALENDAR, ii + 1); + if (xpres) { + xmlXPathFreeObject (xpres); + + xpres = xpath_eval (xpctx, XPATH_SUPPORTED_CALENDAR_COMPONENT_SET, ii + 1); + if (xpres) { + enum_calendars (collection, found_cb, user_data, xpctx, xpres, ii + 1, base_uri, href, display_name, color); + xmlXPathFreeObject (xpres); + } + } + } + + g_free (display_name); + g_free (color); + g_free (href); + } + } + + if (xpathobj) + xmlXPathFreeObject (xpathobj); + xmlXPathFreeContext (xpctx); + xmlFreeDoc (doc); +} + +static void +authenticate_cb (SoupSession *session, + SoupMessage *msg, + SoupAuth *auth, + gboolean retrying, + gpointer user_data) +{ + EOwncloudAuthenticator *authenticator = user_data; + + g_return_if_fail (authenticator != NULL); + + if (retrying || !authenticator->password) { + ESourceRegistryServer *server; + EAuthenticationSession *auth_session; + ESource *source; + + source = e_backend_get_source (E_BACKEND (authenticator->collection)); + server = e_collection_backend_ref_server (authenticator->collection); + + auth_session = e_source_registry_server_new_auth_session (server, E_SOURCE_AUTHENTICATOR (authenticator), e_source_get_uid (source)); + if (!e_source_registry_server_authenticate_sync (server, auth_session, NULL, NULL)) { + if (authenticator->password) + g_string_free (authenticator->password, TRUE); + authenticator->password = NULL; + } + + g_object_unref (auth_session); + g_object_unref (server); + } + + if (authenticator->username && authenticator->password) + soup_auth_authenticate (auth, authenticator->username, authenticator->password->str); +} + +static ETrustPromptResponse +trust_prompt_sync (const ENamedParameters *parameters, + GCancellable *cancellable, + GError **error) +{ + EUserPrompter *prompter; + gint response; + + g_return_val_if_fail (parameters != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN); + + prompter = e_user_prompter_new (); + g_return_val_if_fail (prompter != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN); + + response = e_user_prompter_extension_prompt_sync (prompter, "ETrustPrompt::trust-prompt", parameters, NULL, cancellable, error); + + g_object_unref (prompter); + + if (response == 0) + return E_TRUST_PROMPT_RESPONSE_REJECT; + if (response == 1) + return E_TRUST_PROMPT_RESPONSE_ACCEPT; + if (response == 2) + return E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY; + if (response == -1) + return E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY; + + return E_TRUST_PROMPT_RESPONSE_UNKNOWN; +} + +static gboolean +find_sources (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data, + const gchar *base_url, + const gchar *base_collection_path, + EOwncloudAuthenticator *authenticator) +{ + const gchar *req_body = + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + SoupSession *session; + SoupMessage *msg; + GString *url; + EProxy *proxy; + gboolean tested = FALSE; + + g_return_val_if_fail (base_url && *base_url, FALSE); + g_return_val_if_fail (base_collection_path && *base_collection_path, FALSE); + g_return_val_if_fail (authenticator, FALSE); + + url = g_string_new (base_url); + if (url->str[url->len - 1] != '/') + g_string_append_c (url, '/'); + g_string_append (url, base_collection_path); + g_string_append_c (url, '/'); + g_string_append (url, authenticator->username); + g_string_append_c (url, '/'); + + msg = soup_message_new ("PROPFIND", url->str); + + if (!msg) { + g_string_free (url, TRUE); + return FALSE; + } + + session = soup_session_sync_new (); + g_object_set (session, + SOUP_SESSION_TIMEOUT, 90, + SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, + SOUP_SESSION_SSL_STRICT, TRUE, + NULL); + g_signal_connect (session, "authenticate", G_CALLBACK (authenticate_cb), authenticator); + + proxy = e_proxy_new (); + e_proxy_setup_proxy (proxy); + + if (e_proxy_require_proxy_for_uri (proxy, url->str)) { + SoupURI *proxy_uri; + + proxy_uri = e_proxy_peek_uri_for (proxy, url->str); + g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL); + } else { + g_object_set (session, SOUP_SESSION_PROXY_URI, NULL, NULL); + } + + g_string_free (url, TRUE); + + soup_message_set_request (msg, "application/xml; charset=utf-8", SOUP_MEMORY_STATIC, req_body, strlen (req_body)); + + if (soup_session_send_message (session, msg) == SOUP_STATUS_SSL_FAILED) { + ETrustPromptResponse response; + ENamedParameters *parameters; + ESourceWebdav *extension; + ESource *source; + + source = e_backend_get_source (E_BACKEND (collection)); + extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND); + parameters = e_named_parameters_new (); + + /* this is the master source, thus there is no parent_source */ + response = e_source_webdav_prepare_ssl_trust_prompt_with_parent (extension, msg, NULL, parameters); + if (response == E_TRUST_PROMPT_RESPONSE_UNKNOWN) { + response = trust_prompt_sync (parameters, NULL, NULL); + if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN) + e_source_webdav_store_ssl_trust_prompt (extension, msg, response); + } + + e_named_parameters_free (parameters); + + if (response == E_TRUST_PROMPT_RESPONSE_ACCEPT || + response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY) { + g_object_set (session, SOUP_SESSION_SSL_STRICT, FALSE, NULL); + + soup_session_send_message (session, msg); + } + } + + if (msg->status_code == SOUP_STATUS_MULTI_STATUS && + msg->response_body && msg->response_body->length) { + SoupURI *suri = soup_message_get_uri (msg); + + suri = soup_uri_copy (suri); + + parse_propfind_response (collection, found_cb, user_data, suri, msg->response_body->data, msg->response_body->length); + + soup_uri_free (suri); + tested = TRUE; + } + + g_object_unref (msg); + g_object_unref (proxy); + g_object_unref (session); + + return tested; +} + +gboolean +owncloud_utils_search_server (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data) +{ + ESourceCollection *collection_extension; + ESourceGoa *goa_extension; + ESource *source; + EOwncloudAuthenticator *authenticator; + gchar *url; + gboolean res = TRUE; + + g_return_val_if_fail (collection != NULL, FALSE); + g_return_val_if_fail (found_cb != NULL, FALSE); + + source = e_backend_get_source (E_BACKEND (collection)); + collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION); + goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA); + + authenticator = g_object_new (E_TYPE_OWNCLOUD_AUTHENTICATOR, NULL); + authenticator->collection = collection; + authenticator->username = e_source_collection_dup_identity (collection_extension); + + if (res && e_source_collection_get_calendar_enabled (collection_extension)) { + url = e_source_goa_dup_calendar_url (goa_extension); + + if (url && *url) + res = find_sources (collection, found_cb, user_data, url, "calendars", authenticator); + + g_free (url); + } + + if (res && e_source_collection_get_contacts_enabled (collection_extension)) { + url = e_source_goa_dup_contacts_url (goa_extension); + + if (url && *url) + res = find_sources (collection, found_cb, user_data, url, "addressbooks", authenticator); + + g_free (url); + } + + g_object_unref (authenticator); + + return res; +} diff --git a/modules/owncloud-backend/owncloud-utils.h b/modules/owncloud-backend/owncloud-utils.h new file mode 100644 index 0000000..7c49fac --- /dev/null +++ b/modules/owncloud-backend/owncloud-utils.h @@ -0,0 +1,47 @@ +/* + * owncloud-utils.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program 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 the program; if not, see + * + */ + +#ifndef OWNCLOUD_UTILS_H +#define OWNCLOUD_UTILS_H + +#include +#include + +G_BEGIN_DECLS + +typedef enum { + OwnCloud_Source_Contacts = 1, + OwnCloud_Source_Events, + OwnCloud_Source_Memos, + OwnCloud_Source_Tasks +} OwnCloudSourceType; + +typedef void (*OwnCloudSourceFoundCb) (ECollectionBackend *collection, + OwnCloudSourceType source_type, + SoupURI *uri, + const gchar *display_name, + const gchar *color, + gpointer user_data); + +gboolean owncloud_utils_search_server (ECollectionBackend *collection, + OwnCloudSourceFoundCb found_cb, + gpointer user_data); + +G_END_DECLS + +#endif /* OWNCLOUD_UTILS_H */ -- 2.7.4