[balsa] Password dialogue improvements



commit 968eebea01df1d5403d64f1ee9ed68520719f675
Author: Albrecht Dreß <albrecht dress arcor de>
Date:   Tue Nov 27 14:10:35 2018 -0500

    Password dialogue improvements
    
    * libbalsa/imap-server.c, libbalsa/server-config.c, libinit_balsa/assistant_page_user.c, 
src/save-restore.c: use changed libbalsa_server_set_password() api
    * libbalsa/libbalsa.[c]: implement GTK_DIALOG_USE_HEADER_BAR detection as boolean for GCR dialogue
    * libbalsa/server.[ch]: clean up signal definitions (remove obsolete marshallers); remove unused class 
method; adjust api's for libbalsa_server_set_password(), libbalsa_server_get_password() and 
libbalsa_server_get_cert_pass()
    * libnetclient/net-client.[ch]: pass cert subject only instead of full binary data in the passphrase 
signal
    * src/balsa-app.[ch]: use GCR password dialogue if available; drop set_passwd_from_matching_server() 
which is never used
    
    Signed-off-by: Peter Bloomfield <PeterBloomfield bellsouth net>

 ChangeLog                           |  18 +++
 libbalsa/imap-server.c              |   2 +-
 libbalsa/libbalsa.c                 |  16 ++-
 libbalsa/libbalsa.h                 |   2 +
 libbalsa/server-config.c            |   5 +-
 libbalsa/server.c                   |  67 +++++-----
 libbalsa/server.h                   |  12 +-
 libinit_balsa/assistant_page_user.c |   4 +-
 libnetclient/net-client.c           |  29 +++--
 libnetclient/net-client.h           |   4 +-
 src/balsa-app.c                     | 240 +++++++++++++++++++-----------------
 src/balsa-app.h                     |   4 +-
 src/save-restore.c                  |  11 +-
 13 files changed, 226 insertions(+), 188 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 4c6be8749..914a2bc13 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2018-11-27  Albrecht Dreß  <albrecht dress arcor de>
+
+       Password dialogue improvements
+
+       * libbalsa/imap-server.c, libbalsa/server-config.c,
+       libinit_balsa/assistant_page_user.c, src/save-restore.c: use
+       changed libbalsa_server_set_password() api
+       * libbalsa/libbalsa.[c]: implement GTK_DIALOG_USE_HEADER_BAR
+       detection as boolean for GCR dialogue
+       * libbalsa/server.[ch]: clean up signal definitions (remove
+       obsolete marshallers); remove unused class method;
+       adjust api's for libbalsa_server_set_password(),
+       libbalsa_server_get_password() and libbalsa_server_get_cert_pass()
+       * libnetclient/net-client.[ch]: pass cert subject only
+       instead of full binary data in the passphrase signal
+       * src/balsa-app.[ch]: use GCR password dialogue if available;
+       drop set_passwd_from_matching_server() which is never used
+
 2018-11-04  Albrecht Dreß  <albrecht dress arcor de>
 
        Unified server configuration GUI
