1 /*
2 * evolution-book-config-ldap.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include "evolution-config.h"
19
20 #include <stdlib.h>
21 #include <glib/gi18n-lib.h>
22
23 #include <libebackend/libebackend.h>
24 #include <libedataserver/libedataserver.h>
25
26 #include <e-util/e-util.h>
27
28 /* Combo box ordering */
29 #define LDAP_PORT 389
30 #define LDAPS_PORT 636
31 #define MSGC_PORT 3268
32 #define MSGCS_PORT 3269
33
34 typedef ESourceConfigBackend EBookConfigLDAP;
35 typedef ESourceConfigBackendClass EBookConfigLDAPClass;
36
37 typedef struct _Closure Closure;
38 typedef struct _Context Context;
39
40 struct _Closure {
41 ESourceConfigBackend *backend;
42 ESource *scratch_source;
43 };
44
45 struct _Context {
46 GtkWidget *auth_combo;
47 GtkWidget *auth_entry;
48 GtkWidget *host_entry;
49 GtkWidget *port_combo;
50 GtkWidget *port_error_image;
51 GtkWidget *security_combo;
52 GtkWidget *search_base_combo;
53 GtkWidget *search_base_button;
54 GtkWidget *search_scope_combo;
55 GtkWidget *search_filter_entry;
56 GtkWidget *limit_spinbutton;
57 GtkWidget *can_browse_toggle;
58 };
59
60 /* Module Entry Points */
61 void e_module_load (GTypeModule *type_module);
62 void e_module_unload (GTypeModule *type_module);
63
64 /* Forward Declarations */
65 GType e_book_config_ldap_get_type (void);
66
G_DEFINE_DYNAMIC_TYPE(EBookConfigLDAP,e_book_config_ldap,E_TYPE_SOURCE_CONFIG_BACKEND)67 G_DEFINE_DYNAMIC_TYPE (
68 EBookConfigLDAP,
69 e_book_config_ldap,
70 E_TYPE_SOURCE_CONFIG_BACKEND)
71
72 static Closure *
73 book_config_ldap_closure_new (ESourceConfigBackend *backend,
74 ESource *scratch_source)
75 {
76 Closure *closure;
77
78 closure = g_slice_new (Closure);
79 closure->backend = g_object_ref (backend);
80 closure->scratch_source = g_object_ref (scratch_source);
81
82 return closure;
83 }
84
85 static void
book_config_ldap_closure_free(Closure * closure)86 book_config_ldap_closure_free (Closure *closure)
87 {
88 g_object_unref (closure->backend);
89 g_object_unref (closure->scratch_source);
90
91 g_slice_free (Closure, closure);
92 }
93
94 static void
book_config_ldap_context_free(Context * context)95 book_config_ldap_context_free (Context *context)
96 {
97 g_object_unref (context->auth_combo);
98 g_object_unref (context->auth_entry);
99 g_object_unref (context->host_entry);
100 g_object_unref (context->port_combo);
101 g_object_unref (context->port_error_image);
102 g_object_unref (context->security_combo);
103 g_object_unref (context->search_base_combo);
104 g_object_unref (context->search_base_button);
105 g_object_unref (context->search_scope_combo);
106 g_object_unref (context->search_filter_entry);
107 g_object_unref (context->limit_spinbutton);
108 g_object_unref (context->can_browse_toggle);
109
110 g_slice_free (Context, context);
111 }
112
113 static gboolean
book_config_ldap_port_to_active(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer unused)114 book_config_ldap_port_to_active (GBinding *binding,
115 const GValue *source_value,
116 GValue *target_value,
117 gpointer unused)
118 {
119 guint port;
120 gint active;
121
122 port = g_value_get_uint (source_value);
123
124 switch (port) {
125 case 0: /* initialize to LDAP_PORT */
126 case LDAP_PORT:
127 active = 0;
128 break;
129
130 case LDAPS_PORT:
131 active = 1;
132 break;
133
134 case MSGC_PORT:
135 active = 2;
136 break;
137
138 case MSGCS_PORT:
139 active = 3;
140 break;
141
142 default:
143 active = -1;
144 break;
145 }
146
147 g_value_set_int (target_value, active);
148
149 if (active == -1) {
150 GObject *target;
151 GtkWidget *entry;
152 gchar *text;
153
154 target = g_binding_get_target (binding);
155 entry = gtk_bin_get_child (GTK_BIN (target));
156
157 text = g_strdup_printf ("%u", port);
158 gtk_entry_set_text (GTK_ENTRY (entry), text);
159 g_free (text);
160 }
161
162 return TRUE;
163 }
164
165 static gboolean
book_config_ldap_active_to_port(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer unused)166 book_config_ldap_active_to_port (GBinding *binding,
167 const GValue *source_value,
168 GValue *target_value,
169 gpointer unused)
170 {
171 guint port = LDAP_PORT;
172 gint active;
173
174 active = g_value_get_int (source_value);
175
176 switch (active) {
177 case 0:
178 port = LDAP_PORT;
179 break;
180
181 case 1:
182 port = LDAPS_PORT;
183 break;
184
185 case 2:
186 port = MSGC_PORT;
187 break;
188
189 case 3:
190 port = MSGCS_PORT;
191 break;
192
193 default:
194 active = -1;
195 break;
196 }
197
198 if (active == -1) {
199 GObject *target;
200 GtkWidget *entry;
201 const gchar *text;
202 glong v_long;
203
204 target = g_binding_get_target (binding);
205 entry = gtk_bin_get_child (GTK_BIN (target));
206 text = gtk_entry_get_text (GTK_ENTRY (entry));
207
208 v_long = text ? strtol (text, NULL, 10) : 0;
209 if (v_long != 0 && v_long == CLAMP (v_long, 0, G_MAXUINT16))
210 port = (guint) v_long;
211 }
212
213 g_value_set_uint (target_value, port);
214
215 return TRUE;
216 }
217
218 static void
book_config_ldap_port_combo_changed(GtkComboBox * combo_box)219 book_config_ldap_port_combo_changed (GtkComboBox *combo_box)
220 {
221 if (gtk_combo_box_get_active (combo_box) == -1)
222 g_object_notify (G_OBJECT (combo_box), "active");
223 }
224
225 static gboolean
book_config_ldap_port_to_security(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer unused)226 book_config_ldap_port_to_security (GBinding *binding,
227 const GValue *source_value,
228 GValue *target_value,
229 gpointer unused)
230 {
231 switch (g_value_get_int (source_value)) {
232 case 0: /* LDAP_PORT -> StartTLS */
233 g_value_set_int (
234 target_value,
235 E_SOURCE_LDAP_SECURITY_STARTTLS);
236 return TRUE;
237
238 case 1: /* LDAPS_PORT -> LDAP over SSL */
239 g_value_set_int (
240 target_value,
241 E_SOURCE_LDAP_SECURITY_LDAPS);
242 return TRUE;
243
244 case 2: /* MSGC_PORT -> StartTLS */
245 g_value_set_int (
246 target_value,
247 E_SOURCE_LDAP_SECURITY_STARTTLS);
248 return TRUE;
249
250 case 3: /* MSGCS_PORT -> LDAP over SSL */
251 g_value_set_int (
252 target_value,
253 E_SOURCE_LDAP_SECURITY_LDAPS);
254 return TRUE;
255
256 default:
257 break;
258 }
259
260 return FALSE;
261 }
262
263 typedef struct _SearchBaseData {
264 GtkWindow *parent; /* not referenced */
265 GtkWidget *search_base_combo;
266 GtkWidget *dialog;
267 GCancellable *cancellable;
268 ESource *source;
269 gchar **root_dse;
270 GError *error;
271 } SearchBaseData;
272
273 static void
search_base_data_free(gpointer ptr)274 search_base_data_free (gpointer ptr)
275 {
276 SearchBaseData *sbd = ptr;
277
278 if (sbd) {
279 if (sbd->dialog)
280 gtk_widget_destroy (sbd->dialog);
281 g_clear_object (&sbd->search_base_combo);
282 g_clear_object (&sbd->cancellable);
283 g_clear_object (&sbd->source);
284 g_clear_error (&sbd->error);
285 g_strfreev (sbd->root_dse);
286 g_slice_free (SearchBaseData, sbd);
287 }
288 }
289
290 static void
book_config_ldap_search_base_thread(ESimpleAsyncResult * result,gpointer source_object,GCancellable * cancellable)291 book_config_ldap_search_base_thread (ESimpleAsyncResult *result,
292 gpointer source_object,
293 GCancellable *cancellable)
294 {
295 ESourceAuthentication *extension;
296 SearchBaseData *sbd;
297
298 g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
299
300 sbd = e_simple_async_result_get_user_data (result);
301
302 g_return_if_fail (sbd != NULL);
303
304 extension = e_source_get_extension (sbd->source, E_SOURCE_EXTENSION_AUTHENTICATION);
305
306 if (!e_util_query_ldap_root_dse_sync (
307 e_source_authentication_get_host (extension),
308 e_source_authentication_get_port (extension),
309 &sbd->root_dse, cancellable, &sbd->error)) {
310 sbd->root_dse = NULL;
311 }
312 }
313
314 static void
book_config_ldap_search_base_done(GObject * source_object,GAsyncResult * result,gpointer user_data)315 book_config_ldap_search_base_done (GObject *source_object,
316 GAsyncResult *result,
317 gpointer user_data)
318 {
319 SearchBaseData *sbd = user_data;
320 gboolean was_cancelled = FALSE;
321
322 g_return_if_fail (E_IS_SOURCE_CONFIG_BACKEND (source_object));
323 g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
324
325 sbd = e_simple_async_result_get_user_data (E_SIMPLE_ASYNC_RESULT (result));
326 g_return_if_fail (sbd != NULL);
327
328 if (!g_cancellable_is_cancelled (sbd->cancellable)) {
329 g_clear_pointer (&sbd->dialog, gtk_widget_destroy);
330 } else {
331 was_cancelled = TRUE;
332 }
333
334 if (!was_cancelled) {
335 if (sbd->error) {
336 const gchar *alert_id;
337
338 if (g_error_matches (sbd->error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT))
339 alert_id = "addressbook:ldap-init";
340 else if (g_error_matches (sbd->error, G_IO_ERROR, G_IO_ERROR_FAILED))
341 alert_id = "addressbook:ldap-search-base";
342 else
343 alert_id = "addressbook:ldap-communicate";
344
345 e_alert_run_dialog_for_args (sbd->parent, alert_id, sbd->error->message, NULL);
346 } else if (sbd->root_dse) {
347 GtkComboBox *combo_box;
348 GtkListStore *store;
349 gint ii;
350
351 store = gtk_list_store_new (1, G_TYPE_STRING);
352
353 for (ii = 0; sbd->root_dse[ii]; ii++) {
354 GtkTreeIter iter;
355
356 gtk_list_store_append (store, &iter);
357 gtk_list_store_set (store, &iter, 0, sbd->root_dse[ii], -1);
358 }
359
360 combo_box = GTK_COMBO_BOX (sbd->search_base_combo);
361 gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store));
362 gtk_combo_box_set_active (combo_box, 0);
363
364 g_clear_object (&store);
365 }
366 }
367 }
368
369 static void
search_base_data_response_cb(GtkWidget * dialog,gint response_id,gpointer user_data)370 search_base_data_response_cb (GtkWidget *dialog,
371 gint response_id,
372 gpointer user_data)
373 {
374 SearchBaseData *sbd = user_data;
375
376 g_return_if_fail (sbd != NULL);
377 g_return_if_fail (sbd->dialog == dialog);
378
379 sbd->dialog = NULL;
380
381 g_cancellable_cancel (sbd->cancellable);
382 gtk_widget_destroy (dialog);
383 }
384
385 static void
book_config_ldap_search_base_button_clicked_cb(GtkButton * button,Closure * closure)386 book_config_ldap_search_base_button_clicked_cb (GtkButton *button,
387 Closure *closure)
388 {
389 GtkWidget *dialog, *label, *content, *spinner, *box;
390 GtkWindow *parent;
391 ESimpleAsyncResult *result;
392 Context *context;
393 SearchBaseData *sbd;
394 const gchar *uid;
395
396 uid = e_source_get_uid (closure->scratch_source);
397 context = g_object_get_data (G_OBJECT (closure->backend), uid);
398 g_return_if_fail (context != NULL);
399
400 dialog = gtk_widget_get_toplevel (context->search_base_combo);
401 parent = GTK_IS_WINDOW (dialog) ? GTK_WINDOW (dialog) : NULL;
402
403 dialog = gtk_dialog_new_with_buttons ("",
404 parent,
405 GTK_DIALOG_MODAL,
406 _("_Cancel"), GTK_RESPONSE_CANCEL,
407 NULL);
408
409 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
410
411 spinner = e_spinner_new ();
412 e_spinner_start (E_SPINNER (spinner));
413 gtk_box_pack_start (GTK_BOX (box), spinner, FALSE, FALSE, 0);
414
415 label = gtk_label_new (_("Looking up server search bases, please wait…"));
416 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
417
418 gtk_widget_show_all (box);
419
420 content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
421
422 gtk_container_add (GTK_CONTAINER (content), box);
423 gtk_container_set_border_width (GTK_CONTAINER (content), 12);
424
425 sbd = g_slice_new0 (SearchBaseData);
426 sbd->parent = parent;
427 sbd->search_base_combo = g_object_ref (context->search_base_combo);
428 sbd->dialog = dialog;
429 sbd->cancellable = g_cancellable_new ();
430 sbd->source = g_object_ref (closure->scratch_source);
431
432 result = e_simple_async_result_new (G_OBJECT (closure->backend),
433 book_config_ldap_search_base_done, NULL, book_config_ldap_search_base_done);
434
435 e_simple_async_result_set_user_data (result, sbd, search_base_data_free);
436
437 g_signal_connect (dialog, "response", G_CALLBACK (search_base_data_response_cb), sbd);
438
439 e_simple_async_result_run_in_thread (result, G_PRIORITY_DEFAULT,
440 book_config_ldap_search_base_thread, sbd->cancellable);
441
442 g_object_unref (result);
443
444 gtk_dialog_run (GTK_DIALOG (dialog));
445 }
446
447 static gboolean
book_config_ldap_query_port_tooltip_cb(GtkComboBox * combo_box,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip)448 book_config_ldap_query_port_tooltip_cb (GtkComboBox *combo_box,
449 gint x,
450 gint y,
451 gboolean keyboard_mode,
452 GtkTooltip *tooltip)
453 {
454 GtkTreeModel *model;
455 GtkTreeIter iter;
456 gchar *text;
457
458 /* XXX This only works if the port number was selected from
459 * the drop down menu. No tooltip is shown if the user
460 * types the port number, even if the same port number
461 * is listed in the drop down menu. That's fixable but
462 * the code would be a lot messier, and is arguably a
463 * job for GtkComboBox. */
464
465 if (!gtk_combo_box_get_active_iter (combo_box, &iter))
466 return FALSE;
467
468 model = gtk_combo_box_get_model (combo_box);
469 gtk_tree_model_get (model, &iter, 1, &text, -1);
470 gtk_tooltip_set_text (tooltip, text);
471 g_free (text);
472
473 return TRUE;
474 }
475
476 static GtkWidget *
book_config_build_port_combo(void)477 book_config_build_port_combo (void)
478 {
479 GtkWidget *widget;
480 GtkComboBox *combo_box;
481 GtkCellRenderer *renderer;
482 GtkListStore *store;
483 GtkTreeIter iter;
484
485 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
486
487 gtk_list_store_append (store, &iter);
488 gtk_list_store_set (
489 store, &iter,
490 0, G_STRINGIFY (LDAP_PORT),
491 1, _("Standard LDAP Port"), -1);
492
493 gtk_list_store_append (store, &iter);
494 gtk_list_store_set (
495 store, &iter,
496 0, G_STRINGIFY (LDAPS_PORT),
497 1, _("LDAP over SSL/TLS (deprecated)"), -1);
498
499 gtk_list_store_append (store, &iter);
500 gtk_list_store_set (
501 store, &iter,
502 0, G_STRINGIFY (MSGC_PORT),
503 1, _("Microsoft Global Catalog"), -1);
504
505 gtk_list_store_append (store, &iter);
506 gtk_list_store_set (
507 store, &iter,
508 0, G_STRINGIFY (MSGCS_PORT),
509 1, _("Microsoft Global Catalog over SSL/TLS"), -1);
510
511 widget = gtk_combo_box_new_with_entry ();
512
513 combo_box = GTK_COMBO_BOX (widget);
514 gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store));
515 gtk_combo_box_set_entry_text_column (combo_box, 0);
516
517 renderer = gtk_cell_renderer_text_new ();
518 g_object_set (renderer, "sensitive", FALSE, NULL);
519 gtk_cell_layout_pack_start (
520 GTK_CELL_LAYOUT (widget), renderer, FALSE);
521 gtk_cell_layout_add_attribute (
522 GTK_CELL_LAYOUT (widget), renderer, "text", 1);
523
524 gtk_widget_set_has_tooltip (widget, TRUE);
525
526 g_signal_connect (
527 widget, "query-tooltip",
528 G_CALLBACK (book_config_ldap_query_port_tooltip_cb), NULL);
529
530 g_object_unref (store);
531
532 return widget;
533 }
534
535 static GtkWidget *
book_config_ldap_insert_notebook_widget(GtkWidget * vbox,GtkSizeGroup * size_group,const gchar * caption,GtkWidget * widget)536 book_config_ldap_insert_notebook_widget (GtkWidget *vbox,
537 GtkSizeGroup *size_group,
538 const gchar *caption,
539 GtkWidget *widget)
540 {
541 GtkWidget *hbox;
542 GtkWidget *label;
543
544 /* This is similar to e_source_config_insert_widget(),
545 * but instead adds the widget to the LDAP notebook. */
546
547 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
548 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
549 gtk_widget_show (hbox);
550
551 label = gtk_label_new (caption);
552 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
553 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
554 gtk_size_group_add_widget (size_group, label);
555 gtk_widget_show (label);
556
557 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
558
559 return hbox;
560 }
561
562 static void
book_config_ldap_insert_widgets(ESourceConfigBackend * backend,ESource * scratch_source)563 book_config_ldap_insert_widgets (ESourceConfigBackend *backend,
564 ESource *scratch_source)
565 {
566 ESourceConfig *config;
567 ESourceExtension *extension;
568 GtkSizeGroup *size_group;
569 GtkNotebook *notebook;
570 GtkWidget *container;
571 GtkWidget *widget;
572 GtkWidget *page;
573 GtkWidget *hbox;
574 Context *context;
575 PangoAttribute *attr;
576 PangoAttrList *attr_list;
577 const gchar *extension_name;
578 const gchar *tab_label;
579 const gchar *uid;
580 GtkTreeIter iter;
581 GtkListStore *list_store;
582 GtkCellRenderer *cell;
583 gchar *tmp;
584 gboolean is_new_source;
585
586 context = g_slice_new (Context);
587 uid = e_source_get_uid (scratch_source);
588 config = e_source_config_backend_get_config (backend);
589
590 g_object_set_data_full (
591 G_OBJECT (backend), uid, context,
592 (GDestroyNotify) book_config_ldap_context_free);
593
594 e_book_source_config_add_offline_toggle (
595 E_BOOK_SOURCE_CONFIG (config), scratch_source);
596
597 container = e_source_config_get_page (config, scratch_source);
598
599 /* Extra padding between the notebook and the options above. */
600 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
601 gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 6, 0, 0, 0);
602 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
603 gtk_widget_show (widget);
604
605 container = widget;
606
607 widget = gtk_notebook_new ();
608 gtk_container_add (GTK_CONTAINER (container), widget);
609 gtk_widget_show (widget);
610
611 notebook = GTK_NOTEBOOK (widget);
612
613 /* For bold section headers. */
614 attr_list = pango_attr_list_new ();
615 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
616 pango_attr_list_insert (attr_list, attr);
617
618 /* Page 1 */
619
620 tab_label = _("Connecting to LDAP");
621 page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
622 gtk_container_set_border_width (GTK_CONTAINER (page), 12);
623 gtk_notebook_append_page (notebook, page, NULL);
624 gtk_notebook_set_tab_label_text (notebook, page, tab_label);
625 gtk_widget_show (page);
626
627 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
628
629 /* Page 1 : Server Information */
630
631 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
632 gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
633 gtk_widget_show (widget);
634
635 container = widget;
636
637 widget = gtk_label_new (_("Server Information"));
638 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
639 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
640 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
641 gtk_widget_show (widget);
642
643 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
644 gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0);
645 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
646 gtk_widget_show (widget);
647
648 container = widget;
649
650 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
651 gtk_container_add (GTK_CONTAINER (container), widget);
652 gtk_widget_show (widget);
653
654 container = widget;
655
656 widget = gtk_entry_new ();
657 book_config_ldap_insert_notebook_widget (
658 container, size_group, _("Server:"), widget);
659 context->host_entry = g_object_ref (widget);
660 gtk_widget_show (widget);
661
662 widget = book_config_build_port_combo ();
663 hbox = book_config_ldap_insert_notebook_widget (
664 container, size_group, _("Port:"), widget);
665 context->port_combo = g_object_ref (widget);
666 gtk_widget_show (widget);
667
668 widget = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_BUTTON);
669 g_object_set (G_OBJECT (widget),
670 "visible", FALSE,
671 "has-tooltip", TRUE,
672 "tooltip-text", _("Port number is not valid"),
673 NULL);
674 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
675 context->port_error_image = g_object_ref (widget);
676
677 /* This must follow the order of ESourceLDAPSecurity. */
678 widget = gtk_combo_box_text_new ();
679 gtk_combo_box_text_append_text (
680 GTK_COMBO_BOX_TEXT (widget),
681 _("None"));
682 gtk_combo_box_text_append_text (
683 GTK_COMBO_BOX_TEXT (widget),
684 _("LDAP over SSL/TLS (deprecated)"));
685 gtk_combo_box_text_append_text (
686 GTK_COMBO_BOX_TEXT (widget),
687 _("StartTLS (recommended)"));
688 book_config_ldap_insert_notebook_widget (
689 container, size_group, _("Encryption:"), widget);
690 context->security_combo = g_object_ref (widget);
691 gtk_widget_show (widget);
692
693 e_binding_bind_property_full (
694 context->port_combo, "active",
695 context->security_combo, "active",
696 G_BINDING_DEFAULT,
697 book_config_ldap_port_to_security,
698 NULL, /* binding is one-way */
699 NULL, (GDestroyNotify) NULL);
700
701 /* If this is a new source, initialize security to StartTLS. */
702 if (e_source_config_get_original_source (config) == NULL)
703 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
704
705 /* Page 1 : Authentication */
706
707 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
708 gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
709 gtk_widget_show (widget);
710
711 container = widget;
712
713 widget = gtk_label_new (_("Authentication"));
714 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
715 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
716 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
717 gtk_widget_show (widget);
718
719 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
720 gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0);
721 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
722 gtk_widget_show (widget);
723
724 container = widget;
725
726 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
727 gtk_container_add (GTK_CONTAINER (container), widget);
728 gtk_widget_show (widget);
729
730 container = widget;
731
732 widget = gtk_combo_box_new ();
733 list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
734 gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (list_store));
735
736 cell = gtk_cell_renderer_text_new ();
737 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE);
738 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell, "markup", 0, NULL);
739
740 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0);
741 gtk_combo_box_set_id_column (GTK_COMBO_BOX (widget), 1);
742
743 /* This must follow the order of ESourceLDAPAuthentication. */
744 tmp = g_markup_printf_escaped ("%s\n<span font_size=\"x-small\">%s</span>",
745 _("Anonymous"),
746 _("Username can be left empty"));
747 gtk_list_store_append (list_store, &iter);
748 gtk_list_store_set (list_store, &iter, 0, tmp, -1);
749 g_free (tmp);
750
751 tmp = g_markup_printf_escaped ("%s\n<span font_size=\"x-small\">%s</span>",
752 _("Using email address"),
753 _("requires anonymous access to your LDAP server"));
754 gtk_list_store_append (list_store, &iter);
755 gtk_list_store_set (list_store, &iter, 0, tmp, -1);
756 g_free (tmp);
757
758 tmp = g_markup_printf_escaped ("%s\n<span font_size=\"x-small\">%s</span>",
759 _("Using distinguished name (DN)"),
760 _("for example: uid=user,dc=example,dc=com"));
761 gtk_list_store_append (list_store, &iter);
762 gtk_list_store_set (list_store, &iter, 0, tmp, -1);
763 g_free (tmp);
764
765 g_object_unref (list_store);
766
767 book_config_ldap_insert_notebook_widget (
768 container, size_group, _("Method:"), widget);
769 context->auth_combo = g_object_ref (widget);
770 gtk_widget_show (widget);
771
772 gtk_widget_set_tooltip_text (widget, _("This is the method Evolution will use to authenticate you."));
773
774 widget = gtk_entry_new ();
775 book_config_ldap_insert_notebook_widget (
776 container, size_group, _("Username:"), widget);
777 context->auth_entry = g_object_ref (widget);
778 gtk_widget_show (widget);
779
780 g_object_unref (size_group);
781
782 /* Page 2 */
783
784 tab_label = _("Using LDAP");
785 page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
786 gtk_container_set_border_width (GTK_CONTAINER (page), 12);
787 gtk_notebook_append_page (notebook, page, NULL);
788 gtk_notebook_set_tab_label_text (notebook, page, tab_label);
789 gtk_widget_show (page);
790
791 size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
792
793 /* Page 2 : Searching */
794
795 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
796 gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
797 gtk_widget_show (widget);
798
799 container = widget;
800
801 widget = gtk_label_new (_("Searching"));
802 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
803 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
804 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
805 gtk_widget_show (widget);
806
807 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
808 gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0);
809 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
810 gtk_widget_show (widget);
811
812 container = widget;
813
814 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
815 gtk_container_add (GTK_CONTAINER (container), widget);
816 gtk_widget_show (widget);
817
818 container = widget;
819
820 widget = gtk_combo_box_new_with_entry ();
821 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0);
822 book_config_ldap_insert_notebook_widget (
823 container, size_group, _("Search Base:"), widget);
824 context->search_base_combo = g_object_ref (widget);
825 gtk_widget_show (widget);
826
827 widget = e_dialog_button_new_with_icon ("edit-find", _("Find Possible Search Bases"));
828 book_config_ldap_insert_notebook_widget (
829 container, size_group, NULL, widget);
830 context->search_base_button = g_object_ref (widget);
831 gtk_widget_show (widget);
832
833 /* Only sensitive when we have complete
834 * server and authentication details. */
835 e_binding_bind_property (
836 config, "complete",
837 context->search_base_button, "sensitive",
838 G_BINDING_DEFAULT);
839
840 g_signal_connect_data (
841 widget, "clicked",
842 G_CALLBACK (book_config_ldap_search_base_button_clicked_cb),
843 book_config_ldap_closure_new (backend, scratch_source),
844 (GClosureNotify) book_config_ldap_closure_free, 0);
845
846 /* This must follow the order of ESourceLDAPScope. */
847 widget = gtk_combo_box_text_new ();
848 gtk_combo_box_text_append_text (
849 GTK_COMBO_BOX_TEXT (widget), _("One Level"));
850 gtk_combo_box_text_append_text (
851 GTK_COMBO_BOX_TEXT (widget), _("Subtree"));
852 book_config_ldap_insert_notebook_widget (
853 container, size_group, _("Search Scope:"), widget);
854 context->search_scope_combo = g_object_ref (widget);
855 gtk_widget_show (widget);
856
857 gtk_widget_set_tooltip_text (
858 widget, _("The search scope defines how deep you would "
859 "like the search to extend down the directory tree. A "
860 "search scope of “Subtree” will include all entries "
861 "below your search base. A search scope of “One Level” "
862 "will only include the entries one level beneath your "
863 "search base."));
864
865 widget = gtk_entry_new ();
866 book_config_ldap_insert_notebook_widget (
867 container, size_group, _("Search Filter:"), widget);
868 context->search_filter_entry = g_object_ref (widget);
869 gtk_widget_show (widget);
870
871 /* Page 2 : Downloading */
872
873 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
874 gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
875 gtk_widget_show (widget);
876
877 container = widget;
878
879 widget = gtk_label_new (_("Downloading"));
880 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
881 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
882 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
883 gtk_widget_show (widget);
884
885 widget = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
886 gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 12, 0);
887 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
888 gtk_widget_show (widget);
889
890 container = widget;
891
892 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
893 gtk_container_add (GTK_CONTAINER (container), widget);
894 gtk_widget_show (widget);
895
896 container = widget;
897
898 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
899 book_config_ldap_insert_notebook_widget (
900 container, size_group, _("Limit:"), widget);
901 gtk_widget_show (widget);
902
903 hbox = widget;
904
905 widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
906 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
907 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
908 context->limit_spinbutton = g_object_ref (widget);
909 gtk_widget_show (widget);
910
911 widget = gtk_label_new (_("contacts"));
912 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
913 gtk_widget_show (widget);
914
915 widget = gtk_check_button_new_with_label (
916 _("Browse until limit is reached"));
917 book_config_ldap_insert_notebook_widget (
918 container, size_group, NULL, widget);
919 context->can_browse_toggle = g_object_ref (widget);
920 gtk_widget_show (widget);
921
922 g_object_unref (size_group);
923
924 pango_attr_list_unref (attr_list);
925
926 /* Bind widgets to extension properties. */
927
928 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
929 is_new_source = !e_source_has_extension (scratch_source, extension_name);
930 extension = e_source_get_extension (scratch_source, extension_name);
931
932 e_binding_bind_object_text_property (
933 extension, "host",
934 context->host_entry, "text",
935 G_BINDING_BIDIRECTIONAL |
936 G_BINDING_SYNC_CREATE);
937
938 e_binding_bind_property_full (
939 extension, "port",
940 context->port_combo, "active",
941 G_BINDING_BIDIRECTIONAL |
942 G_BINDING_SYNC_CREATE,
943 book_config_ldap_port_to_active,
944 book_config_ldap_active_to_port,
945 NULL, (GDestroyNotify) NULL);
946
947 /* "active" doesn't change when setting custom port
948 * in entry, so check also on the "changed" signal. */
949 g_signal_connect (
950 context->port_combo, "changed",
951 G_CALLBACK (book_config_ldap_port_combo_changed), NULL);
952
953 e_binding_bind_object_text_property (
954 extension, "user",
955 context->auth_entry, "text",
956 G_BINDING_BIDIRECTIONAL |
957 G_BINDING_SYNC_CREATE);
958
959 extension_name = E_SOURCE_EXTENSION_LDAP_BACKEND;
960 extension = e_source_get_extension (scratch_source, extension_name);
961
962 e_binding_bind_property (
963 extension, "authentication",
964 context->auth_combo, "active",
965 G_BINDING_BIDIRECTIONAL |
966 G_BINDING_SYNC_CREATE);
967
968 e_binding_bind_property (
969 extension, "can-browse",
970 context->can_browse_toggle, "active",
971 G_BINDING_BIDIRECTIONAL |
972 G_BINDING_SYNC_CREATE);
973
974 e_binding_bind_property (
975 extension, "limit",
976 context->limit_spinbutton, "value",
977 G_BINDING_BIDIRECTIONAL |
978 G_BINDING_SYNC_CREATE);
979
980 widget = gtk_bin_get_child (GTK_BIN (context->search_base_combo));
981
982 e_binding_bind_object_text_property (
983 extension, "root-dn",
984 widget, "text",
985 G_BINDING_BIDIRECTIONAL |
986 G_BINDING_SYNC_CREATE);
987
988 e_binding_bind_property (
989 extension, "scope",
990 context->search_scope_combo, "active",
991 G_BINDING_BIDIRECTIONAL |
992 G_BINDING_SYNC_CREATE);
993
994 e_binding_bind_object_text_property (
995 extension, "filter",
996 context->search_filter_entry, "text",
997 G_BINDING_BIDIRECTIONAL |
998 G_BINDING_SYNC_CREATE);
999
1000 e_binding_bind_property (
1001 extension, "security",
1002 context->security_combo, "active",
1003 G_BINDING_BIDIRECTIONAL |
1004 G_BINDING_SYNC_CREATE);
1005
1006 /* Initialize values from UI into extension, if the source
1007 * is a fresh new source; bindings will take care of proper
1008 * values setting into extension properties. */
1009 if (is_new_source) {
1010 g_object_notify (G_OBJECT (context->host_entry), "text");
1011 g_object_notify (G_OBJECT (context->port_combo), "active");
1012 g_object_notify (G_OBJECT (context->auth_entry), "text");
1013 g_object_notify (G_OBJECT (context->auth_combo), "active");
1014 }
1015 }
1016
1017 static gboolean
book_config_ldap_check_complete(ESourceConfigBackend * backend,ESource * scratch_source)1018 book_config_ldap_check_complete (ESourceConfigBackend *backend,
1019 ESource *scratch_source)
1020 {
1021 ESourceLDAPAuthentication auth;
1022 ESourceExtension *extension;
1023 const gchar *extension_name;
1024 const gchar *host;
1025 const gchar *user;
1026 guint16 port;
1027 Context *context;
1028 gboolean correct, complete = TRUE;
1029
1030 context = g_object_get_data (G_OBJECT (backend), e_source_get_uid (scratch_source));
1031 g_return_val_if_fail (context != NULL, FALSE);
1032
1033 extension_name = E_SOURCE_EXTENSION_LDAP_BACKEND;
1034 extension = e_source_get_extension (scratch_source, extension_name);
1035
1036 auth = e_source_ldap_get_authentication (E_SOURCE_LDAP (extension));
1037
1038 extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
1039 extension = e_source_get_extension (scratch_source, extension_name);
1040
1041 host = e_source_authentication_get_host (
1042 E_SOURCE_AUTHENTICATION (extension));
1043 port = e_source_authentication_get_port (
1044 E_SOURCE_AUTHENTICATION (extension));
1045 user = e_source_authentication_get_user (
1046 E_SOURCE_AUTHENTICATION (extension));
1047
1048 correct = host != NULL && *host != '\0';
1049 complete = complete && correct;
1050
1051 e_util_set_entry_issue_hint (context->host_entry, correct ? NULL : _("Server address cannot be empty"));
1052
1053 correct = port != 0;
1054 complete = complete && correct;
1055
1056 gtk_widget_set_visible (context->port_error_image, !correct);
1057
1058 correct = TRUE;
1059
1060 if (auth != E_SOURCE_LDAP_AUTHENTICATION_NONE)
1061 if (user == NULL || *user == '\0')
1062 correct = FALSE;
1063
1064 complete = complete && correct;
1065
1066 e_util_set_entry_issue_hint (context->auth_entry, correct ? NULL : _("User name cannot be empty"));
1067
1068 return complete;
1069 }
1070
1071 static void
e_book_config_ldap_class_init(ESourceConfigBackendClass * class)1072 e_book_config_ldap_class_init (ESourceConfigBackendClass *class)
1073 {
1074 EExtensionClass *extension_class;
1075
1076 extension_class = E_EXTENSION_CLASS (class);
1077 extension_class->extensible_type = E_TYPE_BOOK_SOURCE_CONFIG;
1078
1079 class->parent_uid = "ldap-stub";
1080 class->backend_name = "ldap";
1081 class->insert_widgets = book_config_ldap_insert_widgets;
1082 class->check_complete = book_config_ldap_check_complete;
1083 }
1084
1085 static void
e_book_config_ldap_class_finalize(ESourceConfigBackendClass * class)1086 e_book_config_ldap_class_finalize (ESourceConfigBackendClass *class)
1087 {
1088 }
1089
1090 static void
e_book_config_ldap_init(ESourceConfigBackend * backend)1091 e_book_config_ldap_init (ESourceConfigBackend *backend)
1092 {
1093 }
1094
1095 G_MODULE_EXPORT void
e_module_load(GTypeModule * type_module)1096 e_module_load (GTypeModule *type_module)
1097 {
1098 e_book_config_ldap_register_type (type_module);
1099 }
1100
1101 G_MODULE_EXPORT void
e_module_unload(GTypeModule * type_module)1102 e_module_unload (GTypeModule *type_module)
1103 {
1104 }
1105