[evolution/account-mgmt: 50/50] Add ESourceCamelProvider.



commit b7a9a99bc89c3e10b714b796380b3ce94941f62d
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue Aug 30 10:47:58 2011 -0400

    Add ESourceCamelProvider.

 mail/Makefile.am               |    2 +
 mail/e-mail-backend.c          |    3 +-
 mail/e-source-camel-provider.c |  427 ++++++++++++++++++++++++++++++++++++++++
 mail/e-source-camel-provider.h |   78 ++++++++
 4 files changed, 509 insertions(+), 1 deletions(-)
---
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 5371a9f..ac1dbee 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -74,6 +74,7 @@ mailinclude_HEADERS =					\
 	e-mail-store.h					\
 	e-mail-store-utils.h				\
 	e-mail-tag-editor.h				\
+	e-source-camel-provider.h			\
 	em-account-editor.h				\
 	em-composer-utils.h				\
 	em-config.h					\
@@ -147,6 +148,7 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-store.c					\
 	e-mail-store-utils.c				\
 	e-mail-tag-editor.c				\
+	e-source-camel-provider.c			\
 	em-account-editor.c				\
 	em-composer-utils.c				\
 	em-config.c					\
diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c
index 2b4a81e..46b644a 100644
--- a/mail/e-mail-backend.c
+++ b/mail/e-mail-backend.c
@@ -45,6 +45,7 @@
 #include "mail/e-mail-session.h"
 #include "mail/e-mail-store.h"
 #include "mail/e-mail-store-utils.h"
+#include "mail/e-source-camel-provider.h"
 #include "mail/em-event.h"
 #include "mail/em-folder-tree-model.h"
 #include "mail/em-utils.h"
@@ -784,7 +785,7 @@ mail_backend_constructed (GObject *object)
 	if (camel_init (e_get_user_data_dir (), TRUE) != 0)
 		exit (0);
 
-	camel_provider_init ();
+	e_source_camel_provider_register_types ();
 
 	priv->session = e_mail_session_new ();
 	folder_cache = e_mail_session_get_folder_cache (priv->session);
