1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3 * Copyright © 2011 – 2017 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "config.h"
20
21 #include <glib/gi18n-lib.h>
22
23 #include "goaimapauthlogin.h"
24 #include "goamailclient.h"
25 #include "goaimapsmtpprovider.h"
26 #include "goaprovider.h"
27 #include "goasmtpauth.h"
28 #include "goautils.h"
29
30 struct _GoaImapSmtpProvider
31 {
32 GoaProvider parent_instance;
33 };
34
35 G_DEFINE_TYPE_WITH_CODE (GoaImapSmtpProvider, goa_imap_smtp_provider, GOA_TYPE_PROVIDER,
36 goa_provider_ensure_extension_points_registered ();
37 g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
38 g_define_type_id,
39 GOA_IMAP_SMTP_NAME,
40 0));
41
42 /* ---------------------------------------------------------------------------------------------------- */
43
44 static const gchar *
get_provider_type(GoaProvider * provider)45 get_provider_type (GoaProvider *provider)
46 {
47 return GOA_IMAP_SMTP_NAME;
48 }
49
50 static gchar *
get_provider_name(GoaProvider * provider,GoaObject * object)51 get_provider_name (GoaProvider *provider, GoaObject *object)
52 {
53 return g_strdup (_("IMAP and SMTP"));
54 }
55
56 static GoaProviderGroup
get_provider_group(GoaProvider * provider)57 get_provider_group (GoaProvider *provider)
58 {
59 return GOA_PROVIDER_GROUP_MAIL;
60 }
61
62 static GoaProviderFeatures
get_provider_features(GoaProvider * _provider)63 get_provider_features (GoaProvider *_provider)
64 {
65 return GOA_PROVIDER_FEATURE_MAIL;
66 }
67
68 static GIcon *
get_provider_icon(GoaProvider * provider,GoaObject * object)69 get_provider_icon (GoaProvider *provider, GoaObject *object)
70 {
71 return g_themed_icon_new_with_default_fallbacks ("mail-unread-symbolic");
72 }
73
74 /* ---------------------------------------------------------------------------------------------------- */
75
76 static gboolean on_handle_get_password (GoaPasswordBased *interface,
77 GDBusMethodInvocation *invocation,
78 const gchar *id,
79 gpointer user_data);
80
81 static gboolean
build_object(GoaProvider * provider,GoaObjectSkeleton * object,GKeyFile * key_file,const gchar * group,GDBusConnection * connection,gboolean just_added,GError ** error)82 build_object (GoaProvider *provider,
83 GoaObjectSkeleton *object,
84 GKeyFile *key_file,
85 const gchar *group,
86 GDBusConnection *connection,
87 gboolean just_added,
88 GError **error)
89 {
90 GoaAccount *account = NULL;
91 GoaMail *mail = NULL;
92 GoaPasswordBased *password_based = NULL;
93 gboolean enabled;
94 gboolean imap_accept_ssl_errors;
95 gboolean imap_use_ssl;
96 gboolean imap_use_tls;
97 gboolean ret = FALSE;
98 gboolean smtp_accept_ssl_errors;
99 gboolean smtp_auth_login = FALSE;
100 gboolean smtp_auth_plain = FALSE;
101 gboolean smtp_use_auth;
102 gboolean smtp_use_ssl;
103 gboolean smtp_use_tls;
104 gchar *email_address = NULL;
105 gchar *imap_host = NULL;
106 gchar *imap_username = NULL;
107 gchar *name = NULL;
108 gchar *smtp_host = NULL;
109 gchar *smtp_username = NULL;
110
111 /* Chain up */
112 if (!GOA_PROVIDER_CLASS (goa_imap_smtp_provider_parent_class)->build_object (provider,
113 object,
114 key_file,
115 group,
116 connection,
117 just_added,
118 error))
119 goto out;
120
121 password_based = goa_object_get_password_based (GOA_OBJECT (object));
122 if (password_based == NULL)
123 {
124 password_based = goa_password_based_skeleton_new ();
125 /* Ensure D-Bus method invocations run in their own thread */
126 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (password_based),
127 G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
128 goa_object_skeleton_set_password_based (object, password_based);
129 g_signal_connect (password_based,
130 "handle-get-password",
131 G_CALLBACK (on_handle_get_password),
132 NULL);
133 }
134
135 account = goa_object_get_account (GOA_OBJECT (object));
136
137 /* Email */
138 mail = goa_object_get_mail (GOA_OBJECT (object));
139 enabled = g_key_file_get_boolean (key_file, group, "Enabled", NULL);
140 if (enabled)
141 {
142 if (mail == NULL)
143 {
144 email_address = g_key_file_get_string (key_file, group, "EmailAddress", NULL);
145 name = g_key_file_get_string (key_file, group, "Name", NULL);
146
147 imap_host = g_key_file_get_string (key_file, group, "ImapHost", NULL);
148 imap_username = g_key_file_get_string (key_file, group, "ImapUserName", NULL);
149 if (imap_username == NULL)
150 imap_username = g_strdup (g_get_user_name ());
151 imap_use_ssl = g_key_file_get_boolean (key_file, group, "ImapUseSsl", NULL);
152 imap_use_tls = g_key_file_get_boolean (key_file, group, "ImapUseTls", NULL);
153 imap_accept_ssl_errors = g_key_file_get_boolean (key_file, group, "ImapAcceptSslErrors", NULL);
154
155 smtp_host = g_key_file_get_string (key_file, group, "SmtpHost", NULL);
156 smtp_use_auth = g_key_file_get_boolean (key_file, group, "SmtpUseAuth", NULL);
157 if (smtp_use_auth)
158 {
159 smtp_username = g_key_file_get_string (key_file, group, "SmtpUserName", NULL);
160 if (smtp_username == NULL)
161 smtp_username = g_strdup (g_get_user_name ());
162
163 smtp_auth_login = g_key_file_get_boolean (key_file, group, "SmtpAuthLogin", NULL);
164 smtp_auth_plain = g_key_file_get_boolean (key_file, group, "SmtpAuthPlain", NULL);
165 /* For backwards compatibility: if authentication is
166 * used, assume PLAIN as the SASL scheme if nothing is
167 * specified.
168 */
169 if (!smtp_auth_login && !smtp_auth_plain)
170 smtp_auth_plain = TRUE;
171 }
172 smtp_use_ssl = g_key_file_get_boolean (key_file, group, "SmtpUseSsl", NULL);
173 smtp_use_tls = g_key_file_get_boolean (key_file, group, "SmtpUseTls", NULL);
174 smtp_accept_ssl_errors = g_key_file_get_boolean (key_file, group, "SmtpAcceptSslErrors", NULL);
175
176 mail = goa_mail_skeleton_new ();
177 g_object_set (G_OBJECT (mail),
178 "email-address", email_address,
179 "name", name,
180 "imap-supported", TRUE,
181 "imap-host", imap_host,
182 "imap-user-name", imap_username,
183 "imap-use-ssl", imap_use_ssl,
184 "imap-use-tls", imap_use_tls,
185 "imap-accept-ssl-errors", imap_accept_ssl_errors,
186 "smtp-supported", TRUE,
187 "smtp-host", smtp_host,
188 "smtp-user-name", smtp_username,
189 "smtp-use-auth", smtp_use_auth,
190 "smtp-auth-login", smtp_auth_login,
191 "smtp-auth-plain", smtp_auth_plain,
192 "smtp-use-ssl", smtp_use_ssl,
193 "smtp-use-tls", smtp_use_tls,
194 "smtp-accept-ssl-errors", smtp_accept_ssl_errors,
195 NULL);
196 goa_object_skeleton_set_mail (object, mail);
197 }
198 }
199 else
200 {
201 if (mail != NULL)
202 goa_object_skeleton_set_mail (object, NULL);
203 }
204
205 if (just_added)
206 {
207 goa_account_set_mail_disabled (account, !enabled);
208 g_signal_connect (account,
209 "notify::mail-disabled",
210 G_CALLBACK (goa_util_account_notify_property_cb),
211 (gpointer) "Enabled");
212 }
213
214 ret = TRUE;
215
216 out:
217 g_clear_object (&account);
218 g_clear_object (&mail);
219 g_clear_object (&password_based);
220 g_free (email_address);
221 g_free (imap_host);
222 g_free (imap_username);
223 g_free (name);
224 g_free (smtp_host);
225 g_free (smtp_username);
226 return ret;
227 }
228
229 /* ---------------------------------------------------------------------------------------------------- */
230
231 static GoaTlsType
get_tls_type_from_object(GoaObject * object,const gchar * ssl_key,const gchar * starttls_key)232 get_tls_type_from_object (GoaObject *object, const gchar *ssl_key, const gchar *starttls_key)
233 {
234 GoaTlsType tls_type;
235
236 if (goa_util_lookup_keyfile_boolean (object, ssl_key))
237 tls_type = GOA_TLS_TYPE_SSL;
238 else if (goa_util_lookup_keyfile_boolean (object, starttls_key))
239 tls_type = GOA_TLS_TYPE_STARTTLS;
240 else
241 tls_type = GOA_TLS_TYPE_NONE;
242
243 return tls_type;
244 }
245
246 static GoaTlsType
get_tls_type_from_string_id(const gchar * str)247 get_tls_type_from_string_id (const gchar *str)
248 {
249 GoaTlsType tls_type;
250
251 if (g_strcmp0 (str, "none") == 0)
252 tls_type = GOA_TLS_TYPE_NONE;
253 else if (g_strcmp0 (str, "starttls") == 0)
254 tls_type = GOA_TLS_TYPE_STARTTLS;
255 else if (g_strcmp0 (str, "ssl") == 0)
256 tls_type = GOA_TLS_TYPE_SSL;
257 else
258 g_assert_not_reached ();
259
260 return tls_type;
261 }
262
263 /* ---------------------------------------------------------------------------------------------------- */
264
265 static gboolean
ensure_credentials_sync(GoaProvider * provider,GoaObject * object,gint * out_expires_in,GCancellable * cancellable,GError ** error)266 ensure_credentials_sync (GoaProvider *provider,
267 GoaObject *object,
268 gint *out_expires_in,
269 GCancellable *cancellable,
270 GError **error)
271 {
272 GVariant *credentials = NULL;
273 GoaMailAuth *imap_auth = NULL;
274 GoaMailAuth *smtp_auth = NULL;
275 GoaMailClient *mail_client = NULL;
276 GoaTlsType imap_tls_type;
277 GoaTlsType smtp_tls_type;
278 gboolean imap_accept_ssl_errors;
279 gboolean ret = FALSE;
280 gboolean smtp_accept_ssl_errors;
281 gchar *domain = NULL;
282 gchar *email_address = NULL;
283 gchar *imap_password = NULL;
284 gchar *imap_server = NULL;
285 gchar *imap_username = NULL;
286 gchar *smtp_password = NULL;
287 gchar *smtp_server = NULL;
288 gchar *smtp_username = NULL;
289
290 if (!goa_utils_get_credentials (provider, object, "imap-password", NULL, &imap_password, cancellable, error))
291 {
292 if (error != NULL)
293 {
294 (*error)->domain = GOA_ERROR;
295 (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
296 }
297 goto out;
298 }
299
300 mail_client = goa_mail_client_new ();
301
302 /* IMAP */
303
304 imap_accept_ssl_errors = goa_util_lookup_keyfile_boolean (object, "ImapAcceptSslErrors");
305 imap_server = goa_util_lookup_keyfile_string (object, "ImapHost");
306 imap_username = goa_util_lookup_keyfile_string (object, "ImapUserName");
307 imap_tls_type = get_tls_type_from_object (object, "ImapUseSsl", "ImapUseTls");
308
309 imap_auth = goa_imap_auth_login_new (imap_username, imap_password);
310 if (!goa_mail_client_check_sync (mail_client,
311 imap_server,
312 imap_tls_type,
313 imap_accept_ssl_errors,
314 (imap_tls_type == GOA_TLS_TYPE_SSL) ? 993 : 143,
315 imap_auth,
316 cancellable,
317 error))
318 {
319 if (error != NULL)
320 {
321 g_prefix_error (error,
322 /* Translators: the first %s is a field name. The
323 * second %s is the IMAP
324 * username (eg., rishi), and the (%s, %d)
325 * is the error domain and code.
326 */
327 _("Invalid %s with username “%s” (%s, %d): "),
328 "imap-password",
329 imap_username,
330 g_quark_to_string ((*error)->domain),
331 (*error)->code);
332 (*error)->domain = GOA_ERROR;
333 (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
334 }
335 goto out;
336 }
337
338 /* SMTP */
339
340 if (!goa_util_lookup_keyfile_boolean (object, "SmtpUseAuth"))
341 goto smtp_done;
342
343 if (!goa_utils_get_credentials (provider, object, "smtp-password", NULL, &smtp_password, cancellable, error))
344 {
345 if (error != NULL)
346 {
347 (*error)->domain = GOA_ERROR;
348 (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
349 }
350 goto out;
351 }
352
353 smtp_accept_ssl_errors = goa_util_lookup_keyfile_boolean (object, "SmtpAcceptSslErrors");
354 smtp_server = goa_util_lookup_keyfile_string (object, "SmtpHost");
355 smtp_username = goa_util_lookup_keyfile_string (object, "SmtpUserName");
356 smtp_tls_type = get_tls_type_from_object (object, "SmtpUseSsl", "SmtpUseTls");
357
358 email_address = goa_util_lookup_keyfile_string (object, "EmailAddress");
359 goa_utils_parse_email_address (email_address, NULL, &domain);
360 smtp_auth = goa_smtp_auth_new (domain, smtp_username, smtp_password);
361 if (!goa_mail_client_check_sync (mail_client,
362 smtp_server,
363 smtp_tls_type,
364 smtp_accept_ssl_errors,
365 (smtp_tls_type == GOA_TLS_TYPE_SSL) ? 465 : 587,
366 smtp_auth,
367 cancellable,
368 error))
369 {
370 if (error != NULL)
371 {
372 g_prefix_error (error,
373 /* Translators: the first %s is a field name. The
374 * second %s is the SMTP
375 * username (eg., rishi), and the (%s, %d)
376 * is the error domain and code.
377 */
378 _("Invalid %s with username “%s” (%s, %d): "),
379 "smtp-password",
380 smtp_username,
381 g_quark_to_string ((*error)->domain),
382 (*error)->code);
383 (*error)->domain = GOA_ERROR;
384 (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
385 }
386 goto out;
387 }
388
389 smtp_done:
390
391 if (out_expires_in != NULL)
392 *out_expires_in = 0;
393
394 ret = TRUE;
395
396 out:
397 g_clear_object (&imap_auth);
398 g_clear_object (&smtp_auth);
399 g_clear_object (&mail_client);
400 g_free (domain);
401 g_free (email_address);
402 g_free (imap_password);
403 g_free (imap_server);
404 g_free (imap_username);
405 g_free (smtp_password);
406 g_free (smtp_server);
407 g_free (smtp_username);
408 g_clear_pointer (&credentials, g_variant_unref);
409 return ret;
410 }
411
412 /* ---------------------------------------------------------------------------------------------------- */
413
414 static void
add_combo_box(GtkWidget * grid,gint row,const gchar * text,GtkWidget ** out_combo_box)415 add_combo_box (GtkWidget *grid,
416 gint row,
417 const gchar *text,
418 GtkWidget **out_combo_box)
419 {
420 GtkStyleContext *context;
421 GtkWidget *label;
422 GtkWidget *combo_box;
423
424 label = gtk_label_new_with_mnemonic (text);
425 context = gtk_widget_get_style_context (label);
426 gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
427 gtk_widget_set_halign (label, GTK_ALIGN_END);
428 gtk_widget_set_hexpand (label, TRUE);
429 gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
430
431 combo_box = gtk_combo_box_text_new ();
432 gtk_widget_set_hexpand (combo_box, TRUE);
433 gtk_grid_attach (GTK_GRID (grid), combo_box, 1, row, 3, 1);
434
435 gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
436 if (out_combo_box != NULL)
437 *out_combo_box = combo_box;
438 }
439
440 static void
add_entry(GtkWidget * grid,gint row,const gchar * text,GtkWidget ** out_entry)441 add_entry (GtkWidget *grid,
442 gint row,
443 const gchar *text,
444 GtkWidget **out_entry)
445 {
446 GtkStyleContext *context;
447 GtkWidget *label;
448 GtkWidget *entry;
449
450 label = gtk_label_new_with_mnemonic (text);
451 context = gtk_widget_get_style_context (label);
452 gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
453 gtk_widget_set_halign (label, GTK_ALIGN_END);
454 gtk_widget_set_hexpand (label, TRUE);
455 gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
456
457 entry = gtk_entry_new ();
458 gtk_widget_set_hexpand (entry, TRUE);
459 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
460 gtk_grid_attach (GTK_GRID (grid), entry, 1, row, 3, 1);
461
462 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
463 if (out_entry != NULL)
464 *out_entry = entry;
465 }
466
467 /* ---------------------------------------------------------------------------------------------------- */
468
469 typedef struct
470 {
471 GCancellable *cancellable;
472
473 GtkDialog *dialog;
474 GMainLoop *loop;
475
476 GtkWidget *cluebar;
477 GtkWidget *cluebar_label;
478 GtkWidget *notebook;
479 GtkWidget *forward_button;
480 GtkWidget *progress_grid;
481
482 GtkWidget *email_address;
483 GtkWidget *name;
484
485 GtkWidget *imap_server;
486 GtkWidget *imap_username;
487 GtkWidget *imap_password;
488 GtkWidget *imap_encryption;
489
490 GtkWidget *smtp_server;
491 GtkWidget *smtp_username;
492 GtkWidget *smtp_password;
493 GtkWidget *smtp_encryption;
494
495 gchar *account_object_path;
496
497 GError *error;
498 } AddAccountData;
499
500 /* ---------------------------------------------------------------------------------------------------- */
501
502 static void
on_email_address_changed(GtkEditable * editable,gpointer user_data)503 on_email_address_changed (GtkEditable *editable, gpointer user_data)
504 {
505 AddAccountData *data = user_data;
506 gboolean can_add;
507 const gchar *email;
508
509 email = gtk_entry_get_text (GTK_ENTRY (data->email_address));
510 can_add = goa_utils_parse_email_address (email, NULL, NULL);
511 gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
512 }
513
514 static void
on_imap_changed(GtkEditable * editable,gpointer user_data)515 on_imap_changed (GtkEditable *editable, gpointer user_data)
516 {
517 AddAccountData *data = user_data;
518 gboolean can_add;
519
520 can_add = gtk_entry_get_text_length (GTK_ENTRY (data->imap_password)) != 0
521 && gtk_entry_get_text_length (GTK_ENTRY (data->imap_server)) != 0
522 && gtk_entry_get_text_length (GTK_ENTRY (data->imap_username)) != 0;
523 gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
524 }
525
526 static void
on_smtp_changed(GtkEditable * editable,gpointer user_data)527 on_smtp_changed (GtkEditable *editable, gpointer user_data)
528 {
529 AddAccountData *data = user_data;
530 gboolean can_add = FALSE;
531
532 if (gtk_entry_get_text_length (GTK_ENTRY (data->smtp_server)) == 0)
533 goto out;
534
535 /* If you provide a password then you must provide a username, and
536 * vice versa. If the server does not require authentication then
537 * both should be left empty.
538 */
539 if (gtk_entry_get_text_length (GTK_ENTRY (data->smtp_password)) != 0
540 && gtk_entry_get_text_length (GTK_ENTRY (data->smtp_username)) == 0)
541 goto out;
542
543 if (gtk_entry_get_text_length (GTK_ENTRY (data->smtp_password)) == 0
544 && gtk_entry_get_text_length (GTK_ENTRY (data->smtp_username)) != 0)
545 goto out;
546
547 can_add = TRUE;
548
549 out:
550 gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, can_add);
551 }
552
553 static void
create_encryption_ui(GtkWidget * grid,gint row,GtkWidget ** out_combo_box)554 create_encryption_ui (GtkWidget *grid,
555 gint row,
556 GtkWidget **out_combo_box)
557 {
558 /* Translators: the following four strings are used to show a
559 * combo box similar to the one in the evolution module.
560 * Encryption: None
561 * STARTTLS after connecting
562 * SSL on a dedicated port
563 */
564 add_combo_box (grid, row, _("_Encryption"), out_combo_box);
565 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (*out_combo_box),
566 "none",
567 _("None"));
568 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (*out_combo_box),
569 "starttls",
570 _("STARTTLS after connecting"));
571 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (*out_combo_box),
572 "ssl",
573 _("SSL on a dedicated port"));
574 gtk_combo_box_set_active_id (GTK_COMBO_BOX (*out_combo_box), "starttls");
575 }
576
577 static void
show_progress_ui(GtkContainer * container,gboolean progress)578 show_progress_ui (GtkContainer *container, gboolean progress)
579 {
580 GList *children;
581 GList *l;
582
583 children = gtk_container_get_children (container);
584 for (l = children; l != NULL; l = l->next)
585 {
586 GtkWidget *widget = GTK_WIDGET (l->data);
587 gdouble opacity;
588
589 opacity = progress ? 1.0 : 0.0;
590 gtk_widget_set_opacity (widget, opacity);
591 }
592
593 g_list_free (children);
594 }
595
596 static void
create_account_details_ui(GoaProvider * provider,GtkDialog * dialog,GtkBox * vbox,gboolean new_account,AddAccountData * data)597 create_account_details_ui (GoaProvider *provider,
598 GtkDialog *dialog,
599 GtkBox *vbox,
600 gboolean new_account,
601 AddAccountData *data)
602 {
603 GtkWidget *grid0;
604 GtkWidget *grid1;
605 GtkWidget *label;
606 GtkWidget *spinner;
607 gint row;
608 gint width;
609 const gchar *real_name;
610
611 goa_utils_set_dialog_title (provider, dialog, new_account);
612
613 grid0 = gtk_grid_new ();
614 gtk_container_set_border_width (GTK_CONTAINER (grid0), 5);
615 gtk_widget_set_margin_bottom (grid0, 6);
616 gtk_orientable_set_orientation (GTK_ORIENTABLE (grid0), GTK_ORIENTATION_VERTICAL);
617 gtk_grid_set_row_spacing (GTK_GRID (grid0), 12);
618 gtk_container_add (GTK_CONTAINER (vbox), grid0);
619
620 data->cluebar = gtk_info_bar_new ();
621 gtk_info_bar_set_message_type (GTK_INFO_BAR (data->cluebar), GTK_MESSAGE_ERROR);
622 gtk_widget_set_hexpand (data->cluebar, TRUE);
623 gtk_widget_set_no_show_all (data->cluebar, TRUE);
624 gtk_container_add (GTK_CONTAINER (grid0), data->cluebar);
625
626 data->cluebar_label = gtk_label_new ("");
627 gtk_label_set_line_wrap (GTK_LABEL (data->cluebar_label), TRUE);
628 gtk_label_set_max_width_chars (GTK_LABEL (data->cluebar_label), 36);
629 gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (data->cluebar))),
630 data->cluebar_label);
631
632 data->notebook = gtk_notebook_new ();
633 gtk_notebook_set_show_border (GTK_NOTEBOOK (data->notebook), FALSE);
634 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (data->notebook), FALSE);
635 gtk_container_add (GTK_CONTAINER (grid0), data->notebook);
636
637 /* Introduction*/
638
639 if (new_account)
640 {
641 grid1 = gtk_grid_new ();
642 gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
643 gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
644 gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
645
646 row = 0;
647 add_entry (grid1, row++, _("_E-mail"), &data->email_address);
648 add_entry (grid1, row++, _("_Name"), &data->name);
649
650 real_name = g_get_real_name ();
651 if (g_strcmp0 (real_name, "Unknown") != 0)
652 gtk_entry_set_text (GTK_ENTRY (data->name), real_name);
653
654 g_signal_connect (data->email_address, "changed", G_CALLBACK (on_email_address_changed), data);
655 }
656
657 /* IMAP */
658
659 grid1 = gtk_grid_new ();
660 gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
661 gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
662 gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
663
664 row = 0;
665 add_entry (grid1, row++, _("IMAP _Server"), &data->imap_server);
666 add_entry (grid1, row++, _("User_name"), &data->imap_username);
667 add_entry (grid1, row++, _("_Password"), &data->imap_password);
668 gtk_entry_set_visibility (GTK_ENTRY (data->imap_password), FALSE);
669
670 if (new_account)
671 create_encryption_ui (grid1, row++, &data->imap_encryption);
672
673 g_signal_connect (data->imap_server, "changed", G_CALLBACK (on_imap_changed), data);
674 g_signal_connect (data->imap_username, "changed", G_CALLBACK (on_imap_changed), data);
675 g_signal_connect (data->imap_password, "changed", G_CALLBACK (on_imap_changed), data);
676
677 /* SMTP */
678
679 grid1 = gtk_grid_new ();
680 gtk_grid_set_column_spacing (GTK_GRID (grid1), 12);
681 gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
682 gtk_notebook_append_page (GTK_NOTEBOOK (data->notebook), grid1, NULL);
683
684 row = 0;
685 add_entry (grid1, row++, _("SMTP _Server"), &data->smtp_server);
686 add_entry (grid1, row++, _("User_name"), &data->smtp_username);
687 add_entry (grid1, row++, _("_Password"), &data->smtp_password);
688 gtk_entry_set_visibility (GTK_ENTRY (data->smtp_password), FALSE);
689
690 if (new_account)
691 create_encryption_ui (grid1, row++, &data->smtp_encryption);
692
693 g_signal_connect (data->smtp_server, "changed", G_CALLBACK (on_smtp_changed), data);
694 g_signal_connect (data->smtp_username, "changed", G_CALLBACK (on_smtp_changed), data);
695 g_signal_connect (data->smtp_password, "changed", G_CALLBACK (on_smtp_changed), data);
696
697 /* -- */
698
699 gtk_dialog_add_button (data->dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
700 data->forward_button = gtk_dialog_add_button (data->dialog, _("_Forward"), GTK_RESPONSE_OK);
701 gtk_dialog_set_default_response (data->dialog, GTK_RESPONSE_OK);
702 gtk_dialog_set_response_sensitive (data->dialog, GTK_RESPONSE_OK, FALSE);
703
704 data->progress_grid = gtk_grid_new ();
705 gtk_orientable_set_orientation (GTK_ORIENTABLE (data->progress_grid), GTK_ORIENTATION_HORIZONTAL);
706 gtk_grid_set_column_spacing (GTK_GRID (data->progress_grid), 3);
707 gtk_container_add (GTK_CONTAINER (grid0), data->progress_grid);
708
709 spinner = gtk_spinner_new ();
710 gtk_widget_set_opacity (spinner, 0.0);
711 gtk_widget_set_size_request (spinner, 20, 20);
712 gtk_spinner_start (GTK_SPINNER (spinner));
713 gtk_container_add (GTK_CONTAINER (data->progress_grid), spinner);
714
715 label = gtk_label_new (_("Connecting…"));
716 gtk_widget_set_opacity (label, 0.0);
717 gtk_container_add (GTK_CONTAINER (data->progress_grid), label);
718
719 if (new_account)
720 {
721 gtk_window_get_size (GTK_WINDOW (data->dialog), &width, NULL);
722 gtk_window_set_default_size (GTK_WINDOW (data->dialog), width, -1);
723 }
724 else
725 {
726 GtkWindow *parent;
727
728 /* Keep in sync with GoaPanelAddAccountDialog in
729 * gnome-control-center.
730 */
731 parent = gtk_window_get_transient_for (GTK_WINDOW (data->dialog));
732 if (parent != NULL)
733 {
734 gtk_window_get_size (parent, &width, NULL);
735 gtk_window_set_default_size (GTK_WINDOW (data->dialog), (gint) (0.5 * width), -1);
736 }
737 }
738 }
739
740 /* ---------------------------------------------------------------------------------------------------- */
741
742 static void
guess_imap_smtp(AddAccountData * data)743 guess_imap_smtp (AddAccountData *data)
744 {
745 const gchar *email_address;
746 gchar *imap_server = NULL;
747 gchar *smtp_server = NULL;
748 gchar *username = NULL;
749 gchar *domain = NULL;
750
751 email_address = gtk_entry_get_text (GTK_ENTRY (data->email_address));
752 if (!goa_utils_parse_email_address (email_address, &username, &domain))
753 goto out;
754
755 /* TODO: Consult http://api.gnome.org/evolution/autoconfig/1.1/<domain> */
756
757 imap_server = g_strconcat ("imap.", domain, NULL);
758 smtp_server = g_strconcat ("smtp.", domain, NULL);
759
760 gtk_entry_set_text (GTK_ENTRY (data->imap_username), username);
761 gtk_entry_set_text (GTK_ENTRY (data->smtp_username), username);
762 gtk_entry_set_text (GTK_ENTRY (data->imap_server), imap_server);
763 gtk_entry_set_text (GTK_ENTRY (data->smtp_server), smtp_server);
764
765 out:
766 g_free (imap_server);
767 g_free (smtp_server);
768 g_free (username);
769 g_free (domain);
770 }
771
772 /* ---------------------------------------------------------------------------------------------------- */
773
774 static void
add_account_cb(GoaManager * manager,GAsyncResult * res,gpointer user_data)775 add_account_cb (GoaManager *manager, GAsyncResult *res, gpointer user_data)
776 {
777 AddAccountData *data = user_data;
778 goa_manager_call_add_account_finish (manager,
779 &data->account_object_path,
780 res,
781 &data->error);
782 g_main_loop_quit (data->loop);
783 }
784
785 static void
dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)786 dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
787 {
788 AddAccountData *data = user_data;
789
790 if (response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT)
791 g_cancellable_cancel (data->cancellable);
792 }
793
794 static void
mail_check_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)795 mail_check_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
796 {
797 GoaMailClient *client = GOA_MAIL_CLIENT (source_object);
798 AddAccountData *data = user_data;
799
800 goa_mail_client_check_finish (client, res, &data->error);
801 g_main_loop_quit (data->loop);
802 gtk_widget_set_sensitive (data->forward_button, TRUE);
803 show_progress_ui (GTK_CONTAINER (data->progress_grid), FALSE);
804 }
805
806 /* ---------------------------------------------------------------------------------------------------- */
807
808 static GoaObject *
add_account(GoaProvider * provider,GoaClient * client,GtkDialog * dialog,GtkBox * vbox,GError ** error)809 add_account (GoaProvider *provider,
810 GoaClient *client,
811 GtkDialog *dialog,
812 GtkBox *vbox,
813 GError **error)
814 {
815 AddAccountData data;
816 GVariantBuilder credentials;
817 GVariantBuilder details;
818 GoaMailAuth *imap_auth = NULL;
819 GoaMailAuth *smtp_auth = NULL;
820 GoaMailClient *mail_client = NULL;
821 GoaObject *ret = NULL;
822 GoaTlsType imap_tls_type;
823 GoaTlsType smtp_tls_type;
824 gboolean imap_accept_ssl_errors;
825 gboolean smtp_accept_ssl_errors;
826 gboolean smtp_auth_login;
827 gboolean smtp_auth_plain;
828 gboolean smtp_use_auth;
829 const gchar *email_address;
830 const gchar *encryption;
831 const gchar *imap_password;
832 const gchar *imap_server;
833 const gchar *imap_username;
834 const gchar *name;
835 const gchar *provider_type;
836 const gchar *smtp_password;
837 const gchar *smtp_server;
838 const gchar *smtp_username;
839 gchar *domain = NULL;
840 gint response;
841
842 memset (&data, 0, sizeof (AddAccountData));
843 data.cancellable = g_cancellable_new ();
844 data.loop = g_main_loop_new (NULL, FALSE);
845 data.dialog = dialog;
846 data.error = NULL;
847
848 create_account_details_ui (provider, dialog, vbox, TRUE, &data);
849 gtk_widget_show_all (GTK_WIDGET (vbox));
850 g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &data);
851
852 mail_client = goa_mail_client_new ();
853
854 /* Introduction */
855
856 gtk_notebook_set_current_page (GTK_NOTEBOOK (data.notebook), 0);
857 gtk_widget_grab_focus (data.email_address);
858
859 response = gtk_dialog_run (GTK_DIALOG (dialog));
860 if (response != GTK_RESPONSE_OK)
861 {
862 g_set_error (&data.error,
863 GOA_ERROR,
864 GOA_ERROR_DIALOG_DISMISSED,
865 _("Dialog was dismissed"));
866 goto out;
867 }
868
869 email_address = gtk_entry_get_text (GTK_ENTRY (data.email_address));
870 name = gtk_entry_get_text (GTK_ENTRY (data.name));
871
872 /* See if there's already an account of this type with the
873 * given identity
874 */
875 provider_type = goa_provider_get_provider_type (provider);
876 if (!goa_utils_check_duplicate (client,
877 email_address,
878 email_address,
879 provider_type,
880 (GoaPeekInterfaceFunc) goa_object_peek_password_based,
881 &data.error))
882 goto out;
883
884 guess_imap_smtp (&data);
885
886 /* IMAP */
887
888 gtk_notebook_next_page (GTK_NOTEBOOK (data.notebook));
889 gtk_widget_grab_focus (data.imap_password);
890
891 imap_accept_ssl_errors = FALSE;
892
893 imap_again:
894 response = gtk_dialog_run (GTK_DIALOG (dialog));
895 if (response != GTK_RESPONSE_OK)
896 {
897 g_set_error (&data.error,
898 GOA_ERROR,
899 GOA_ERROR_DIALOG_DISMISSED,
900 _("Dialog was dismissed"));
901 goto out;
902 }
903
904 gtk_widget_set_no_show_all (data.cluebar, TRUE);
905 gtk_widget_hide (data.cluebar);
906
907 encryption = gtk_combo_box_get_active_id (GTK_COMBO_BOX (data.imap_encryption));
908 imap_tls_type = get_tls_type_from_string_id (encryption);
909
910 imap_password = gtk_entry_get_text (GTK_ENTRY (data.imap_password));
911 imap_server = gtk_entry_get_text (GTK_ENTRY (data.imap_server));
912 imap_username = gtk_entry_get_text (GTK_ENTRY (data.imap_username));
913
914 g_cancellable_reset (data.cancellable);
915 imap_auth = goa_imap_auth_login_new (imap_username, imap_password);
916 goa_mail_client_check (mail_client,
917 imap_server,
918 imap_tls_type,
919 imap_accept_ssl_errors,
920 (imap_tls_type == GOA_TLS_TYPE_SSL) ? 993 : 143,
921 imap_auth,
922 data.cancellable,
923 mail_check_cb,
924 &data);
925
926 gtk_widget_set_sensitive (data.forward_button, FALSE);
927 show_progress_ui (GTK_CONTAINER (data.progress_grid), TRUE);
928 g_main_loop_run (data.loop);
929
930 if (g_cancellable_is_cancelled (data.cancellable))
931 {
932 g_prefix_error (&data.error,
933 _("Dialog was dismissed (%s, %d): "),
934 g_quark_to_string (data.error->domain),
935 data.error->code);
936 data.error->domain = GOA_ERROR;
937 data.error->code = GOA_ERROR_DIALOG_DISMISSED;
938 goto out;
939 }
940 else if (data.error != NULL)
941 {
942 gchar *markup;
943
944 if (data.error->code == GOA_ERROR_SSL)
945 {
946 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Ignore"));
947 imap_accept_ssl_errors = TRUE;
948 }
949 else
950 {
951 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
952 imap_accept_ssl_errors = FALSE;
953 }
954
955 markup = g_strdup_printf ("<b>%s</b>\n%s",
956 _("Error connecting to IMAP server"),
957 data.error->message);
958 g_clear_error (&data.error);
959
960 gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
961 g_free (markup);
962
963 gtk_widget_set_no_show_all (data.cluebar, FALSE);
964 gtk_widget_show_all (data.cluebar);
965
966 g_clear_object (&imap_auth);
967 goto imap_again;
968 }
969
970 gtk_widget_set_no_show_all (data.cluebar, TRUE);
971 gtk_widget_hide (data.cluebar);
972 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Forward"));
973
974 /* SMTP */
975
976 /* Re-use the username and password from the IMAP page */
977 gtk_entry_set_text (GTK_ENTRY (data.smtp_username), imap_username);
978 gtk_entry_set_text (GTK_ENTRY (data.smtp_password), imap_password);
979
980 gtk_notebook_next_page (GTK_NOTEBOOK (data.notebook));
981 gtk_widget_grab_focus (data.smtp_password);
982
983 smtp_accept_ssl_errors = FALSE;
984
985 smtp_again:
986 response = gtk_dialog_run (GTK_DIALOG (dialog));
987 if (response != GTK_RESPONSE_OK)
988 {
989 g_set_error (&data.error,
990 GOA_ERROR,
991 GOA_ERROR_DIALOG_DISMISSED,
992 _("Dialog was dismissed"));
993 goto out;
994 }
995
996 gtk_widget_set_no_show_all (data.cluebar, TRUE);
997 gtk_widget_hide (data.cluebar);
998
999 encryption = gtk_combo_box_get_active_id (GTK_COMBO_BOX (data.smtp_encryption));
1000 smtp_tls_type = get_tls_type_from_string_id (encryption);
1001
1002 smtp_password = gtk_entry_get_text (GTK_ENTRY (data.smtp_password));
1003 smtp_server = gtk_entry_get_text (GTK_ENTRY (data.smtp_server));
1004 smtp_username = gtk_entry_get_text (GTK_ENTRY (data.smtp_username));
1005
1006 g_cancellable_reset (data.cancellable);
1007 goa_utils_parse_email_address (email_address, NULL, &domain);
1008 smtp_auth = goa_smtp_auth_new (domain, smtp_username, smtp_password);
1009 goa_mail_client_check (mail_client,
1010 smtp_server,
1011 smtp_tls_type,
1012 smtp_accept_ssl_errors,
1013 (smtp_tls_type == GOA_TLS_TYPE_SSL) ? 465 : 587,
1014 smtp_auth,
1015 data.cancellable,
1016 mail_check_cb,
1017 &data);
1018
1019 gtk_widget_set_sensitive (data.forward_button, FALSE);
1020 show_progress_ui (GTK_CONTAINER (data.progress_grid), TRUE);
1021 g_main_loop_run (data.loop);
1022
1023 smtp_use_auth = goa_mail_auth_is_needed (smtp_auth);
1024 smtp_auth_login = goa_smtp_auth_is_login (GOA_SMTP_AUTH (smtp_auth));
1025 smtp_auth_plain = goa_smtp_auth_is_plain (GOA_SMTP_AUTH (smtp_auth));
1026
1027 if (g_cancellable_is_cancelled (data.cancellable))
1028 {
1029 g_prefix_error (&data.error,
1030 _("Dialog was dismissed (%s, %d): "),
1031 g_quark_to_string (data.error->domain),
1032 data.error->code);
1033 data.error->domain = GOA_ERROR;
1034 data.error->code = GOA_ERROR_DIALOG_DISMISSED;
1035 goto out;
1036 }
1037 else if (data.error != NULL)
1038 {
1039 gchar *markup;
1040
1041 if (data.error->code == GOA_ERROR_SSL)
1042 {
1043 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Ignore"));
1044 smtp_accept_ssl_errors = TRUE;
1045 }
1046 else
1047 {
1048 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
1049 smtp_accept_ssl_errors = FALSE;
1050 }
1051
1052 markup = g_strdup_printf ("<b>%s</b>\n%s",
1053 _("Error connecting to SMTP server"),
1054 data.error->message);
1055 g_clear_error (&data.error);
1056
1057 gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
1058 g_free (markup);
1059
1060 gtk_widget_set_no_show_all (data.cluebar, FALSE);
1061 gtk_widget_show_all (data.cluebar);
1062
1063 g_clear_object (&smtp_auth);
1064 g_clear_pointer (&domain, g_free);
1065 goto smtp_again;
1066 }
1067
1068 gtk_widget_hide (GTK_WIDGET (dialog));
1069
1070 g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
1071 g_variant_builder_add (&credentials, "{sv}", "imap-password", g_variant_new_string (imap_password));
1072 if (smtp_use_auth)
1073 g_variant_builder_add (&credentials, "{sv}", "smtp-password", g_variant_new_string (smtp_password));
1074
1075 g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
1076 g_variant_builder_add (&details, "{ss}", "Enabled", "true");
1077 g_variant_builder_add (&details, "{ss}", "EmailAddress", email_address);
1078 g_variant_builder_add (&details, "{ss}", "Name", name);
1079 g_variant_builder_add (&details, "{ss}", "ImapHost", imap_server);
1080 g_variant_builder_add (&details, "{ss}", "ImapUserName", imap_username);
1081 g_variant_builder_add (&details, "{ss}",
1082 "ImapUseSsl", (imap_tls_type == GOA_TLS_TYPE_SSL) ? "true" : "false");
1083 g_variant_builder_add (&details, "{ss}",
1084 "ImapUseTls", (imap_tls_type == GOA_TLS_TYPE_STARTTLS) ? "true" : "false");
1085 g_variant_builder_add (&details, "{ss}",
1086 "ImapAcceptSslErrors", (imap_accept_ssl_errors) ? "true" : "false");
1087 g_variant_builder_add (&details, "{ss}", "SmtpHost", smtp_server);
1088 g_variant_builder_add (&details, "{ss}", "SmtpUseAuth", (smtp_use_auth) ? "true" : "false");
1089 if (smtp_use_auth)
1090 {
1091 g_variant_builder_add (&details, "{ss}", "SmtpUserName", smtp_username);
1092 g_variant_builder_add (&details, "{ss}", "SmtpAuthLogin", (smtp_auth_login) ? "true" : "false");
1093 g_variant_builder_add (&details, "{ss}", "SmtpAuthPlain", (smtp_auth_plain) ? "true" : "false");
1094 }
1095 g_variant_builder_add (&details, "{ss}",
1096 "SmtpUseSsl", (smtp_tls_type == GOA_TLS_TYPE_SSL) ? "true" : "false");
1097 g_variant_builder_add (&details, "{ss}",
1098 "SmtpUseTls", (smtp_tls_type == GOA_TLS_TYPE_STARTTLS) ? "true" : "false");
1099 g_variant_builder_add (&details, "{ss}",
1100 "SmtpAcceptSslErrors", (smtp_accept_ssl_errors) ? "true" : "false");
1101
1102 /* OK, everything is dandy, add the account */
1103 /* we want the GoaClient to update before this method returns (so it
1104 * can create a proxy for the new object) so run the mainloop while
1105 * waiting for this to complete
1106 */
1107 goa_manager_call_add_account (goa_client_get_manager (client),
1108 goa_provider_get_provider_type (provider),
1109 email_address,
1110 email_address,
1111 g_variant_builder_end (&credentials),
1112 g_variant_builder_end (&details),
1113 NULL, /* GCancellable* */
1114 (GAsyncReadyCallback) add_account_cb,
1115 &data);
1116 g_main_loop_run (data.loop);
1117 if (data.error != NULL)
1118 goto out;
1119
1120 ret = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
1121 data.account_object_path));
1122 out:
1123 /* We might have an object even when data.error is set.
1124 * eg., if we failed to store the credentials in the keyring.
1125 */
1126 if (data.error != NULL)
1127 g_propagate_error (error, data.error);
1128 else
1129 g_assert (ret != NULL);
1130
1131 g_signal_handlers_disconnect_by_func (dialog, dialog_response_cb, &data);
1132
1133 g_free (domain);
1134 g_free (data.account_object_path);
1135 g_clear_pointer (&data.loop, g_main_loop_unref);
1136 g_clear_object (&data.cancellable);
1137 g_clear_object (&imap_auth);
1138 g_clear_object (&smtp_auth);
1139 g_clear_object (&mail_client);
1140 return ret;
1141 }
1142
1143 /* ---------------------------------------------------------------------------------------------------- */
1144
1145 static gboolean
refresh_account(GoaProvider * provider,GoaClient * client,GoaObject * object,GtkWindow * parent,GError ** error)1146 refresh_account (GoaProvider *provider,
1147 GoaClient *client,
1148 GoaObject *object,
1149 GtkWindow *parent,
1150 GError **error)
1151 {
1152 AddAccountData data;
1153 GVariantBuilder builder;
1154 GoaAccount *account;
1155 GoaMailAuth *imap_auth = NULL;
1156 GoaMailAuth *smtp_auth = NULL;
1157 GoaMailClient *mail_client = NULL;
1158 GoaTlsType imap_tls_type;
1159 GoaTlsType smtp_tls_type;
1160 GtkWidget *dialog;
1161 GtkWidget *vbox;
1162 gboolean imap_accept_ssl_errors;
1163 gboolean ret = FALSE;
1164 gboolean smtp_accept_ssl_errors;
1165 gboolean smtp_use_auth;
1166 const gchar *imap_password;
1167 const gchar *smtp_password;
1168 gchar *domain = NULL;
1169 gchar *email_address = NULL;
1170 gchar *imap_server = NULL;
1171 gchar *imap_username = NULL;
1172 gchar *smtp_server = NULL;
1173 gchar *smtp_username = NULL;
1174 gint response;
1175
1176 g_return_val_if_fail (GOA_IS_IMAP_SMTP_PROVIDER (provider), FALSE);
1177 g_return_val_if_fail (GOA_IS_CLIENT (client), FALSE);
1178 g_return_val_if_fail (GOA_IS_OBJECT (object), FALSE);
1179 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
1180 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1181
1182 dialog = gtk_dialog_new_with_buttons (NULL,
1183 parent,
1184 GTK_DIALOG_MODAL
1185 | GTK_DIALOG_DESTROY_WITH_PARENT
1186 | GTK_DIALOG_USE_HEADER_BAR,
1187 NULL,
1188 NULL);
1189 gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
1190 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1191 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1192
1193 vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1194 gtk_box_set_spacing (GTK_BOX (vbox), 12);
1195
1196 memset (&data, 0, sizeof (AddAccountData));
1197 data.cancellable = g_cancellable_new ();
1198 data.loop = g_main_loop_new (NULL, FALSE);
1199 data.dialog = GTK_DIALOG (dialog);
1200 data.error = NULL;
1201
1202 create_account_details_ui (provider, GTK_DIALOG (dialog), GTK_BOX (vbox), FALSE, &data);
1203
1204 email_address = goa_util_lookup_keyfile_string (object, "EmailAddress");
1205
1206 imap_accept_ssl_errors = goa_util_lookup_keyfile_boolean (object, "ImapAcceptSslErrors");
1207 smtp_accept_ssl_errors = goa_util_lookup_keyfile_boolean (object, "SmtpAcceptSslErrors");
1208
1209 imap_tls_type = get_tls_type_from_object (object, "ImapUseSsl", "ImapUseTls");
1210 smtp_tls_type = get_tls_type_from_object (object, "SmtpUseSsl", "SmtpUseTls");
1211
1212 imap_server = goa_util_lookup_keyfile_string (object, "ImapHost");
1213 gtk_entry_set_text (GTK_ENTRY (data.imap_server), imap_server);
1214 gtk_editable_set_editable (GTK_EDITABLE (data.imap_server), FALSE);
1215
1216 imap_username = goa_util_lookup_keyfile_string (object, "ImapUserName");
1217 gtk_entry_set_text (GTK_ENTRY (data.imap_username), imap_username);
1218 gtk_editable_set_editable (GTK_EDITABLE (data.imap_username), FALSE);
1219
1220 smtp_use_auth = goa_util_lookup_keyfile_boolean (object, "SmtpUseAuth");
1221 if (smtp_use_auth)
1222 {
1223 smtp_server = goa_util_lookup_keyfile_string (object, "SmtpHost");
1224 gtk_entry_set_text (GTK_ENTRY (data.smtp_server), smtp_server);
1225 gtk_editable_set_editable (GTK_EDITABLE (data.smtp_server), FALSE);
1226
1227 smtp_username = goa_util_lookup_keyfile_string (object, "SmtpUserName");
1228 gtk_entry_set_text (GTK_ENTRY (data.smtp_username), smtp_username);
1229 gtk_editable_set_editable (GTK_EDITABLE (data.smtp_username), FALSE);
1230 }
1231
1232 gtk_widget_show_all (dialog);
1233 g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &data);
1234
1235 mail_client = goa_mail_client_new ();
1236
1237 /* IMAP */
1238
1239 gtk_notebook_set_current_page (GTK_NOTEBOOK (data.notebook), 0);
1240 gtk_widget_grab_focus (data.imap_password);
1241
1242 imap_again:
1243 response = gtk_dialog_run (GTK_DIALOG (dialog));
1244 if (response != GTK_RESPONSE_OK)
1245 {
1246 g_set_error (&data.error,
1247 GOA_ERROR,
1248 GOA_ERROR_DIALOG_DISMISSED,
1249 _("Dialog was dismissed"));
1250 goto out;
1251 }
1252
1253 gtk_widget_set_no_show_all (data.cluebar, TRUE);
1254 gtk_widget_hide (data.cluebar);
1255
1256 imap_password = gtk_entry_get_text (GTK_ENTRY (data.imap_password));
1257 g_cancellable_reset (data.cancellable);
1258 imap_auth = goa_imap_auth_login_new (imap_username, imap_password);
1259 goa_mail_client_check (mail_client,
1260 imap_server,
1261 imap_tls_type,
1262 imap_accept_ssl_errors,
1263 (imap_tls_type == GOA_TLS_TYPE_SSL) ? 993 : 143,
1264 imap_auth,
1265 data.cancellable,
1266 mail_check_cb,
1267 &data);
1268
1269 gtk_widget_set_sensitive (data.forward_button, FALSE);
1270 show_progress_ui (GTK_CONTAINER (data.progress_grid), TRUE);
1271 g_main_loop_run (data.loop);
1272
1273 if (g_cancellable_is_cancelled (data.cancellable))
1274 {
1275 g_prefix_error (&data.error,
1276 _("Dialog was dismissed (%s, %d): "),
1277 g_quark_to_string (data.error->domain),
1278 data.error->code);
1279 data.error->domain = GOA_ERROR;
1280 data.error->code = GOA_ERROR_DIALOG_DISMISSED;
1281 goto out;
1282 }
1283 else if (data.error != NULL)
1284 {
1285 gchar *markup;
1286
1287 markup = g_strdup_printf ("<b>%s</b>\n%s",
1288 _("Error connecting to IMAP server"),
1289 data.error->message);
1290 g_clear_error (&data.error);
1291
1292 gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
1293 g_free (markup);
1294
1295 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
1296 gtk_widget_set_no_show_all (data.cluebar, FALSE);
1297 gtk_widget_show_all (data.cluebar);
1298
1299 g_clear_object (&imap_auth);
1300 goto imap_again;
1301 }
1302
1303 gtk_widget_set_no_show_all (data.cluebar, TRUE);
1304 gtk_widget_hide (data.cluebar);
1305 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Forward"));
1306
1307 /* SMTP */
1308
1309 if (!smtp_use_auth)
1310 goto smtp_done;
1311
1312 /* Re-use the password from the IMAP page */
1313 gtk_entry_set_text (GTK_ENTRY (data.smtp_password), imap_password);
1314
1315 gtk_notebook_next_page (GTK_NOTEBOOK (data.notebook));
1316 gtk_widget_grab_focus (data.smtp_password);
1317
1318 smtp_again:
1319 response = gtk_dialog_run (GTK_DIALOG (dialog));
1320 if (response != GTK_RESPONSE_OK)
1321 {
1322 g_set_error (&data.error,
1323 GOA_ERROR,
1324 GOA_ERROR_DIALOG_DISMISSED,
1325 _("Dialog was dismissed"));
1326 goto out;
1327 }
1328
1329 gtk_widget_set_no_show_all (data.cluebar, TRUE);
1330 gtk_widget_hide (data.cluebar);
1331
1332 smtp_password = gtk_entry_get_text (GTK_ENTRY (data.smtp_password));
1333 g_cancellable_reset (data.cancellable);
1334 goa_utils_parse_email_address (email_address, NULL, &domain);
1335 smtp_auth = goa_smtp_auth_new (domain, smtp_username, smtp_password);
1336 goa_mail_client_check (mail_client,
1337 smtp_server,
1338 smtp_tls_type,
1339 smtp_accept_ssl_errors,
1340 (smtp_tls_type == GOA_TLS_TYPE_SSL) ? 465 : 587,
1341 smtp_auth,
1342 data.cancellable,
1343 mail_check_cb,
1344 &data);
1345
1346 gtk_widget_set_sensitive (data.forward_button, FALSE);
1347 show_progress_ui (GTK_CONTAINER (data.progress_grid), TRUE);
1348 g_main_loop_run (data.loop);
1349
1350 if (g_cancellable_is_cancelled (data.cancellable))
1351 {
1352 g_prefix_error (&data.error,
1353 _("Dialog was dismissed (%s, %d): "),
1354 g_quark_to_string (data.error->domain),
1355 data.error->code);
1356 data.error->domain = GOA_ERROR;
1357 data.error->code = GOA_ERROR_DIALOG_DISMISSED;
1358 goto out;
1359 }
1360 else if (data.error != NULL)
1361 {
1362 gchar *markup;
1363
1364 markup = g_strdup_printf ("<b>%s</b>\n%s",
1365 _("Error connecting to SMTP server"),
1366 data.error->message);
1367 g_clear_error (&data.error);
1368
1369 gtk_label_set_markup (GTK_LABEL (data.cluebar_label), markup);
1370 g_free (markup);
1371
1372 gtk_button_set_label (GTK_BUTTON (data.forward_button), _("_Try Again"));
1373 gtk_widget_set_no_show_all (data.cluebar, FALSE);
1374 gtk_widget_show_all (data.cluebar);
1375
1376 g_clear_object (&smtp_auth);
1377 g_clear_pointer (&domain, g_free);
1378 goto smtp_again;
1379 }
1380
1381 smtp_done:
1382
1383 /* TODO: run in worker thread */
1384 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
1385 g_variant_builder_add (&builder, "{sv}", "imap-password", g_variant_new_string (imap_password));
1386 if (smtp_use_auth)
1387 g_variant_builder_add (&builder, "{sv}", "smtp-password", g_variant_new_string (smtp_password));
1388
1389 if (!goa_utils_store_credentials_for_object_sync (provider,
1390 object,
1391 g_variant_builder_end (&builder),
1392 NULL, /* GCancellable */
1393 &data.error))
1394 goto out;
1395
1396 account = goa_object_peek_account (object);
1397 goa_account_call_ensure_credentials (account,
1398 NULL, /* GCancellable */
1399 NULL, NULL); /* callback, user_data */
1400
1401 ret = TRUE;
1402
1403 out:
1404 if (data.error != NULL)
1405 g_propagate_error (error, data.error);
1406
1407 gtk_widget_destroy (dialog);
1408 g_free (domain);
1409 g_free (email_address);
1410 g_free (imap_server);
1411 g_free (imap_username);
1412 g_free (smtp_server);
1413 g_free (smtp_username);
1414 g_clear_pointer (&data.loop, g_main_loop_unref);
1415 g_clear_object (&data.cancellable);
1416 g_clear_object (&imap_auth);
1417 g_clear_object (&smtp_auth);
1418 g_clear_object (&mail_client);
1419 return ret;
1420 }
1421
1422 /* ---------------------------------------------------------------------------------------------------- */
1423
1424 static void
show_label(GtkWidget * grid,gint row,const gchar * left,const gchar * right)1425 show_label (GtkWidget *grid, gint row, const gchar *left, const gchar *right)
1426 {
1427 GtkStyleContext *context;
1428 GtkWidget *label;
1429
1430 label = gtk_label_new (left);
1431 context = gtk_widget_get_style_context (label);
1432 gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
1433 gtk_widget_set_halign (label, GTK_ALIGN_END);
1434 gtk_widget_set_hexpand (label, TRUE);
1435 gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
1436
1437 label = gtk_label_new (right);
1438 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
1439 gtk_label_set_max_width_chars (GTK_LABEL (label), 24);
1440 gtk_label_set_width_chars (GTK_LABEL (label), 24);
1441 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1442 gtk_grid_attach (GTK_GRID (grid), label, 1, row, 3, 1);
1443 }
1444
1445 static void
show_account(GoaProvider * provider,GoaClient * client,GoaObject * object,GtkBox * vbox,G_GNUC_UNUSED GtkGrid * dummy1,G_GNUC_UNUSED GtkGrid * dummy2)1446 show_account (GoaProvider *provider,
1447 GoaClient *client,
1448 GoaObject *object,
1449 GtkBox *vbox,
1450 G_GNUC_UNUSED GtkGrid *dummy1,
1451 G_GNUC_UNUSED GtkGrid *dummy2)
1452 {
1453 GtkWidget *grid;
1454 const gchar *username;
1455 gchar *value_str;
1456 gchar *value_str_1;
1457 gint row = 0;
1458
1459 goa_utils_account_add_attention_needed (client, object, provider, vbox);
1460
1461 grid = gtk_grid_new ();
1462 gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
1463 gtk_widget_set_hexpand (grid, TRUE);
1464 gtk_widget_set_margin_end (grid, 72);
1465 gtk_widget_set_margin_start (grid, 72);
1466 gtk_widget_set_margin_top (grid, 24);
1467 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
1468 gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
1469 gtk_container_add (GTK_CONTAINER (vbox), grid);
1470
1471 goa_utils_account_add_header (object, GTK_GRID (grid), row++);
1472
1473 username = g_get_user_name ();
1474
1475 value_str = goa_util_lookup_keyfile_string (object, "EmailAddress");
1476 show_label (GTK_WIDGET (grid), row++, _("E-mail"), value_str);
1477 g_free (value_str);
1478
1479 value_str = goa_util_lookup_keyfile_string (object, "Name");
1480 show_label (GTK_WIDGET (grid), row++, _("Name"), value_str);
1481 g_free (value_str);
1482
1483 value_str = goa_util_lookup_keyfile_string (object, "ImapHost");
1484 value_str_1 = goa_util_lookup_keyfile_string (object, "ImapUserName");
1485 if (g_strcmp0 (username, value_str_1) != 0)
1486 {
1487 gchar *tmp;
1488
1489 tmp = g_strconcat (value_str_1, "@", value_str, NULL);
1490 show_label (GTK_WIDGET (grid), row++, _("IMAP"), tmp);
1491 g_free (tmp);
1492 }
1493 else
1494 show_label (GTK_WIDGET (grid), row++, _("IMAP"), value_str);
1495 g_free (value_str_1);
1496 g_free (value_str);
1497
1498 value_str = goa_util_lookup_keyfile_string (object, "SmtpHost");
1499 value_str_1 = goa_util_lookup_keyfile_string (object, "SmtpUserName");
1500 if (value_str_1 != NULL && g_strcmp0 (username, value_str_1) != 0)
1501 {
1502 gchar *tmp;
1503
1504 tmp = g_strconcat (value_str_1, "@", value_str, NULL);
1505 show_label (GTK_WIDGET (grid), row++, _("SMTP"), tmp);
1506 g_free (tmp);
1507 }
1508 else
1509 show_label (GTK_WIDGET (grid), row++, _("SMTP"), value_str);
1510 g_free (value_str_1);
1511 g_free (value_str);
1512 }
1513
1514 /* ---------------------------------------------------------------------------------------------------- */
1515
1516 static void
goa_imap_smtp_provider_init(GoaImapSmtpProvider * provider)1517 goa_imap_smtp_provider_init (GoaImapSmtpProvider *provider)
1518 {
1519 }
1520
1521 static void
goa_imap_smtp_provider_class_init(GoaImapSmtpProviderClass * klass)1522 goa_imap_smtp_provider_class_init (GoaImapSmtpProviderClass *klass)
1523 {
1524 GoaProviderClass *provider_class;
1525
1526 provider_class = GOA_PROVIDER_CLASS (klass);
1527 provider_class->get_provider_type = get_provider_type;
1528 provider_class->get_provider_name = get_provider_name;
1529 provider_class->get_provider_group = get_provider_group;
1530 provider_class->get_provider_features = get_provider_features;
1531 provider_class->get_provider_icon = get_provider_icon;
1532 provider_class->add_account = add_account;
1533 provider_class->refresh_account = refresh_account;
1534 provider_class->build_object = build_object;
1535 provider_class->show_account = show_account;
1536 provider_class->ensure_credentials_sync = ensure_credentials_sync;
1537 }
1538
1539 /* ---------------------------------------------------------------------------------------------------- */
1540
1541 static gboolean
on_handle_get_password(GoaPasswordBased * interface,GDBusMethodInvocation * invocation,const gchar * id,gpointer user_data)1542 on_handle_get_password (GoaPasswordBased *interface,
1543 GDBusMethodInvocation *invocation,
1544 const gchar *id,
1545 gpointer user_data)
1546 {
1547 GoaObject *object;
1548 GoaAccount *account;
1549 GoaProvider *provider;
1550 GError *error;
1551 const gchar *account_id;
1552 const gchar *method_name;
1553 const gchar *provider_type;
1554 gchar *password = NULL;
1555
1556 /* TODO: maybe log what app is requesting access */
1557
1558 object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
1559 account = goa_object_peek_account (object);
1560 account_id = goa_account_get_id (account);
1561 provider_type = goa_account_get_provider_type (account);
1562 method_name = g_dbus_method_invocation_get_method_name (invocation);
1563 g_debug ("Handling %s for account (%s, %s)", method_name, provider_type, account_id);
1564
1565 provider = goa_provider_get_for_provider_type (provider_type);
1566
1567 error = NULL;
1568 if (!goa_utils_get_credentials (provider, object, id, NULL, &password, NULL, &error))
1569 {
1570 g_dbus_method_invocation_take_error (invocation, error);
1571 goto out;
1572 }
1573
1574 goa_password_based_complete_get_password (interface, invocation, password);
1575
1576 out:
1577 g_free (password);
1578 g_object_unref (provider);
1579 return TRUE; /* invocation was handled */
1580 }
1581