[Commits] [SCM] claws branch, master, updated. 3.9.3-140-g3dc522b

colin at claws-mail.org colin at claws-mail.org
Fri May 2 09:24:54 CEST 2014


The branch master of project "claws" (Claws Mail) has been updated
       via  3dc522b3ecbe48cf25f9d315b9ef123b2ebc226b (commit)
       via  6e2e1c8bcd096d117dc22dfd9989c5c922d64f8f (commit)
       via  94ec77b15d34079fa6752fcd1a6a687782b07f9c (commit)
       via  a3b08204f9687fcf35d833bd46b61059bf6bd2b7 (commit)
       via  73088e2d091346b9770dbbb98a61e76620417f44 (commit)
       via  868bbb342eb035f62c003daaef076cdaedb84539 (commit)
      from  594f864375dd7441081db52aac3edcc68e18ce8d (commit)


- Log -----------------------------------------------------------------
commit 3dc522b3ecbe48cf25f9d315b9ef123b2ebc226b
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 30 13:06:58 2014 +0200

    Implement saving of the certificate chain, making the offline status
    check correct.

diff --git a/src/common/ssl.c b/src/common/ssl.c
index b64ab5e..28ba896 100644
--- a/src/common/ssl.c
+++ b/src/common/ssl.c
@@ -260,14 +260,56 @@ gboolean ssl_init_socket(SockInfo *sockinfo)
 	return ssl_init_socket_with_method(sockinfo, SSL_METHOD_SSLv23);
 }
 
+gnutls_x509_crt_t *ssl_get_certificate_chain(gnutls_session_t session, gint *list_len)
+{
+	const gnutls_datum *raw_cert_list;
+	gnutls_x509_crt_t *certs = NULL;
+	gboolean result = TRUE;
+
+	*list_len = -1;
+	if (!session)
+		return NULL;
+
+	raw_cert_list = gnutls_certificate_get_peers(session, list_len);
+
+	if (raw_cert_list && gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
+		int i = 0;
+
+		certs = g_malloc(sizeof(gnutls_x509_crt_t) * (*list_len));
+
+		for(i = 0 ; i < (*list_len) ; i++) {
+			int r;
+
+			gnutls_x509_crt_init(&certs[i]);
+			r = gnutls_x509_crt_import(certs[i], &raw_cert_list[i], GNUTLS_X509_FMT_DER);
+			if (r < 0) {
+				g_warning("cert get failure: %d %s\n", r, gnutls_strerror(r));
+
+				result = FALSE;
+				i--;
+				break;
+			}
+		}
+		if (!result) {
+			for (; i >= 0; i--)
+				gnutls_x509_crt_deinit(certs[i]);
+
+			g_free(certs);
+			*list_len = -1;
+
+			return NULL;
+		}
+	}
+
+	return certs;
+}
+
 gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
 {
 	gnutls_session_t session;
-	int r;
-	const gnutls_datum_t *raw_cert_list;
-	unsigned int raw_cert_list_length;
-	gnutls_x509_crt_t cert = NULL;
-	guint status;
+	int r, i;
+	unsigned int cert_list_length;
+	gnutls_x509_crt_t *certs = NULL;
 	gnutls_certificate_credentials_t xcred;
 
 	if (gnutls_certificate_allocate_credentials (&xcred) != 0)
@@ -321,28 +363,26 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
 	}
 
 	/* Get server's certificate (note: beware of dynamic allocation) */
-	raw_cert_list = gnutls_certificate_get_peers(session, &raw_cert_list_length);
+	certs = ssl_get_certificate_chain(session, &cert_list_length);
 
