[balsa] SMTP extensions: TLS client cert; rework dialog



commit ef318bebdbf14c677574032279c542ce9593ae94
Author: Albrecht Dreß <albrecht dress arcor de>
Date:   Sun Feb 19 18:59:47 2017 -0500

    SMTP extensions: TLS client cert; rework dialog
    
        * README: make it not quite so out of date.
        * libbalsa/send.c (get_auth), (get_cert_pass),
        (lbs_process_queue): use client cert if required.
        * libbalsa/smtp-server.c (libbalsa_smtp_server_finalize),
        (libbalsa_smtp_server_new_from_config),
        (libbalsa_smtp_server_save_config),
        (libbalsa_smtp_server_require_client_cert),
        (libbalsa_smtp_server_get_cert_file), (smtp_server_response),
        (smtp_server_changed), (libbalsa_smtp_server_dialog): add
        cert-related entries to LibBalsaSmtpServer, and set and use
        them.
        * libbalsa/smtp-server.h: add cert-related API.
    
    Signed-off-by: Peter Bloomfield <PeterBloomfield bellsouth net>

 ChangeLog              |   17 +++
 README                 |   54 ++++------
 libbalsa/send.c        |   34 ++++++-
 libbalsa/smtp-server.c |  269 ++++++++++++++++++++++++++++++++----------------
 libbalsa/smtp-server.h |    2 +
 5 files changed, 249 insertions(+), 127 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 7445ae3..d700acc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2017-02-19  Peter Bloomfield  <pbloomfield bellsouth net>
+
+       SMTP extensions: TLS client cert; rework config dialog
+
+       * README: make it not quite so out of date.
+       * libbalsa/send.c (get_auth), (get_cert_pass),
+       (lbs_process_queue): use client cert if required.
+       * libbalsa/smtp-server.c (libbalsa_smtp_server_finalize),
+       (libbalsa_smtp_server_new_from_config),
+       (libbalsa_smtp_server_save_config),
+       (libbalsa_smtp_server_require_client_cert),
+       (libbalsa_smtp_server_get_cert_file), (smtp_server_response),
+       (smtp_server_changed), (libbalsa_smtp_server_dialog): add
+       cert-related entries to LibBalsaSmtpServer, and set and use
+       them.
+       * libbalsa/smtp-server.h: add cert-related API.
+
 2017-02-19  Albrecht Dreß
 
        Make "Select Filters..." dialogue respect the headerbars config
diff --git a/README b/README
index ec9630f..55ac09b 100644
--- a/README
+++ b/README
@@ -116,10 +116,7 @@ messages, and for syntax highlighting in attachments.
 
 Libraries:
 ---------