diff --git a/libbalsa/imap-server.c b/libbalsa/imap-server.c
index 61067c553..7f4a4ca1b 100644
--- a/libbalsa/imap-server.c
+++ b/libbalsa/imap-server.c
@@ -491,7 +491,7 @@ handle_connection_error(int rc, struct handle_info *info,
     gchar *msg = imap_mbox_handle_get_last_msg(info->handle);
     switch(rc) {
     case IMAP_AUTH_FAILURE:
-        libbalsa_server_set_password(server, NULL); break;
+        libbalsa_server_set_password(server, NULL, FALSE); break;
     case IMAP_CONNECT_FAILED:
         g_set_error(err, LIBBALSA_MAILBOX_ERROR,
                     LIBBALSA_MAILBOX_NETWORK_ERROR,
diff --git a/libbalsa/libbalsa.c b/libbalsa/libbalsa.c
index fabdcaa6e..38096642c 100644
--- a/libbalsa/libbalsa.c
+++ b/libbalsa/libbalsa.c
@@ -947,10 +947,10 @@ libbalsa_image_error_quark(void)
 }
 
 #if GTK_CHECK_VERSION(3, 12, 0)
-GtkDialogFlags
-libbalsa_dialog_flags(void)
+gboolean
+libbalsa_use_headerbar(void)
 {
-       static GtkDialogFlags dialog_flags = GTK_DIALOG_USE_HEADER_BAR;
+       static gboolean use_headerbar = TRUE;
        static gint check_done = 0;
 
        if (g_atomic_int_get(&check_done) == 0) {
@@ -958,10 +958,16 @@ libbalsa_dialog_flags(void)
 
                dialog_env = g_getenv("BALSA_DIALOG_HEADERBAR");
                if ((dialog_env != NULL) && (atoi(dialog_env) == 0)) {
-                       dialog_flags = (GtkDialogFlags) 0;
+                       use_headerbar = FALSE;
                }
                g_atomic_int_set(&check_done, 1);
        }
-       return dialog_flags;
+       return use_headerbar;
+}
+
+GtkDialogFlags
+libbalsa_dialog_flags(void)
+{
+       return libbalsa_use_headerbar() ? GTK_DIALOG_USE_HEADER_BAR : (GtkDialogFlags) 0;
 }
 #endif
diff --git a/libbalsa/libbalsa.h b/libbalsa/libbalsa.h
index 2ce1e62be..6471340b7 100644
--- a/libbalsa/libbalsa.h
+++ b/libbalsa/libbalsa.h
@@ -191,8 +191,10 @@ enum LibBalsaImageError {
 };
 
 #if GTK_CHECK_VERSION(3, 12, 0)
+gboolean libbalsa_use_headerbar(void);
 GtkDialogFlags libbalsa_dialog_flags(void);
 #else
+#define libbalsa_use_headerbar()       (FALSE)
 #define libbalsa_dialog_flags()                (GtkDialogFlags) (0)
 #endif
 
diff --git a/libbalsa/server-config.c b/libbalsa/server-config.c
index 3c23110c7..1e00927b6 100644
--- a/libbalsa/server-config.c
+++ b/libbalsa/server-config.c
@@ -284,15 +284,14 @@ libbalsa_server_cfg_assign_server(LibBalsaServerCfg *server_cfg, LibBalsaServer
        server->try_anonymous = FALSE;
     }
     libbalsa_server_set_username(server, gtk_entry_get_text(GTK_ENTRY(priv->username)));
-    libbalsa_server_set_password(server, gtk_entry_get_text(GTK_ENTRY(priv->password)));
+    libbalsa_server_set_password(server, gtk_entry_get_text(GTK_ENTRY(priv->password)), FALSE);
     server->remember_passwd = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->remember_pass));
 
     /* client certificate */
     server->client_cert = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->require_cert));
     g_free(server->cert_file);
     server->cert_file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->cert_file));
-    g_free(server->cert_passphrase);
-    server->cert_passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->cert_pass)));
+    libbalsa_server_set_password(server, gtk_entry_get_text(GTK_ENTRY(priv->cert_pass)), TRUE);
     server->remember_cert_passphrase = 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->remember_cert_pass));
 }
 
diff --git a/libbalsa/server.c b/libbalsa/server.c
index bb50934d1..46be161b6 100644
--- a/libbalsa/server.c
+++ b/libbalsa/server.c
@@ -69,8 +69,8 @@ static void libbalsa_server_real_set_username(LibBalsaServer * server,
 static void libbalsa_server_real_set_host(LibBalsaServer     *server,
                                                                                  const gchar        *host,
                                                                                  NetClientCryptMode  
security);
-static gchar *libbalsa_server_get_password(LibBalsaServer  *server,
-                                                                          LibBalsaMailbox *mbox);
+static gchar *libbalsa_server_get_password(LibBalsaServer *server,
+                                                                                  gchar          
*cert_subject);
 static gchar *libbalsa_free_password(gchar *password);
 
 enum {
@@ -126,8 +126,7 @@ libbalsa_server_class_init(LibBalsaServerClass * klass)
                      G_SIGNAL_RUN_FIRST,
                     G_STRUCT_OFFSET(LibBalsaServerClass,
                                     set_username),
-                     NULL, NULL,
-                     g_cclosure_marshal_VOID__STRING,
+                     NULL, NULL, NULL,
                      G_TYPE_NONE, 1,
                     G_TYPE_STRING);
     libbalsa_server_signals[SET_HOST] =
@@ -136,8 +135,7 @@ libbalsa_server_class_init(LibBalsaServerClass * klass)
                      G_SIGNAL_RUN_FIRST,
                     G_STRUCT_OFFSET(LibBalsaServerClass,
                                      set_host),
-                     NULL, NULL,
-                     libbalsa_VOID__POINTER_INT,
+                     NULL, NULL, NULL,
                      G_TYPE_NONE, 2,
                      G_TYPE_POINTER, G_TYPE_INT
                     );
