"Fossies" - the Fresh Open Source Software Archive 
Member "evolution-mapi-3.46.1/src/configuration/e-mail-config-mapi-backend.c" (2 Dec 2022, 27632 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "e-mail-config-mapi-backend.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * e-mail-config-mapi-backend.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #include "evolution-mapi-config.h"
20
21 #include <glib/gi18n-lib.h>
22
23 #include <camel/camel.h>
24 #include <libebackend/libebackend.h>
25 #include <libedataserver/libedataserver.h>
26
27 #include <mail/e-mail-config-auth-check.h>
28 #include <mail/e-mail-config-receiving-page.h>
29 #include <shell/e-shell.h>
30
31 #include "camel-mapi-settings.h"
32 #include "e-mapi-folder.h"
33 #include "e-mapi-connection.h"
34 #include "e-mapi-utils.h"
35 #include "e-mapi-config-utils.h"
36
37 #include "e-mail-config-mapi-backend.h"
38
39 struct _EMailConfigMapiBackendPrivate {
40 gint unused;
41 };
42
43 G_DEFINE_DYNAMIC_TYPE_EXTENDED (
44 EMailConfigMapiBackend,
45 e_mail_config_mapi_backend,
46 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
47 0,
48 G_ADD_PRIVATE_DYNAMIC (EMailConfigMapiBackend))
49
50 enum {
51 COL_MAPI_FULL_NAME = 0,
52 COL_MAPI_ACCOUNT,
53 COL_MAPI_INDEX,
54 COLS_MAX
55 };
56
57 static void
58 tree_selection_changed (GtkTreeSelection *selection, GtkDialog *dialog)
59 {
60 gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_ACCEPT, gtk_tree_selection_get_selected (selection, NULL, NULL));
61 }
62
63 static gboolean
64 transform_security_method_to_boolean (GBinding *binding,
65 const GValue *source_value,
66 GValue *target_value,
67 gpointer not_used)
68 {
69 CamelNetworkSecurityMethod security_method;
70 gboolean use_ssl;
71
72 security_method = g_value_get_enum (source_value);
73 use_ssl = (security_method != CAMEL_NETWORK_SECURITY_METHOD_NONE);
74 g_value_set_boolean (target_value, use_ssl);
75
76 return TRUE;
77 }
78
79 static gboolean
80 transform_boolean_to_security_method (GBinding *binding,
81 const GValue *source_value,
82 GValue *target_value,
83 gpointer not_used)
84 {
85 CamelNetworkSecurityMethod security_method;
86 gboolean use_ssl;
87
88 use_ssl = g_value_get_boolean (source_value);
89 if (use_ssl)
90 security_method = CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT;
91 else
92 security_method = CAMEL_NETWORK_SECURITY_METHOD_NONE;
93 g_value_set_enum (target_value, security_method);
94
95 return TRUE;
96 }
97
98 struct ECreateProfileData
99 {
100 const gchar *username;
101 struct PropertyRowSet_r *rowset;
102 gint index;
103 EFlag *flag;
104 };
105
106 static gboolean
107 create_profile_callback_in_main (gpointer user_data)
108 {
109 struct ECreateProfileData *cpd = user_data;
110 gint response;
111 gint i, index = 0;
112 GtkTreeIter iter;
113 GtkListStore *store;
114 GtkCellRenderer *renderer;
115 GtkTreeSelection *selection;
116 GtkWidget *dialog, *view;
117 GtkBox *content_area;
118
119 g_return_val_if_fail (cpd != NULL, FALSE);
120
121 dialog = gtk_dialog_new_with_buttons (_("Select username"),
122 NULL, GTK_DIALOG_MODAL,
123 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
124 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
125 NULL);
126
127 /*Tree View */
128 view = gtk_tree_view_new ();
129 renderer = gtk_cell_renderer_text_new ();
130 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
131 -1, _("Full name"), renderer,
132 "text", COL_MAPI_FULL_NAME, NULL);
133
134 renderer = gtk_cell_renderer_text_new ();
135 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
136 -1, _("Username"), renderer,
137 "text", COL_MAPI_ACCOUNT, NULL);
138
139 gtk_tree_view_column_set_resizable (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0), TRUE);
140 gtk_tree_view_column_set_resizable (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 1), TRUE);
141
142 /* Model for TreeView */
143 store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
144 gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (store));
145
146 for (i = 0; i < cpd->rowset->cRows; i++) {
147 const gchar *fullname = e_mapi_util_find_propertyrow_propval (&(cpd->rowset->aRow[i]), PidTagDisplayName);
148 const gchar *account = e_mapi_util_find_propertyrow_propval (&(cpd->rowset->aRow[i]), PidTagAccount);
149
150 if (fullname && account) {
151 gtk_list_store_append (store, &iter);
152 /* Preserve the index inside the store*/
153 gtk_list_store_set (store, &iter,
154 COL_MAPI_FULL_NAME, fullname,
155 COL_MAPI_ACCOUNT, account,
156 COL_MAPI_INDEX, i, -1);
157 }
158 }
159
160 /* Pack the TreeView into dialog's content area */
161 content_area = GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog)));
162
163 gtk_box_pack_start (content_area, gtk_label_new (_("There are more users with similar user name on a server.\nPlease select that you would like to use from the below list.")), TRUE, TRUE, 6);
164 gtk_box_pack_start (content_area, view, TRUE, TRUE, 6);
165
166 gtk_widget_show_all (GTK_WIDGET (content_area));
167
168 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
169 g_signal_connect (selection, "changed", G_CALLBACK (tree_selection_changed), dialog);
170 tree_selection_changed (selection, GTK_DIALOG (dialog));
171
172 response = gtk_dialog_run (GTK_DIALOG (dialog));
173 if (response == GTK_RESPONSE_ACCEPT) {
174 /* Get the index from the selected value */
175 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
176 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_MAPI_INDEX, &index, -1);
177 else
178 index = cpd->rowset->cRows + 1;
179 } else /* If we return a value > available, we are canceling the login.*/
180 index = cpd->rowset->cRows + 1;
181
182 gtk_widget_destroy (dialog);
183
184 cpd->index = index;
185 e_flag_set (cpd->flag);
186
187 return FALSE;
188 }
189
190 /* Callback for ProcessNetworkProfile. If we have more than one username,
191 we need to let the user select. */
192 static gint
193 create_profile_callback_in_thread (struct PropertyRowSet_r *rowset,
194 gconstpointer data)
195 {
196 struct ECreateProfileData cpd;
197 const gchar *username = (const gchar *) data;
198 gint i;
199
200 /* If we can find the exact username, then find & return its index. */
201 for (i = 0; i < rowset->cRows; i++) {
202 const gchar *account = e_mapi_util_find_propertyrow_propval (&(rowset->aRow[i]), PidTagAccount);
203
204 if (account && g_strcmp0 (username, account) == 0)
205 return i;
206 }
207
208 cpd.username = username;
209 cpd.rowset = rowset;
210 cpd.index = -1;
211 cpd.flag = e_flag_new ();
212
213 g_timeout_add (100, create_profile_callback_in_main, &cpd);
214
215 e_flag_wait (cpd.flag);
216 e_flag_free (cpd.flag);
217
218 return cpd.index;
219 }
220
221 static gboolean
222 validate_credentials_test (ESourceRegistry *registry,
223 EMapiProfileData *empd,
224 CamelMapiSettings *mapi_settings,
225 GCancellable *cancellable,
226 GError **perror)
227 {
228 gboolean status, success = FALSE;
229 struct mapi_context *mapi_ctx = NULL;
230
231 status = e_mapi_utils_create_mapi_context (&mapi_ctx, perror);
232 status = status && e_mapi_create_profile (mapi_ctx, empd, create_profile_callback_in_thread, empd->username, NULL, perror);
233 if (status && !g_cancellable_is_cancelled (cancellable)) {
234 /* profile was created, try to connect to the server */
235 EMapiConnection *conn;
236 gchar *profname;
237
238 status = FALSE;
239 profname = e_mapi_util_profile_name (mapi_ctx, empd, FALSE);
240
241 conn = e_mapi_connection_new (registry, profname, empd->credentials, cancellable, perror);
242 if (conn) {
243 status = e_mapi_connection_connected (conn);
244 g_object_unref (conn);
245 }
246
247 g_free (profname);
248 }
249
250 if (status) {
251 /* Things are successful */
252 gchar *profname = NULL;
253
254 profname = e_mapi_util_profile_name (mapi_ctx, empd, FALSE);
255 camel_mapi_settings_set_profile (mapi_settings, profname);
256 g_free (profname);
257
258 success = TRUE;
259 }
260
261 e_mapi_utils_destroy_mapi_context (mapi_ctx);
262
263 return success;
264 }
265
266 typedef struct _TryCredentialsData {
267 gchar *username;
268 gchar *domain;
269 gchar *server;
270 gboolean use_ssl;
271 gboolean krb_sso;
272 gchar *krb_realm;
273 CamelMapiSettings *mapi_settings;
274 EMailConfigServiceBackend *backend;
275 gboolean success;
276 } TryCredentialsData;
277
278 static void
279 try_credentials_data_free (gpointer ptr)
280 {
281 TryCredentialsData *data = ptr;
282
283 if (data) {
284 g_free (data->username);
285 g_free (data->domain);
286 g_free (data->server);
287 g_free (data->krb_realm);
288 g_object_unref (data->mapi_settings);
289 g_object_unref (data->backend);
290 g_slice_free (TryCredentialsData, data);
291 }
292 }
293
294 static gboolean
295 mail_config_mapi_try_credentials_sync (ECredentialsPrompter *prompter,
296 ESource *source,
297 const ENamedParameters *credentials,
298 gboolean *out_authenticated,
299 gpointer user_data,
300 GCancellable *cancellable,
301 GError **error)
302 {
303 TryCredentialsData *data = user_data;
304 EMailConfigServicePage *page;
305 ESourceRegistry *registry;
306 EMapiProfileData empd = { 0 };
307 GError *mapi_error = NULL;
308
309 empd.username = data->username;
310 empd.domain = data->domain;
311 empd.server = data->server;
312 empd.credentials = (ENamedParameters *) credentials;
313 empd.use_ssl = data->use_ssl;
314 empd.krb_sso = data->krb_sso;
315 empd.krb_realm = data->krb_realm;
316
317 page = e_mail_config_service_backend_get_page (data->backend);
318 registry = e_mail_config_service_page_get_registry (page);
319
320 data->success = validate_credentials_test (
321 registry,
322 &empd,
323 data->mapi_settings,
324 cancellable,
325 &mapi_error);
326
327 if (mapi_error) {
328 gboolean is_network_error = mapi_error && mapi_error->domain != E_MAPI_ERROR;
329
330 g_warn_if_fail (!data->success);
331 data->success = FALSE;
332
333 if (is_network_error)
334 g_propagate_error (error, mapi_error);
335 else
336 g_clear_error (&mapi_error);
337
338 return is_network_error ? FALSE : TRUE;
339 }
340
341 g_warn_if_fail (data->success);
342
343 *out_authenticated = data->success;
344
345 return TRUE;
346 }
347
348 static void
349 validate_credentials_idle (GObject *button,
350 gpointer user_data,
351 GCancellable *cancellable,
352 GError **perror)
353 {
354 TryCredentialsData *data = user_data;
355
356 g_return_if_fail (data != NULL);
357
358 if (data->success)
359 e_notice (NULL, GTK_MESSAGE_INFO, "%s", _("Authentication finished successfully."));
360 else
361 e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Authentication failed."));
362 }
363
364 static void
365 validate_credentials_thread (GObject *button,
366 gpointer user_data,
367 GCancellable *cancellable,
368 GError **perror)
369 {
370 TryCredentialsData *data = user_data;
371 EMailConfigServicePage *page;
372 ESourceRegistry *registry;
373
374 g_return_if_fail (data != NULL);
375
376 page = e_mail_config_service_backend_get_page (data->backend);
377 registry = e_mail_config_service_page_get_registry (page);
378
379 if (data->krb_sso) {
380 GError *krb_error = NULL, *local_error = NULL;
381 EMapiProfileData empd = { 0 };
382
383 empd.username = data->username;
384 empd.domain = data->domain;
385 empd.server = data->server;
386 empd.use_ssl = data->use_ssl;
387 empd.krb_sso = data->krb_sso;
388 empd.krb_realm = data->krb_realm;
389
390 e_mapi_util_trigger_krb_auth (&empd, &krb_error);
391
392 data->success = validate_credentials_test (
393 registry,
394 &empd,
395 data->mapi_settings,
396 cancellable,
397 &local_error);
398
399 if (!data->success) {
400 if (krb_error && local_error) {
401 GError *new_error = g_error_new (local_error->domain, local_error->code,
402 /* Translators: the first '%s' is replaced with a generic error message,
403 the second '%s' is replaced with additional error information. */
404 C_("gssapi_error", "%s (%s)"), local_error->message, krb_error->message);
405 g_propagate_error (perror, new_error);
406 } else if (krb_error) {
407 g_propagate_error (perror, krb_error);
408 krb_error = NULL;
409 } else if (local_error) {
410 g_propagate_error (perror, local_error);
411 local_error = NULL;
412 }
413 }
414
415 g_clear_error (&krb_error);
416 g_clear_error (&local_error);
417 } else {
418 EShell *shell;
419 ESource *source;
420
421 shell = e_shell_get_default ();
422 source = e_mail_config_service_backend_get_source (data->backend);
423
424 e_credentials_prompter_loop_prompt_sync (e_shell_get_credentials_prompter (shell),
425 source, E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE,
426 mail_config_mapi_try_credentials_sync, data, cancellable, perror);
427 }
428 }
429
430 static void
431 validate_credentials_cb (GtkWidget *widget,
432 EMailConfigServiceBackend *backend)
433 {
434 EMapiProfileData empd = { 0 };
435 CamelSettings *settings;
436 CamelMapiSettings *mapi_settings;
437 CamelNetworkSettings *network_settings;
438 const gchar *host;
439 const gchar *user;
440
441 if (!e_mapi_config_utils_is_online ()) {
442 e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Cannot authenticate MAPI accounts in offline mode"));
443 return;
444 }
445
446 settings = e_mail_config_service_backend_get_settings (backend);
447 mapi_settings = CAMEL_MAPI_SETTINGS (settings);
448 network_settings = CAMEL_NETWORK_SETTINGS (settings);
449
450 host = camel_network_settings_get_host (network_settings);
451 user = camel_network_settings_get_user (network_settings);
452
453 /* Silently remove domain part from a username when user enters it as such.
454 This change will be visible in the UI on new edit open. */
455 if (user != NULL && strchr (user, '\\') != NULL) {
456 gchar *at;
457
458 at = strrchr (user, '\\') + 1;
459 camel_network_settings_set_user (network_settings, at);
460 user = camel_network_settings_get_user (network_settings);
461 }
462
463 empd.server = host;
464 empd.username = user;
465 e_mapi_util_profiledata_from_settings (&empd, mapi_settings);
466
467 if (!empd.username || !*(empd.username)
468 || !empd.server || !*(empd.server)
469 || ((!empd.domain || !*(empd.domain))
470 && !empd.krb_sso)) {
471 e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Server, username and domain name cannot be empty. Please fill them with correct values."));
472 return;
473 } else if (empd.krb_sso && (!empd.krb_realm || !*(empd.krb_realm))) {
474 e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Realm name cannot be empty when kerberos is selected. Please fill them with correct values."));
475 return;
476 }
477
478 if (COMPLETE_PROFILEDATA (&empd)) {
479 TryCredentialsData *data = g_slice_new0 (TryCredentialsData);
480
481 data->username = g_strdup (empd.username);
482 data->domain = g_strdup (empd.domain);
483 data->server = g_strdup (empd.server);
484 data->use_ssl = empd.use_ssl;
485 data->krb_sso = empd.krb_sso;
486 data->krb_realm = g_strdup (empd.krb_realm);
487 data->mapi_settings = g_object_ref (mapi_settings);
488 data->backend = g_object_ref (backend);
489 data->success = FALSE;
490
491 e_mapi_config_utils_run_in_thread_with_feedback_modal (e_mapi_config_utils_get_widget_toplevel_window (widget),
492 G_OBJECT (widget),
493 _("Connecting to the server, please wait…"),
494 validate_credentials_thread,
495 validate_credentials_idle,
496 data,
497 try_credentials_data_free);
498 } else {
499 e_notice (NULL, GTK_MESSAGE_ERROR, "%s", _("Authentication failed."));
500 }
501
502 g_warn_if_fail (empd.credentials == NULL);
503 }
504
505 static ESource *
506 mail_config_mapi_backend_new_collection (EMailConfigServiceBackend *backend)
507 {
508 EMailConfigServiceBackendClass *class;
509 ESourceBackend *extension;
510 ESource *source;
511 const gchar *extension_name;
512
513 /* This backend serves double duty. One instance holds the
514 * mail account source, another holds the mail transport source.
515 * We can differentiate by examining the EMailConfigServicePage
516 * the backend is associated with. We return a new collection
517 * for both the Receiving Page and Sending Page. Although the
518 * Sending Page instance ultimately gets discarded, it's still
519 * needed to avoid creating a [Mapi Backend] extension in the
520 * mail transport source. */
521
522 class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
523
524 source = e_source_new (NULL, NULL, NULL);
525 extension_name = E_SOURCE_EXTENSION_COLLECTION;
526 extension = e_source_get_extension (source, extension_name);
527 e_source_backend_set_backend_name (extension, class->backend_name);
528
529 return source;
530 }
531
532 static GHashTable *
533 get_kerberos_realms (void)
534 {
535 GFile *file;
536 GHashTable *realms = NULL;
537
538 file = g_file_new_for_path ("/etc/krb5.conf");
539
540 if (file) {
541 GFileInputStream *input_stream = g_file_read (file, NULL, NULL);
542
543 if (input_stream) {
544 GDataInputStream *data = g_data_input_stream_new (G_INPUT_STREAM (input_stream));
545
546 if (data) {
547 gchar *line;
548 gboolean in_domain_realm = FALSE;
549
550 while (line = g_data_input_stream_read_line_utf8 (data, NULL, NULL, NULL), line) {
551 g_strstrip (line);
552
553 if (line [0] == '[') {
554 if (in_domain_realm) {
555 g_free (line);
556 break;
557 }
558
559 if (g_str_equal (line, "[domain_realm]"))
560 in_domain_realm = TRUE;
561 } else if (in_domain_realm) {
562 gchar **split = g_strsplit (line, "=", 2);
563
564 if (split && split[0] && split[1] && !split[2]) {
565 g_strstrip (split[0]);
566 g_strstrip (split[1]);
567
568 if (split[0][0] && split[1][0]) {
569 if (!realms)
570 realms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
571
572 g_hash_table_insert (realms, g_strdup (split[0]), g_strdup (split[1]));
573 }
574 }
575
576 g_strfreev (split);
577 }
578
579 g_free (line);
580 }
581
582 g_object_unref (data);
583 }
584
585 g_object_unref (input_stream);
586 }
587
588 g_object_unref (file);
589 }
590
591 return realms;
592 }
593
594 static const gchar *
595 find_in_realms (GHashTable *realms, const gchar *domain)
596 {
597 GHashTableIter iter;
598 gpointer key, value;
599
600 g_return_val_if_fail (realms != NULL, NULL);
601 g_return_val_if_fail (domain != NULL, NULL);
602
603 if (!*domain)
604 return NULL;
605
606 g_hash_table_iter_init (&iter, realms);
607 while (g_hash_table_iter_next (&iter, &key, &value)) {
608 if (g_ascii_strcasecmp (domain, key) == 0)
609 return value;
610 }
611
612 return NULL;
613 }
614
615 static void
616 kerberos_toggled_cb (GtkWidget *check_button,
617 GParamSpec *param,
618 CamelMapiSettings *settings)
619 {
620 gchar *host;
621
622 if (!camel_mapi_settings_get_kerberos (settings))
623 return;
624
625 host = camel_network_settings_dup_host (CAMEL_NETWORK_SETTINGS (settings));
626
627 if (host && *host) {
628 /* guess realm from /etc/krb5.conf, if available;
629 it's just trying to be nice to the user, no big deal if this fails */
630 GHashTable *realms;
631
632 realms = get_kerberos_realms ();
633 if (realms) {
634 const gchar *dot;
635
636 dot = host;
637 while (dot) {
638 const gchar *realm;
639
640 realm = find_in_realms (realms, dot);
641 if (realm && *realm) {
642 camel_mapi_settings_set_realm (settings, realm);
643 break;
644 }
645
646 dot = *dot ? strchr (dot + 1, '.') : NULL;
647 }
648
649 g_hash_table_destroy (realms);
650 }
651 }
652
653 g_free (host);
654 }
655
656 static void
657 mail_config_mapi_backend_insert_widgets (EMailConfigServiceBackend *backend,
658 GtkBox *parent)
659 {
660 EMailConfigServicePage *page;
661 ESource *source;
662 ESourceExtension *extension;
663 CamelSettings *settings;
664 GtkWidget *hgrid = NULL;
665 GtkWidget *label, *entry;
666 GtkWidget *auth_button;
667 GtkWidget *secure_conn;
668 GtkWidget *krb_sso;
669 GtkGrid *content_grid;
670 gchar *markup;
671 gint irow;
672
673 page = e_mail_config_service_backend_get_page (backend);
674
675 /* This backend serves double duty. One instance holds the
676 * mail account source, another holds the mail transport source.
677 * We can differentiate by examining the EMailConfigServicePage
678 * the backend is associated with. This method only applies to
679 * the Receiving Page. */
680 if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
681 return;
682
683 /* This needs to come _after_ the page type check so we don't
684 * introduce a backend extension in the mail transport source. */
685 settings = e_mail_config_service_backend_get_settings (backend);
686
687 content_grid = GTK_GRID (gtk_grid_new ());
688 gtk_widget_set_margin_left (GTK_WIDGET (content_grid), 12);
689 gtk_grid_set_row_spacing (content_grid, 6);
690 gtk_grid_set_column_spacing (content_grid, 6);
691 gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (content_grid), FALSE, FALSE, 0);
692
693 irow = 0;
694
695 markup = g_markup_printf_escaped ("<b>%s</b>", _("Configuration"));
696 label = gtk_label_new (markup);
697 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
698 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
699 g_free (markup);
700
701 gtk_grid_attach (content_grid, label, 0, irow, 2, 1);
702 irow++;
703
704 label = gtk_label_new_with_mnemonic (_("_Server:"));
705 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
706
707 entry = gtk_entry_new ();
708 gtk_widget_set_hexpand (entry, TRUE);
709 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
710
711 e_binding_bind_object_text_property (
712 settings, "host",
713 entry, "text",
714 G_BINDING_BIDIRECTIONAL |
715 G_BINDING_SYNC_CREATE);
716
717 gtk_grid_attach (content_grid, label, 0, irow, 1, 1);
718 gtk_grid_attach (content_grid, entry, 1, irow, 1, 1);
719 irow++;
720
721 label = gtk_label_new_with_mnemonic (_("User_name:"));
722 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
723
724 entry = gtk_entry_new ();
725 gtk_widget_set_hexpand (entry, TRUE);
726 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
727
728 e_binding_bind_object_text_property (
729 settings, "user",
730 entry, "text",
731 G_BINDING_BIDIRECTIONAL |
732 G_BINDING_SYNC_CREATE);
733
734 gtk_grid_attach (content_grid, label, 0, irow, 1, 1);
735 gtk_grid_attach (content_grid, entry, 1, irow, 1, 1);
736 irow++;
737
738 /* Domain name & Authenticate Button */
739 hgrid = g_object_new (GTK_TYPE_GRID,
740 "column-homogeneous", FALSE,
741 "column-spacing", 6,
742 "orientation", GTK_ORIENTATION_HORIZONTAL,
743 NULL);
744 gtk_widget_set_hexpand (hgrid, TRUE);
745
746 label = gtk_label_new_with_mnemonic (_("_Domain name:"));
747 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
748
749 entry = gtk_entry_new ();
750 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
751 gtk_widget_set_hexpand (entry, TRUE);
752 gtk_container_add (GTK_CONTAINER (hgrid), entry);
753 e_binding_bind_object_text_property (
754 settings, "domain",
755 entry, "text",
756 G_BINDING_BIDIRECTIONAL |
757 G_BINDING_SYNC_CREATE);
758
759 auth_button = gtk_button_new_with_mnemonic (_("_Authenticate"));
760 gtk_container_add (GTK_CONTAINER (hgrid), auth_button);
761 g_signal_connect (auth_button, "clicked", G_CALLBACK (validate_credentials_cb), backend);
762
763 gtk_grid_attach (content_grid, label, 0, irow, 1, 1);
764 gtk_grid_attach (content_grid, hgrid, 1, irow, 1, 1);
765 irow++;
766
767 secure_conn = gtk_check_button_new_with_mnemonic (_("_Use secure connection"));
768 gtk_widget_set_hexpand (secure_conn, TRUE);
769
770 gtk_grid_attach (content_grid, secure_conn, 1, irow, 1, 1);
771 irow++;
772
773 e_binding_bind_property_full (
774 settings, "security-method",
775 secure_conn, "active",
776 G_BINDING_BIDIRECTIONAL |
777 G_BINDING_SYNC_CREATE,
778 transform_security_method_to_boolean,
779 transform_boolean_to_security_method,
780 NULL, NULL);
781
782 krb_sso = gtk_check_button_new_with_mnemonic (_("_Kerberos authentication"));
783 gtk_widget_set_hexpand (secure_conn, TRUE);
784
785 e_binding_bind_property (
786 settings, "kerberos",
787 krb_sso, "active",
788 G_BINDING_BIDIRECTIONAL |
789 G_BINDING_SYNC_CREATE);
790
791 gtk_grid_attach (content_grid, krb_sso, 1, irow, 1, 1);
792 irow++;
793
794 label = gtk_label_new_with_mnemonic (_("_Realm name:"));
795 gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
796
797 e_binding_bind_property (
798 settings, "kerberos",
799 label, "sensitive",
800 G_BINDING_SYNC_CREATE);
801
802 g_signal_connect_object (settings, "notify::kerberos",
803 G_CALLBACK (kerberos_toggled_cb), settings,
804 G_CONNECT_AFTER);
805
806 entry = gtk_entry_new ();
807 gtk_widget_set_hexpand (entry, TRUE);
808 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
809
810 e_binding_bind_object_text_property (
811 settings, "realm",
812 entry, "text",
813 G_BINDING_BIDIRECTIONAL |
814 G_BINDING_SYNC_CREATE);
815
816 e_binding_bind_property (
817 settings, "kerberos",
818 entry, "sensitive",
819 G_BINDING_SYNC_CREATE);
820
821 gtk_grid_attach (content_grid, label, 0, irow, 1, 1);
822 gtk_grid_attach (content_grid, entry, 1, irow, 1, 1);
823
824 source = e_mail_config_service_backend_get_collection (backend);
825 extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
826
827 /* The collection identity is the user name. */
828 e_binding_bind_property (
829 settings, "user",
830 extension, "identity",
831 G_BINDING_BIDIRECTIONAL |
832 G_BINDING_SYNC_CREATE);
833
834 gtk_widget_show_all (GTK_WIDGET (content_grid));
835 }
836
837 static void
838 mail_config_mapi_backend_setup_defaults (EMailConfigServiceBackend *backend)
839 {
840 CamelSettings *settings;
841 EMailConfigServicePage *page;
842 const gchar *email_address;
843 gchar **parts = NULL;
844
845 page = e_mail_config_service_backend_get_page (backend);
846
847 /* This backend serves double duty. One instance holds the
848 * mail account source, another holds the mail transport source.
849 * We can differentiate by examining the EMailConfigServicePage
850 * the backend is associated with. This method only applies to
851 * the Receiving Page. */
852 if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
853 return;
854
855 /* This needs to come _after_ the page type check so we don't
856 * introduce a backend extension in the mail transport source. */
857 settings = e_mail_config_service_backend_get_settings (backend);
858
859 email_address = e_mail_config_service_page_get_email_address (page);
860 if (email_address != NULL)
861 parts = g_strsplit (email_address, "@", 2);
862
863 if (parts != NULL && g_strv_length (parts) >= 2) {
864 CamelNetworkSettings *network_settings;
865 gchar *host;
866
867 g_strstrip (parts[0]); /* user name */
868 g_strstrip (parts[1]); /* domain name */
869
870 host = g_strdup_printf ("exchange.%s", parts[1]);
871
872 network_settings = CAMEL_NETWORK_SETTINGS (settings);
873 camel_network_settings_set_host (network_settings, host);
874 camel_network_settings_set_user (network_settings, parts[0]);
875
876 g_free (host);
877 }
878
879 g_strfreev (parts);
880 }
881
882 static gboolean
883 mail_config_mapi_backend_check_complete (EMailConfigServiceBackend *backend)
884 {
885 EMailConfigServicePage *page;
886 CamelSettings *settings;
887 CamelMapiSettings *mapi_settings;
888 const gchar *profile;
889
890 page = e_mail_config_service_backend_get_page (backend);
891
892 /* This backend serves double duty. One instance holds the
893 * mail account source, another holds the mail transport source.
894 * We can differentiate by examining the EMailConfigServicePage
895 * the backend is associated with. This method only applies to
896 * the Receiving Page. */
897 if (!E_IS_MAIL_CONFIG_RECEIVING_PAGE (page))
898 return TRUE;
899
900 /* This needs to come _after_ the page type check so we don't
901 * introduce a backend extension in the mail transport source. */
902 settings = e_mail_config_service_backend_get_settings (backend);
903 mapi_settings = CAMEL_MAPI_SETTINGS (settings);
904
905 /* We assume that if the profile is set, then the setting is valid. */
906 profile = camel_mapi_settings_get_profile (mapi_settings);
907
908 /* Profile not set. Do not proceed with account creation.*/
909 return (profile != NULL && *profile != '\0');
910 }
911
912 static void
913 e_mail_config_mapi_backend_class_init (EMailConfigMapiBackendClass *class)
914 {
915 EMailConfigServiceBackendClass *backend_class;
916
917 backend_class = E_MAIL_CONFIG_SERVICE_BACKEND_CLASS (class);
918 backend_class->backend_name = "mapi";
919 backend_class->new_collection = mail_config_mapi_backend_new_collection;
920 backend_class->insert_widgets = mail_config_mapi_backend_insert_widgets;
921 backend_class->setup_defaults = mail_config_mapi_backend_setup_defaults;
922 backend_class->check_complete = mail_config_mapi_backend_check_complete;
923 }
924
925 static void
926 e_mail_config_mapi_backend_class_finalize (EMailConfigMapiBackendClass *class)
927 {
928 }
929
930 static void
931 e_mail_config_mapi_backend_init (EMailConfigMapiBackend *backend)
932 {
933 backend->priv = e_mail_config_mapi_backend_get_instance_private (backend);
934 }
935
936 void
937 e_mail_config_mapi_backend_type_register (GTypeModule *type_module)
938 {
939 /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
940 * function, so we have to wrap it with a public function in
941 * order to register types from a separate compilation unit. */
942 e_mail_config_mapi_backend_register_type (type_module);
943 }