-       Balsa uses libESMTP library available at 
-http://www.stafford.uklinux.net/libesmtp/
-
-Balsa also needs the aspell spell checking libraries.
+Balsa needs the aspell spell checking libraries.
 
        Make sure you have libtool installed (if you get some error 
 messages during compilation or when running precompiled binaries saying that
@@ -145,17 +142,22 @@ https://wiki.gnome.org/Git/Developers
 Specifying the SMTP Server:
 ---------------------------
 
-       when compiled to use libESMTP, the remote SMTP server details
-are configured on the Mail Servers tab of the Preferences dialogue box
-as follows:-
-
 Remote SMTP Server:
        Specify the domain name and optionally the port for of the SMTP
        server you use for submitting mail.  Please note that the
-       default port number is 587.  The syntax is hostname[:port].
-       Port can be a decimal number or the name of the service as
-       specified in /etc/services.  Typically you can just set this to
-       localhost:25.
+       default port number is 587 or 465 for SMTPS (see below).  The
+       syntax is hostname[:port].  Port can be a decimal number or the
+       name of the service as specified in /etc/services.  Typically
+       you can just set this to localhost:25.
+
+Security:
+       Specify the security level.  For an ISP, this is typically "SMTP
+       over SSL (SMTPS)" (default port 465) or "TLS required" (default
+       587, but many ISP's listen on port 25).  If your ISP does not
+       support either, choose a different ISP.  For a local connection
+       (i.e. to localhost), an unencrypted connection is fine.
+       Note that Balsa will not use the PLAIN or LOGIN authentication
+       mechanisms if the connection is not encrypted.
 
 User:
        If the remote SMTP server requires authentication, enter your
@@ -169,28 +171,14 @@ Pass Phrase:
        password.  Limitations on the length of the pass phrase depend
        on the SMTP server.
 
+Client Certificate and Pass Phrase:
+       Few ISP's hand over a client certificate Balsa must present when
+       connecting.  Choose the PEM-encoded certificate file and -if it
+       has an encrypted private key- set the key's pass phrase.
 
-TLS extension in SMTP mail submission:
---------------------------------------
-
-    If you have libESMTP 0.8.5{preX} there will be a box for entry of
-    the client certificate's password.  The client certificate should
-    be stored in PEM format in the file
-
-    $HOME/.authenticate/$HOSTNAME/private/smtp-starttls.pem
-    
-    Both the certificate and the private key are stored in the same
-    file.  The permissions on the certificate file *must* be 0600 or 0400
-    otherwise libESMTP will ignore it.
-
-    libESMTP 0.8.4 will establish an encrypted connection with servers
-    supporting STARTTLS but there is no certificate support.  If the
-    remote SMTP server requires a certificate, you will have to set
-    "Use TLS" to "Never".
-
-    Note that libESMTP 0.8.5 will only negotiate a TLS connection.  It
-    will not use SSLv2 or SSLv3 which are subject to downgrade
-    attacks.
+Split large messages:
+       Some ISP's impose a message size limit.  In this case, enter the
+       appropriate value here.
 
 
 Gtk+-3 Dialog Header Bars:
diff --git a/libbalsa/send.c b/libbalsa/send.c
index d579c70..9055e73 100644
--- a/libbalsa/send.c
+++ b/libbalsa/send.c
@@ -654,8 +654,7 @@ get_auth(NetClient *client,
 
     g_debug("%s: %p %p: encrypted = %d", __func__, client, user_data,
             net_client_is_encrypted(client));
-    /* Note: if the usr name is empty, we assume anonymous access */
-    if ((server->try_anonymous == 0U) && (server->user != NULL) && (server->user[0] != '\0')) {
+    if (server->try_anonymous == 0U) {
         result = g_new0(gchar *, 3U);
         result[0] = g_strdup(server->user);
         if ((server->passwd != NULL) && (server->passwd[0] != '\0')) {
@@ -668,6 +667,16 @@ get_auth(NetClient *client,
 }
 
 
+static gchar *
+get_cert_pass(NetClient        *client,
+                         const GByteArray *cert_der,
+                         gpointer          user_data)
+{
+       /* FIXME - we just return the passphrase from the config, but we may also want to show a dialogue 
here... */
+       return g_strdup(libbalsa_smtp_server_get_cert_passphrase(LIBBALSA_SMTP_SERVER(user_data)));
+}
+
+
 /* libbalsa_process_queue:
    treats given mailbox as a set of messages to send. Loads them up and
    launches sending thread/routine.
@@ -700,8 +709,25 @@ lbs_process_queue(LibBalsaMailbox     *outbox,
         // FIXME - submission (587) is the standard, but most isp's use 25...
         session = net_client_smtp_new(server->host, 587U, server->security);
     }
-    // FIXME - set user cert and connect cert-pass signal if we have a user cert
-    g_signal_connect(G_OBJECT(session), "cert-check", G_CALLBACK(check_cert), session);         // FIXME!!
+
+    /* load client certificate if configured */
+    if (libbalsa_smtp_server_require_client_cert(smtp_server)) {
+        const gchar *client_cert = libbalsa_smtp_server_get_cert_file(smtp_server);
+       GError *error = NULL;
+
+       g_signal_connect(G_OBJECT(session), "cert-pass", G_CALLBACK(get_cert_pass), smtp_server);
+       if (!net_client_set_cert_from_file(NET_CLIENT(session), client_cert, &error)) {
+            libbalsa_information(LIBBALSA_INFORMATION_ERROR,
+                                 _("Cannot load certificate file %s: %s"),
+                                                                client_cert, error->message);
+            g_error_free(error);
+            g_mutex_unlock(&send_messages_lock);
+               return FALSE;
+       }
+    }
+
+    /* connect signals */
+    g_signal_connect(G_OBJECT(session), "cert-check", G_CALLBACK(check_cert), session);
     g_signal_connect(G_OBJECT(session), "auth", G_CALLBACK(get_auth), smtp_server);
 
     send_message_info =
diff --git a/libbalsa/smtp-server.c b/libbalsa/smtp-server.c
index c91e81a..d1296bd 100644
--- a/libbalsa/smtp-server.c
+++ b/libbalsa/smtp-server.c
@@ -45,8 +45,10 @@ struct _LibBalsaSmtpServer {
     LibBalsaServer server;
 
     gchar *name;
-    gchar *cert_passphrase;
-    guint big_message; /* size of partial messages; in kB */
+    gboolean client_cert;              // FIXME - maybe move to the server base class?
+    gchar *cert_file;                  // FIXME - maybe move to the server base class?
+    gchar *cert_passphrase;            // FIXME - maybe move to the server base class?
+    guint big_message; /* size of partial messages; in kB; 0 disables splitting */
 };
 
 typedef struct _LibBalsaSmtpServerClass {
@@ -67,6 +69,7 @@ libbalsa_smtp_server_finalize(GObject * object)
     smtp_server = LIBBALSA_SMTP_SERVER(object);
 
     g_free(smtp_server->name);
+    g_free(smtp_server->cert_file);
     g_free(smtp_server->cert_passphrase);
 
     G_OBJECT_CLASS(parent_class)->finalize(object);
@@ -152,8 +155,9 @@ libbalsa_smtp_server_new_from_config(const gchar * name)
 
     libbalsa_server_load_config(LIBBALSA_SERVER(smtp_server));
 
-    smtp_server->cert_passphrase =
-        libbalsa_conf_private_get_string("CertificatePassphrase");
+    smtp_server->client_cert = libbalsa_conf_get_bool("NeedClientCert=false");
+    smtp_server->cert_file = libbalsa_conf_get_string("UserCertificateFile");
+    smtp_server->cert_passphrase = libbalsa_conf_private_get_string("CertificatePassphrase");
     if (smtp_server->cert_passphrase) {
         gchar *tmp = libbalsa_rot(smtp_server->cert_passphrase);
         g_free(smtp_server->cert_passphrase);
@@ -170,6 +174,10 @@ libbalsa_smtp_server_save_config(LibBalsaSmtpServer * smtp_server)
 {
     libbalsa_server_save_config(LIBBALSA_SERVER(smtp_server));
 
+    libbalsa_conf_set_bool("NeedClientCert", smtp_server->client_cert);
+    if (smtp_server->cert_file != NULL) {
+       libbalsa_conf_set_string("UserCertificateFile", smtp_server->cert_file);
+    }
     if (smtp_server->cert_passphrase) {
         gchar *tmp = libbalsa_rot(smtp_server->cert_passphrase);
         libbalsa_conf_private_set_string("CertificatePassphrase", tmp);
@@ -192,6 +200,18 @@ libbalsa_smtp_server_get_name(LibBalsaSmtpServer * smtp_server)
     return smtp_server ? smtp_server->name : _("Default");
 }
 
+gboolean
+libbalsa_smtp_server_require_client_cert(LibBalsaSmtpServer *smtp_server)
+{
+       return smtp_server->client_cert;
+}
+
+const gchar *
+libbalsa_smtp_server_get_cert_file(LibBalsaSmtpServer *smtp_server)
+{
+       return smtp_server->cert_file;
+}
+
 void
 libbalsa_smtp_server_set_cert_passphrase(LibBalsaSmtpServer * smtp_server,
                                          const gchar * passphrase)
@@ -255,7 +275,10 @@ struct smtp_server_dialog_info {
     GtkWidget *user;
     GtkWidget *pass;
     GtkWidget *tlsm;
-    GtkWidget *cert;
+    GtkWidget *auth_button;
+    GtkWidget *cert_button;
+    GtkWidget *cert_file;
+    GtkWidget *cert_pass;
     GtkWidget *split_button;
     GtkWidget *big_message;
 };
@@ -333,6 +356,7 @@ smtp_server_response(GtkDialog * dialog, gint response,
         libbalsa_server_set_host(server,
                                  gtk_entry_get_text(GTK_ENTRY(sdi->host)),
                                  FALSE);
+        server->try_anonymous = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->auth_button)) ? 0U : 1U;
         libbalsa_server_set_username(server,
                                      gtk_entry_get_text(GTK_ENTRY
                                                         (sdi->user)));
@@ -340,17 +364,19 @@ smtp_server_response(GtkDialog * dialog, gint response,
                                      gtk_entry_get_text(GTK_ENTRY
                                                         (sdi->pass)));
         server->security = (NetClientCryptMode) (gtk_combo_box_get_active(GTK_COMBO_BOX(sdi->tlsm)) + 1);
+        sdi->smtp_server->client_cert = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->cert_button));
+        g_free(sdi->smtp_server->cert_file);
+        sdi->smtp_server->cert_file = 
g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(sdi->cert_file)));
         libbalsa_smtp_server_set_cert_passphrase(sdi->smtp_server,
                                                  gtk_entry_get_text
-                                                 (GTK_ENTRY(sdi->cert)));
-        if (gtk_toggle_button_get_active
-            (GTK_TOGGLE_BUTTON(sdi->split_button)))
+                                                 (GTK_ENTRY(sdi->cert_pass)));
+        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->split_button))) {
             /* big_message is stored in kB, but the widget is in MB. */
-            LIBBALSA_SMTP_SERVER(server)->big_message =
-                gtk_spin_button_get_value(GTK_SPIN_BUTTON
-                                          (sdi->big_message)) * 1024;
-        else
-            LIBBALSA_SMTP_SERVER(server)->big_message = 0;
+               sdi->smtp_server->big_message =
+                gtk_spin_button_get_value(GTK_SPIN_BUTTON(sdi->big_message)) * 1024.0;
+        } else {
+               sdi->smtp_server->big_message = 0U;
+        }
         break;
     default:
         break;