diff --git a/mail/e-source-camel-provider.c b/mail/e-source-camel-provider.c
new file mode 100644
index 0000000..7e2a1e5
--- /dev/null
+++ b/mail/e-source-camel-provider.c
@@ -0,0 +1,427 @@
+/*
+ * e-source-camel-provider.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-camel-provider
+ * @include: mail/e-source-camel-provider.h
+ * @short_description: #ESource extension for #CamelSettings
+ *
+ * #ESourceCamelProvider itself is abstract.  Its sole function is to
+ * bridge #GObject properties from the #CamelSettings framework to the
+ * #ESource framework.  It does this by procedurally registering an
+ * #ESourceCamelProvider subtype for each available #CamelService subtype,
+ * and then registering #GObject properties to proxy the properties in the
+ * corresponding #CamelSettings subtype.  The #ESourceCamelProvider owns an
+ * instance of the appropriate #CamelSettings subtype, and redirects all
+ * get/set operations on its own #GObject properties to its #CamelSettings
+ * instance.  The #CamelSettings instance, now fully initialized from a key
+ * file, can then be inserted into a new #CamelService instance using
+ * camel_service_set_settings().
+ *
+ * Ultimately, this is all just implementation detail for glueing two
+ * unrelated class hierarchies together.  If you need to access provider
+ * specific settings, use the #CamelSettings API, not this.
+ **/
+
+/* XXX This class MIGHT make sense in libedataserver with the other
+ *     ESourceExtensions were it not for the fact that Camel links
+ *     to libedataserver, so we'd have a circular dependency. */
+
+#include "e-source-camel-provider.h"
+
+#include <e-util/e-util.h>
+#include <libedataserver/e-source-offline.h>
+#include <libedataserver/e-source-security.h>
+
+#define E_SOURCE_CAMEL_PROVIDER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_CAMEL_PROVIDER, ESourceCamelProviderPrivate))
+
+struct _ESourceCamelProviderPrivate {
+	CamelSettings *settings;
+};
+
+enum {
+	PROP_0,
+	PROP_SETTINGS
+};
+
+static struct {
+	const gchar *extension_name;
+	const gchar *extension_property_name;
+	const gchar *settings_property_name;
+	GBindingTransformFunc extension_to_settings;
+	GBindingTransformFunc settings_to_extension;
+} bindings[] = {
+
+	{ E_SOURCE_EXTENSION_OFFLINE,
+	  "stay-synchronized", "stay-synchronized" },
+
+	{ E_SOURCE_EXTENSION_SECURITY,
+	  "method", "security-method",
+	  e_binding_transform_enum_nick_to_value,
+	  e_binding_transform_enum_value_to_nick }
+};
+
+G_DEFINE_ABSTRACT_TYPE (
+	ESourceCamelProvider,
+	e_source_camel_provider,
+	E_TYPE_SOURCE_EXTENSION)
+
+static gint
+subclass_get_binding_index (GParamSpec *settings_property)
+{
+	gint ii;
+
+	/* Return the index in the bindings list for the given
+	 * CamelSettings property specification, or else -1. */
+
+	for (ii = 0; ii < G_N_ELEMENTS (bindings); ii++) {
+		const gchar *property_name;
+
+		property_name = bindings[ii].settings_property_name;
+		if (g_strcmp0 (settings_property->name, property_name) == 0)
+			return ii;
+	}
+
+	return -1;
+}
+
+static void
+subclass_set_property (GObject *object,
+                       guint property_id,
+                       const GValue *value,
+                       GParamSpec *pspec)
+{
+	ESourceCamelProvider *extension;
+	CamelSettings *settings;
+
+	/* Forward the value to CamelSettings. */
+	extension = E_SOURCE_CAMEL_PROVIDER (object);
+	settings = e_source_camel_provider_get_settings (extension);
+	g_object_set_property (G_OBJECT (settings), pspec->name, value);
+}
+
+static void
+subclass_get_property (GObject *object,
+                       guint property_id,
+                       GValue *value,
+                       GParamSpec *pspec)
+{
+	ESourceCamelProvider *extension;
+	CamelSettings *settings;
+
+	/* Obtain the value from CamelSettings. */
+	extension = E_SOURCE_CAMEL_PROVIDER (object);
+	settings = e_source_camel_provider_get_settings (extension);
+	g_object_get_property (G_OBJECT (settings), pspec->name, value);
+}
+
+static void
+subclass_init (gpointer g_class,
+               gpointer class_data)
+{
+	GObjectClass *object_class;
+	ESourceCamelProviderClass *extension_class;
+	GObjectClass *settings_class;
+	GParamSpec **properties;
+	GType settings_type;
+	guint ii, n_properties;
+
+	settings_type = GPOINTER_TO_SIZE (class_data);
+
+	object_class = G_OBJECT_CLASS (g_class);
+	object_class->set_property = subclass_set_property;
+	object_class->get_property = subclass_get_property;
+
+	extension_class = E_SOURCE_CAMEL_PROVIDER_CLASS (g_class);
+	extension_class->settings_type = settings_type;
+
+	settings_class = g_type_class_ref (settings_type);
+
+	properties = g_object_class_list_properties (
+		settings_class, &n_properties);
+
+	/* For each property in the CamelSettings class, register
+	 * an equivalent GObject property in this class and add an
+	 * E_SOURCE_PARAM_SETTING flag so the value gets written to
+	 * the ESource's key file. */
+	for (ii = 0; ii < n_properties; ii++) {
+		GParamSpec *pspec;
+		const gchar *name;
+
+		/* Some properties in CamelSettings may be covered
+		 * by other ESourceExtensions.  Skip them here. */
+		if (subclass_get_binding_index (properties[ii]) >= 0)
+			continue;
+
+		name = properties[ii]->name;
+		pspec = g_param_spec_override (name, properties[ii]);
+		pspec->flags |= E_SOURCE_PARAM_SETTING;
+		g_object_class_install_property (object_class, ii, pspec);
+	}
+
+	g_free (properties);
+
+	g_type_class_unref (settings_class);
+}
+
+static void
+source_camel_provider_register_subtype (GType service_type,
+                                        const gchar *type_name,
+                                        const gchar *extension_name)
+{
+	CamelServiceClass *service_class;
+	GTypeInfo type_info;
+	GType settings_type;
+	GType parent_type;
+
+	/* Check if the type name is already registered. */
+	if (g_type_from_name (type_name) != G_TYPE_INVALID)
+		return;
+
+	service_class = g_type_class_ref (service_type);
+	settings_type = service_class->settings_type;
+	g_type_class_unref (service_class);
+
+	type_info.class_size = sizeof (ESourceCamelProviderClass);
+	type_info.base_init = NULL;
+	type_info.base_finalize = NULL;
+	type_info.class_init = subclass_init;
+	type_info.class_finalize = NULL;
+	type_info.class_data = GSIZE_TO_POINTER (settings_type);
+	type_info.instance_size = sizeof (ESourceCamelProvider);
+	type_info.n_preallocs = 0;
+	type_info.instance_init = NULL;
+	type_info.value_table = NULL;
+
+	parent_type = E_TYPE_SOURCE_CAMEL_PROVIDER;
+	g_type_register_static (parent_type, type_name, &type_info, 0);
+}
+
+static void
+source_camel_provider_notify_cb (GObject *object,
+                                 GParamSpec *pspec)
+{
+	g_object_notify (object, pspec->name);
+}
+
+static void
+source_camel_provider_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SETTINGS:
+			g_value_set_object (
+				value,
+				e_source_camel_provider_get_settings (
+				E_SOURCE_CAMEL_PROVIDER (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_camel_provider_dispose (GObject *object)
+{
+	ESourceCamelProviderPrivate *priv;
+
+	priv = E_SOURCE_CAMEL_PROVIDER_GET_PRIVATE (object);
+
+	if (priv->settings != NULL) {
+		g_object_unref (priv->settings);
+		priv->settings = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_source_camel_provider_parent_class)->dispose (object);
+}
+
+static void
+source_camel_provider_constructed (GObject *object)
+{
+	ESource *source;
+	ESourceCamelProviderClass *class;
+	ESourceCamelProviderPrivate *priv;
+	GObjectClass *settings_class;
+	GParamSpec **properties;
+	guint ii, n_properties;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_source_camel_provider_parent_class)->
+		constructed (object);
+
+	class = E_SOURCE_CAMEL_PROVIDER_GET_CLASS (object);
+	priv = E_SOURCE_CAMEL_PROVIDER_GET_PRIVATE (object);
+
+	source = e_source_extension_get_source (E_SOURCE_EXTENSION (object));
+
+	priv->settings = g_object_new (class->settings_type, NULL);
+
+	g_signal_connect (
+		priv->settings, "notify",
+		G_CALLBACK (source_camel_provider_notify_cb), NULL);
+
+	/* Here we bind all the GObject properties in the newly-created
+	 * CamelSettings instance to either our own identical properties
+	 * or properties in another ESourceExtensions.  The bindings list
+	 * at the top of the file maps out bindings to other extensions. */
+
+	settings_class = G_OBJECT_GET_CLASS (priv->settings);
+
+	properties = g_object_class_list_properties (
+		settings_class, &n_properties);
+
+	for (ii = 0; ii < n_properties; ii++) {
+		gint index;
+
+		index = subclass_get_binding_index (properties[ii]);
+
+		/* Bind the CamelSettings property to a
+		 * one in a different ESourceExtension. */
+		if (index >= 0) {
+			ESourceExtension *extension;
+
+			extension = e_source_get_extension (
+				source, bindings[index].extension_name);
+
+			g_object_bind_property_full (
+				extension,
+				bindings[index].extension_property_name,
+				priv->settings,
+				bindings[index].settings_property_name,
+				G_BINDING_BIDIRECTIONAL |
+				G_BINDING_SYNC_CREATE,
+				bindings[index].extension_to_settings,
+				bindings[index].settings_to_extension,
+				NULL, (GDestroyNotify) NULL);
+
+		/* Bind the CamelSettings property to our own
+		 * equivalent E_SOURCE_PARAM_SETTING property. */
+		} else {
+			ESourceExtension *extension;
+
+			extension = E_SOURCE_EXTENSION (object);
+
+			g_object_bind_property (
+				extension,
+				properties[ii]->name,
+				priv->settings,
+				properties[ii]->name,
+				G_BINDING_BIDIRECTIONAL |
+				G_BINDING_SYNC_CREATE);
+		}
+	}
+
+	g_free (properties);
+}
+
+static void
+e_source_camel_provider_class_init (ESourceCamelProviderClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (ESourceCamelProviderPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->get_property = source_camel_provider_get_property;
+	object_class->dispose = source_camel_provider_dispose;
+	object_class->constructed = source_camel_provider_constructed;
+
+	/* CamelSettings itself has no properties. */
+	class->settings_type = CAMEL_TYPE_SETTINGS;
+
+	/* XXX This kind of stomps on CamelSettings' namespace, but it's
+	 *     unlikely a CamelSettings subclass would define a property
+	 *     named "settings". */
+	g_object_class_install_property (
+		object_class,
+		PROP_SETTINGS,
+		g_param_spec_object (
+			"settings",
+			"Settings",
+			"The CamelSettings instance being proxied",
+			CAMEL_TYPE_SETTINGS,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_source_camel_provider_init (ESourceCamelProvider *extension)
+{
+	extension->priv = E_SOURCE_CAMEL_PROVIDER_GET_PRIVATE (extension);
+}
+
+void
+e_source_camel_provider_register_types (void)
+{
+	GList *list, *link;
+
+	/* This implicitly takes care of provider initialization. */
+	list = camel_provider_list (TRUE);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		CamelProvider *provider;
+		gchar *extension_name;
+		gchar *type_name;
+		gchar *name;
+		gint ii;
+
+		provider = (CamelProvider *) list->data;
+
+		name = g_strdup (provider->protocol);
+		name[0] = g_ascii_toupper (name[0]);
+
+		/* Use the term "backend" for consistency with other
+		 * calendar and address book backend extension names. */
+		extension_name = g_strdup_printf ("%s Backend", name);
+		type_name = g_strdup_printf ("ESourceCamel%sProvider", name);
+
+		/* This is the novel part: fabricate and register
+		 * a new ESourceCamelProvider subclass on-the-fly
+		 * for each object type listed in the provider. */
+		for (ii = 0; ii < CAMEL_NUM_PROVIDER_TYPES; ii++) {
+			GType service_type;
+
+			service_type = provider->object_types[ii];
+
+			if (service_type == G_TYPE_INVALID)
+				continue;
+
+			source_camel_provider_register_subtype (
+				service_type, type_name, extension_name);
+		}
+
+		g_free (extension_name);
+		g_free (type_name);
+		g_free (name);
+	}
+
+	g_list_free (list);
+}
+
+CamelSettings *
+e_source_camel_provider_get_settings (ESourceCamelProvider *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_CAMEL_PROVIDER (extension), NULL);
+
+	return extension->priv->settings;
+}
diff --git a/mail/e-source-camel-provider.h b/mail/e-source-camel-provider.h
new file mode 100644
index 0000000..f20253e
--- /dev/null
+++ b/mail/e-source-camel-provider.h
@@ -0,0 +1,78 @@
+/*
+ * e-source-camel-provider.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 E_SOURCE_CAMEL_PROVIDER_H
+#define E_SOURCE_CAMEL_PROVIDER_H
+
+#include <camel/camel.h>
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CAMEL_PROVIDER \
+	(e_source_camel_provider_get_type ())
+#define E_SOURCE_CAMEL_PROVIDER(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_CAMEL_PROVIDER, ESourceCamelProvider))
+#define E_SOURCE_CAMEL_PROVIDER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_CAMEL_PROVIDER, ESourceCamelProviderClass))
+#define E_IS_SOURCE_CAMEL_PROVIDER(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_CAMEL_PROVIDER))
+#define E_IS_SOURCE_CAMEL_PROVIDER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_CAMEL_PROVIDER))
+#define E_SOURCE_CAMEL_PROVIDER_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_CAMEL_PROVIDER, ESourceCamelProviderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceCamelProvider ESourceCamelProvider;
+typedef struct _ESourceCamelProviderClass ESourceCamelProviderClass;
+typedef struct _ESourceCamelProviderPrivate ESourceCamelProviderPrivate;
+
+/**
+ * ESourceCamelProvider:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceCamelProvider {
+	ESourceExtension parent;
+	ESourceCamelProviderPrivate *priv;
+};
+
+struct _ESourceCamelProviderClass {
+	ESourceExtensionClass parent_class;
+
+	/* Same idea as in CamelServiceClass. */
+	GType settings_type;
+};
+
+GType		e_source_camel_provider_get_type	(void);
+void		e_source_camel_provider_register_types	(void);
+CamelSettings *
+		e_source_camel_provider_get_settings
+					(ESourceCamelProvider *extension);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CAMEL_PROVIDER_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]