@@ -147,25 +145,20 @@ libbalsa_server_class_init(LibBalsaServerClass * klass)
                      G_SIGNAL_RUN_FIRST,
                     G_STRUCT_OFFSET(LibBalsaServerClass,
                                     config_changed),
-                     NULL, NULL,
-                     g_cclosure_marshal_VOID__VOID,
+                     NULL, NULL, NULL,
                      G_TYPE_NONE, 0);
 
-
     libbalsa_server_signals[GET_PASSWORD] =
        g_signal_new("get-password",
                      G_TYPE_FROM_CLASS(object_class),
                      G_SIGNAL_RUN_LAST,
-                    G_STRUCT_OFFSET(LibBalsaServerClass,
-                                    get_password),
-                     NULL, NULL,
-                    libbalsa_POINTER__OBJECT,
-                     G_TYPE_POINTER, 1,
-                     LIBBALSA_TYPE_MAILBOX);
+                                        0U,
+                     NULL, NULL, NULL,
+                     G_TYPE_STRING, 1,
+                                        G_TYPE_BYTE_ARRAY);
 
     klass->set_username = libbalsa_server_real_set_username;
     klass->set_host = libbalsa_server_real_set_host;
-    klass->get_password = NULL;        /* libbalsa_server_real_get_password; */
 }
 
 static void
@@ -222,14 +215,22 @@ libbalsa_server_set_username(LibBalsaServer * server,
 }
 
 void
-libbalsa_server_set_password(LibBalsaServer * server,
-                             const gchar * passwd)
+libbalsa_server_set_password(LibBalsaServer *server,
+                             const gchar    *passwd,
+                                                        gboolean        for_cert)
 {
+       gchar **target;
     g_return_if_fail(LIBBALSA_IS_SERVER(server));
 
-    server->passwd = libbalsa_free_password(server->passwd);
+    if (for_cert) {
+       target = &server->cert_passphrase;
+    } else {
+       target = &server->passwd;
+    }
+
+    *target = libbalsa_free_password(*target);
     if ((passwd != NULL) && (passwd[0] != '\0')) {
-       server->passwd = g_strdup(passwd);
+       *target = g_strdup(passwd);
     }
 }
 
@@ -256,16 +257,15 @@ libbalsa_server_config_changed(LibBalsaServer * server)
 }
 
 static gchar *
-libbalsa_server_get_password(LibBalsaServer  *server,
-                                                LibBalsaMailbox *mbox)
+libbalsa_server_get_password(LibBalsaServer *server,
+                                                gchar          *cert_subject)
 {
     gchar *retval = NULL;
 
     g_return_val_if_fail(server != NULL, NULL);
     g_return_val_if_fail(LIBBALSA_IS_SERVER(server), NULL);
 
-    g_signal_emit(G_OBJECT(server), libbalsa_server_signals[GET_PASSWORD],
-                  0, mbox, &retval);
+    g_signal_emit(G_OBJECT(server), libbalsa_server_signals[GET_PASSWORD], 0, cert_subject, &retval);
     return retval;
 }
 
@@ -290,17 +290,6 @@ libbalsa_server_real_set_host(LibBalsaServer * server, const gchar * host,
     server->security = security;
 }
 