@@ -367,30 +393,61 @@ smtp_server_response(GtkDialog * dialog, gint response,
 }
 
 static void
-smtp_server_changed(GtkWidget * widget,
+smtp_server_changed(GtkWidget G_GNUC_UNUSED *widget,
                     struct smtp_server_dialog_info *sdi)
 {
-    gboolean ok;
+       gboolean sensitive;
+       gboolean enable_ok = FALSE;
 
-    /* Minimal sanity check: Name and Host fields both non-blank. */
-    ok = *gtk_entry_get_text(GTK_ENTRY(sdi->name))
-        && *gtk_entry_get_text(GTK_ENTRY(sdi->host));
+       /* enable ok button only if a name and a host have been given */
+    if ((sdi->name != NULL) && (sdi->host != NULL)) {
+       enable_ok = (*gtk_entry_get_text(GTK_ENTRY(sdi->name)) != '\0')
+               && (*gtk_entry_get_text(GTK_ENTRY(sdi->host)) != '\0');
+    }
 
-    gtk_dialog_set_response_sensitive(GTK_DIALOG(sdi->dialog),
-                                      GTK_RESPONSE_OK, ok);
+       /* user name/password only if authentication is required */
+       if ((sdi->auth_button != NULL) && (sdi->user != NULL) && (sdi->pass != NULL)) {
+               sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->auth_button));
+               gtk_widget_set_sensitive(sdi->user, sensitive);
+               gtk_widget_set_sensitive(sdi->pass, sensitive);
+
+               /* disable ok if authentication is required, but no user name given */
+               if (sensitive && (*gtk_entry_get_text(GTK_ENTRY(sdi->user)) == '\0')) {
+                       enable_ok = FALSE;
+               }
+       }
+
+       /* client certificate and passphrase stuff only if TLS/SSL is enabled */
+       if ((sdi->tlsm != NULL) && (sdi->cert_button != NULL) && (sdi->cert_file != NULL) && (sdi->cert_pass 
!= NULL)) {
+               sensitive = (NetClientCryptMode) (gtk_combo_box_get_active(GTK_COMBO_BOX(sdi->tlsm)) + 1) != 
NET_CLIENT_CRYPT_NONE;
+               gtk_widget_set_sensitive(sdi->cert_button, sensitive);
+               if (sensitive) {
+                       sensitive = sensitive && 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->cert_button));
+               }
+
+               gtk_widget_set_sensitive(sdi->cert_file, sensitive);
+               gtk_widget_set_sensitive(sdi->cert_pass, sensitive);
+
+               /* disable ok if a certificate is required, but no file name given */
+               if (sensitive) {
+                       gchar *cert_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(sdi->cert_file));
+
+                       if ((cert_file == NULL) || (cert_file[0] == '\0')) {
+                               enable_ok = FALSE;
+                       }
+                       g_free(cert_file);
+               }
+       }
+
+       /* split big messages */
+       if ((sdi->big_message != NULL) && (sdi->split_button != NULL)) {
+               sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sdi->split_button));
+           gtk_widget_set_sensitive(sdi->big_message, sensitive);
+       }
+
+    gtk_dialog_set_response_sensitive(GTK_DIALOG(sdi->dialog), GTK_RESPONSE_OK, enable_ok);
     gtk_dialog_set_default_response(GTK_DIALOG(sdi->dialog),
-                                    ok ? GTK_RESPONSE_OK :
-                                    GTK_RESPONSE_CANCEL);
-}
-
-static void
-smtp_server_split_button_changed(GtkWidget * button,
-                                 struct smtp_server_dialog_info *sdi)
-{
-    gtk_widget_set_sensitive(sdi->big_message,
-                             gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
-                                                          (button)));
-    smtp_server_changed(button, sdi);
+       enable_ok ? GTK_RESPONSE_OK : GTK_RESPONSE_CANCEL);
 }
 
 void
