[evolution-data-server] Bug #686528 - Pickup ownCloud accounts from GOA
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #686528 - Pickup ownCloud accounts from GOA
- Date: Tue, 12 Feb 2013 12:21:28 +0000 (UTC)
commit 00740be9b52cce08611062a4b3e5b5e75e7b8c86
Author: Milan Crha <mcrha redhat com>
Date: Tue Feb 12 13:21:06 2013 +0100
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(-)
---
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 ("<b>", host, "</b>", 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 (
- "<b>%s: %s</b>",
- parent_display_name,
- display_name);
- g_object_unref (parent);
- }
+ parent_display_name = e_source_get_display_name (parent_source);
+ bname = g_strdup_printf ("<b>%s: %s</b>", 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libebackend/libebackend.h>
+
+#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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <libsoup/soup.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <libebackend/libebackend.h>
+
+#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 =
+ "<D:propfind "
+ "xmlns:C=\"urn:ietf:params:xml:ns:caldav\" "
+ "xmlns:IC=\"http://apple.com/ns/ical/\" "
+ "xmlns:D=\"DAV:\">\n"
+ " <D:prop>\n"
+ " <D:displayname/>\n"
+ " <D:resourcetype/>\n"
+ " <C:supported-calendar-component-set/>\n"
+ " <IC:calendar-color/>\n"
+ " </D:prop>\n"
+ "</D:propfind>\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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef OWNCLOUD_UTILS_H
+#define OWNCLOUD_UTILS_H
+
+#include <libebackend/libebackend.h>
+#include <libsoup/soup.h>
+
+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 */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]