-
-#if 0
-static gchar *
-libbalsa_server_real_get_password(LibBalsaServer * server)
-{
-    g_return_val_if_fail(LIBBALSA_IS_SERVER(server), NULL);
-
-    return g_strdup(server->passwd);
-}
-#endif
-
 void
 libbalsa_server_load_security_config(LibBalsaServer *server)
 {
@@ -602,9 +591,9 @@ libbalsa_server_check_cert(NetClient           *client,
 
 
 gchar *
-libbalsa_server_get_cert_pass(NetClient        *client,
-                                                         const GByteArray *cert_der,
-                                                         gpointer          user_data)
+libbalsa_server_get_cert_pass(NetClient *client,
+                                                         gchar     *cert_subject,
+                                                         gpointer   user_data)
 {
     LibBalsaServer *server = LIBBALSA_SERVER(user_data);
     gchar *result;
@@ -612,7 +601,7 @@ libbalsa_server_get_cert_pass(NetClient        *client,
     if ((server->cert_passphrase != NULL) && (server->cert_passphrase[0] != '\0')) {
        result = g_strdup(server->cert_passphrase);
     } else {
-       result = NULL;  // FIXME - dialogue to read passphrase
+       result = libbalsa_server_get_password(server, cert_subject);
     }
        return result;
 }
diff --git a/libbalsa/server.h b/libbalsa/server.h
index 1378b91f2..7610e6341 100644
--- a/libbalsa/server.h
+++ b/libbalsa/server.h
@@ -69,15 +69,15 @@ struct _LibBalsaServerClass {
     void (*set_host) (LibBalsaServer * server,
                      const gchar * host, NetClientCryptMode  security);
     void (*config_changed) (LibBalsaServer * server);
-    gchar *(*get_password) (LibBalsaServer * server);
 };
 
 LibBalsaServer *libbalsa_server_new(void);
 
 void libbalsa_server_set_username(LibBalsaServer * server,
                                  const gchar * username);
-void libbalsa_server_set_password(LibBalsaServer * server,
-                                 const gchar * passwd);
+void libbalsa_server_set_password(LibBalsaServer *server,
+                                                                 const gchar    *passwd,
+                                                                 gboolean        for_cert);
 void libbalsa_server_set_host(LibBalsaServer     *server,
                                                          const gchar        *host,
                                                          NetClientCryptMode  security);
@@ -96,9 +96,9 @@ gboolean libbalsa_server_check_cert(NetClient           *client,
                                                            GTlsCertificate     *peer_cert,
                                                                        GTlsCertificateFlags errors,
                                                                        gpointer             user_data);
-gchar *libbalsa_server_get_cert_pass(NetClient        *client,
-                                                                        const GByteArray *cert_der,
-                                                                        gpointer          user_data);
+gchar *libbalsa_server_get_cert_pass(NetClient *client,
+                                                                        gchar     *cert_subject,
+                                                                        gpointer   user_data);
 
 void libbalsa_server_connect_signals(LibBalsaServer * server, GCallback cb,
                                      gpointer cb_data);
diff --git a/libinit_balsa/assistant_page_user.c b/libinit_balsa/assistant_page_user.c
index de6b7ed0a..741f76de0 100644
--- a/libinit_balsa/assistant_page_user.c
+++ b/libinit_balsa/assistant_page_user.c
@@ -202,7 +202,7 @@ create_pop3_mbx(const gchar *name, const gchar* host, gint security,
     LibBalsaServer *server = LIBBALSA_MAILBOX_REMOTE_SERVER(pop);
 
     libbalsa_server_set_username(server, login);
-    libbalsa_server_set_password(server, passwd);
+    libbalsa_server_set_password(server, passwd, FALSE);
     libbalsa_server_set_host(server, host, security);
     server->security        = security;
     server->remember_passwd = remember;
@@ -225,7 +225,7 @@ create_imap_mbx(const gchar *name, const gchar* host, NetClientCryptMode securit
     LibBalsaServer *server =
         LIBBALSA_SERVER(libbalsa_imap_server_new(login, host));
     libbalsa_server_set_username(server, login);
-    libbalsa_server_set_password(server, passwd);
+    libbalsa_server_set_password(server, passwd, FALSE);
     libbalsa_server_set_host(server, host, security);
     server->remember_passwd = remember;
     mbnode = balsa_mailbox_node_new_imap_folder(server, NULL);
diff --git a/libnetclient/net-client.c b/libnetclient/net-client.c
index 7b4c376da..39b4d17f6 100644
--- a/libnetclient/net-client.c
+++ b/libnetclient/net-client.c
@@ -395,28 +395,33 @@ net_client_set_cert_from_pem(NetClient *client, const gchar *pem_data, GError **
                        } else {
                                res = gnutls_x509_privkey_import2(key, &data, GNUTLS_X509_FMT_PEM, NULL, 0);
                                if (res == GNUTLS_E_DECRYPTION_FAILED) {
-                                       size_t der_size;
-                                       guint8 *der_data;
+                                       size_t dn_size;
+                                       gchar *dn_str;
 
-                                       /* determine cert buffer size requirements */
-                                       der_size = 0U;
-                                       (void) gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, NULL, 
&der_size);
-                                       der_data = g_malloc(der_size);          /*lint !e9079 (MISRA C:2012 
Rule 11.5) */
+                                       /* determine dn string buffer size requirements */
+                                       dn_size = 0U;
+                                       (void) gnutls_x509_crt_get_dn(cert, NULL, &dn_size);
+                                       dn_str = g_malloc0(dn_size + 1U);               /*lint !e9079 (MISRA 
C:2012 Rule 11.5) */
 
-                                       res = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der_data, 
&der_size);
+                                       res = gnutls_x509_crt_get_dn(cert, dn_str, &dn_size);
                                        if (res == GNUTLS_E_SUCCESS) {
-                                               GByteArray *cert_der;
                                                gchar *key_pass = NULL;
 
-                                               cert_der = g_byte_array_new_take(der_data, der_size);
+                                               if (!g_utf8_validate(dn_str, -1, NULL)) {
+                                                       gchar *buf;
+
+                                                       buf = g_locale_to_utf8(dn_str, -1, NULL, NULL, NULL);
+                                                       g_free(dn_str);
+                                                       dn_str = buf;
+                                               }
                                                g_debug("emit 'cert-pass' signal for client %p", client);
-                                               g_signal_emit(client, signals[2], 0, cert_der, &key_pass);
-                                               g_byte_array_unref(cert_der);
+                                               g_signal_emit(client, signals[2], 0, dn_str, &key_pass);
                                                if (key_pass != NULL) {
                                                        res = gnutls_x509_privkey_import2(key, &data, 
GNUTLS_X509_FMT_PEM, key_pass, 0);
                                                        net_client_free_authstr(key_pass);
                                                }
                                        }
+                                       g_free(dn_str);
                                }
 
                                /* on success, set the certificate using the unencrypted key */
@@ -594,7 +599,7 @@ net_client_class_init(NetClientClass *klass)
                G_TYPE_TLS_CERTIFICATE, G_TYPE_TLS_CERTIFICATE_FLAGS);
        signals[1] = g_signal_new("auth", NET_CLIENT_TYPE, G_SIGNAL_RUN_LAST, 0U, NULL, NULL, NULL, 
G_TYPE_STRV, 1U, G_TYPE_BOOLEAN);
        signals[2] = g_signal_new("cert-pass", NET_CLIENT_TYPE, G_SIGNAL_RUN_LAST, 0U, NULL, NULL, NULL, 
G_TYPE_STRING, 1U,
-               G_TYPE_BYTE_ARRAY);
+               G_TYPE_STRING);
 }
 
 
diff --git a/libnetclient/net-client.h b/libnetclient/net-client.h
index cd57be4e0..d0a394e23 100644
--- a/libnetclient/net-client.h
+++ b/libnetclient/net-client.h
@@ -339,8 +339,8 @@ gboolean net_client_can_read(NetClient *client);
  * The following signals are implemented:
  *
  * - @anchor cert-pass cert-pass
- *   @code gchar *cert_pass(NetClient *client, GByteArray *peer_cert_der, gpointer user_data) @endcode The 
client certificate used
- *   for the connection has a password-protected key.  The certificate in DER format is passed to the signal 
handler, and shall
+ *   @code gchar *cert_pass(NetClient *client, char *cert_subject, gpointer user_data) @endcode The client 
certificate used
+ *   for the connection has a password-protected key.  The certificate subject is passed to the signal 
handler, which shall
  *   return a newly allocated string containing the password.  The string is wiped and freed when it is not 
needed any more.
  * - @anchor cert-check cert-check
  *   @code gboolean check_cert(NetClient *client, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, 
gpointer user_data)
diff --git a/src/balsa-app.c b/src/balsa-app.c
index 3d51715d4..39e23a2a9 100644
--- a/src/balsa-app.c
+++ b/src/balsa-app.c
@@ -26,11 +26,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-/* for creat(2) */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
 #include "filter-funcs.h"
 #include "libbalsa-conf.h"
 #include "misc.h"
@@ -43,22 +38,93 @@
 #  include "macosx-helpers.h"
 #endif
 
+#if HAVE_GCR
+#define GCR_API_SUBJECT_TO_CHANGE
+#include <gcr/gcr.h>
+#else
+#include <gnutls/x509.h>
+#endif
+
 #include <glib/gi18n.h>        /* Must come after balsa-app.h. */
 
 /* Global application structure */
 struct BalsaApplication balsa_app;
 
+#if HAVE_GCR
+
+static gchar *
+ask_password_real(LibBalsaServer *server, const gchar *cert_subject)
+{
+#if defined(HAVE_LIBSECRET)
+    static const gchar *remember_password_message =
+        N_("_Remember password in Secret Service");
+#else
+    static const gchar *remember_password_message =
+        N_("_Remember password");
+#endif                          /* defined(HAVE_LIBSECRET) */
+       GcrPromptDialog *dialog;
+       gchar *prompt;
+       gboolean *remember;
+       gchar *passwd;
+
+    g_return_val_if_fail(server != NULL, NULL);
+
+    if (cert_subject != NULL) {
+       prompt = g_strdup_printf(_("Password to unlock the user certificate\n%s\nfor %s@%s (%s)"),
+               cert_subject, server->user, server->host, server->protocol);
+       remember = &server->remember_cert_passphrase;
+    } else {
+       prompt = g_strdup_printf(_("Password for %s@%s (%s)"), server->user, server->host, server->protocol);
+       remember = &server->remember_passwd;
+    }
+       dialog = g_object_new(GCR_TYPE_PROMPT_DIALOG,
+                                                 "use-header-bar", libbalsa_use_headerbar(),
+                                                 "title", _("Password needed"),
+                                                 "description", prompt,
+                                                 "message", _("Password needed"),
+                                                 "choice-label", remember_password_message,
+                                                 "cancel-label", _("_Cancel"),
+                                                 "continue-label", _("_OK"),
+                                                 "choice-chosen", *remember,
+                                                 "destroy-with-parent", TRUE,
+                                                 "transient-for", GTK_WINDOW(balsa_app.main_window),
+                                                 "modal", TRUE,
+                                                 NULL);
+       g_free(prompt);
+       passwd = g_strdup(gcr_prompt_password_run(GCR_PROMPT(dialog), NULL, NULL));
+       if (passwd != NULL) {
+               gboolean old_remember;
+
+               old_remember = *remember;
+               *remember = gcr_prompt_get_choice_chosen(GCR_PROMPT(dialog));
+               libbalsa_server_set_password(server, passwd, cert_subject != NULL);
+               if (*remember || old_remember) {
+                       libbalsa_server_config_changed(server);
+               }
+       }
+    gtk_widget_destroy(GTK_WIDGET(dialog));
+    return passwd;
+}
+
+#else
+
 #define HIG_PADDING 12
 
 /* ask_password:
    asks the user for the password to the mailbox on given remote server.
 */
 static gchar *
-ask_password_real(LibBalsaServer * server, LibBalsaMailbox * mbox)
+ask_password_real(LibBalsaServer * server, const gchar *cert_subject)
 {
-    GtkWidget *dialog, *entry, *rememb;
-    GtkWidget *content_area;
-    gchar *prompt, *passwd = NULL;
+       GtkWidget *dialog;
+       GtkWidget *content;
+       GtkWidget *grid;
+       GtkWidget *label;
+    GtkWidget *entry;
+    GtkWidget *rememb_check;
+    gchar *prompt;
+    gchar *passwd;
+       gboolean *remember;
 #if defined(HAVE_LIBSECRET)
     static const gchar *remember_password_message =
         N_("_Remember password in Secret Service");
@@ -68,15 +134,14 @@ ask_password_real(LibBalsaServer * server, LibBalsaMailbox * mbox)
 #endif                          /* defined(HAVE_LIBSECRET) */
 
     g_return_val_if_fail(server != NULL, NULL);
-    if (mbox)
-       prompt =
-           g_strdup_printf(_("Opening remote mailbox %s.\n"
-                              "The _password for %s@%s:"),
-                           mbox->name, server->user, server->host);
-    else
-       prompt =
-           g_strdup_printf(_("_Password for %s@%s (%s):"), server->user,
-                           server->host, server->protocol);
+    if (cert_subject != NULL) {
+       prompt = g_strdup_printf(_("Password to unlock the user certificate\n%s\nfor %s@%s (%s)"),
+               cert_subject, server->user, server->host, server->protocol);
+       remember = &server->remember_cert_passphrase;
+    } else {
+       prompt = g_strdup_printf(_("Password for %s@%s (%s)"), server->user, server->host, server->protocol);
+               remember = &server->remember_passwd;
+    }
 
     dialog = gtk_dialog_new_with_buttons(_("Password needed"),
                                          GTK_WINDOW(balsa_app.main_window),
@@ -88,43 +153,51 @@ ask_password_real(LibBalsaServer * server, LibBalsaMailbox * mbox)
 #if HAVE_MACOSX_DESKTOP
     libbalsa_macosx_menu_for_parent(dialog, GTK_WINDOW(balsa_app.main_window));
 #endif
-    content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-    gtk_box_set_spacing(GTK_BOX(content_area), HIG_PADDING);
-    gtk_container_add(GTK_CONTAINER(content_area),
-                      gtk_label_new_with_mnemonic(prompt));
+
+    content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+    gtk_container_set_border_width(GTK_CONTAINER(content), HIG_PADDING);
+
+    grid = libbalsa_create_grid();
+    gtk_container_add(GTK_CONTAINER(content), grid);
+
+    gtk_grid_attach(GTK_GRID(grid), gtk_label_new(prompt), 0, 0, 2, 1);
     g_free(prompt);
-    gtk_container_add(GTK_CONTAINER(content_area),
-                      entry = gtk_entry_new());
-    gtk_entry_set_width_chars(GTK_ENTRY(entry), 20);
+
+    label = libbalsa_create_grid_label(_("Password:"), grid, 1);
+    entry = libbalsa_create_grid_entry(grid, NULL, NULL, 1, NULL, label);
+    g_object_set(G_OBJECT(entry), "input-purpose", GTK_INPUT_PURPOSE_PASSWORD, NULL);
     gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+    gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+    gtk_widget_grab_focus(entry);
 
-    rememb =  gtk_check_button_new_with_mnemonic(_(remember_password_message));
-    gtk_container_add(GTK_CONTAINER(content_area), rememb);
-    if(server->remember_passwd)
-        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rememb), TRUE);
+    rememb_check = libbalsa_create_grid_check(remember_password_message, grid, 2, *remember);
 
-    gtk_widget_show_all(content_area);
-    gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+    gtk_widget_show_all(grid);
     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
-    gtk_widget_grab_focus (entry);
-
-    if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
-        unsigned old_rem = server->remember_passwd;
-        passwd = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
-        server->remember_passwd = 
-            !!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rememb));
-        libbalsa_server_set_password(server, passwd);
-        if( server->remember_passwd || old_rem )
-            libbalsa_server_config_changed(server);
+
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
+               gboolean old_remember;
+
+               old_remember = *remember;
+               passwd = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+               *remember = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rememb_check));
+               libbalsa_server_set_password(server, passwd, cert_subject != NULL);
+               if (*remember || old_remember) {
+                       libbalsa_server_config_changed(server);
+               }
+    } else {
+       passwd = NULL;
     }
     gtk_widget_destroy(dialog);
     return passwd;
 }
 