@@ -401,6 +458,7 @@ libbalsa_smtp_server_dialog(LibBalsaSmtpServer * smtp_server,
     LibBalsaServer *server = LIBBALSA_SERVER(smtp_server);
     struct smtp_server_dialog_info *sdi;
     GtkWidget *dialog;
+    GtkWidget *notebook;
     GtkWidget *grid;
     gint row;
     GtkWidget *label, *hbox;
@@ -408,12 +466,12 @@ libbalsa_smtp_server_dialog(LibBalsaSmtpServer * smtp_server,
     /* Show only one dialog at a time. */
     sdi = g_object_get_data(G_OBJECT(smtp_server),
                             LIBBALSA_SMTP_SERVER_DIALOG_KEY);
-    if (sdi) {
+    if (sdi != NULL) {
         gtk_window_present(GTK_WINDOW(sdi->dialog));
         return;
     }
 
-    sdi = g_new(struct smtp_server_dialog_info, 1);
+    sdi = g_new0(struct smtp_server_dialog_info, 1U);
     g_object_set_data_full(G_OBJECT(smtp_server),
                            LIBBALSA_SMTP_SERVER_DIALOG_KEY, sdi,
                            (GDestroyNotify) smtp_server_destroy_notify);
@@ -442,84 +500,115 @@ libbalsa_smtp_server_dialog(LibBalsaSmtpServer * smtp_server,
     gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK,
                                       FALSE);
 
+    notebook = gtk_notebook_new();
+    gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), notebook);
+
 #define HIG_PADDING 12
-    grid = libbalsa_create_grid();
-    gtk_container_set_border_width(GTK_CONTAINER(grid), HIG_PADDING);
-    gtk_container_add(GTK_CONTAINER
-                      (gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
-                      grid);
 
+    /* notebook page with basic options */
+    grid = libbalsa_create_grid();
     row = 0;
-    smtp_server_add_widget(grid, row, _("_Descriptive Name:"),
-                           sdi->name = gtk_entry_new());
-    if (smtp_server->name)
+    gtk_container_set_border_width(GTK_CONTAINER(grid), HIG_PADDING);
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid,
+                             gtk_label_new_with_mnemonic(_("_Basic")));
+
+    /* server descriptive name */
+    sdi->name = gtk_entry_new();
+    gtk_widget_set_hexpand(sdi->name, TRUE);
+    smtp_server_add_widget(grid, row, _("_Descriptive Name:"), sdi->name);
+    if (smtp_server->name != NULL) {
         gtk_entry_set_text(GTK_ENTRY(sdi->name), smtp_server->name);
-    g_signal_connect(sdi->name, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
+    }
+    g_signal_connect(sdi->name, "changed", G_CALLBACK(smtp_server_changed), sdi);
 
-    smtp_server_add_widget(grid, ++row, _("_Server:"),
-                           sdi->host = gtk_entry_new());
-    if (server->host)
+    /* host and port */
+    sdi->host = gtk_entry_new();
+    smtp_server_add_widget(grid, ++row, _("_Server:"), sdi->host);
+    if (server->host != NULL) {
         gtk_entry_set_text(GTK_ENTRY(sdi->host), server->host);
-    g_signal_connect(sdi->host, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
-
-    smtp_server_add_widget(grid, ++row, _("_User Name:"),
-                           sdi->user = gtk_entry_new());
-    if (server->user)
+    }
+    g_signal_connect(sdi->host, "changed", G_CALLBACK(smtp_server_changed), sdi);
+
+    /* security settings */
+    sdi->tlsm = smtp_server_tls_widget(smtp_server);
+    smtp_server_add_widget(grid, ++row, _("Se_curity:"), sdi->tlsm);
+    g_signal_connect(sdi->tlsm, "changed", G_CALLBACK(smtp_server_changed), sdi);
+
+    /* authentication or anonymous access */
+    sdi->auth_button = gtk_check_button_new_with_mnemonic(_("Server requires authentication"));
+    smtp_server_add_widget(grid, ++row, _("_Authentication:"), sdi->auth_button);
+    g_signal_connect(sdi->auth_button, "toggled", G_CALLBACK(smtp_server_changed), sdi);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->auth_button), server->try_anonymous == 0U);
+
+    /* user name and password */
+    sdi->user = gtk_entry_new();
+    smtp_server_add_widget(grid, ++row, _("_User Name:"), sdi->user);
+    if (server->user != NULL) {
         gtk_entry_set_text(GTK_ENTRY(sdi->user), server->user);
-    g_signal_connect(sdi->user, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
+    }
+    g_signal_connect(sdi->user, "changed", G_CALLBACK(smtp_server_changed), sdi);
 
-    smtp_server_add_widget(grid, ++row, _("_Pass Phrase:"),
-                           sdi->pass = gtk_entry_new());
+    sdi->pass = gtk_entry_new();
+    smtp_server_add_widget(grid, ++row, _("_Pass Phrase:"), sdi->pass);
+    g_object_set(G_OBJECT(sdi->pass), "input-purpose", GTK_INPUT_PURPOSE_PASSWORD, NULL);
     gtk_entry_set_visibility(GTK_ENTRY(sdi->pass), FALSE);
-    if (server->passwd)
+    if (server->passwd != NULL) {
         gtk_entry_set_text(GTK_ENTRY(sdi->pass), server->passwd);
-    g_signal_connect(sdi->pass, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
-
-    smtp_server_add_widget(grid, ++row, _("Se_curity:"), sdi->tlsm =
-                           smtp_server_tls_widget(smtp_server));
-    g_signal_connect(sdi->tlsm, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
-
-    smtp_server_add_widget(grid, ++row, _("C_ertificate Pass Phrase:"),
-                           sdi->cert = gtk_entry_new());
-    gtk_entry_set_visibility(GTK_ENTRY(sdi->cert), FALSE);
-    if (smtp_server->cert_passphrase)
-        gtk_entry_set_text(GTK_ENTRY(sdi->cert),
-                           smtp_server->cert_passphrase);
-    g_signal_connect(sdi->cert, "changed", G_CALLBACK(smtp_server_changed),
-                     sdi);
-
-    ++row;
-    sdi->split_button =
-        gtk_check_button_new_with_mnemonic(_("Sp_lit message larger than"));
-    gtk_grid_attach(GTK_GRID(grid), sdi->split_button, 0, row, 1, 1);
+    }
+    g_signal_connect(sdi->pass, "changed", G_CALLBACK(smtp_server_changed), sdi);
+
+    /* notebook page with advanced options */
+    grid = libbalsa_create_grid();
+    row = 0;
+    gtk_container_set_border_width(GTK_CONTAINER(grid), HIG_PADDING);
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), grid,
+                             gtk_label_new_with_mnemonic(_("_Advanced")));
+
+    /* client certificate and passphrase */
+    sdi->cert_button = gtk_check_button_new_with_mnemonic(_("Server requires client certificate"));
+    smtp_server_add_widget(grid, row, _("_Client Certificate:"), sdi->cert_button);
+    g_signal_connect(sdi->cert_button, "toggled", G_CALLBACK(smtp_server_changed), sdi);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->cert_button), smtp_server->client_cert);
+
+    sdi->cert_file = gtk_file_chooser_button_new(_("Choose Client Certificate"), 
GTK_FILE_CHOOSER_ACTION_OPEN);
+    gtk_widget_set_hexpand(sdi->cert_file, TRUE);
+    smtp_server_add_widget(grid, ++row, _("Certificate _File:"), sdi->cert_file);
+    if (smtp_server->cert_file != NULL) {
+       gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(sdi->cert_file), smtp_server->cert_file);
+    }
+    g_signal_connect(sdi->cert_file, "file-set", G_CALLBACK(smtp_server_changed), sdi);
+
+       sdi->cert_pass = gtk_entry_new();
+    smtp_server_add_widget(grid, ++row, _("Certificate _Pass Phrase:"), sdi->cert_pass);
+    g_object_set(G_OBJECT(sdi->cert_pass), "input-purpose", GTK_INPUT_PURPOSE_PASSWORD, NULL);
+    gtk_entry_set_visibility(GTK_ENTRY(sdi->cert_pass), FALSE);
+    if (smtp_server->cert_passphrase != NULL) {
+        gtk_entry_set_text(GTK_ENTRY(sdi->cert_pass), smtp_server->cert_passphrase);
+    }
+    g_signal_connect(sdi->cert_pass, "changed", G_CALLBACK(smtp_server_changed), sdi);
+
+    /* split large messages */
+    sdi->split_button = gtk_check_button_new_with_mnemonic(_("Sp_lit message larger than"));
+    gtk_grid_attach(GTK_GRID(grid), sdi->split_button, 0, ++row, 1, 1);
     hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
     sdi->big_message = gtk_spin_button_new_with_range(0.1, 100, 0.1);
     gtk_box_pack_start(GTK_BOX(hbox), sdi->big_message, TRUE, TRUE, 0);
     label = gtk_label_new(_("MB"));
     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
     if (smtp_server->big_message > 0) {
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->split_button),
-                                     TRUE);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->split_button), TRUE);
         /* The widget is in MB, but big_message is stored in kB. */
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdi->big_message),
-                                  ((float) smtp_server->big_message) /
-                                  1024);
+                                  ((gdouble) smtp_server->big_message) / 1024.0);
     } else {
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->split_button),
-                                     FALSE);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sdi->split_button), FALSE);
         gtk_spin_button_set_value(GTK_SPIN_BUTTON(sdi->big_message), 1);
