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