-	if (!raw_cert_list 
-	||  gnutls_certificate_type_get(session) != GNUTLS_CRT_X509
-	||  (r = gnutls_x509_crt_init(&cert)) < 0
-	||  (r = gnutls_x509_crt_import(cert, &raw_cert_list[0], GNUTLS_X509_FMT_DER)) < 0) {
-		g_warning("cert get failure: %d %s\n", r, gnutls_strerror(r));
+	if (!certs) {
 		gnutls_certificate_free_credentials(xcred);
 		gnutls_deinit(session);
 		return FALSE;
 	}
 
-	r = gnutls_certificate_verify_peers2(session, &status);
-
-	if (r < 0 || !ssl_certificate_check(cert, status, sockinfo->hostname, sockinfo->port)) {
-		gnutls_x509_crt_deinit(cert);
+	if (!ssl_certificate_check_chain(certs, cert_list_length, sockinfo->hostname, sockinfo->port)) {
+		for (i = 0; i < cert_list_length; i++)
+			gnutls_x509_crt_deinit(certs[i]);
+		g_free(certs);
 		gnutls_certificate_free_credentials(xcred);
 		gnutls_deinit(session);
 		return FALSE;
 	}
 
-	gnutls_x509_crt_deinit(cert);
+	for (i = 0; i < cert_list_length; i++)
+		gnutls_x509_crt_deinit(certs[i]);
+	g_free(certs);
 
 	sockinfo->ssl = session;
 	sockinfo->xcred = xcred;
diff --git a/src/common/ssl_certificate.c b/src/common/ssl_certificate.c
index 1381aa1..b48d4d4 100644
--- a/src/common/ssl_certificate.c
+++ b/src/common/ssl_certificate.c
@@ -65,6 +65,16 @@ static gchar *get_certificate_path(const gchar *host, const gchar *port, const g
 			  host, ".", port, ".cert", NULL);
 }
 
+static gchar *get_certificate_chain_path(const gchar *host, const gchar *port, const gchar *fp)
+{
+	gchar *tmp = get_certificate_path(host, port, fp);
+	gchar *result = g_strconcat(tmp, ".chain", NULL);
+
+	g_free(tmp);
+
+	return result;
+}
+
 char * readable_fingerprint(unsigned char *src, int len) 
 {
 	int i=0;
@@ -393,6 +403,9 @@ void ssl_certificate_delete_from_disk(SSLCertificate *cert)
 	file = get_certificate_path(cert->host, buf, cert->fingerprint);
 	claws_unlink (file);
 	g_free(file);
+	file = get_certificate_chain_path(cert->host, buf, cert->fingerprint);
+	claws_unlink (file);
+	g_free(file);
 	g_free(buf);
 }
 
@@ -507,13 +520,15 @@ static gboolean ssl_certificate_compare (SSLCertificate *cert_a, SSLCertificate
 	return TRUE;
 }
 
-static guint check_cert(gnutls_x509_crt_t cert)
+static guint check_cert(SSLCertificate *cert)
 {
-	gnutls_x509_crt_t *ca_list;
-	unsigned int max = 512;
+	gnutls_x509_crt_t *ca_list = NULL;
+	gnutls_x509_crt_t *chain = NULL;
+	unsigned int max_ca = 512, max_certs;
 	unsigned int flags = 0;
 	int r, i;
 	unsigned int status;
+	gchar *chain_file = NULL, *buf = NULL;
 	FILE *fp;
 
 	if (claws_ssl_get_cert_file())
@@ -521,16 +536,63 @@ static guint check_cert(gnutls_x509_crt_t cert)
 	else
 		return (guint)-1;
 
-	if ((r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &ca_list, &max)) < 0) {
-		debug_print("cert import failed: %s\n", gnutls_strerror(r));
+	if ((r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &ca_list, &max_ca)) < 0) {
+		debug_print("CA import failed: %s\n", gnutls_strerror(r));
 		fclose(fp);
 		return (guint)-1;
 	}
-
-	r = gnutls_x509_crt_verify(cert, ca_list, max, flags, &status);
 	fclose(fp);
+	fp = NULL;
+	
+	buf = g_strdup_printf("%d", cert->port);
+	chain_file = get_certificate_chain_path(cert->host, buf, cert->fingerprint);
+	g_free(buf);
+	if (is_file_exist(chain_file)) {
+		unsigned char md[128];
+		size_t n;
+		char *fingerprint;
+
+		fp = g_fopen(chain_file, "r");
+		if ((r = gnutls_import_X509_list_fp(fp, GNUTLS_X509_FMT_PEM, &chain, &max_certs)) < 0) {
+			debug_print("chain import failed: %s\n", gnutls_strerror(r));
+			fclose(fp);
+			g_free(chain_file);
+			return (guint)-1;
+		}
+		g_free(chain_file);
+		fclose(fp);
+		fp = NULL;
+
+		gnutls_x509_crt_get_fingerprint(chain[0], GNUTLS_DIG_MD5, md, &n);
+		fingerprint = readable_fingerprint(md, n);
+		if (!fingerprint || strcmp(fingerprint, cert->fingerprint)) {
+			debug_print("Saved chain fingerprint does not match current : %s / %s",
+				cert->fingerprint, fingerprint);
+				
+			return (guint)-1;
+		}
+		g_free(fingerprint);
+
+		r = gnutls_x509_crt_list_verify (chain,
+				     max_certs,
+				     ca_list, max_ca,
+				     NULL, 0,
+				     GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+				     &status);
+		if (r < 0)
+			debug_print("chain check failed: %s\n", gnutls_strerror(r));
+
+		for (i = 0; i < max_certs; i++)
+			gnutls_x509_crt_deinit(chain[i]);
+		free(chain);
 
-	for (i = 0; i < max; i++)
+	} else {
+		r = gnutls_x509_crt_verify(cert->x509_cert, ca_list, max_ca, flags, &status);
+		if (r < 0)
+			debug_print("cert check failed: %s\n", gnutls_strerror(r));
+	}
+
+	for (i = 0; i < max_ca; i++)
 		gnutls_x509_crt_deinit(ca_list[i]);
 	free(ca_list);
 
@@ -541,15 +603,20 @@ static guint check_cert(gnutls_x509_crt_t cert)
 
 }
 
