diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile.am | 5 | ||||
-rw-r--r-- | modules/book-config-ldap/Makefile.am | 31 | ||||
-rw-r--r-- | modules/book-config-ldap/e-source-ldap.c | 659 | ||||
-rw-r--r-- | modules/book-config-ldap/e-source-ldap.h | 123 | ||||
-rw-r--r-- | modules/book-config-ldap/evolution-book-config-ldap.c | 990 |
5 files changed, 1808 insertions, 0 deletions
diff --git a/modules/Makefile.am b/modules/Makefile.am index 1668322e8b..8c4cb9b4eb 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -1,3 +1,7 @@ +if ENABLE_LDAP +CONFIG_LDAP_DIR = book-config-ldap +endif + if ENABLE_MONO MONO_DIR = plugin-mono endif @@ -17,6 +21,7 @@ SUBDIRS = \ mail \ backup-restore \ book-config-google \ + $(CONFIG_LDAP_DIR) \ book-config-local \ composer-autosave \ mailto-handler \ diff --git a/modules/book-config-ldap/Makefile.am b/modules/book-config-ldap/Makefile.am new file mode 100644 index 0000000000..bcb9cd0695 --- /dev/null +++ b/modules/book-config-ldap/Makefile.am @@ -0,0 +1,31 @@ +module_LTLIBRARIES = module-book-config-ldap.la + +module_book_config_ldap_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DG_LOG_DOMAIN=\"evolution-book-config-ldap\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(LDAP_CFLAGS) + +module_book_config_ldap_la_SOURCES = \ + evolution-book-config-ldap.c \ + e-source-ldap.c \ + e-source-ldap.h + +module_book_config_ldap_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/addressbook/printing/libecontactprint.la \ + $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ + $(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(LDAP_LIBS) + +module_book_config_ldap_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/book-config-ldap/e-source-ldap.c b/modules/book-config-ldap/e-source-ldap.c new file mode 100644 index 0000000000..4e182dc625 --- /dev/null +++ b/modules/book-config-ldap/e-source-ldap.c @@ -0,0 +1,659 @@ +/* + * e-source-ldap.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/> + * + */ + +#include "e-source-ldap.h" + +#include <ldap.h> + +#include <libedataserver/e-data-server-util.h> +#include <libedataserver/e-source-authentication.h> +#include <libedataserver/e-source-security.h> + +#define E_SOURCE_LDAP_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SOURCE_LDAP, ESourceLDAPPrivate)) + +struct _ESourceLDAPPrivate { + GMutex *property_lock; + gboolean can_browse; + gchar *filter; + guint limit; + gchar *root_dn; + ESourceLDAPScope scope; + + /* These are bound to other extensions. */ + ESourceLDAPAuthentication authentication; + ESourceLDAPSecurity security; +}; + +enum { + PROP_0, + PROP_AUTHENTICATION, + PROP_CAN_BROWSE, + PROP_FILTER, + PROP_LIMIT, + PROP_ROOT_DN, + PROP_SCOPE, + PROP_SECURITY +}; + +static GType e_source_ldap_authentication_type = G_TYPE_INVALID; +static GType e_source_ldap_scope_type = G_TYPE_INVALID; +static GType e_source_ldap_security_type = G_TYPE_INVALID; + +G_DEFINE_DYNAMIC_TYPE ( + ESourceLDAP, + e_source_ldap, + E_TYPE_SOURCE_EXTENSION) + +static gboolean +source_ldap_transform_enum_nick_to_value (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer not_used) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + const gchar *string; + gboolean success = FALSE; + + enum_class = g_type_class_peek (G_VALUE_TYPE (target_value)); + g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), FALSE); + + string = g_value_get_string (source_value); + enum_value = g_enum_get_value_by_nick (enum_class, string); + if (enum_value != NULL) { + g_value_set_enum (target_value, enum_value->value); + success = TRUE; + } + + return success; +} + +static gboolean +source_ldap_transform_enum_value_to_nick (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer not_used) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + gint value; + gboolean success = FALSE; + + enum_class = g_type_class_peek (G_VALUE_TYPE (source_value)); + g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), FALSE); + + value = g_value_get_enum (source_value); + enum_value = g_enum_get_value (enum_class, value); + if (enum_value != NULL) { + g_value_set_string (target_value, enum_value->value_nick); + success = TRUE; + } + + return success; +} + +static void +source_ldap_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_AUTHENTICATION: + e_source_ldap_set_authentication ( + E_SOURCE_LDAP (object), + g_value_get_enum (value)); + return; + + case PROP_CAN_BROWSE: + e_source_ldap_set_can_browse ( + E_SOURCE_LDAP (object), + g_value_get_boolean (value)); + return; + + case PROP_FILTER: + e_source_ldap_set_filter ( + E_SOURCE_LDAP (object), + g_value_get_string (value)); + return; + + case PROP_LIMIT: + e_source_ldap_set_limit ( + E_SOURCE_LDAP (object), + g_value_get_uint (value)); + return; + + case PROP_ROOT_DN: + e_source_ldap_set_root_dn ( + E_SOURCE_LDAP (object), + g_value_get_string (value)); + return; + + case PROP_SCOPE: + e_source_ldap_set_scope ( + E_SOURCE_LDAP (object), + g_value_get_enum (value)); + return; + + case PROP_SECURITY: + e_source_ldap_set_security ( + E_SOURCE_LDAP (object), + g_value_get_enum (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +source_ldap_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_AUTHENTICATION: + g_value_set_enum ( + value, + e_source_ldap_get_authentication ( + E_SOURCE_LDAP (object))); + return; + + case PROP_CAN_BROWSE: + g_value_set_boolean ( + value, + e_source_ldap_get_can_browse ( + E_SOURCE_LDAP (object))); + return; + + case PROP_FILTER: + g_value_take_string ( + value, + e_source_ldap_dup_filter ( + E_SOURCE_LDAP (object))); + return; + + case PROP_LIMIT: + g_value_set_uint ( + value, + e_source_ldap_get_limit ( + E_SOURCE_LDAP (object))); + return; + + case PROP_ROOT_DN: + g_value_take_string ( + value, + e_source_ldap_dup_root_dn ( + E_SOURCE_LDAP (object))); + return; + + case PROP_SCOPE: + g_value_set_enum ( + value, + e_source_ldap_get_scope ( + E_SOURCE_LDAP (object))); + return; + + case PROP_SECURITY: + g_value_set_enum ( + value, + e_source_ldap_get_security ( + E_SOURCE_LDAP (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +source_ldap_finalize (GObject *object) +{ + ESourceLDAPPrivate *priv; + + priv = E_SOURCE_LDAP_GET_PRIVATE (object); + + g_mutex_free (priv->property_lock); + + g_free (priv->filter); + g_free (priv->root_dn); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_source_ldap_parent_class)->finalize (object); +} + +static void +source_ldap_constructed (GObject *object) +{ + ESource *source; + ESourceExtension *this_extension; + ESourceExtension *other_extension; + const gchar *extension_name; + + this_extension = E_SOURCE_EXTENSION (object); + source = e_source_extension_get_source (this_extension); + + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + other_extension = e_source_get_extension (source, extension_name); + + g_object_bind_property_full ( + other_extension, "method", + this_extension, "authentication", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE, + source_ldap_transform_enum_nick_to_value, + source_ldap_transform_enum_value_to_nick, + NULL, (GDestroyNotify) NULL); + + extension_name = E_SOURCE_EXTENSION_SECURITY; + other_extension = e_source_get_extension (source, extension_name); + + g_object_bind_property_full ( + other_extension, "method", + this_extension, "security", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE, + source_ldap_transform_enum_nick_to_value, + source_ldap_transform_enum_value_to_nick, + NULL, (GDestroyNotify) NULL); +} + +static void +e_source_ldap_class_init (ESourceLDAPClass *class) +{ + GObjectClass *object_class; + ESourceExtensionClass *extension_class; + + g_type_class_add_private (class, sizeof (ESourceLDAPPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = source_ldap_set_property; + object_class->get_property = source_ldap_get_property; + object_class->finalize = source_ldap_finalize; + object_class->constructed = source_ldap_constructed; + + extension_class = E_SOURCE_EXTENSION_CLASS (class); + extension_class->name = E_SOURCE_EXTENSION_LDAP_BACKEND; + + /* This is bound to the authentication extension. + * Do not use E_SOURCE_PARAM_SETTING here. */ + g_object_class_install_property ( + object_class, + PROP_AUTHENTICATION, + g_param_spec_enum ( + "authentication", + "Authentication", + "LDAP authentication method", + E_TYPE_SOURCE_LDAP_AUTHENTICATION, + E_SOURCE_LDAP_AUTHENTICATION_NONE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CAN_BROWSE, + g_param_spec_boolean ( + "can-browse", + "Can Browse", + "Allow browsing contacts", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_FILTER, + g_param_spec_string ( + "filter", + "Filter", + "LDAP search filter", + "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_LIMIT, + g_param_spec_uint ( + "limit", + "Limit", + "Download limit", + 0, G_MAXUINT, 100, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_ROOT_DN, + g_param_spec_string ( + "root-dn", + "Root DN", + "LDAP search base", + "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_SCOPE, + g_param_spec_enum ( + "scope", + "Scope", + "LDAP search scope", + E_TYPE_SOURCE_LDAP_SCOPE, + E_SOURCE_LDAP_SCOPE_ONELEVEL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + /* This is bound to the security extension. + * Do not use E_SOURCE_PARAM_SETTING here. */ + g_object_class_install_property ( + object_class, + PROP_SECURITY, + g_param_spec_enum ( + "security", + "Security", + "LDAP security method", + E_TYPE_SOURCE_LDAP_SECURITY, + E_SOURCE_LDAP_SECURITY_NONE, + G_PARAM_READWRITE)); +} + +static void +e_source_ldap_class_finalize (ESourceLDAPClass *class) +{ +} + +static void +e_source_ldap_init (ESourceLDAP *extension) +{ + extension->priv = E_SOURCE_LDAP_GET_PRIVATE (extension); + extension->priv->property_lock = g_mutex_new (); +} + +void +e_source_ldap_type_register (GTypeModule *type_module) +{ + static const GEnumValue e_source_ldap_authentication_values[] = { + { E_SOURCE_LDAP_AUTHENTICATION_NONE, + "E_SOURCE_LDAP_AUTHENTICATION_NONE", + "none" }, + { E_SOURCE_LDAP_AUTHENTICATION_EMAIL, + "E_SOURCE_LDAP_AUTHENTICATION_EMAIL", + "ldap/simple-email" }, + { E_SOURCE_LDAP_AUTHENTICATION_BINDDN, + "E_SOURCE_LDAP_AUTHENTICATION_BINDDN", + "ldap/simple-binddn" }, + { 0, NULL, NULL } + }; + + static const GEnumValue e_source_ldap_scope_values[] = { + { E_SOURCE_LDAP_SCOPE_ONELEVEL, + "E_SOURCE_LDAP_SCOPE_ONELEVEL", + "onelevel" }, + { E_SOURCE_LDAP_SCOPE_SUBTREE, + "E_SOURCE_LDAP_SCOPE_SUBTREE", + "subtree" }, + { 0, NULL, NULL } + }; + + static const GEnumValue e_source_ldap_security_values[] = { + { E_SOURCE_LDAP_SECURITY_NONE, + "E_SOURCE_LDAP_SECURITY_NONE", + "none" }, + { E_SOURCE_LDAP_SECURITY_LDAPS, + "E_SOURCE_LDAP_SECURITY_LDAPS", + "ldaps" }, + { E_SOURCE_LDAP_SECURITY_STARTTLS, + "E_SOURCE_LDAP_SECURITY_STARTTLS", + "starttls" }, + { 0, NULL, NULL } + }; + + e_source_ldap_authentication_type = + g_type_module_register_enum ( + type_module, "ESourceLDAPAuthentication", + e_source_ldap_authentication_values); + + e_source_ldap_scope_type = + g_type_module_register_enum ( + type_module, "ESourceLDAPScope", + e_source_ldap_scope_values); + + e_source_ldap_security_type = + g_type_module_register_enum ( + type_module, "ESourceLDAPSecurity", + e_source_ldap_security_values); + + /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration + * function, so we have to wrap it with a public function in + * order to register types from a separate compilation unit. */ + e_source_ldap_register_type (type_module); +} + +ESourceLDAPAuthentication +e_source_ldap_get_authentication (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), 0); + + return extension->priv->authentication; +} + +void +e_source_ldap_set_authentication (ESourceLDAP *extension, + ESourceLDAPAuthentication authentication) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + extension->priv->authentication = authentication; + + g_object_notify (G_OBJECT (extension), "authentication"); +} + +gboolean +e_source_ldap_get_can_browse (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), FALSE); + + return extension->priv->can_browse; +} + +void +e_source_ldap_set_can_browse (ESourceLDAP *extension, + gboolean can_browse) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + extension->priv->can_browse = can_browse; + + g_object_notify (G_OBJECT (extension), "can-browse"); +} + +const gchar * +e_source_ldap_get_filter (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), NULL); + + return extension->priv->filter; +} + +gchar * +e_source_ldap_dup_filter (ESourceLDAP *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), NULL); + + g_mutex_lock (extension->priv->property_lock); + + protected = e_source_ldap_get_filter (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (extension->priv->property_lock); + + return duplicate; +} + +void +e_source_ldap_set_filter (ESourceLDAP *extension, + const gchar *filter) +{ + gboolean needs_parens; + + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + needs_parens = + (filter != NULL) && (*filter != '\0') && + !g_str_has_prefix (filter, "(") && + !g_str_has_suffix (filter, ")"); + + g_mutex_lock (extension->priv->property_lock); + + g_free (extension->priv->filter); + if (needs_parens) + extension->priv->filter = g_strdup_printf ("(%s)", filter); + else + extension->priv->filter = g_strdup (filter); + + g_mutex_unlock (extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "filter"); +} + +guint +e_source_ldap_get_limit (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), 0); + + return extension->priv->limit; +} + +void +e_source_ldap_set_limit (ESourceLDAP *extension, + guint limit) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + extension->priv->limit = limit; + + g_object_notify (G_OBJECT (extension), "limit"); +} + +const gchar * +e_source_ldap_get_root_dn (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), NULL); + + return extension->priv->root_dn; +} + +gchar * +e_source_ldap_dup_root_dn (ESourceLDAP *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), NULL); + + g_mutex_lock (extension->priv->property_lock); + + protected = e_source_ldap_get_root_dn (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (extension->priv->property_lock); + + return duplicate; +} + +void +e_source_ldap_set_root_dn (ESourceLDAP *extension, + const gchar *root_dn) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + g_mutex_lock (extension->priv->property_lock); + + g_free (extension->priv->root_dn); + extension->priv->root_dn = e_util_strdup_strip (root_dn); + + g_mutex_unlock (extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "root-dn"); +} + +ESourceLDAPScope +e_source_ldap_get_scope (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), 0); + + return extension->priv->scope; +} + +void +e_source_ldap_set_scope (ESourceLDAP *extension, + ESourceLDAPScope scope) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + extension->priv->scope = scope; + + g_object_notify (G_OBJECT (extension), "scope"); +} + +ESourceLDAPSecurity +e_source_ldap_get_security (ESourceLDAP *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_LDAP (extension), 0); + + return extension->priv->security; +} + +void +e_source_ldap_set_security (ESourceLDAP *extension, + ESourceLDAPSecurity security) +{ + g_return_if_fail (E_IS_SOURCE_LDAP (extension)); + + extension->priv->security = security; + + g_object_notify (G_OBJECT (extension), "security"); +} + +GType +e_source_ldap_authentication_get_type (void) +{ + return e_source_ldap_authentication_type; +} + +GType +e_source_ldap_scope_get_type (void) +{ + return e_source_ldap_scope_type; +} + +GType +e_source_ldap_security_get_type (void) +{ + return e_source_ldap_security_type; +} diff --git a/modules/book-config-ldap/e-source-ldap.h b/modules/book-config-ldap/e-source-ldap.h new file mode 100644 index 0000000000..ea9cb9fd8c --- /dev/null +++ b/modules/book-config-ldap/e-source-ldap.h @@ -0,0 +1,123 @@ +/* + * e-source-ldap.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_LDAP_H +#define E_SOURCE_LDAP_H + +#include <libedataserver/e-source-extension.h> + +/* Standard GObject macros */ +#define E_TYPE_SOURCE_LDAP \ + (e_source_ldap_get_type ()) +#define E_SOURCE_LDAP(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SOURCE_LDAP, ESourceLDAP)) +#define E_SOURCE_LDAP_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SOURCE_LDAP, ESourceLDAPClass)) +#define E_IS_SOURCE_LDAP(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SOURCE_LDAP)) +#define E_IS_SOURCE_LDAP_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SOURCE_LDAP)) +#define E_SOURCE_LDAP_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SOURCE_LDAP, ESourceLDAPClass)) + +#define E_TYPE_SOURCE_LDAP_AUTHENTICATION \ + (e_source_ldap_authentication_get_type ()) + +#define E_TYPE_SOURCE_LDAP_SCOPE \ + (e_source_ldap_scope_get_type ()) + +#define E_TYPE_SOURCE_LDAP_SECURITY \ + (e_source_ldap_security_get_type ()) + +#define E_SOURCE_EXTENSION_LDAP_BACKEND "LDAP Backend" + +G_BEGIN_DECLS + +typedef struct _ESourceLDAP ESourceLDAP; +typedef struct _ESourceLDAPClass ESourceLDAPClass; +typedef struct _ESourceLDAPPrivate ESourceLDAPPrivate; + +struct _ESourceLDAP { + ESourceExtension parent; + ESourceLDAPPrivate *priv; +}; + +struct _ESourceLDAPClass { + ESourceExtensionClass parent_class; +}; + +typedef enum { + E_SOURCE_LDAP_AUTHENTICATION_NONE, + E_SOURCE_LDAP_AUTHENTICATION_EMAIL, + E_SOURCE_LDAP_AUTHENTICATION_BINDDN +} ESourceLDAPAuthentication; + +typedef enum { + E_SOURCE_LDAP_SCOPE_ONELEVEL, + E_SOURCE_LDAP_SCOPE_SUBTREE +} ESourceLDAPScope; + +typedef enum { + E_SOURCE_LDAP_SECURITY_NONE, + E_SOURCE_LDAP_SECURITY_LDAPS, + E_SOURCE_LDAP_SECURITY_STARTTLS +} ESourceLDAPSecurity; + +GType e_source_ldap_get_type (void); +void e_source_ldap_type_register (GTypeModule *type_module); +ESourceLDAPAuthentication + e_source_ldap_get_authentication + (ESourceLDAP *extension); +void e_source_ldap_set_authentication + (ESourceLDAP *extension, + ESourceLDAPAuthentication authentication); +gboolean e_source_ldap_get_can_browse (ESourceLDAP *extension); +void e_source_ldap_set_can_browse (ESourceLDAP *extension, + gboolean can_browse); +const gchar * e_source_ldap_get_filter (ESourceLDAP *extension); +gchar * e_source_ldap_dup_filter (ESourceLDAP *extension); +void e_source_ldap_set_filter (ESourceLDAP *extension, + const gchar *filter); +guint e_source_ldap_get_limit (ESourceLDAP *extension); +void e_source_ldap_set_limit (ESourceLDAP *extension, + guint limit); +const gchar * e_source_ldap_get_root_dn (ESourceLDAP *extension); +gchar * e_source_ldap_dup_root_dn (ESourceLDAP *extension); +void e_source_ldap_set_root_dn (ESourceLDAP *extension, + const gchar *root_dn); +ESourceLDAPScope + e_source_ldap_get_scope (ESourceLDAP *extension); +void e_source_ldap_set_scope (ESourceLDAP *extension, + ESourceLDAPScope scope); +ESourceLDAPSecurity + e_source_ldap_get_security (ESourceLDAP *extension); +void e_source_ldap_set_security (ESourceLDAP *extension, + ESourceLDAPSecurity security); + +GType e_source_ldap_authentication_get_type (void); +GType e_source_ldap_scope_get_type (void); +GType e_source_ldap_security_get_type (void); + +G_END_DECLS + +#endif /* E_SOURCE_LDAP_H */ diff --git a/modules/book-config-ldap/evolution-book-config-ldap.c b/modules/book-config-ldap/evolution-book-config-ldap.c new file mode 100644 index 0000000000..a957e4c94a --- /dev/null +++ b/modules/book-config-ldap/evolution-book-config-ldap.c @@ -0,0 +1,990 @@ +/* + * evolution-book-config-ldap.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/> + * + */ + +#include <config.h> +#include <stdlib.h> +#include <glib/gi18n-lib.h> + +#include <libebackend/e-extension.h> +#include <libedataserver/e-source-authentication.h> + +#include <libevolution-utils/e-alert-dialog.h> +#include <misc/e-source-config-backend.h> +#include <addressbook/gui/widgets/e-book-source-config.h> + +#include "e-source-ldap.h" + +#ifndef G_OS_WIN32 +#include <ldap.h> +#ifndef SUNLDAP +#include <ldap_schema.h> +#endif +#else +#include <winldap.h> +#include "openldap-extract.h" +#endif + +/* Combo box ordering */ +#define LDAP_PORT 389 +#define LDAPS_PORT 636 +#define MSGC_PORT 3268 +#define MSGCS_PORT 3269 + +typedef ESourceConfigBackend EBookConfigLDAP; +typedef ESourceConfigBackendClass EBookConfigLDAPClass; + +typedef struct _Closure Closure; +typedef struct _Context Context; + +struct _Closure { + ESourceConfigBackend *backend; + ESource *scratch_source; +}; + +struct _Context { + GtkWidget *auth_combo; + GtkWidget *auth_entry; + GtkWidget *host_entry; + GtkWidget *port_combo; + GtkWidget *security_combo; + GtkWidget *search_base_combo; + GtkWidget *search_base_button; + GtkWidget *search_scope_combo; + GtkWidget *search_filter_entry; + GtkWidget *limit_spinbutton; + GtkWidget *can_browse_toggle; +}; + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +/* Forward Declarations */ +GType e_book_config_ldap_get_type (void); + +G_DEFINE_DYNAMIC_TYPE ( + EBookConfigLDAP, + e_book_config_ldap, + E_TYPE_SOURCE_CONFIG_BACKEND) + +static Closure * +book_config_ldap_closure_new (ESourceConfigBackend *backend, + ESource *scratch_source) +{ + Closure *closure; + + closure = g_slice_new (Closure); + closure->backend = g_object_ref (backend); + closure->scratch_source = g_object_ref (scratch_source); + + return closure; +} + +static void +book_config_ldap_closure_free (Closure *closure) +{ + g_object_unref (closure->backend); + g_object_unref (closure->scratch_source); + + g_slice_free (Closure, closure); +} + +static void +book_config_ldap_context_free (Context *context) +{ + g_object_unref (context->auth_combo); + g_object_unref (context->auth_entry); + g_object_unref (context->host_entry); + g_object_unref (context->port_combo); + g_object_unref (context->security_combo); + g_object_unref (context->search_base_combo); + g_object_unref (context->search_base_button); + g_object_unref (context->search_scope_combo); + g_object_unref (context->search_filter_entry); + g_object_unref (context->limit_spinbutton); + g_object_unref (context->can_browse_toggle); + + g_slice_free (Context, context); +} + +static GtkTreeModel * +book_config_ldap_root_dse_query (ESourceConfigBackend *backend, + ESource *scratch_source) +{ + LDAP *ldap; + LDAPMessage *result = NULL; + GtkListStore *store = NULL; + ESourceAuthentication *extension; + struct timeval timeout; + const gchar *alert_id = NULL; + const gchar *extension_name; + const gchar *host; + gchar **values = NULL; + gint ldap_error; + gint option; + gint version; + guint16 port; + gint ii; + + const gchar *attrs[] = { "namingContexts", NULL }; + + /* FIXME This all runs synchronously in the main loop. + * We should do this in a separate thread behind + * async/finish functions. May need to define + * some custom GError codes, or maybe just an + * LDAP GError domain that reuses LDAP result + * codes from <ldap.h>. */ + + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + extension = e_source_get_extension (scratch_source, extension_name); + + host = e_source_authentication_get_host (extension); + port = e_source_authentication_get_port (extension); + + timeout.tv_sec = 60; + timeout.tv_usec = 0; + + ldap = ldap_init (host, port); + if (ldap == NULL) { + alert_id = "addressbook:ldap-init"; + goto exit; + } + + version = LDAP_VERSION3; + option = LDAP_OPT_PROTOCOL_VERSION; + if (ldap_set_option (ldap, option, &version) != LDAP_SUCCESS) { + /* XXX Define an alert for this. */ + g_warning ("Failed to set protocol version to LDAPv3"); + goto exit; + } + + /* FIXME Use the user's actual authentication settings. */ + if (ldap_simple_bind_s (ldap, NULL, NULL) != LDAP_SUCCESS) { + alert_id = "addressbook:ldap-auth"; + goto exit; + } + + ldap_error = ldap_search_ext_s ( + ldap, LDAP_ROOT_DSE, LDAP_SCOPE_BASE, + "(objectclass=*)", (gchar **) attrs, 0, + NULL, NULL, &timeout, LDAP_NO_LIMIT, &result); + if (ldap_error != LDAP_SUCCESS) { + alert_id = "addressbook:ldap-search-base"; + goto exit; + } + + values = ldap_get_values (ldap, result, "namingContexts"); + if (values == NULL || values[0] == NULL || *values[0] == '\0') { + alert_id = "addressbook:ldap-search-base"; + goto exit; + } + + store = gtk_list_store_new (1, G_TYPE_STRING); + + for (ii = 0; values[ii] != NULL; ii++) { + GtkTreeIter iter; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, values[ii], -1); + } + +exit: + if (alert_id != NULL) { + ESourceConfig *config; + gpointer parent; + + config = e_source_config_backend_get_config (backend); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (config)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + e_alert_run_dialog_for_args (parent, alert_id, NULL); + } + + if (values != NULL) + ldap_value_free (values); + + if (result != NULL) + ldap_msgfree (result); + + if (ldap != NULL) + ldap_unbind_s (ldap); + + /* This may be NULL, so don't use a cast macro. */ + return (GtkTreeModel *) store; +} + +static gboolean +book_config_ldap_port_to_active (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer unused) +{ + guint port; + gint active; + + port = g_value_get_uint (source_value); + + switch (port) { + case 0: /* initialize to LDAP_PORT */ + case LDAP_PORT: + active = 0; + break; + + case LDAPS_PORT: + active = 1; + break; + + case MSGC_PORT: + active = 2; + break; + + case MSGCS_PORT: + active = 3; + break; + + default: + active = -1; + break; + } + + g_value_set_int (target_value, active); + + if (active == -1) { + GObject *target; + GtkWidget *entry; + gchar *text; + + target = g_binding_get_target (binding); + entry = gtk_bin_get_child (GTK_BIN (target)); + + text = g_strdup_printf ("%u", port); + gtk_entry_set_text (GTK_ENTRY (entry), text); + g_free (text); + } + + return TRUE; +} + +static gboolean +book_config_ldap_active_to_port (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer unused) +{ + guint port = LDAP_PORT; + gint active; + + active = g_value_get_int (source_value); + + switch (active) { + case 0: + port = LDAP_PORT; + break; + + case 1: + port = LDAPS_PORT; + break; + + case 2: + port = MSGC_PORT; + break; + + case 3: + port = MSGCS_PORT; + break; + + default: + active = -1; + break; + } + + if (active == -1) { + GObject *source; + GtkWidget *entry; + const gchar *text; + glong v_long; + + source = g_binding_get_source (binding); + entry = gtk_bin_get_child (GTK_BIN (source)); + text = gtk_entry_get_text (GTK_ENTRY (entry)); + + v_long = strtol (text, NULL, 10); + if (v_long != 0 && v_long == CLAMP (v_long, 0, G_MAXUINT16)) + port = (guint) v_long; + } + + g_value_set_uint (target_value, port); + + return TRUE; +} + +static gboolean +book_config_ldap_port_to_security (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer unused) +{ + switch (g_value_get_int (source_value)) { + case 0: /* LDAP_PORT -> StartTLS */ + g_value_set_int ( + target_value, + E_SOURCE_LDAP_SECURITY_STARTTLS); + return TRUE; + + case 1: /* LDAPS_PORT -> LDAP over SSL */ + g_value_set_int ( + target_value, + E_SOURCE_LDAP_SECURITY_LDAPS); + return TRUE; + + case 2: /* MSGC_PORT -> StartTLS */ + g_value_set_int ( + target_value, + E_SOURCE_LDAP_SECURITY_STARTTLS); + return TRUE; + + case 3: /* MSGCS_PORT -> LDAP over SSL */ + g_value_set_int ( + target_value, + E_SOURCE_LDAP_SECURITY_LDAPS); + return TRUE; + + default: + break; + } + + return FALSE; +} + +static void +book_config_ldap_search_base_button_clicked_cb (GtkButton *button, + Closure *closure) +{ + Context *context; + GtkComboBox *combo_box; + GtkTreeModel *model; + const gchar *uid; + + uid = e_source_get_uid (closure->scratch_source); + context = g_object_get_data (G_OBJECT (closure->backend), uid); + g_return_if_fail (context != NULL); + + model = book_config_ldap_root_dse_query ( + closure->backend, closure->scratch_source); + + combo_box = GTK_COMBO_BOX (context->search_base_combo); + gtk_combo_box_set_model (combo_box, model); + gtk_combo_box_set_active (combo_box, 0); + + if (model != NULL) + g_object_unref (model); +} + +static gboolean +book_config_ldap_query_port_tooltip_cb (GtkComboBox *combo_box, + gint x, + gint y, + gboolean keyboard_mode, + GtkTooltip *tooltip) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *text; + + /* XXX This only works if the port number was selected from + * the drop down menu. No tooltip is shown if the user + * types the port number, even if the same port number + * is listed in the drop down menu. That's fixable but + * the code would be a lot messier, and is arguably a + * job for GtkComboBox. */ + + if (!gtk_combo_box_get_active_iter (combo_box, &iter)) + return FALSE; + + model = gtk_combo_box_get_model (combo_box); + gtk_tree_model_get (model, &iter, 1, &text, -1); + gtk_tooltip_set_text (tooltip, text); + g_free (text); + + return TRUE; +} + +static GtkWidget * +book_config_build_port_combo (void) +{ + GtkWidget *widget; + GtkComboBox *combo_box; + GtkCellRenderer *renderer; + GtkListStore *store; + GtkTreeIter iter; + + store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + gtk_list_store_append (store, &iter); + gtk_list_store_set ( + store, &iter, + 0, G_STRINGIFY (LDAP_PORT), + 1, _("Standard LDAP Port"), -1); + + gtk_list_store_append (store, &iter); + gtk_list_store_set ( + store, &iter, + 0, G_STRINGIFY (LDAPS_PORT), + 1, _("LDAP over SSL (deprecated)"), -1); + + gtk_list_store_append (store, &iter); + gtk_list_store_set ( + store, &iter, + 0, G_STRINGIFY (MSGC_PORT), + 1, _("Microsoft Global Catalog"), -1); + + gtk_list_store_append (store, &iter); + gtk_list_store_set ( + store, &iter, + 0, G_STRINGIFY (MSGCS_PORT), + 1, _("Microsoft Global Catalog over SSL"), -1); + + widget = gtk_combo_box_new_with_entry (); + + combo_box = GTK_COMBO_BOX (widget); + gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store)); + gtk_combo_box_set_entry_text_column (combo_box, 0); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "sensitive", FALSE, NULL); + gtk_cell_layout_pack_start ( + GTK_CELL_LAYOUT (widget), renderer, FALSE); + gtk_cell_layout_add_attribute ( + GTK_CELL_LAYOUT (widget), renderer, "text", 1); + + gtk_widget_set_has_tooltip (widget, TRUE); + + g_signal_connect ( + widget, "query-tooltip", + G_CALLBACK (book_config_ldap_query_port_tooltip_cb), NULL); + + g_object_unref (store); + + return widget; +} + +static void +book_config_ldap_insert_notebook_widget (GtkWidget *vbox, + GtkSizeGroup *size_group, + const gchar *caption, + GtkWidget *widget) +{ + GtkWidget *hbox; + GtkWidget *label; + + /* This is similar to e_source_config_insert_widget(), + * but instead adds the widget to the LDAP notebook. */ + + hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_widget_show (hbox); + + label = gtk_label_new (caption); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + gtk_size_group_add_widget (size_group, label); + gtk_widget_show (label); + + gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); +} + +static void +book_config_ldap_insert_widgets (ESourceConfigBackend *backend, + ESource *scratch_source) +{ + ESourceConfig *config; + ESourceExtension *extension; + GtkSizeGroup *size_group; + GtkNotebook *notebook; + GtkWidget *container; + GtkWidget *widget; + GtkWidget *page; + GtkWidget *hbox; + Context *context; + PangoAttribute *attr; + PangoAttrList *attr_list; + const gchar *extension_name; + const gchar *tab_label; + const gchar *uid; + + context = g_slice_new (Context); + uid = e_source_get_uid (scratch_source); + config = e_source_config_backend_get_config (backend); + + g_object_set_data_full ( + G_OBJECT (backend), uid, context, + (GDestroyNotify) book_config_ldap_context_free); + + e_book_source_config_add_offline_toggle ( + E_BOOK_SOURCE_CONFIG (config), scratch_source); + + container = e_source_config_get_page (config, scratch_source); + + /* Extra padding between the notebook and the options above. */ + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 6, 0, 0, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_notebook_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + notebook = GTK_NOTEBOOK (widget); + + /* For bold section headers. */ + attr_list = pango_attr_list_new (); + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (attr_list, attr); + + /* Page 1 */ + + tab_label = _("Connecting to LDAP"); + page = gtk_vbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (page), 12); + gtk_notebook_append_page (notebook, page, NULL); + gtk_notebook_set_tab_label_text (notebook, page, tab_label); + gtk_widget_show (page); + + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + /* Page 1 : Server Information */ + + widget = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_label_new (_("Server Information")); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_label_set_attributes (GTK_LABEL (widget), attr_list); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_entry_new (); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Server:"), widget); + context->host_entry = g_object_ref (widget); + gtk_widget_show (widget); + + widget = book_config_build_port_combo (); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Port:"), widget); + context->port_combo = g_object_ref (widget); + gtk_widget_show (widget); + + /* This must follow the order of ESourceLDAPSecurity. */ + widget = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("None")); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("LDAP over SSL (deprecated)")); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("StartTLS (recommended)")); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Encryption:"), widget); + context->security_combo = g_object_ref (widget); + gtk_widget_show (widget); + + g_object_bind_property_full ( + context->port_combo, "active", + context->security_combo, "active", + G_BINDING_DEFAULT, + book_config_ldap_port_to_security, + NULL, /* binding is one-way */ + NULL, (GDestroyNotify) NULL); + + /* If this is a new source, initialize security to StartTLS. */ + if (e_source_config_get_original_source (config) == NULL) + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2); + + /* Page 1 : Authentication */ + + widget = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_label_new (_("Authentication")); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_label_set_attributes (GTK_LABEL (widget), attr_list); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + /* This must follow the order of ESourceLDAPAuthentication. */ + widget = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("Anonymous")); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("Using email address")); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), + _("Using distinguished name (DN)")); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Method:"), widget); + context->auth_combo = g_object_ref (widget); + gtk_widget_show (widget); + + gtk_widget_set_tooltip_text ( + widget, _("This is the method Evolution will use to " + "authenticate you. Note that setting this to \"Using " + "email address\" requires anonymous access to your LDAP " + "server.")); + + widget = gtk_entry_new (); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Username:"), widget); + context->auth_entry = g_object_ref (widget); + gtk_widget_show (widget); + + g_object_unref (size_group); + + /* Page 2 */ + + tab_label = _("Using LDAP"); + page = gtk_vbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (page), 12); + gtk_notebook_append_page (notebook, page, NULL); + gtk_notebook_set_tab_label_text (notebook, page, tab_label); + gtk_widget_show (page); + + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + /* Page 2 : Searching */ + + widget = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_label_new (_("Searching")); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_label_set_attributes (GTK_LABEL (widget), attr_list); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_combo_box_new_with_entry (); + gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Search Base:"), widget); + context->search_base_combo = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_button_new_with_label ( + _("Find Possible Search Bases")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON)); + book_config_ldap_insert_notebook_widget ( + container, size_group, NULL, widget); + context->search_base_button = g_object_ref (widget); + gtk_widget_show (widget); + + /* Only sensitive when we have complete + * server and authentication details. */ + g_object_bind_property ( + config, "complete", + context->search_base_button, "sensitive", + G_BINDING_DEFAULT); + + g_signal_connect_data ( + widget, "clicked", + G_CALLBACK (book_config_ldap_search_base_button_clicked_cb), + book_config_ldap_closure_new (backend, scratch_source), + (GClosureNotify) book_config_ldap_closure_free, 0); + + /* This must follow the order of ESourceLDAPScope. */ + widget = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), _("One Level")); + gtk_combo_box_text_append_text ( + GTK_COMBO_BOX_TEXT (widget), _("Subtree")); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Search Scope:"), widget); + context->search_scope_combo = g_object_ref (widget); + gtk_widget_show (widget); + + gtk_widget_set_tooltip_text ( + widget, _("The search scope defines how deep you would " + "like the search to extend down the directory tree. A " + "search scope of \"Subtree\" will include all entries " + "below your search base. A search scope of \"One Level\" " + "will only include the entries one level beneath your " + "search base.")); + + widget = gtk_entry_new (); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Search Filter:"), widget); + context->search_filter_entry = g_object_ref (widget); + gtk_widget_show (widget); + + /* Page 2 : Downloading */ + + widget = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_label_new (_("Downloading")); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_label_set_attributes (GTK_LABEL (widget), attr_list); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_hbox_new (FALSE, 6); + book_config_ldap_insert_notebook_widget ( + container, size_group, _("Limit:"), widget); + gtk_widget_show (widget); + + hbox = widget; + + widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE); + gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); + context->limit_spinbutton = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_label_new (_("contacts")); + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_check_button_new_with_label ( + _("Browse until limit is reached")); + book_config_ldap_insert_notebook_widget ( + container, size_group, NULL, widget); + context->can_browse_toggle = g_object_ref (widget); + gtk_widget_show (widget); + + g_object_unref (size_group); + + pango_attr_list_unref (attr_list); + + /* Bind widgets to extension properties. */ + + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + extension = e_source_get_extension (scratch_source, extension_name); + + g_object_bind_property ( + extension, "host", + context->host_entry, "text", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property_full ( + extension, "port", + context->port_combo, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE, + book_config_ldap_port_to_active, + book_config_ldap_active_to_port, + NULL, (GDestroyNotify) NULL); + + g_object_bind_property ( + extension, "user", + context->auth_entry, "text", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + extension_name = E_SOURCE_EXTENSION_LDAP_BACKEND; + extension = e_source_get_extension (scratch_source, extension_name); + + g_object_bind_property ( + extension, "authentication", + context->auth_combo, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + extension, "can-browse", + context->can_browse_toggle, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + extension, "limit", + context->limit_spinbutton, "value", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + widget = gtk_bin_get_child (GTK_BIN (context->search_base_combo)); + + g_object_bind_property ( + extension, "root-dn", + widget, "text", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + extension, "scope", + context->search_scope_combo, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + extension, "filter", + context->search_filter_entry, "text", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + extension, "security", + context->security_combo, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); +} + +static gboolean +book_config_ldap_check_complete (ESourceConfigBackend *backend, + ESource *scratch_source) +{ + ESourceLDAPAuthentication auth; + ESourceExtension *extension; + const gchar *extension_name; + const gchar *host; + const gchar *user; + guint16 port; + + extension_name = E_SOURCE_EXTENSION_LDAP_BACKEND; + extension = e_source_get_extension (scratch_source, extension_name); + + auth = e_source_ldap_get_authentication (E_SOURCE_LDAP (extension)); + + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + extension = e_source_get_extension (scratch_source, extension_name); + + host = e_source_authentication_get_host ( + E_SOURCE_AUTHENTICATION (extension)); + port = e_source_authentication_get_port ( + E_SOURCE_AUTHENTICATION (extension)); + user = e_source_authentication_get_user ( + E_SOURCE_AUTHENTICATION (extension)); + + if (host == NULL || *host == '\0' || port == 0) + return FALSE; + + if (auth != E_SOURCE_LDAP_AUTHENTICATION_NONE) + if (user == NULL || *user == '\0') + return FALSE; + + return TRUE; +} + +static void +e_book_config_ldap_class_init (ESourceConfigBackendClass *class) +{ + EExtensionClass *extension_class; + + extension_class = E_EXTENSION_CLASS (class); + extension_class->extensible_type = E_TYPE_BOOK_SOURCE_CONFIG; + + class->parent_uid = "ldap-stub"; + class->backend_name = "ldap"; + class->insert_widgets = book_config_ldap_insert_widgets; + class->check_complete = book_config_ldap_check_complete; +} + +static void +e_book_config_ldap_class_finalize (ESourceConfigBackendClass *class) +{ +} + +static void +e_book_config_ldap_init (ESourceConfigBackend *backend) +{ +} + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + e_source_ldap_type_register (type_module); + e_book_config_ldap_register_type (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} |