-        gtk_widget_set_sensitive(sdi->big_message, FALSE);
     }
-    g_signal_connect(sdi->split_button, "toggled",
-                     G_CALLBACK(smtp_server_split_button_changed), sdi);
-    g_signal_connect(sdi->big_message, "changed",
-                     G_CALLBACK(smtp_server_changed), sdi);
+    g_signal_connect(sdi->split_button, "toggled", G_CALLBACK(smtp_server_changed), sdi);
+    g_signal_connect(sdi->big_message, "changed", G_CALLBACK(smtp_server_changed), sdi);
     gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
 
+    smtp_server_changed(NULL, sdi);
+
     gtk_widget_show_all(dialog);
 }
diff --git a/libbalsa/smtp-server.h b/libbalsa/smtp-server.h
index 3f757f3..0915060 100644
--- a/libbalsa/smtp-server.h
+++ b/libbalsa/smtp-server.h
@@ -46,6 +46,8 @@ void libbalsa_smtp_server_set_name(LibBalsaSmtpServer * smtp_server,
                                    const gchar * name);
 const gchar *libbalsa_smtp_server_get_name(LibBalsaSmtpServer *
                                            smtp_server);
+gboolean libbalsa_smtp_server_require_client_cert(LibBalsaSmtpServer *smtp_server);
+const gchar *libbalsa_smtp_server_get_cert_file(LibBalsaSmtpServer *smtp_server);
 void libbalsa_smtp_server_set_cert_passphrase(LibBalsaSmtpServer *
                                               smtp_server,
                                               const gchar * passphrase);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]