-char *ssl_certificate_check_signer (gnutls_x509_crt_t cert, guint status) 
+char *ssl_certificate_check_signer (SSLCertificate *cert, guint status) 
 {
+	gnutls_x509_crt_t x509_cert = cert ? cert->x509_cert : NULL;
+
+	if (!cert) 
+		return g_strdup(_("Internal error"));
+
 	if (status == (guint)-1) {
 		status = check_cert(cert);
 		if (status == -1)
 			return g_strdup(_("Uncheckable"));
 	}
 	if (status & GNUTLS_CERT_INVALID) {
-		if (gnutls_x509_crt_check_issuer(cert, cert))
+		if (gnutls_x509_crt_check_issuer(x509_cert, x509_cert))
 			return g_strdup(_("Self-signed certificate"));
 	}
 	if (status & GNUTLS_CERT_REVOKED)
@@ -563,6 +630,43 @@ char *ssl_certificate_check_signer (gnutls_x509_crt_t cert, guint status)
 	return NULL;
 }
 
+static void ssl_certificate_save_chain(gnutls_x509_crt_t *certs, gint len, const gchar *host, gushort port)
+{
+	gint i;
+	gchar *file = NULL;
+	FILE *fp = NULL;
+	
+	for (i = 0; i < len; i++) {
+		size_t n;
+		unsigned char md[128];	
+		gnutls_x509_crt_t cert = certs[i];
+		gchar *fingerprint;
+
+		if (i == 0) {
+			gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, md, &n);
+			fingerprint = readable_fingerprint(md, n);
+			gchar *buf = g_strdup_printf("%d", port);
+
+			file = get_certificate_chain_path(host, buf, fingerprint);
+
+			g_free(buf);
+
+			fp = g_fopen(file, "wb");
+			if (fp == NULL) {
+				g_free(file);
+				debug_print("Can't save certificate !\n");
+				return;
+			}
+			g_free(file);
+		}
+
+		gnutls_export_X509_fp(fp, cert, GNUTLS_X509_FMT_PEM);
+
+	}
+	if (fp)
+		fclose(fp);
+}
+
 gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const gchar *host, gushort port)
 {
 	SSLCertificate *current_cert = NULL;
@@ -663,9 +767,8 @@ gboolean ssl_certificate_check (gnutls_x509_crt_t x509_cert, guint status, const
 
 gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, const gchar *host, gushort port)
 {
-	int ncas = 0, ncrls = 0;
+	int ncas = 0;
 	gnutls_x509_crt_t *cas = NULL;
-	gnutls_x509_crl_t *crls = NULL;
 	gboolean result = FALSE;
 	int i;
 	gint status;
@@ -697,6 +800,10 @@ gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, c
 
 	result = ssl_certificate_check(certs[0], status, host, port);
 
+	if (result == TRUE) {
+		ssl_certificate_save_chain(certs, chain_len, host, port);
+	}
+
 	for (i = 0; i < ncas; i++)
 		gnutls_x509_crt_deinit(cas[i]);
 	free(cas);
diff --git a/src/common/ssl_certificate.h b/src/common/ssl_certificate.h
index fd8822a..9f4ecf0 100644
--- a/src/common/ssl_certificate.h
+++ b/src/common/ssl_certificate.h
@@ -62,7 +62,7 @@ gboolean ssl_certificate_check_chain(gnutls_x509_crt_t *certs, gint chain_len, c
 void ssl_certificate_destroy(SSLCertificate *cert);
 void ssl_certificate_delete_from_disk(SSLCertificate *cert);
 char * readable_fingerprint(unsigned char *src, int len);
-char *ssl_certificate_check_signer (gnutls_x509_crt_t cert, guint status);
+char *ssl_certificate_check_signer (SSLCertificate *cert, guint status);
 
 gnutls_x509_crt_t ssl_certificate_get_x509_from_pem_file(const gchar *file);
 gnutls_x509_privkey_t ssl_certificate_get_pkey_from_pem_file(const gchar *file);
diff --git a/src/gtk/sslcertwindow.c b/src/gtk/sslcertwindow.c
index b03463f..c6fe7e4 100644
--- a/src/gtk/sslcertwindow.c
+++ b/src/gtk/sslcertwindow.c
@@ -151,7 +151,7 @@ static GtkWidget *cert_presenter(SSLCertificate *cert)
 	sha1_fingerprint = readable_fingerprint(md, (int)n);
 
 	/* signature */
-	sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
+	sig_status = ssl_certificate_check_signer(cert, cert->status);
 
 	if (sig_status==NULL)
 		sig_status = g_strdup(_("Correct"));
@@ -343,7 +343,7 @@ static gboolean sslcertwindow_ask_new_cert(SSLCertificate *cert)
 	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
 	g_free(buf);
 	
-	sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
+	sig_status = ssl_certificate_check_signer(cert, cert->status);
 	if (sig_status==NULL)
 		sig_status = g_strdup(_("Correct"));
 
@@ -392,7 +392,7 @@ static gboolean sslcertwindow_ask_expired_cert(SSLCertificate *cert)
 	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
 	g_free(buf);
 	
-	sig_status = ssl_certificate_check_signer(cert->x509_cert, cert->status);
+	sig_status = ssl_certificate_check_signer(cert, cert->status);
 
 	if (sig_status==NULL)
 		sig_status = g_strdup(_("Correct"));
@@ -456,7 +456,7 @@ static gboolean sslcertwindow_ask_changed_cert(SSLCertificate *old_cert, SSLCert
 	gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
 	g_free(buf);
 	
-	sig_status = ssl_certificate_check_signer(new_cert->x509_cert, new_cert->status);
+	sig_status = ssl_certificate_check_signer(new_cert, new_cert->status);
 
 	if (sig_status==NULL)
 		sig_status = g_strdup(_("Correct"));
diff --git a/src/ssl_manager.c b/src/ssl_manager.c
index 6cc058c..6b2f665 100644
--- a/src/ssl_manager.c
+++ b/src/ssl_manager.c
@@ -341,7 +341,7 @@ static void ssl_manager_load_certs (void)
 		gchar *server, *port, *fp;
 		SSLCertificate *cert;
 
-		if(!strstr(d->d_name, ".cert")) 
+		if(strstr(d->d_name, ".cert") != d->d_name + (strlen(d->d_name) - strlen(".cert"))) 
 			continue;
 
 		server = get_server(d->d_name);

commit 6e2e1c8bcd096d117dc22dfd9989c5c922d64f8f
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 30 11:37:05 2014 +0200

    Check smtp auth if autoconfig works. This is probably required.

diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index 9ec493c..e2c0a71 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -1906,6 +1906,12 @@ static void auto_configure_done(const gchar *hostname, gint port, gboolean ssl,
 			gtk_toggle_button_set_active(data->tls_checkbtn, TRUE);
 		}
 
+		/* Check authentication by default. This is probably required if
+		 * auto-configuration worked.
+		 */
+		if (data->auth_checkbtn)
+			gtk_toggle_button_set_active(data->auth_checkbtn, TRUE);
+
 		gtk_label_set_text(data->info_label, _("Done."));
 	} else {
 	gtk_label_set_text(data->info_label, _("Failed."));
diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h
index 43649a2..8c3849f 100644
--- a/src/gtk/gtkutils.h
+++ b/src/gtk/gtkutils.h
@@ -222,6 +222,7 @@ typedef struct _AutoConfigureData {
 	gint default_ssl_port;
 	GtkToggleButton *tls_checkbtn;
 	GtkToggleButton *ssl_checkbtn;
+	GtkToggleButton *auth_checkbtn;
 	GtkLabel *info_label;
 	GtkButton *configure_button;
 	GtkButton *cancel_button;
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 65c7d81..d9d52bb 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -3888,6 +3888,7 @@ static void auto_configure_cb (GtkWidget *widget, gpointer data)
 	send_data->ssl_checkbtn = NULL;
 	send_data->default_port = 25;
 	send_data->default_ssl_port = -1;
+	send_data->auth_checkbtn = send_page.smtp_auth_checkbtn;
 
 	auto_configure_service(send_data);
 
diff --git a/src/wizard.c b/src/wizard.c
index 1c05f27..c17e13d 100644
--- a/src/wizard.c
+++ b/src/wizard.c
@@ -1429,6 +1429,7 @@ static void auto_configure_cb (GtkWidget *widget, gpointer data)
 	send_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(wizard->smtp_use_ssl);
 	send_data->default_port = 25;
 	send_data->default_ssl_port = -1;
+	send_data->auth_checkbtn = wizard->smtp_auth;
 
 	auto_configure_service(send_data);
 

commit 94ec77b15d34079fa6752fcd1a6a687782b07f9c
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 30 11:19:05 2014 +0200

    Implement autoconfiguration in wizard

diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index 07b8b31..9ec493c 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -1895,10 +1895,16 @@ static void auto_configure_done(const gchar *hostname, gint port, gboolean ssl,
 			g_free(tmp);
 		}
 
-		if (ssl && data->ssl_checkbtn)
+		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, FALSE);
+		} else if (data->tls_checkbtn) {
+			if (!GTK_IS_RADIO_BUTTON(data->ssl_checkbtn)) {
+				/* Wizard where TLS is [x]SSL + [x]TLS */
+				gtk_toggle_button_set_active(data->ssl_checkbtn, TRUE);
+			}
 			gtk_toggle_button_set_active(data->tls_checkbtn, TRUE);
+		}
 
 		gtk_label_set_text(data->info_label, _("Done."));
 	} else {
@@ -1943,7 +1949,7 @@ static void resolve_done(GObject *source, GAsyncResult *result, gpointer user_da
 	}
 
 	if (found) {
-		auto_configure_done(hostname, port, TRUE, data);
+		auto_configure_done(hostname, port, data->ssl_service != NULL, data);
 	} else if (data->ssl_service && !abort) {
 		/* Fallback to TLS */
 		data->ssl_service = NULL;
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 7740264..65c7d81 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -1124,7 +1124,7 @@ static void basic_create_widget_func(PrefsPage * _page,
 	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_label_set_justify(GTK_LABEL(auto_configure_lbl), GTK_JUSTIFY_LEFT);
 	gtk_box_pack_start(GTK_BOX (optmenubox), auto_configure_lbl, FALSE, FALSE, 0);
 #if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
 	gtk_widget_show(auto_configure_btn);
@@ -3871,14 +3871,14 @@ static void auto_configure_cb (GtkWidget *widget, gpointer data)
 		}
 		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->ssl_service = NULL;
 	send_data->tls_service = "submission";
 	send_data->domain = g_strdup(domain);
 	send_data->hostname_entry = GTK_ENTRY(basic_page.smtpserv_entry);
diff --git a/src/wizard.c b/src/wizard.c
index fb677a8..1c05f27 100644
--- a/src/wizard.c
+++ b/src/wizard.c
@@ -112,6 +112,11 @@ typedef struct
 	GtkWidget *smtp_cert_table;
 	GtkWidget *recv_cert_table;
 #endif
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+	GtkWidget *auto_configure_lbl;
+	GtkWidget *auto_configure_btn;
+	GtkWidget *auto_configure_cancel_btn;
+#endif
 	gboolean create_mailbox;
 	gboolean finished;
 	gboolean result;
@@ -1234,6 +1239,11 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_show(wizard->recv_use_tls);
 		gtk_widget_show(wizard->recv_cert_table);
 #endif
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+		gtk_widget_show(wizard->auto_configure_btn);
+		gtk_widget_hide(wizard->auto_configure_cancel_btn);
+		gtk_widget_show(wizard->auto_configure_lbl);
+#endif
 		gtk_label_set_text(GTK_LABEL(wizard->recv_label), _("<span weight=\"bold\">Server address:</span>"));
 		gtk_label_set_use_markup(GTK_LABEL(wizard->recv_label), TRUE);
 		gtk_dialog_set_response_sensitive (GTK_DIALOG(wizard->window), GO_FORWARD, TRUE);
@@ -1259,6 +1269,11 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_show(wizard->recv_use_tls);
 		gtk_widget_show(wizard->recv_cert_table);
 #endif
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+		gtk_widget_show(wizard->auto_configure_btn);
+		gtk_widget_hide(wizard->auto_configure_cancel_btn);
+		gtk_widget_show(wizard->auto_configure_lbl);
+#endif
 		gtk_label_set_text(GTK_LABEL(wizard->recv_label), _("<span weight=\"bold\">Server address:</span>"));
 		gtk_label_set_use_markup(GTK_LABEL(wizard->recv_label), TRUE);
 		gtk_dialog_set_response_sensitive (GTK_DIALOG(wizard->window), GO_FORWARD, TRUE);
@@ -1299,6 +1314,11 @@ static void wizard_protocol_change(WizardWindow *wizard, RecvProtocol protocol)
 		gtk_widget_hide(wizard->recv_password);
 		gtk_widget_hide(wizard->recv_username_label);
 		gtk_widget_hide(wizard->recv_password_label);
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+		gtk_widget_hide(wizard->auto_configure_btn);
+		gtk_widget_hide(wizard->auto_configure_cancel_btn);
+		gtk_widget_hide(wizard->auto_configure_lbl);
+#endif
 #ifdef USE_GNUTLS
 		gtk_widget_hide(wizard->recv_use_ssl);
 		gtk_widget_hide(wizard->recv_use_tls);
@@ -1320,6 +1340,102 @@ static void wizard_protocol_changed(GtkComboBox *combo, gpointer data)
 	wizard_protocol_change(wizard, protocol);	
 }
 
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+static void auto_configure_cb (GtkWidget *widget, gpointer data)
+{
+	gchar *address = NULL;
+	const gchar *domain = NULL;
+	AutoConfigureData *recv_data;
+	AutoConfigureData *send_data;
+	static GCancellable *recv_cancel = NULL;
+	static GCancellable *send_cancel = NULL;
+	WizardWindow *wizard = (WizardWindow *)data;
+	RecvProtocol protocol = combobox_get_active_data(GTK_COMBO_BOX(wizard->recv_type));
+
+	if (!recv_cancel) {
+		recv_cancel = g_cancellable_new();
+		send_cancel = g_cancellable_new();
+	}
+
+	if (widget == wizard->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;
+	}
+
+	address = gtk_editable_get_chars(GTK_EDITABLE(wizard->email), 0, -1);
+
+	if (strchr(address, '@') < 0) {
+		g_free(address);
+		gtk_label_set_text(GTK_LABEL(wizard->auto_configure_lbl),
+			   _("Failed (wrong address)"));
+	}
+	domain = strchr(address, '@') + 1;
+
+	if (protocol == A_POP3 || protocol == A_IMAP4) {
+		recv_data = g_new0(AutoConfigureData, 1);
+		recv_data->configure_button = GTK_BUTTON(wizard->auto_configure_btn);
+		recv_data->cancel_button = GTK_BUTTON(wizard->auto_configure_cancel_btn);
+		recv_data->info_label = GTK_LABEL(wizard->auto_configure_lbl);
+		recv_data->cancel = recv_cancel;
+		switch(protocol) {
+		case A_POP3:
+			recv_data->ssl_service = "pop3s";
+			recv_data->tls_service = "pop3";
+			recv_data->domain = g_strdup(domain);
+			recv_data->hostname_entry = GTK_ENTRY(wizard->recv_server);
+			recv_data->set_port = NULL;
+			recv_data->port = NULL;
+			recv_data->tls_checkbtn = GTK_TOGGLE_BUTTON(wizard->recv_use_tls);
+			recv_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(wizard->recv_use_ssl);
+			recv_data->default_port = 110;
+			recv_data->default_ssl_port = 995;
+			break;
+		case A_IMAP4:
+			recv_data->ssl_service = "imaps";
+			recv_data->tls_service = "imap";
+			recv_data->domain = g_strdup(domain);
+			recv_data->hostname_entry = GTK_ENTRY(wizard->recv_server);
+			recv_data->set_port = NULL;
+			recv_data->port = NULL;
+			recv_data->tls_checkbtn = GTK_TOGGLE_BUTTON(wizard->recv_use_tls);
+			recv_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(wizard->recv_use_ssl);
+			recv_data->default_port = 143;
+			recv_data->default_ssl_port = 993;
+			break;
+		default:
+			cm_return_if_fail(FALSE);
+		}
+		auto_configure_service(recv_data);
+	}
+
+	send_data = g_new0(AutoConfigureData, 1);
+	send_data->configure_button = GTK_BUTTON(wizard->auto_configure_btn);
+	send_data->cancel_button = GTK_BUTTON(wizard->auto_configure_cancel_btn);
+	send_data->info_label = GTK_LABEL(wizard->auto_configure_lbl);
+	send_data->cancel = send_cancel;
+
+	send_data->ssl_service = NULL;
+	send_data->tls_service = "submission";
+	send_data->domain = g_strdup(domain);
+	send_data->hostname_entry = GTK_ENTRY(wizard->smtp_server);
+	send_data->set_port = NULL;
+	send_data->port = NULL;
+	send_data->tls_checkbtn = GTK_TOGGLE_BUTTON(wizard->smtp_use_tls);
+	send_data->ssl_checkbtn = GTK_TOGGLE_BUTTON(wizard->smtp_use_ssl);
+	send_data->default_port = 25;
+	send_data->default_ssl_port = -1;
+
+	auto_configure_service(send_data);
+
+	g_free(address);
+}
+#endif
+
 static GtkWidget* recv_page (WizardWindow * wizard)
 {
 	GtkWidget *table = gtk_table_new(1,1, FALSE);
@@ -1332,6 +1448,11 @@ static GtkWidget* recv_page (WizardWindow * wizard)
 	GtkWidget *button;
 	GtkWidget *recv_cert_table;
 #endif
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+	GtkWidget *auto_configure_btn;
+	GtkWidget *auto_configure_cancel_btn;
+	GtkWidget *auto_configure_lbl;
+#endif
 	GtkListStore *store;
 	GtkTreeIter iter;
 	gchar *text;
@@ -1347,8 +1468,31 @@ static GtkWidget* recv_page (WizardWindow * wizard)
 			 GTK_EXPAND|GTK_FILL, 0, 0, 0);
 
 	recv_table = gtk_table_new(4, 2, FALSE); 
+
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+	hbox = gtk_hbox_new(FALSE, VSPACING_NARROW);
+	auto_configure_btn = gtk_button_new_with_label(_("Auto-configure"));
+	gtk_box_pack_start(GTK_BOX (hbox), auto_configure_btn, FALSE, FALSE, 0);
+	auto_configure_cancel_btn = gtk_button_new_with_label(_("Cancel"));
+	gtk_box_pack_start(GTK_BOX (hbox), auto_configure_cancel_btn, FALSE, FALSE, 0);
+	auto_configure_lbl = gtk_label_new("");
+	gtk_label_set_justify(GTK_LABEL(auto_configure_lbl), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX (hbox), auto_configure_lbl, FALSE, FALSE, 0);
+	gtk_widget_show(auto_configure_btn);
+	gtk_widget_show(auto_configure_lbl);
+	gtk_widget_show(hbox);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	wizard->auto_configure_lbl = auto_configure_lbl;
+	wizard->auto_configure_btn = auto_configure_btn;
+	wizard->auto_configure_cancel_btn = auto_configure_cancel_btn;
+	g_signal_connect (G_OBJECT (auto_configure_btn), "clicked",
+			  G_CALLBACK (auto_configure_cb), wizard);
+	g_signal_connect (G_OBJECT (auto_configure_cancel_btn), "clicked",
+			  G_CALLBACK (auto_configure_cb), wizard);
+#endif
 	gtk_box_pack_start(GTK_BOX(vbox), recv_table, FALSE, FALSE, 0);
 
+
 	label = gtk_label_new(_("<span weight=\"bold\">Server type:</span>"));
 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
 	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
@@ -1769,7 +1913,9 @@ gboolean run_wizard(MainWindow *mainwin, gboolean create_mailbox) {
 	gtk_widget_hide(wizard->recv_imap_label);
 	gtk_widget_hide(wizard->recv_imap_subdir);
 	gtk_widget_hide(wizard->subsonly_checkbtn);
-
+#if (defined USE_GNUTLS && GLIB_CHECK_VERSION(2,22,0))
+	gtk_widget_hide(wizard->auto_configure_cancel_btn);
+#endif
 	wizard_protocol_change(wizard, tmpl.recvtype);
 
 	while (!wizard->finished)

commit a3b08204f9687fcf35d833bd46b61059bf6bd2b7
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 30 10:48:20 2014 +0200

    Make autoconfiguration non-blocking

diff --git a/src/common/utils.c b/src/common/utils.c
index 52f6bac..472b1cc 100644
--- 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
index d15c66a..434b684 100644
--- 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
index 1f05268..07b8b31 100644
--- 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
index a961dd8..43649a2 100644
--- 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
index d539f35..7740264 100644
--- 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

commit 73088e2d091346b9770dbbb98a61e76620417f44
Author: Colin Leroy <colin at colino.net>
Date:   Wed Apr 30 10:47:53 2014 +0200

    Have a way for folder klasses to register specific prefs pages

diff --git a/src/folder.c b/src/folder.c
index 6fa6d78..1bd7d98 100644
--- a/src/folder.c
+++ b/src/folder.c
@@ -169,6 +169,9 @@ void folder_unregister_class(FolderClass *klass)
 		}
 	}
 	g_list_free(folderlist);
+
+	if (klass->prefs_pages)
+		g_slist_free(klass->prefs_pages);
 }
 
 Folder *folder_new(FolderClass *klass, const gchar *name, const gchar *path)
diff --git a/src/folder.h b/src/folder.h
index 6ba032d..b54c9f4 100644
--- a/src/folder.h
+++ b/src/folder.h
@@ -200,7 +200,12 @@ struct _FolderClass
 	*/
 	gboolean    supports_server_search;
 
+	/**
+	 * Klass-specific prefs pages
+	 */
 	
+	GSList *prefs_pages;
+
 	/* virtual functions */
 
 	/* Folder funtions */
diff --git a/src/prefs_folder_item.c b/src/prefs_folder_item.c
index 3402d0f..7997ab5 100644
--- a/src/prefs_folder_item.c
+++ b/src/prefs_folder_item.c
@@ -61,8 +61,6 @@
 		string = (value); \
 	}
 
