I#27 - [IMAPx] Ignore DavMail's CR/LF in BODYSTRUCTURE response
[evolution-data-server.git] / src / libedataserverui / e-trust-prompt.c
blob50d7634ee9a1fc87ff555d17bf46af37a35f8794
1 /*
2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-data-server-config.h"
20 #include <string.h>
22 #include <glib.h>
23 #include <glib/gi18n-lib.h>
25 #define GCR_API_SUBJECT_TO_CHANGE
26 #include <gcr/gcr.h>
27 #undef GCR_API_SUBJECT_TO_CHANGE
29 #include <camel/camel.h>
30 #include <libebackend/libebackend.h>
31 #include <libedataserver/libedataserver.h>
33 #include "e-trust-prompt.h"
35 static void
36 trust_prompt_add_info_line (GtkGrid *grid,
37 const gchar *label_text,
38 const gchar *value_text,
39 gboolean ellipsize,
40 gboolean wrap,
41 gboolean use_bold,
42 gint *at_row)
44 GtkWidget *widget;
45 PangoAttribute *attr;
46 PangoAttrList *bold;
48 g_return_if_fail (grid != NULL);
49 g_return_if_fail (label_text != NULL);
50 g_return_if_fail (at_row != NULL);
52 if (!value_text || !*value_text)
53 return;
55 bold = pango_attr_list_new ();
56 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
57 pango_attr_list_insert (bold, attr);
59 widget = gtk_label_new (label_text);
60 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
61 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
63 gtk_grid_attach (grid, widget, 1, *at_row, 1, 1);
65 widget = gtk_label_new (value_text);
66 gtk_label_set_line_wrap (GTK_LABEL (widget), wrap);
67 g_object_set (
68 G_OBJECT (widget),
69 "hexpand", TRUE,
70 "halign", GTK_ALIGN_FILL,
71 "justify", GTK_JUSTIFY_LEFT,
72 "attributes", use_bold ? bold : NULL,
73 "selectable", TRUE,
74 "ellipsize", ellipsize ? PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_NONE,
75 "width-chars", 60,
76 "max-width-chars", 80,
77 "xalign", 0.0,
78 "yalign", 0.0,
79 NULL);
81 gtk_grid_attach (grid, widget, 2, *at_row, 1, 1);
83 *at_row = (*at_row) + 1;
85 pango_attr_list_unref (bold);
88 static ETrustPromptResponse
89 trust_prompt_show (GtkWindow *parent,
90 const gchar *source_extension,
91 const gchar *source_display_name,
92 const gchar *host,
93 const gchar *error_text,
94 GcrParsed *parsed,
95 const gchar *reason,
96 void (* dialog_ready_cb) (GtkDialog *dialog, gpointer user_data),
97 gpointer user_data)
99 ETrustPromptResponse response;
100 GcrCertificateWidget *certificate_widget;
101 GcrCertificate *certificate;
102 GckAttributes *attributes;
103 GtkWidget *dialog, *widget;
104 GtkGrid *grid;
105 const guchar *data;
106 gchar *bhost, *tmp;
107 gsize length;
108 gint row = 0;
110 dialog = gtk_dialog_new_with_buttons (
111 _("Certificate trust..."), parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
112 _("_Cancel"), GTK_RESPONSE_CANCEL,
113 _("_Reject"), GTK_RESPONSE_REJECT,
114 _("Accept _Temporarily"), GTK_RESPONSE_YES,
115 _("_Accept Permanently"), GTK_RESPONSE_ACCEPT,
116 NULL);
118 widget = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
120 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
122 grid = g_object_new (
123 GTK_TYPE_GRID,
124 "orientation", GTK_ORIENTATION_HORIZONTAL,
125 "row-homogeneous", FALSE,
126 "row-spacing", 6,
127 "column-homogeneous", FALSE,
128 "column-spacing", 12,
129 "hexpand", TRUE,
130 "halign", GTK_ALIGN_FILL,
131 "vexpand", TRUE,
132 "valign", GTK_ALIGN_FILL,
133 NULL);
135 gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
136 gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (grid));
138 widget = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_DIALOG);
139 g_object_set (
140 G_OBJECT (widget),
141 "vexpand", FALSE,
142 "valign", GTK_ALIGN_START,
143 NULL);
144 gtk_grid_attach (grid, widget, 0, row, 1, 3);
146 tmp = g_markup_escape_text (host, -1);
147 bhost = g_strconcat ("<b>", tmp, "</b>", NULL);
148 g_free (tmp);
149 tmp = NULL;
150 if (source_extension && source_display_name) {
151 gchar *bsource_display_name = g_strconcat ("<b>", source_display_name, "</b>", NULL);
153 if (g_str_equal (source_extension, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
154 tmp = g_strdup_printf (
155 "An address book '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
156 bsource_display_name, bhost);
157 } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_CALENDAR)) {
158 tmp = g_strdup_printf (
159 "A calendar '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
160 bsource_display_name, bhost);
161 } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MEMO_LIST)) {
162 tmp = g_strdup_printf (
163 "A memo list '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
164 bsource_display_name, bhost);
165 } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_TASK_LIST)) {
166 tmp = g_strdup_printf (
167 "A task list '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
168 bsource_display_name, bhost);
169 } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
170 tmp = g_strdup_printf (
171 "A mail account '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
172 bsource_display_name, bhost);
173 } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
174 tmp = g_strdup_printf (
175 "A mail transport '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
176 bsource_display_name, bhost);
177 } else {
178 tmp = g_strdup_printf (
179 "An account '%s' cannot connect, because an SSL/TLS certificate for '%s' is not trusted. Do you wish to accept it?",
180 bsource_display_name, bhost);
183 g_free (bsource_display_name);
185 if (!tmp)
186 tmp = g_strdup_printf (_("SSL/TLS certificate for ā€œ%sā€ is not trusted. Do you wish to accept it?"), bhost);
187 g_free (bhost);
189 widget = gtk_label_new (NULL);
190 gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
191 gtk_label_set_markup (GTK_LABEL (widget), tmp);
192 g_object_set (
193 G_OBJECT (widget),
194 "hexpand", TRUE,
195 "halign", GTK_ALIGN_FILL,
196 "valign", GTK_ALIGN_CENTER,
197 "width-chars", 60,
198 "max-width-chars", 80,
199 "xalign", 0.0,
200 "yalign", 0.0,
201 NULL);
203 g_free (tmp);
205 gtk_grid_attach (grid, widget, 1, row, 2, 1);
206 row++;
208 trust_prompt_add_info_line (grid, _("Reason:"), reason, FALSE, FALSE, TRUE, &row);
210 if (error_text)
211 trust_prompt_add_info_line (grid, _("Detailed error:"), error_text, FALSE, TRUE, FALSE, &row);
213 data = gcr_parsed_get_data (parsed, &length);
214 attributes = gcr_parsed_get_attributes (parsed);
216 certificate = gcr_simple_certificate_new (data, length);
218 certificate_widget = gcr_certificate_widget_new (certificate);
219 gcr_certificate_widget_set_attributes (certificate_widget, attributes);
221 widget = GTK_WIDGET (certificate_widget);
222 gtk_grid_attach (grid, widget, 1, row, 2, 1);
223 gtk_widget_show (widget);
225 g_clear_object (&certificate);
227 gtk_widget_show_all (GTK_WIDGET (grid));
229 if (dialog_ready_cb)
230 dialog_ready_cb (GTK_DIALOG (dialog), user_data);
232 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
233 case GTK_RESPONSE_REJECT:
234 response = E_TRUST_PROMPT_RESPONSE_REJECT;
235 break;
236 case GTK_RESPONSE_ACCEPT:
237 response = E_TRUST_PROMPT_RESPONSE_ACCEPT;
238 break;
239 case GTK_RESPONSE_YES:
240 response = E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY;
241 break;
242 default:
243 response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
244 break;
247 gtk_widget_destroy (dialog);
249 return response;
253 * e_trust_prompt_describe_certificate_errors:
254 * @flags: a #GTlsCertificateFlags to describe
256 * Converts @flags into a localized text description of the set bits, one
257 * bit description per line. If no bit is set, then an empty string is
258 * returned.
260 * Returns: A newly allocated string with text description
261 * of @flags. Free the returned pointer with g_free() when no longer needed.
263 * Since: 3.16
265 gchar *
266 e_trust_prompt_describe_certificate_errors (GTlsCertificateFlags flags)
268 struct _convert_table {
269 GTlsCertificateFlags flag;
270 const gchar *description;
271 } convert_table[] = {
272 { G_TLS_CERTIFICATE_UNKNOWN_CA,
273 N_("The signing certificate authority is not known.") },
274 { G_TLS_CERTIFICATE_BAD_IDENTITY,
275 N_("The certificate does not match the expected identity of the site that it was retrieved from.") },
276 { G_TLS_CERTIFICATE_NOT_ACTIVATED,
277 N_("The certificateā€™s activation time is still in the future.") },
278 { G_TLS_CERTIFICATE_EXPIRED,
279 N_("The certificate has expired.") },
280 { G_TLS_CERTIFICATE_REVOKED,
281 N_("The certificate has been revoked according to the connectionā€™s certificate revocation list.") },
282 { G_TLS_CERTIFICATE_INSECURE,
283 N_("The certificateā€™s algorithm is considered insecure.") }
286 GString *reason = g_string_new ("");
287 gint ii;
289 for (ii = 0; ii < G_N_ELEMENTS (convert_table); ii++) {
290 if ((flags & convert_table[ii].flag) != 0) {
291 if (reason->len > 0)
292 g_string_append (reason, "\n");
294 g_string_append (reason, _(convert_table[ii].description));
298 return g_string_free (reason, FALSE);
301 static void
302 trust_prompt_parser_parsed_cb (GcrParser *parser,
303 GcrParsed **out_parsed)
305 GcrParsed *parsed;
307 parsed = gcr_parser_get_parsed (parser);
308 g_return_if_fail (parsed != NULL);
310 *out_parsed = gcr_parsed_ref (parsed);
313 static ETrustPromptResponse
314 e_trust_prompt_run_with_dialog_ready_callback (GtkWindow *parent,
315 const gchar *source_extension,
316 const gchar *source_display_name,
317 const gchar *host,
318 const gchar *certificate_pem,
319 GTlsCertificateFlags certificate_errors,
320 const gchar *error_text,
321 void (* dialog_ready_cb) (GtkDialog *dialog, gpointer user_data),
322 gpointer user_data)
324 ETrustPromptResponse response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
325 GcrParser *parser;
326 GcrParsed *parsed = NULL;
327 GError *local_error = NULL;
329 if (parent)
330 g_return_val_if_fail (GTK_IS_WINDOW (parent), E_TRUST_PROMPT_RESPONSE_UNKNOWN);
331 g_return_val_if_fail (host != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
332 g_return_val_if_fail (certificate_pem != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
334 /* Continue even if PKCS#11 module registration fails.
335 * Certificate details won't display correctly but the
336 * user can still respond to the prompt. */
337 gcr_pkcs11_initialize (NULL, &local_error);
338 if (local_error != NULL) {
339 g_warning ("%s: gcr_pkcs11_initialize() call failed: %s", G_STRFUNC, local_error->message);
340 g_clear_error (&local_error);
343 parser = gcr_parser_new ();
345 g_signal_connect (
346 parser, "parsed",
347 G_CALLBACK (trust_prompt_parser_parsed_cb), &parsed);
349 gcr_parser_parse_data (parser, (const guchar *) certificate_pem, strlen (certificate_pem), &local_error);
351 g_object_unref (parser);
353 /* Sanity check. */
354 g_warn_if_fail (
355 ((parsed != NULL) && (local_error == NULL)) ||
356 ((parsed == NULL) && (local_error != NULL)));
358 if (parsed != NULL) {
359 gchar *reason;
361 reason = e_trust_prompt_describe_certificate_errors (certificate_errors);
363 response = trust_prompt_show (parent, source_extension, source_display_name, host, error_text, parsed, reason, dialog_ready_cb, user_data);
365 gcr_parsed_unref (parsed);
366 g_free (reason);
369 g_clear_error (&local_error);
371 return response;
375 * e_trust_prompt_run_modal:
376 * @parent: A #GtkWindow to use as a parent for the trust prompt dialog
377 * @source_extension: (allow-none): an #ESource extension, to identify a kind of the source; or %NULL
378 * @source_display_name: (allow-none): an #ESource display name, to identify what prompts; or %NULL
379 * @host: a host name to which the certificate belongs
380 * @certificate_pem: a PEM-encoded certificate for which to show the trust prompt
381 * @certificate_errors: errors of the @certificate_pem
382 * @error_text: (allow-none): an optional error text to show in the dialog; can be %NULL
384 * Runs modal (doesn't return until the dialog is closed) a trust prompt dialog,
385 * it is a prompt whether a user wants to accept or reject the @certificate_pem
386 * for the @host due to the @certificate_errors errors.
388 * The pair @source_extension and @source_display_name influences the trust prompt message.
389 * If both are set, then the message also contains which source failed to connect according
390 * to these two arguments.
392 * The dialog can contain a custom error text, passed in as @error_text.
393 * The error might be a detailed error string returned by the server. If set,
394 * it is prefixed with "Detailed error:" string.
396 * Returns: A code of the user's choice. The #E_TRUST_PROMPT_RESPONSE_UNKNOWN
397 * is returned, when the user cancelled the trust prompt dialog.
399 * Since: 3.16
401 ETrustPromptResponse
402 e_trust_prompt_run_modal (GtkWindow *parent,
403 const gchar *source_extension,
404 const gchar *source_display_name,
405 const gchar *host,
406 const gchar *certificate_pem,
407 GTlsCertificateFlags certificate_errors,
408 const gchar *error_text)
410 if (parent)
411 g_return_val_if_fail (GTK_IS_WINDOW (parent), E_TRUST_PROMPT_RESPONSE_UNKNOWN);
412 g_return_val_if_fail (host != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
413 g_return_val_if_fail (certificate_pem != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
415 return e_trust_prompt_run_with_dialog_ready_callback (parent, source_extension, source_display_name, host,
416 certificate_pem, certificate_errors, error_text, NULL, NULL);
419 static void
420 source_connection_status_changed_cb (ESource *source,
421 GParamSpec *param,
422 GtkDialog *dialog)
424 g_return_if_fail (GTK_IS_DIALOG (dialog));
426 /* Do not close the prompt when the source is still waiting for the credentials. */
427 if (e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS &&
428 e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_SSL_FAILED)
429 gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
432 static void
433 trust_prompt_listen_for_source_changes_cb (GtkDialog *dialog,
434 gpointer user_data)
436 ESource *source = user_data;
438 g_return_if_fail (GTK_IS_DIALOG (dialog));
439 g_return_if_fail (E_IS_SOURCE (source));
441 g_signal_connect (source, "notify::connection-status",
442 G_CALLBACK (source_connection_status_changed_cb), dialog);
445 typedef struct _SaveSourceData {
446 ETrustPromptResponse response;
447 gboolean call_save;
448 GError *error;
449 } SaveSourceData;
451 static void
452 save_source_data_free (gpointer ptr)
454 SaveSourceData *data = ptr;
456 if (data) {
457 g_clear_error (&data->error);
458 g_free (data);
462 static void
463 save_source_thread (GTask *task,
464 gpointer source_object,
465 gpointer task_data,
466 GCancellable *cancellable)
468 ESource *source = source_object;
469 SaveSourceData *data = task_data;
470 GError *local_error = NULL;
472 g_return_if_fail (E_IS_SOURCE (source));
473 g_return_if_fail (data != NULL);
475 if (data->error)
476 local_error = g_error_copy (data->error);
477 else if (data->call_save)
478 e_source_write_sync (source, cancellable, &local_error);
480 if (local_error != NULL) {
481 g_task_return_error (task, local_error);
482 } else {
483 g_task_return_boolean (task, TRUE);
487 static gchar *
488 trust_prompt_get_host_from_url (const gchar *url)
490 SoupURI *suri;
491 gchar *host;
493 if (!url || !*url)
494 return NULL;
496 suri = soup_uri_new (url);
497 if (!suri)
498 return NULL;
500 host = g_strdup (soup_uri_get_host (suri));
502 if (!host || !*host) {
503 g_free (host);
504 host = NULL;
507 soup_uri_free (suri);
509 return host;
513 * e_trust_prompt_run_for_source:
514 * @parent: A #GtkWindow to use as a parent for the trust prompt dialog
515 * @source: an #ESource, with %E_SOURCE_EXTENSION_AUTHENTICATION
516 * @certificate_pem: a PEM-encoded certificate for which to show the trust prompt
517 * @certificate_errors: errors of the @certificate_pem
518 * @error_text: (allow-none): an optional error text to show in the dialog; can be %NULL
519 * @allow_source_save: whether can also save any @source changes
520 * @cancellable: (allow-none): a #GCancellable, or %NULL
521 * @callback: a callback to call, when the prompt (an @source save) is done
522 * @user_data: user data passed into @callback
524 * Similar to e_trust_prompt_run_modal(), except it also manages all the necessary things
525 * around the @source<!-- -->'s SSL/TLS trust properties when it also contains %E_SOURCE_EXTENSION_WEBDAV,
526 * thus the SSL/TLS trust on the WebDAV @source is properly updated based on the user's choice.
527 * The call is finished with e_trust_prompt_run_for_source_finish(),
528 * which also returns the user's choice. The finish happens in the @callback.
529 * This is necessary, because the @source can be also saved.
531 * The function fails, if the @source doesn't contain the %E_SOURCE_EXTENSION_AUTHENTICATION.
533 * Note: The dialog is not shown when the stored certificate trust in the WebDAV @source
534 * matches the @certificate_pem and the stored result is #E_TRUST_PROMPT_RESPONSE_REJECT.
536 * Since: 3.16
538 void
539 e_trust_prompt_run_for_source (GtkWindow *parent,
540 ESource *source,
541 const gchar *certificate_pem,
542 GTlsCertificateFlags certificate_errors,
543 const gchar *error_text,
544 gboolean allow_source_save,
545 GCancellable *cancellable,
546 GAsyncReadyCallback callback,
547 gpointer user_data)
549 ESourceAuthentication *extension_authentication = NULL;
550 ESourceWebdav *extension_webdav = NULL;
551 SaveSourceData *save_data;
552 GTlsCertificate *certificate;
553 gchar *host;
554 GTask *task;
556 if (parent)
557 g_return_if_fail (GTK_IS_WINDOW (parent));
558 g_return_if_fail (E_IS_SOURCE (source));
559 g_return_if_fail (certificate_pem != NULL);
561 if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA) ||
562 e_source_has_extension (source, E_SOURCE_EXTENSION_UOA)) {
563 /* Make sure that GOA/UOA collection sources contain these extensions too */
564 g_warn_if_fail (e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION));
565 g_warn_if_fail (e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND));
568 if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION))
569 extension_authentication = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
570 if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND))
571 extension_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
573 save_data = g_new0 (SaveSourceData, 1);
574 save_data->response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
575 save_data->call_save = FALSE;
577 /* Lookup used host name */
578 if (extension_authentication)
579 host = e_source_authentication_dup_host (extension_authentication);
580 else
581 host = NULL;
583 if (!host || !*host) {
584 g_free (host);
585 host = NULL;
587 if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA)) {
588 ESourceGoa *goa_extension;
589 gchar *url;
591 goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA);
593 url = e_source_goa_dup_calendar_url (goa_extension);
594 host = trust_prompt_get_host_from_url (url);
595 g_free (url);
597 if (!host) {
598 url = e_source_goa_dup_contacts_url (goa_extension);
599 host = trust_prompt_get_host_from_url (url);
600 g_free (url);
605 certificate = g_tls_certificate_new_from_pem (certificate_pem, -1, &save_data->error);
606 if (certificate) {
607 if (extension_webdav && host)
608 save_data->response = e_source_webdav_verify_ssl_trust (extension_webdav, host, certificate, 0);
609 else
610 save_data->response = E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;
612 if (save_data->response != E_TRUST_PROMPT_RESPONSE_REJECT) {
613 const gchar *source_extension = NULL;
615 if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
616 source_extension = E_SOURCE_EXTENSION_ADDRESS_BOOK;
618 if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
619 if (!source_extension)
620 source_extension = E_SOURCE_EXTENSION_CALENDAR;
621 else
622 source_extension = E_SOURCE_EXTENSION_COLLECTION;
625 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
626 if (!source_extension)
627 source_extension = E_SOURCE_EXTENSION_MEMO_LIST;
628 else
629 source_extension = E_SOURCE_EXTENSION_COLLECTION;
632 if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
633 if (!source_extension)
634 source_extension = E_SOURCE_EXTENSION_TASK_LIST;
635 else
636 source_extension = E_SOURCE_EXTENSION_COLLECTION;
639 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
640 if (!source_extension)
641 source_extension = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
642 else
643 source_extension = E_SOURCE_EXTENSION_COLLECTION;
646 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
647 if (!source_extension)
648 source_extension = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
649 else
650 source_extension = E_SOURCE_EXTENSION_COLLECTION;
653 save_data->response = e_trust_prompt_run_with_dialog_ready_callback (parent,
654 source_extension, e_source_get_display_name (source), host,
655 certificate_pem, certificate_errors, error_text,
656 trust_prompt_listen_for_source_changes_cb, source);
660 g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
661 source_connection_status_changed_cb, NULL);
663 if (save_data->response != E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
664 if (certificate && extension_webdav) {
665 e_source_webdav_update_ssl_trust (extension_webdav, host, certificate, save_data->response);
666 save_data->call_save = allow_source_save;
670 g_clear_object (&certificate);
671 g_free (host);
673 task = g_task_new (source, cancellable, callback, user_data);
674 g_task_set_source_tag (task, e_trust_prompt_run_for_source);
675 g_task_set_task_data (task, save_data, save_source_data_free);
677 g_task_run_in_thread (task, save_source_thread);
679 g_object_unref (task);
683 * e_trust_prompt_run_for_source_finish:
684 * @source: an #ESource which was used with e_trust_prompt_run_for_source()
685 * @result: a #GAsyncResult
686 * @response: an output argument, user's response to the trust prompt
687 * @error: return location for a #GError, or %NULL
689 * Finishes the operation started with e_trust_prompt_run_for_source().
690 * The @response will contain a code of the user's choice.
691 * The #E_TRUST_PROMPT_RESPONSE_UNKNOWN is used, when the user cancelled the trust
692 * prompt dialog and no changes are made with the @source.
694 * If an error occurs, the function sets @error and returns %FALSE.
696 * Returns: %TRUE on success, %FALSE on error
698 * Since: 3.16
700 gboolean
701 e_trust_prompt_run_for_source_finish (ESource *source,
702 GAsyncResult *result,
703 ETrustPromptResponse *response,
704 GError **error)
706 gboolean success;
708 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
709 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
710 g_return_val_if_fail (response != NULL, FALSE);
712 g_return_val_if_fail (
713 g_async_result_is_tagged (
714 result, e_trust_prompt_run_for_source), FALSE);
716 success = g_task_propagate_boolean (G_TASK (result), error);
718 if (success) {
719 SaveSourceData *save_data;
721 save_data = g_task_get_task_data (G_TASK (result));
722 g_return_val_if_fail (save_data != NULL, FALSE);
724 *response = save_data->response;
727 return success;