aboutsummaryrefslogtreecommitdiffstats
path: root/modules/book-config-ldap/evolution-book-config-ldap.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/book-config-ldap/evolution-book-config-ldap.c')
-rw-r--r--modules/book-config-ldap/evolution-book-config-ldap.c990
1 files changed, 990 insertions, 0 deletions
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)
+{
+}