-static void prefs_folder_item_register_page	(PrefsPage 	*page);
-
 typedef struct _FolderItemGeneralPage FolderItemGeneralPage;
 typedef struct _FolderItemComposePage FolderItemComposePage;
 typedef struct _FolderItemTemplatesPage FolderItemTemplatesPage;
@@ -1822,7 +1820,7 @@ static void register_general_page()
         folder_item_general_page.page.destroy_widget = prefs_folder_item_general_destroy_widget_func;
         folder_item_general_page.page.save_page = prefs_folder_item_general_save_func;
         
-	prefs_folder_item_register_page((PrefsPage *) &folder_item_general_page);
+	prefs_folder_item_register_page((PrefsPage *) &folder_item_general_page, NULL);
 }
 
 
@@ -1839,7 +1837,7 @@ static void register_compose_page(void)
         folder_item_compose_page.page.destroy_widget = prefs_folder_item_compose_destroy_widget_func;
         folder_item_compose_page.page.save_page = prefs_folder_item_compose_save_func;
         
-	prefs_folder_item_register_page((PrefsPage *) &folder_item_compose_page);
+	prefs_folder_item_register_page((PrefsPage *) &folder_item_compose_page, NULL);
 }
 
 static void register_templates_page(void)
@@ -1855,7 +1853,7 @@ static void register_templates_page(void)
         folder_item_templates_page.page.destroy_widget = prefs_folder_item_templates_destroy_widget_func;
         folder_item_templates_page.page.save_page = prefs_folder_item_templates_save_func;
         