+#endif
+
 typedef struct {
     GCond cond;
     LibBalsaServer* server;
-    LibBalsaMailbox* mbox;
+    const gchar *cert_subject;
     gchar* res;
     gboolean done;
 } AskPasswdData;
@@ -136,7 +209,7 @@ static gboolean
 ask_passwd_idle(gpointer data)
 {
     AskPasswdData* apd = (AskPasswdData*)data;
-    apd->res = ask_password_real(apd->server, apd->mbox);
+    apd->res = ask_password_real(apd->server, apd->cert_subject);
     apd->done = TRUE;
     g_cond_signal(&apd->cond);
     return FALSE;
@@ -146,7 +219,7 @@ ask_passwd_idle(gpointer data)
    GDK lock must not be held.
 */
 static gchar *
-ask_password_mt(LibBalsaServer * server, LibBalsaMailbox * mbox)
+ask_password_mt(LibBalsaServer * server, const gchar *cert_subject)
 {
     static GMutex ask_passwd_lock;
     AskPasswdData apd;
@@ -154,7 +227,7 @@ ask_password_mt(LibBalsaServer * server, LibBalsaMailbox * mbox)
     g_mutex_lock(&ask_passwd_lock);
     g_cond_init(&apd.cond);
     apd.server = server;
-    apd.mbox   = mbox;
+    apd.cert_subject = cert_subject;
     apd.done   = FALSE;
     g_idle_add(ask_passwd_idle, &apd);
     while (!apd.done) {
@@ -166,84 +239,27 @@ ask_password_mt(LibBalsaServer * server, LibBalsaMailbox * mbox)
     return apd.res;
 }
 
-static gboolean
-set_passwd_from_matching_server(GtkTreeModel *model,
-                               GtkTreePath *path,
-                               GtkTreeIter *iter,
-                               gpointer data)
-{
-    LibBalsaServer *server;
-    LibBalsaServer *master;
-    LibBalsaMailbox *mbox;
-    BalsaMailboxNode *node;
-
-    gtk_tree_model_get(model, iter, 0, &node, -1);
-    g_return_val_if_fail(node != NULL, FALSE);
-    if(node->server) {
-        server = node->server;
-       g_object_unref(node);
-    } else {
-        mbox = node->mailbox;
-       g_object_unref(node);
-        if(!mbox) /* eg. a collection of mboxes */
-            return FALSE;
-        g_return_val_if_fail(LIBBALSA_IS_MAILBOX(mbox), FALSE);
-
-        if (!LIBBALSA_IS_MAILBOX_REMOTE(mbox)) return FALSE;
-        server = LIBBALSA_MAILBOX_REMOTE_SERVER(mbox);
-        g_return_val_if_fail(server != NULL, FALSE);
-    }
-    g_return_val_if_fail(server->host != NULL, FALSE);
-    g_return_val_if_fail(server->user != NULL, FALSE);
-    if (server->passwd == NULL) return FALSE;
-
-    master = (LibBalsaServer *)data;
-    g_return_val_if_fail(LIBBALSA_IS_SERVER(master), FALSE);
-    if (master == server) return FALSE;
 
-    g_return_val_if_fail(server->host != NULL, FALSE);
-    g_return_val_if_fail(server->user != NULL, FALSE);
-
-    if ((strcmp(server->host, master->host) == 0) &&
-       (strcmp(server->user, master->user) == 0)) {
-       g_free(master->passwd);
-       master->passwd = g_strdup(server->passwd);
-       return TRUE;
-    };
-    
-    return FALSE;
-}
 /* ask_password:
    when called from thread, gdk lock must not be held.
+   @param cert_data
 */
 gchar *
-ask_password(LibBalsaServer *server, LibBalsaMailbox *mbox)
+ask_password(LibBalsaServer *server, const gchar *cert_subject, gpointer user_data)
 {
+    G_LOCK_DEFINE_STATIC(ask_password);
     gchar *password;
 
     g_return_val_if_fail(server != NULL, NULL);
-    
-    password = NULL;
-    if (mbox) {
-       gtk_tree_model_foreach(GTK_TREE_MODEL(balsa_app.mblist_tree_store),
-                              (GtkTreeModelForeachFunc)
-                              set_passwd_from_matching_server, server);
-
-       if (server->passwd != NULL) {
-           password = server->passwd;
-           server->passwd = NULL;
-       }
-    }
-
-    if (!password) {
-        G_LOCK_DEFINE_STATIC(ask_password);
 
-        G_LOCK(ask_password);
-       password = !libbalsa_am_i_subthread() ?
-            ask_password_real(server, mbox) : ask_password_mt(server, mbox);
-        G_UNLOCK(ask_password);
-       return password;
+    G_LOCK(ask_password);
+    if (libbalsa_am_i_subthread()) {
+       password = ask_password_mt(server, cert_subject);
+    } else {
+       password = ask_password_real(server, cert_subject);
     }
+       G_UNLOCK(ask_password);
+
        return password;
 }
 
diff --git a/src/balsa-app.h b/src/balsa-app.h
index 27a401dea..79ca4be1a 100644
--- a/src/balsa-app.h
+++ b/src/balsa-app.h
@@ -390,7 +390,9 @@ void balsa_app_init(void);
 void balsa_app_destroy(void);
 void update_timer(gboolean update, guint minutes);
 
-gchar *ask_password(LibBalsaServer * server, LibBalsaMailbox * mbox);
+gchar *ask_password(LibBalsaServer *server,
+                       const gchar    *cert_subject,
+                                       gpointer        user_data);
 void balsa_open_mailbox_list(gchar ** urls);
 
 /* Search functions */
diff --git a/src/save-restore.c b/src/save-restore.c
index 97cc21e37..09193cf84 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -37,6 +37,7 @@
 #include "filter-funcs.h"
 #include "mailbox-filter.h"
 #include "libbalsa-conf.h"
+#include "net-client-utils.h"
 
 #include "smtp-server.h"
 #include "send.h"
@@ -420,7 +421,7 @@ config_mailbox_init(const gchar * prefix)
     if (LIBBALSA_IS_MAILBOX_REMOTE(mailbox)) {
        LibBalsaServer *server = LIBBALSA_MAILBOX_REMOTE_SERVER(mailbox);
         libbalsa_server_connect_signals(server,
-                                        G_CALLBACK(ask_password), mailbox);
+                                        G_CALLBACK(ask_password), NULL);
        g_signal_connect_swapped(server, "config-changed",
                                  G_CALLBACK(config_mailbox_update),
                                 mailbox);
@@ -963,15 +964,15 @@ config_global_load(void)
 
         passphrase = libbalsa_conf_private_get_string("ESMTPPassphrase", TRUE);
        if (passphrase) {
-            libbalsa_server_set_password(server, passphrase);
-           g_free(passphrase);
+            libbalsa_server_set_password(server, passphrase, FALSE);
+            net_client_free_authstr(passphrase);
         }
 
        passphrase =
            libbalsa_conf_private_get_string("ESMTPCertificatePassphrase", TRUE);
        if (passphrase) {
-           g_free(server->cert_passphrase);
-           server->cert_passphrase = passphrase;
+        libbalsa_server_set_password(server, passphrase, TRUE);
+        net_client_free_authstr(passphrase);
        }
     }
 


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