talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit a3b08204f9687fcf35d833bd46b61059bf6bd2b7
parent 73088e2d091346b9770dbbb98a61e76620417f44
Author: Colin Leroy <colin@colino.net>
Date:   Wed, 30 Apr 2014 10:48:20 +0200

Make autoconfiguration non-blocking

Diffstat:
Msrc/common/utils.c | 43-------------------------------------------
Msrc/common/utils.h | 4----
Msrc/gtk/gtkutils.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gtk/gtkutils.h | 24++++++++++++++++++++++++
Msrc/prefs_account.c | 138++++++++++++++++++++++++++++++++++++++++++-------------------------------------
5 files changed, 194 insertions(+), 112 deletions(-)

diff --git a/src/common/utils.c b/src/common/utils.c @@ -5515,45 +5515,3 @@ int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name) { slist_free_strings_full(canonical_parts); return 0; } - -#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0)) -gboolean auto_configure_service(const gchar *service, const gchar *domain, gchar **srvhost, guint16 *srvport) -{ - GResolver *resolver; - GList *answers, *cur; - GError *error = NULL; - gboolean result = FALSE; - - cm_return_val_if_fail(service != NULL, FALSE); - cm_return_val_if_fail(domain != NULL, FALSE); - - resolver = g_resolver_get_default(); - if (resolver == NULL) - return FALSE; - - answers = g_resolver_lookup_service(resolver, service, "tcp", domain, NULL, &error); - - *srvhost = NULL; - *srvport = 0; - - if (answers) { - for (cur = g_srv_target_list_sort(answers); cur; cur = cur->next) { - GSrvTarget *target = (GSrvTarget *)cur->data; - const gchar *hostname = g_srv_target_get_hostname(target); - guint16 port = g_srv_target_get_port(target); - if (hostname && strcmp(hostname,"") && port > 0) { - result = TRUE; - *srvhost = g_strdup(hostname); - *srvport = port; - break; - } - } - g_resolver_free_targets(answers); - } else if (error) { - g_error_free(error); - } - - g_object_unref(resolver); - return result; -} -#endif -\ No newline at end of file diff --git a/src/common/utils.h b/src/common/utils.h @@ -599,10 +599,6 @@ void cm_mutex_free(GMutex *mutex); int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name); -#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0)) -gboolean auto_configure_service(const gchar *service, const gchar *domain, gchar **srvhost, guint16 *srvport); -#endif - #ifdef __cplusplus } #endif diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c @@ -1877,3 +1877,99 @@ GdkPixbuf *claws_load_pixbuf_fitting(GdkPixbuf *src_pixbuf, int box_width, return pixbuf; } + +#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0)) +static void auto_configure_done(const gchar *hostname, gint port, gboolean ssl, AutoConfigureData *data) +{ + if (hostname != NULL) { + if (data->hostname_entry) + gtk_entry_set_text(data->hostname_entry, hostname); + if (data->set_port) + gtk_toggle_button_set_active(data->set_port, + (ssl && port == data->default_ssl_port) || (!ssl && port == data->default_port)); + if (data->port) + gtk_spin_button_set_value(data->port, port); + else if (data->hostname_entry) { + gchar *tmp = g_strdup_printf("%s:%d", hostname, port); + gtk_entry_set_text(data->hostname_entry, tmp); + g_free(tmp); + } + + if (ssl && data->ssl_checkbtn) + gtk_toggle_button_set_active(data->ssl_checkbtn, TRUE); + else if (data->tls_checkbtn) + gtk_toggle_button_set_active(data->tls_checkbtn, TRUE); + + gtk_label_set_text(data->info_label, _("Done.")); + } else { + gtk_label_set_text(data->info_label, _("Failed.")); + } + gtk_widget_show(GTK_WIDGET(data->configure_button)); + gtk_widget_hide(GTK_WIDGET(data->cancel_button)); + g_free(data->domain); + g_free(data); +} + +static void resolve_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + AutoConfigureData *data = (AutoConfigureData *)user_data; + GResolver *resolver = (GResolver *)source; + GError *error = NULL; + gchar *hostname = NULL; + guint16 port; + GList *answers, *cur; + gboolean found = FALSE; + gboolean abort = FALSE; + + answers = g_resolver_lookup_service_finish(resolver, result, &error); + + if (answers) { + for (cur = g_srv_target_list_sort(answers); cur; cur = cur->next) { + GSrvTarget *target = (GSrvTarget *)cur->data; + const gchar *h = g_srv_target_get_hostname(target); + port = g_srv_target_get_port(target); + if (h && strcmp(h,"") && port > 0) { + hostname = g_strdup(h); + found = TRUE; + break; + } + } + g_resolver_free_targets(answers); + } else if (error) { + if (error->code == G_IO_ERROR_CANCELLED) + abort = TRUE; + debug_print("error %s\n", error->message); + g_error_free(error); + } + + if (found) { + auto_configure_done(hostname, port, TRUE, data); + } else if (data->ssl_service && !abort) { + /* Fallback to TLS */ + data->ssl_service = NULL; + auto_configure_service(data); + } else { + auto_configure_done(NULL, 0, FALSE, data); + } + g_free(hostname); + g_object_unref(resolver); +} + +void auto_configure_service(AutoConfigureData *data) +{ + GResolver *resolver; + const gchar *cur_service = data->ssl_service != NULL ? data->ssl_service : data->tls_service; + + cm_return_if_fail(cur_service != NULL); + cm_return_if_fail(data->domain != NULL); + + resolver = g_resolver_get_default(); + if (resolver != NULL) { + gtk_label_set_text(data->info_label, _("Configuring...")); + gtk_widget_hide(GTK_WIDGET(data->configure_button)); + gtk_widget_show(GTK_WIDGET(data->cancel_button)); + g_resolver_lookup_service_async(resolver, cur_service, "tcp", data->domain, + data->cancel, resolve_done, data); + } +} +#endif +\ No newline at end of file diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h @@ -209,6 +209,30 @@ claws_input_add (gint source, gtk_widget_set_has_tooltip(GTK_WIDGET(widget), FALSE); \ } +#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0)) +typedef struct _AutoConfigureData { + const gchar *ssl_service; + const gchar *tls_service; + gchar *domain; + + GtkEntry *hostname_entry; + GtkToggleButton *set_port; + GtkSpinButton *port; + gint default_port; + gint default_ssl_port; + GtkToggleButton *tls_checkbtn; + GtkToggleButton *ssl_checkbtn; + GtkLabel *info_label; + GtkButton *configure_button; + GtkButton *cancel_button; + GCancellable *cancel; + GMainLoop *main_loop; +} AutoConfigureData; + +void auto_configure_service(AutoConfigureData *data); +#endif + + #if GTK_CHECK_VERSION (3, 2, 0) #define GTK_TYPE_VBOX GTK_TYPE_BOX #define GtkVBox GtkBox diff --git a/src/prefs_account.c b/src/prefs_account.c @@ -120,6 +120,7 @@ typedef struct BasicPage GtkWidget *uid_entry; GtkWidget *pass_entry; GtkWidget *auto_configure_btn; + GtkWidget *auto_configure_cancel_btn; GtkWidget *auto_configure_lbl; } BasicPage; @@ -1007,6 +1008,7 @@ static void basic_create_widget_func(PrefsPage * _page, GtkWidget *uid_entry; GtkWidget *pass_entry; GtkWidget *auto_configure_btn; + GtkWidget *auto_configure_cancel_btn; GtkWidget *auto_configure_lbl; GtkListStore *menu; GtkTreeIter iter; @@ -1119,6 +1121,8 @@ static void basic_create_widget_func(PrefsPage * _page, auto_configure_btn = gtk_button_new_with_label(_("Auto-configure")); gtk_box_pack_start(GTK_BOX (optmenubox), auto_configure_btn, FALSE, FALSE, 0); + auto_configure_cancel_btn = gtk_button_new_with_label(_("Cancel")); + gtk_box_pack_start(GTK_BOX (optmenubox), auto_configure_cancel_btn, FALSE, FALSE, 0); auto_configure_lbl = gtk_label_new(""); gtk_label_set_justify(GTK_LABEL(optlabel), GTK_JUSTIFY_LEFT); gtk_box_pack_start(GTK_BOX (optmenubox), auto_configure_lbl, FALSE, FALSE, 0); @@ -1127,6 +1131,8 @@ static void basic_create_widget_func(PrefsPage * _page, gtk_widget_show(auto_configure_lbl); g_signal_connect (G_OBJECT (auto_configure_btn), "clicked", G_CALLBACK (auto_configure_cb), NULL); + g_signal_connect (G_OBJECT (auto_configure_cancel_btn), "clicked", + G_CALLBACK (auto_configure_cb), NULL); #endif no_imap_warn_icon = gtk_image_new_from_stock @@ -1314,6 +1320,7 @@ static void basic_create_widget_func(PrefsPage * _page, page->uid_entry = uid_entry; page->pass_entry = pass_entry; page->auto_configure_btn = auto_configure_btn; + page->auto_configure_cancel_btn = auto_configure_cancel_btn; page->auto_configure_lbl = auto_configure_lbl; if (new_account) { @@ -3793,17 +3800,30 @@ static void prefs_account_select_folder_cb(GtkWidget *widget, gpointer data) static void auto_configure_cb (GtkWidget *widget, gpointer data) { gchar *address = NULL; - const gchar *service = NULL; - const gchar *secure_service = NULL; const gchar *domain = NULL; - gchar *hostname; - guint16 port = 0; - gboolean r = FALSE; - gboolean ssl = FALSE; + AutoConfigureData *recv_data; + AutoConfigureData *send_data; + static GCancellable *recv_cancel = NULL; + static GCancellable *send_cancel = NULL; RecvProtocol protocol; struct BasicProtocol *protocol_optmenu = (struct BasicProtocol *) basic_page.protocol_optmenu; GtkWidget *optmenu = protocol_optmenu->combobox; + if (!recv_cancel) { + recv_cancel = g_cancellable_new(); + send_cancel = g_cancellable_new(); + } + + if (widget == basic_page.auto_configure_cancel_btn) { + g_cancellable_cancel(recv_cancel); + g_cancellable_cancel(send_cancel); + g_object_unref(recv_cancel); + g_object_unref(send_cancel); + recv_cancel = NULL; + send_cancel = NULL; + return; + } + protocol = combobox_get_active_data(GTK_COMBO_BOX(optmenu)); address = gtk_editable_get_chars(GTK_EDITABLE(basic_page.addr_entry), 0, -1); @@ -3815,74 +3835,62 @@ static void auto_configure_cb (GtkWidget *widget, gpointer data) } domain = strchr(address, '@') + 1; - switch(protocol) { - case A_POP3: - secure_service = "pop3s"; - service = "pop3"; - break; - case A_IMAP4: - secure_service = "imaps"; - service = "imap"; - break; - default: - secure_service = NULL; - service = NULL; - } - - gtk_label_set_text(GTK_LABEL(basic_page.auto_configure_lbl), - _("Configuring...")); - GTK_EVENTS_FLUSH(); - - if (service) { - r = auto_configure_service(secure_service, domain, &hostname, &port); - if (r) - ssl = TRUE; - else - r = auto_configure_service(service, domain, &hostname, &port); - } - - if (r) { + if (protocol == A_POP3 || protocol == A_IMAP4) { + recv_data = g_new0(AutoConfigureData, 1); + recv_data->configure_button = GTK_BUTTON(basic_page.auto_configure_btn); + recv_data->cancel_button = GTK_BUTTON(basic_page.auto_configure_cancel_btn); + recv_data->info_label = GTK_LABEL(basic_page.auto_configure_lbl); + recv_data->cancel = recv_cancel; switch(protocol) { case A_POP3: - gtk_entry_set_text(GTK_ENTRY(basic_page.recvserv_entry), hostname); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(advanced_page.popport_checkbtn), - (ssl && port == 995) || (!ssl && port == 110)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(advanced_page.popport_spinbtn), port); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( - ssl ? ssl_page.pop_ssltunnel_radiobtn : ssl_page.pop_starttls_radiobtn), - TRUE); + recv_data->ssl_service = "pop3s"; + recv_data->tls_service = "pop3"; + recv_data->domain = g_strdup(domain); + recv_data->hostname_entry = GTK_ENTRY(basic_page.recvserv_entry); + recv_data->set_port = GTK_TOGGLE_BUTTON(advanced_page.popport_checkbtn); + recv_data->port = GTK_SPIN_BUTTON(advanced_page.popport_spinbtn); + recv_data->tls_checkbtn = GTK_TOGGLE_BUTTON(ssl_page.pop_starttls_radiobtn); + recv_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(ssl_page.pop_ssltunnel_radiobtn); + recv_data->default_port = 110; + recv_data->default_ssl_port = 995; break; case A_IMAP4: - gtk_entry_set_text(GTK_ENTRY(basic_page.recvserv_entry), hostname); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(advanced_page.imapport_checkbtn), - (ssl && port == 993) || (!ssl && port == 143)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(advanced_page.imapport_spinbtn), port); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( - ssl ? ssl_page.imap_ssltunnel_radiobtn : ssl_page.imap_starttls_radiobtn), - TRUE); + recv_data->ssl_service = "imaps"; + recv_data->tls_service = "imap"; + recv_data->domain = g_strdup(domain); + recv_data->hostname_entry = GTK_ENTRY(basic_page.recvserv_entry); + recv_data->set_port = GTK_TOGGLE_BUTTON(advanced_page.imapport_checkbtn); + recv_data->port = GTK_SPIN_BUTTON(advanced_page.imapport_spinbtn); + recv_data->tls_checkbtn = GTK_TOGGLE_BUTTON(ssl_page.imap_starttls_radiobtn); + recv_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(ssl_page.imap_ssltunnel_radiobtn); + recv_data->default_port = 143; + recv_data->default_ssl_port = 993; break; default: - secure_service = NULL; - service = NULL; + cm_return_if_fail(FALSE); } - g_free(hostname); - } - - r = auto_configure_service("submission", domain, &hostname, &port); - - if (r) { - gtk_entry_set_text(GTK_ENTRY(basic_page.smtpserv_entry), hostname); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(advanced_page.smtpport_checkbtn), - port == 25); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(advanced_page.smtpport_spinbtn), port); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_page.smtp_starttls_radiobtn), TRUE); - gtk_label_set_text(GTK_LABEL(basic_page.auto_configure_lbl), - _("Done.")); - } else { - gtk_label_set_text(GTK_LABEL(basic_page.auto_configure_lbl), - _("Auto-configuration failed.")); + auto_configure_service(recv_data); } + send_data = g_new0(AutoConfigureData, 1); + send_data->configure_button = GTK_BUTTON(basic_page.auto_configure_btn); + send_data->cancel_button = GTK_BUTTON(basic_page.auto_configure_cancel_btn); + send_data->info_label = GTK_LABEL(basic_page.auto_configure_lbl); + send_data->cancel = send_cancel; + + send_data->ssl_service = "submissions"; + send_data->tls_service = "submission"; + send_data->domain = g_strdup(domain); + send_data->hostname_entry = GTK_ENTRY(basic_page.smtpserv_entry); + send_data->set_port = GTK_TOGGLE_BUTTON(advanced_page.smtpport_checkbtn); + send_data->port = GTK_SPIN_BUTTON(advanced_page.smtpport_spinbtn); + send_data->tls_checkbtn = GTK_TOGGLE_BUTTON(ssl_page.smtp_starttls_radiobtn); + send_data->ssl_checkbtn = NULL; + send_data->default_port = 25; + send_data->default_ssl_port = -1; + + auto_configure_service(send_data); + g_free(address); } #endif