-	prefs_folder_item_register_page((PrefsPage *) &folder_item_templates_page);
+	prefs_folder_item_register_page((PrefsPage *) &folder_item_templates_page, NULL);
 }
 
 static GSList *prefs_pages = NULL;
@@ -1873,6 +1871,8 @@ static void prefs_folder_item_address_completion_end(GtkWindow * window)
 void prefs_folder_item_open(FolderItem *item)
 {
 	gchar *id, *title;
+	GSList *pages;
+
 	if (prefs_pages == NULL) {
 		register_general_page();
 		register_compose_page();
@@ -1886,17 +1886,34 @@ void prefs_folder_item_open(FolderItem *item)
 		id = g_strdup(item->name);
 		can_save = FALSE;
 	}
+	
+	pages = g_slist_concat(
+			g_slist_copy(prefs_pages),
+			g_slist_copy(item->folder->klass->prefs_pages));
+
 	title = g_strdup_printf (_("Properties for folder %s"), id);
 	g_free (id);
-	prefswindow_open(title, prefs_pages, item,
+	prefswindow_open(title, pages, item,
 			&prefs_common.folderitemwin_width, &prefs_common.folderitemwin_height,
 			prefs_folder_item_address_completion_start,
 			prefs_folder_item_address_completion_end);
 
+	g_slist_free(pages);
 	g_free (title);
 }
 
-static void prefs_folder_item_register_page(PrefsPage *page)
+void prefs_folder_item_register_page(PrefsPage *page, FolderClass *klass)
 {
-	prefs_pages = g_slist_append(prefs_pages, page);
+	if (klass != NULL)
+		klass->prefs_pages = g_slist_append(klass->prefs_pages, page);
+	else
+		prefs_pages = g_slist_append(prefs_pages, page);
 }
+
+void prefs_folder_item_unregister_page(PrefsPage *page, FolderClass *klass)
+{
+	if (klass != NULL)
+		klass->prefs_pages = g_slist_remove(klass->prefs_pages, page);
+	else
+		prefs_pages = g_slist_remove(prefs_pages, page);
+}
\ No newline at end of file
diff --git a/src/prefs_folder_item.h b/src/prefs_folder_item.h
index bfe7790..189ae29 100644
--- a/src/prefs_folder_item.h
+++ b/src/prefs_folder_item.h
@@ -32,4 +32,7 @@ void prefs_folder_item_create(FolderView *folderview, FolderItem *item);
 
 void prefs_folder_item_open		(FolderItem 	*item);
 
+void prefs_folder_item_register_page(PrefsPage *page, FolderClass *klass);
+void prefs_folder_item_unregister_page(PrefsPage *page, FolderClass *klass);
+
 #endif /* PREFS_FOLDER_ITEM_H */

commit 868bbb342eb035f62c003daaef076cdaedb84539
Author: Colin Leroy <colin at colino.net>
Date:   Tue Apr 29 15:31:16 2014 +0200

    Fix wrong free, and fix useless g_slist_concat

diff --git a/src/imap.c b/src/imap.c
index 5764922..e2eee5e 100644
--- a/src/imap.c
+++ b/src/imap.c
@@ -95,7 +95,7 @@ struct _IMAPFolder
 	gchar last_seen_separator;
 	guint refcnt;
 	guint max_set_size;
-	const gchar *search_charset;
+	gchar *search_charset;
 	gboolean search_charset_supported;
 };
 
@@ -779,7 +779,7 @@ static void imap_folder_init(Folder *folder, const gchar *name,
 	folder_remote_folder_init((Folder *)folder, name, path);
 	IMAP_FOLDER(folder)->max_set_size = IMAP_SET_MAX_COUNT;
 	IMAP_FOLDER(folder)->search_charset_supported = TRUE;
-	IMAP_FOLDER(folder)->search_charset = conv_get_locale_charset_str_no_utf8();
+	IMAP_FOLDER(folder)->search_charset = g_strdup(conv_get_locale_charset_str_no_utf8());
 }
 
 static FolderItem *imap_folder_item_new(Folder *folder)
@@ -4434,11 +4434,8 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte
 	}
 	
 	if (r == MAILIMAP_NO_ERROR) {
-		GSList * fetchuid_list =
-			imap_uid_list_from_lep(lep_uidlist, NULL);
+		uidlist = imap_uid_list_from_lep(lep_uidlist, NULL);
 		mailimap_search_result_free(lep_uidlist);
-		
-		uidlist = g_slist_concat(fetchuid_list, uidlist);
 	} else {
 		carray * lep_uidtab;
 		if (r != -1) { /* inited */
@@ -4449,10 +4446,8 @@ static gint get_list_of_uids(IMAPSession *session, Folder *folder, IMAPFolderIte
 		r = imap_threaded_fetch_uid(folder, 1,
 				    &lep_uidtab);
 		if (r == MAILIMAP_NO_ERROR) {
-			GSList * fetchuid_list =
-				imap_uid_list_from_lep_tab(lep_uidtab);
+			uidlist = imap_uid_list_from_lep_tab(lep_uidtab);
 			imap_fetch_uid_list_free(lep_uidtab);
-			uidlist = g_slist_concat(fetchuid_list, uidlist);
 		}
 	}
 	

-----------------------------------------------------------------------

Summary of changes:
 src/common/ssl.c             |   72 +++++++++++++++-----
 src/common/ssl_certificate.c |  131 +++++++++++++++++++++++++++++++++----
 src/common/ssl_certificate.h |    2 +-
 src/common/utils.c           |   42 ------------
 src/common/utils.h           |    4 --
 src/folder.c                 |    3 +
 src/folder.h                 |    5 ++
 src/gtk/gtkutils.c           |  108 ++++++++++++++++++++++++++++++
 src/gtk/gtkutils.h           |   25 +++++++
 src/gtk/sslcertwindow.c      |    8 +--
 src/imap.c                   |   13 ++--
 src/prefs_account.c          |  143 +++++++++++++++++++++-------------------
 src/prefs_folder_item.c      |   33 +++++++---
 src/prefs_folder_item.h      |    3 +
 src/ssl_manager.c            |    2 +-
 src/wizard.c                 |  149 +++++++++++++++++++++++++++++++++++++++++-
 16 files changed, 578 insertions(+), 165 deletions(-)


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list