This commit was manufactured by cvs2svn to create branch 'gtk2'.
authorClaws Mail Team <theteam@claws-mail.org>
Fri, 8 Oct 2004 17:19:46 +0000 (17:19 +0000)
committerClaws Mail Team <theteam@claws-mail.org>
Fri, 8 Oct 2004 17:19:46 +0000 (17:19 +0000)
Cherrypick from master 2004-10-08 17:19:45 UTC reboot '2004-10-08 [christoph] 0.9.12cvs123':
    src/plugins/pgpmime/passphrase.c
    src/plugins/pgpmime/passphrase.h
    src/plugins/pgpmime/prefs_gpg.c
    src/plugins/pgpmime/prefs_gpg.h
    src/plugins/pgpmime/select-keys.c
    src/plugins/pgpmime/select-keys.h

src/plugins/pgpmime/passphrase.c [new file with mode: 0644]
src/plugins/pgpmime/passphrase.h [new file with mode: 0644]
src/plugins/pgpmime/prefs_gpg.c [new file with mode: 0644]
src/plugins/pgpmime/prefs_gpg.h [new file with mode: 0644]
src/plugins/pgpmime/select-keys.c [new file with mode: 0644]
src/plugins/pgpmime/select-keys.h [new file with mode: 0644]

diff --git a/src/plugins/pgpmime/passphrase.c b/src/plugins/pgpmime/passphrase.c
new file mode 100644 (file)
index 0000000..adf7626
--- /dev/null
@@ -0,0 +1,333 @@
+/* passphrase.c - GTK+ based passphrase callback
+ *      Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#if USE_GPGME
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>  /* GDK_DISPLAY() */
+#include <gtk/gtkmain.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkfilesel.h>
+#include <gtk/gtksignal.h>
+
+#include "intl.h"
+#include "passphrase.h"
+#include "prefs_common.h"
+#include "manage_window.h"
+#include "utils.h"
+#include "prefs_gpg.h"
+
+extern struct GPGConfig prefs_gpg;
+
+static int grab_all = 0;
+
+static gboolean pass_ack;
+static gchar *last_pass = NULL;
+
+static void passphrase_ok_cb(GtkWidget *widget, gpointer data);
+static void passphrase_cancel_cb(GtkWidget *widget, gpointer data);
+static gint passphrase_deleted(GtkWidget *widget, GdkEventAny *event,
+                              gpointer data);
+static void passphrase_key_pressed(GtkWidget *widget, GdkEventKey *event,
+                                  gpointer data);
+static gchar* passphrase_mbox (const gchar *desc);
+
+
+static GtkWidget *create_description (const gchar *desc);
+
+void
+gpgmegtk_set_passphrase_grab (gint yes)
+{
+    grab_all = yes;
+}
+
+static gchar*
+passphrase_mbox (const gchar *desc)
+{
+    gchar *the_passphrase = NULL;
+    GtkWidget *vbox;
+    GtkWidget *table;
+    GtkWidget *pass_label;
+    GtkWidget *confirm_box;
+    GtkWidget *window;
+    GtkWidget *pass_entry;
+    GtkWidget *ok_button;
+    GtkWidget *cancel_button;
+
+    window = gtk_window_new(GTK_WINDOW_DIALOG);
+    gtk_window_set_title(GTK_WINDOW(window), _("Passphrase"));
+    gtk_widget_set_usize(window, 450, -1);
+    gtk_container_set_border_width(GTK_CONTAINER(window), 4);
+    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+    gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+    gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
+    gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+                       GTK_SIGNAL_FUNC(passphrase_deleted), NULL);
+    gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+                       GTK_SIGNAL_FUNC(passphrase_key_pressed), NULL);
+    MANAGE_WINDOW_SIGNALS_CONNECT(window);
+    manage_window_set_transient(GTK_WINDOW(window));
+
+    vbox = gtk_vbox_new(FALSE, 8);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+
+    if (desc) {
+        GtkWidget *label;
+        label = create_description (desc);
+        gtk_box_pack_start (GTK_BOX(vbox), label, TRUE, TRUE, 0);
+    }
+
+    table = gtk_table_new(2, 2, FALSE);
+    gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(table), 8);
+    gtk_table_set_row_spacings(GTK_TABLE(table), 12);
+    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
+
+
+    pass_label = gtk_label_new("");
+    gtk_table_attach (GTK_TABLE(table), pass_label, 0, 1, 0, 1,
+                      GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (pass_label), 1, 0.5);
+
+    pass_entry = gtk_entry_new();
+    gtk_table_attach (GTK_TABLE(table), pass_entry, 1, 2, 0, 1,
+                      GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
+    gtk_entry_set_visibility (GTK_ENTRY(pass_entry), FALSE);
+    gtk_widget_grab_focus (pass_entry);
+
+
+    confirm_box = gtk_hbutton_box_new ();
+    gtk_button_box_set_layout (GTK_BUTTON_BOX(confirm_box), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing (GTK_BUTTON_BOX(confirm_box), 5);
+
+    ok_button = gtk_button_new_with_label (_("OK"));
+    GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
+    gtk_box_pack_start (GTK_BOX(confirm_box), ok_button, TRUE, TRUE, 0);
+
+    cancel_button = gtk_button_new_with_label (_("Cancel"));
+    GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(confirm_box), cancel_button, TRUE, TRUE, 0);
+
+    gtk_box_pack_end(GTK_BOX(vbox), confirm_box, FALSE, FALSE, 0);
+    gtk_widget_grab_default (ok_button);
+
+    gtk_signal_connect(GTK_OBJECT(ok_button), "clicked",
+                       GTK_SIGNAL_FUNC(passphrase_ok_cb), NULL);
+    gtk_signal_connect(GTK_OBJECT(pass_entry), "activate",
+                       GTK_SIGNAL_FUNC(passphrase_ok_cb), NULL);
+    gtk_signal_connect(GTK_OBJECT(cancel_button), "clicked",
+                       GTK_SIGNAL_FUNC(passphrase_cancel_cb), NULL);
+
+    if (grab_all)
+        gtk_object_set (GTK_OBJECT(window), "type", GTK_WINDOW_POPUP, NULL);
+    gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+    if (grab_all)   
+        gtk_window_set_policy (GTK_WINDOW(window), FALSE, FALSE, TRUE);
+    
+    gtk_widget_show_all(window);
+
+    /* don't use XIM on entering passphrase */
+    gtkut_editable_disable_im(GTK_EDITABLE(pass_entry));
+
+    if (grab_all) {
+        XGrabServer(GDK_DISPLAY());
+        if ( gdk_pointer_grab ( window->window, TRUE, 0,
+                                NULL, NULL, GDK_CURRENT_TIME)) {
+            XUngrabServer ( GDK_DISPLAY() );
+            g_warning ("OOPS: Could not grab mouse\n");
+            gtk_widget_destroy (window);
+            return NULL;
+        }
+        if ( gdk_keyboard_grab( window->window, FALSE, GDK_CURRENT_TIME )) {
+            gdk_pointer_ungrab (GDK_CURRENT_TIME);
+            XUngrabServer ( GDK_DISPLAY() );
+            g_warning ("OOPS: Could not grab keyboard\n");
+            gtk_widget_destroy (window);
+            return NULL;
+        }
+    }
+
+    gtk_main();
+
+    if (grab_all) {
+        XUngrabServer (GDK_DISPLAY());
+        gdk_pointer_ungrab (GDK_CURRENT_TIME);
+        gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+        gdk_flush();
+    }
+
+    manage_window_focus_out(window, NULL, NULL);
+
+    if (pass_ack) {
+        the_passphrase = gtk_entry_get_text(GTK_ENTRY(pass_entry));
+        if (the_passphrase) /* Hmmm: Do we really need this? */
+            the_passphrase = g_strdup (the_passphrase);
+    }
+    gtk_widget_destroy (window);
+
+    return the_passphrase;
+}
+
+
+static void 
+passphrase_ok_cb(GtkWidget *widget, gpointer data)
+{
+    pass_ack = TRUE;
+    gtk_main_quit();
+}
+
+static void 
+passphrase_cancel_cb(GtkWidget *widget, gpointer data)
+{
+    pass_ack = FALSE;
+    gtk_main_quit();
+}
+
+
+static gint
+passphrase_deleted(GtkWidget *widget, GdkEventAny *event, gpointer data)
+{
+    passphrase_cancel_cb(NULL, NULL);
+    return TRUE;
+}
+
+
+static void 
+passphrase_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+    if (event && event->keyval == GDK_Escape)
+        passphrase_cancel_cb(NULL, NULL);
+}
+
+static gint 
+linelen (const gchar *s)
+{
+    gint i;
+
+    for (i = 0; *s && *s != '\n'; s++, i++)
+        ;
+
+    return i;
+}
+
+static GtkWidget *
+create_description (const gchar *desc)
+{
+    const gchar *cmd = NULL, *uid = NULL, *info = NULL;
+    gchar *buf;
+    GtkWidget *label;
+
+    cmd = desc;
+    uid = strchr (cmd, '\n');
+    if (uid) {
+        info = strchr (++uid, '\n');
+        if (info )
+            info++;
+    }
+
+    if (!uid)
+        uid = _("[no user id]");
+    if (!info)
+        info = "";
+
+    buf = g_strdup_printf (_("%sPlease enter the passphrase for:\n\n"
+                           "  %.*s  \n"
+                           "(%.*s)\n"),
+                           !strncmp (cmd, "TRY_AGAIN", 9 ) ?
+                           _("Bad passphrase! Try again...\n\n") : "",
+                           linelen (uid), uid, linelen (info), info);
+
+    label = gtk_label_new (buf);
+    g_free (buf);
+
+    return label;
+}
+
+static int free_passphrase(gpointer _unused)
+{
+    if (last_pass != NULL) {
+        munlock(last_pass, strlen(last_pass));
+        g_free(last_pass);
+        last_pass = NULL;
+        debug_print("%% passphrase removed");
+    }
+    
+    return FALSE;
+}
+
+const char*
+gpgmegtk_passphrase_cb (void *opaque, const char *desc, void **r_hd)
+{
+    struct passphrase_cb_info_s *info = opaque;
+    GpgmeCtx ctx = info ? info->c : NULL;
+    const char *pass;
+
+    if (!desc) {
+        /* FIXME: cleanup by looking at *r_hd */
+        return NULL;
+    }
+    if (prefs_gpg.store_passphrase && last_pass != NULL &&
+        strncmp(desc, "TRY_AGAIN", 9) != 0)
+        return g_strdup(last_pass);
+
+    gpgmegtk_set_passphrase_grab (prefs_gpg.passphrase_grab);
+    debug_print ("%% requesting passphrase for `%s': ", desc);
+    pass = passphrase_mbox (desc);
+    gpgmegtk_free_passphrase();
+    if (!pass) {
+        debug_print ("%% cancel passphrase entry");
+        gpgme_cancel (ctx);
+    }
+    else {
+        if (prefs_gpg.store_passphrase) {
+            last_pass = g_strdup(pass);
+            if (mlock(last_pass, strlen(last_pass)) == -1)
+                debug_print("%% locking passphrase failed");
+
+            if (prefs_gpg.store_passphrase_timeout > 0) {
+                gtk_timeout_add(prefs_gpg.store_passphrase_timeout*60*1000,
+                                free_passphrase, NULL);
+            }
+        }
+        debug_print ("%% sending passphrase");
+    }
+
+    return pass;
+}
+
+void gpgmegtk_free_passphrase(void)
+{
+    (void)free_passphrase(NULL); /* could be inline */
+}
+
+#endif /* USE_GPGME */
diff --git a/src/plugins/pgpmime/passphrase.h b/src/plugins/pgpmime/passphrase.h
new file mode 100644 (file)
index 0000000..5556a50
--- /dev/null
@@ -0,0 +1,34 @@
+/* passphrase.h - GTK+ based passphrase callback
+ *      Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GPGMEGTK_PASSPHRASE_H
+#define GPGMEGTK_PASSPHRASE_H
+
+#include <glib.h>
+#include <gpgme.h>
+
+struct passphrase_cb_info_s {
+    GpgmeCtx c;
+    int did_it;
+};
+
+void gpgmegtk_set_passphrase_grab (gint yesno);
+const char* gpgmegtk_passphrase_cb(void *opaque, const char *desc, void **r_hd);
+void gpgmegtk_free_passphrase (void);
+
+#endif /* GPGMEGTK_PASSPHRASE_H */
diff --git a/src/plugins/pgpmime/prefs_gpg.c b/src/plugins/pgpmime/prefs_gpg.c
new file mode 100644 (file)
index 0000000..d6c367b
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004 Hiroyuki Yamamoto & the Sylpheed-Claws team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include "defs.h"
+#include "intl.h"
+#include "utils.h"
+#include "prefs.h"
+#include "prefs_gtk.h"
+#include "prefs_gpg.h"
+
+struct GPGConfig prefs_gpg;
+
+static PrefParam param[] = {
+       /* Privacy */
+       {"auto_check_signatures", "TRUE",
+        &prefs_gpg.auto_check_signatures, P_BOOL,
+        NULL, NULL, NULL},
+       {"store_passphrase", "FALSE", &prefs_gpg.store_passphrase, P_BOOL,
+        NULL, NULL, NULL},
+       {"store_passphrase_timeout", "0",
+        &prefs_gpg.store_passphrase_timeout, P_INT,
+        NULL, NULL, NULL},
+#ifndef __MINGW32__
+       {"passphrase_grab", "FALSE", &prefs_gpg.passphrase_grab, P_BOOL,
+        NULL, NULL, NULL},
+#endif /* __MINGW32__ */
+       {"gpg_warning", "TRUE", &prefs_gpg.gpg_warning, P_BOOL,
+        NULL, NULL, NULL},
+
+       {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
+};
+
+static void prefs_privacy_create(void)
+{
+       GtkWidget *vbox1;
+       GtkWidget *vbox2;
+       GtkWidget *vbox3;
+       GtkWidget *hbox1;
+       GtkWidget *hbox_spc;
+       GtkWidget *label;
+       GtkWidget *checkbtn_auto_check_signatures;
+       GtkWidget *checkbtn_store_passphrase;
+       GtkObject *spinbtn_store_passphrase_adj;
+       GtkWidget *spinbtn_store_passphrase;
+       GtkTooltips *store_tooltip;
+       GtkWidget *checkbtn_passphrase_grab;
+       GtkWidget *checkbtn_gpg_warning;
+
+       vbox1 = gtk_vbox_new (FALSE, VSPACING);
+       gtk_widget_show (vbox1);
+       gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
+
+       vbox2 = gtk_vbox_new (FALSE, 0);
+       gtk_widget_show (vbox2);
+       gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
+
+       PACK_CHECK_BUTTON (vbox2, checkbtn_auto_check_signatures,
+                          _("Automatically check signatures"));
+
+       PACK_CHECK_BUTTON (vbox2, checkbtn_store_passphrase,
+                          _("Store passphrase in memory temporarily"));
+
+       vbox3 = gtk_vbox_new (FALSE, 0);
+       gtk_widget_show (vbox3);
+       gtk_box_pack_start (GTK_BOX (vbox2), vbox3, FALSE, FALSE, 0);
+
+       hbox1 = gtk_hbox_new (FALSE, 8);
+       gtk_widget_show (hbox1);
+       gtk_box_pack_start (GTK_BOX (vbox3), hbox1, FALSE, FALSE, 0);
+
+       hbox_spc = gtk_hbox_new (FALSE, 0);
+       gtk_widget_show (hbox_spc);
+       gtk_box_pack_start (GTK_BOX (hbox1), hbox_spc, FALSE, FALSE, 0);
+       gtk_widget_set_usize (hbox_spc, 12, -1);
+
+       label = gtk_label_new (_("Expire after"));
+       gtk_widget_show (label);
+       gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0);
+
+       store_tooltip = gtk_tooltips_new();
+
+       spinbtn_store_passphrase_adj = gtk_adjustment_new (0, 0, 1440, 1, 5, 5);
+       spinbtn_store_passphrase = gtk_spin_button_new
+               (GTK_ADJUSTMENT (spinbtn_store_passphrase_adj), 1, 0);
+       gtk_widget_show (spinbtn_store_passphrase);
+       gtk_tooltips_set_tip(GTK_TOOLTIPS(store_tooltip), spinbtn_store_passphrase,
+                            _("Setting to '0' will store the passphrase"
+                              " for the whole session"),
+                            NULL);
+       gtk_box_pack_start (GTK_BOX (hbox1), spinbtn_store_passphrase, FALSE, FALSE, 0);
+       gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_store_passphrase),
+                                    TRUE);
+       gtk_widget_set_usize (spinbtn_store_passphrase, 64, -1);
+
+       label = gtk_label_new (_("minute(s) "));
+       gtk_widget_show (label);
+       gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0);
+
+       hbox1 = gtk_hbox_new (FALSE, 8);
+       gtk_widget_show (hbox1);
+       gtk_box_pack_start (GTK_BOX (vbox3), hbox1, FALSE, FALSE, 0);
+
+       hbox_spc = gtk_hbox_new (FALSE, 0);
+       gtk_widget_show (hbox_spc);
+       gtk_box_pack_start (GTK_BOX (hbox1), hbox_spc, FALSE, FALSE, 0);
+       gtk_widget_set_usize (hbox_spc, 12, -1);
+
+       SET_TOGGLE_SENSITIVITY (checkbtn_store_passphrase, vbox3);
+
+#ifndef __MINGW32__
+       PACK_CHECK_BUTTON (vbox2, checkbtn_passphrase_grab,
+                          _("Grab input while entering a passphrase"));
+#endif
+
+       PACK_CHECK_BUTTON
+               (vbox2, checkbtn_gpg_warning,
+                _("Display warning on startup if GnuPG doesn't work"));
+
+       hbox1 = gtk_hbox_new (FALSE, 8);
+       gtk_widget_show (hbox1);
+       gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
+
+/*
+       privacy.checkbtn_auto_check_signatures
+                                            = checkbtn_auto_check_signatures;
+       privacy.checkbtn_store_passphrase    = checkbtn_store_passphrase;
+       privacy.spinbtn_store_passphrase     = spinbtn_store_passphrase;
+       privacy.spinbtn_store_passphrase_adj = spinbtn_store_passphrase_adj;
+       privacy.checkbtn_passphrase_grab     = checkbtn_passphrase_grab;
+       privacy.checkbtn_gpg_warning         = checkbtn_gpg_warning;
+*/
+}
+
+GPGConfig *prefs_gpg_get_config(void)
+{
+       return &prefs_gpg;
+}
+
+void prefs_gpg_save_config(void)
+{
+       PrefFile *pfile;
+       gchar *rcpath;
+
+       debug_print("Saving GPGME config\n");
+
+       rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+       pfile = prefs_write_open(rcpath);
+       g_free(rcpath);
+       if (!pfile || (prefs_set_block_label(pfile, "GPGME") < 0))
+               return;
+
+       if (prefs_write_param(param, pfile->fp) < 0) {
+               g_warning("failed to write GPGME configuration to file\n");
+               prefs_file_close_revert(pfile);
+               return;
+       }
+       fprintf(pfile->fp, "\n");
+
+       prefs_file_close(pfile);
+}
+
+void prefs_gpg_init()
+{
+       prefs_set_default(param);
+       prefs_read_config(param, "GPGME", COMMON_RC);
+}
+
+void prefs_gpg_done()
+{
+}
diff --git a/src/plugins/pgpmime/prefs_gpg.h b/src/plugins/pgpmime/prefs_gpg.h
new file mode 100644 (file)
index 0000000..055f227
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2004 Hiroyuki Yamamoto & the Sylpheed-Claws team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+typedef struct GPGConfig GPGConfig;
+
+struct GPGConfig
+{
+       gboolean auto_check_signatures;
+       gboolean gpg_signature_popup;
+       gboolean store_passphrase;
+       gint store_passphrase_timeout;
+       gboolean passphrase_grab;
+       gboolean gpg_warning;
+};
+
+void prefs_gpg_init();
+void prefs_gpg_done();
diff --git a/src/plugins/pgpmime/select-keys.c b/src/plugins/pgpmime/select-keys.c
new file mode 100644 (file)
index 0000000..00da2e0
--- /dev/null
@@ -0,0 +1,545 @@
+/* select-keys.c - GTK+ based key selection
+ *      Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This program is free software; you can redistribute it and/or modify        
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef USE_GPGME
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkclist.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtksignal.h>
+
+#include "intl.h"
+#include "select-keys.h"
+#include "utils.h"
+#include "gtkutils.h"
+#include "inputdialog.h"
+#include "manage_window.h"
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member)   DIM(((type *)0)->member)
+
+
+enum col_titles { 
+    COL_ALGO,
+    COL_KEYID,
+    COL_NAME,
+    COL_EMAIL,
+    COL_VALIDITY,
+
+    N_COL_TITLES
+};
+
+struct select_keys_s {
+    int okay;
+    GtkWidget *window;
+    GtkLabel *toplabel;
+    GtkCList *clist;
+    const char *pattern;
+    GpgmeRecipients rset;
+    GpgmeCtx select_ctx;
+
+    GtkSortType sort_type;
+    enum col_titles sort_column;
+    
+};
+
+
+static void set_row (GtkCList *clist, GpgmeKey key);
+static void fill_clist (struct select_keys_s *sk, const char *pattern);
+static void create_dialog (struct select_keys_s *sk);
+static void open_dialog (struct select_keys_s *sk);
+static void close_dialog (struct select_keys_s *sk);
+static gint delete_event_cb (GtkWidget *widget,
+                             GdkEventAny *event, gpointer data);
+static void key_pressed_cb (GtkWidget *widget,
+                            GdkEventKey *event, gpointer data);
+static void showall_btn_cb (GtkWidget *widget, gpointer data);
+static void select_btn_cb (GtkWidget *widget, gpointer data);
+static void cancel_btn_cb (GtkWidget *widget, gpointer data);
+static void other_btn_cb (GtkWidget *widget, gpointer data);
+static void sort_keys (struct select_keys_s *sk, enum col_titles column);
+static void sort_keys_name (GtkWidget *widget, gpointer data);
+static void sort_keys_email (GtkWidget *widget, gpointer data);
+
+
+static void
+update_progress (struct select_keys_s *sk, int running, const char *pattern)
+{
+    static int windmill[] = { '-', '\\', '|', '/' };
+    char *buf;
+
+    if (!running)
+        buf = g_strdup_printf (_("Please select key for `%s'"), 
+                               pattern);
+    else 
+        buf = g_strdup_printf (_("Collecting info for `%s' ... %c"), 
+                               pattern,
+                               windmill[running%DIM(windmill)]);
+    gtk_label_set_text (sk->toplabel, buf);
+    g_free (buf);
+}
+
+
+/**
+ * select_keys_get_recipients:
+ * @recp_names: A list of email addresses
+ * 
+ * Select a list of recipients from a given list of email addresses.
+ * This may pop up a window to present the user a choice, it will also
+ * check that the recipients key are all valid.
+ * 
+ * Return value: NULL on error or a list of list of recipients.
+ **/
+GpgmeRecipients
+gpgmegtk_recipient_selection (GSList *recp_names)
+{
+    struct select_keys_s sk;
+    GpgmeError err;
+
+    memset (&sk, 0, sizeof sk);
+
+    err = gpgme_recipients_new (&sk.rset);
+    if (err) {
+        g_warning ("failed to allocate recipients set: %s",
+                   gpgme_strerror (err));
+        return NULL;
+    }
+
+    open_dialog (&sk);
+
+    do {
+        sk.pattern = recp_names? recp_names->data:NULL;
+        gtk_clist_clear (sk.clist);
+        fill_clist (&sk, sk.pattern);
+        update_progress (&sk, 0, sk.pattern);
+        gtk_main ();
+        if (recp_names)
+            recp_names = recp_names->next;
+    } while (sk.okay && recp_names);
+
+    close_dialog (&sk);
+
+    if (!sk.okay) {
+        gpgme_recipients_release (sk.rset);
+        sk.rset = NULL;
+    }
+    return sk.rset;
+} 
+
+static void
+destroy_key (gpointer data)
+{
+    GpgmeKey key = data;
+    gpgme_key_release (key);
+}
+
+static void
+set_row (GtkCList *clist, GpgmeKey key)
+{
+    const char *s;
+    const char *text[N_COL_TITLES];
+    char *algo_buf;
+    int row;
+
+    /* first check whether the key is capable of encryption which is not
+     * the case for revoked, expired or sign-only keys */
+    if ( !gpgme_key_get_ulong_attr (key, GPGME_ATTR_CAN_ENCRYPT, NULL, 0 ) )
+        return;
+    
+    algo_buf = g_strdup_printf ("%lu/%s", 
+         gpgme_key_get_ulong_attr (key, GPGME_ATTR_LEN, NULL, 0 ),
+         gpgme_key_get_string_attr (key, GPGME_ATTR_ALGO, NULL, 0 ) );
+    text[COL_ALGO] = algo_buf;
+
+    s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID, NULL, 0);
+    if (strlen (s) == 16)
+        s += 8; /* show only the short keyID */
+    text[COL_KEYID] = s;
+
+    s = gpgme_key_get_string_attr (key, GPGME_ATTR_NAME, NULL, 0);
+    text[COL_NAME] = s;
+
+    s = gpgme_key_get_string_attr (key, GPGME_ATTR_EMAIL, NULL, 0);
+    text[COL_EMAIL] = s;
+
+    s = gpgme_key_get_string_attr (key, GPGME_ATTR_VALIDITY, NULL, 0);
+    text[COL_VALIDITY] = s;
+
+    row = gtk_clist_append (clist, (gchar**)text);
+    g_free (algo_buf);
+
+    gtk_clist_set_row_data_full (clist, row, key, destroy_key);
+}
+
+
+static void 
+fill_clist (struct select_keys_s *sk, const char *pattern)
+{
+    GtkCList *clist;
+    GpgmeCtx ctx;
+    GpgmeError err;
+    GpgmeKey key;
+    int running=0;
+
+    g_return_if_fail (sk);
+    clist = sk->clist;
+    g_return_if_fail (clist);
+
+    debug_print ("select_keys:fill_clist:  pattern `%s'\n", pattern);
+
+    /*gtk_clist_freeze (select_keys.clist);*/
+    err = gpgme_new (&ctx);
+    g_assert (!err);
+
+    sk->select_ctx = ctx;
+
+    update_progress (sk, ++running, pattern);
+    while (gtk_events_pending ())
+        gtk_main_iteration ();
+
+    err = gpgme_op_keylist_start (ctx, pattern, 0);
+    if (err) {
+        debug_print ("** gpgme_op_keylist_start(%s) failed: %s",
+                     pattern, gpgme_strerror (err));
+        sk->select_ctx = NULL;
+        return;
+    }
+    update_progress (sk, ++running, pattern);
+    while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) {
+        debug_print ("%% %s:%d:  insert\n", __FILE__ ,__LINE__ );
+        set_row (clist, key ); key = NULL;
+        update_progress (sk, ++running, pattern);
+        while (gtk_events_pending ())
+            gtk_main_iteration ();
+    }
+    debug_print ("%% %s:%d:  ready\n", __FILE__ ,__LINE__ );
+    if (err != GPGME_EOF)
+        debug_print ("** gpgme_op_keylist_next failed: %s",
+                     gpgme_strerror (err));
+    sk->select_ctx = NULL;
+    gpgme_release (ctx);
+    /*gtk_clist_thaw (select_keys.clist);*/
+}
+
+
+static void 
+create_dialog (struct select_keys_s *sk)
+{
+    GtkWidget *window;
+    GtkWidget *vbox, *vbox2, *hbox;
+    GtkWidget *bbox;
+    GtkWidget *scrolledwin;
+    GtkWidget *clist;
+    GtkWidget *label;
+    GtkWidget *select_btn, *cancel_btn, *other_btn;
+    GtkWidget *showall_btn;
+    const char *titles[N_COL_TITLES];
+
+    g_assert (!sk->window);
+    window = gtk_window_new (GTK_WINDOW_DIALOG);
+    gtk_widget_set_usize (window, 520, 280);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+    gtk_window_set_title (GTK_WINDOW (window), _("Select Keys"));
+    gtk_window_set_modal (GTK_WINDOW (window), TRUE);
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        GTK_SIGNAL_FUNC (delete_event_cb), sk);
+    gtk_signal_connect (GTK_OBJECT (window), "key_press_event",
+                        GTK_SIGNAL_FUNC (key_pressed_cb), sk);
+    MANAGE_WINDOW_SIGNALS_CONNECT (window);
+
+    vbox = gtk_vbox_new (FALSE, 8);
+    gtk_container_add (GTK_CONTAINER (window), vbox);
+
+    hbox  = gtk_hbox_new(FALSE, 4);
+    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+    label = gtk_label_new ( "" );
+    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+    hbox = gtk_hbox_new (FALSE, 8);
+    gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
+
+    scrolledwin = gtk_scrolled_window_new (NULL, NULL);
+    gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
+                                    GTK_POLICY_AUTOMATIC,
+                                    GTK_POLICY_AUTOMATIC);
+
+    titles[COL_ALGO]     = _("Size");
+    titles[COL_KEYID]    = _("Key ID");
+    titles[COL_NAME]     = _("Name");
+    titles[COL_EMAIL]    = _("Address");
+    titles[COL_VALIDITY] = _("Val");
+
+    clist = gtk_clist_new_with_titles (N_COL_TITLES, (char**)titles);
+    gtk_container_add (GTK_CONTAINER (scrolledwin), clist);
+    gtk_clist_set_column_width (GTK_CLIST(clist), COL_ALGO,      72);
+    gtk_clist_set_column_width (GTK_CLIST(clist), COL_KEYID,     76);
+    gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME,     130);
+    gtk_clist_set_column_width (GTK_CLIST(clist), COL_EMAIL,    130);
+    gtk_clist_set_column_width (GTK_CLIST(clist), COL_VALIDITY,  20);
+    gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE);
+    gtk_signal_connect (GTK_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button),
+                       "clicked",
+                        GTK_SIGNAL_FUNC(sort_keys_name), sk);
+    gtk_signal_connect (GTK_OBJECT(GTK_CLIST(clist)->column[COL_EMAIL].button),
+                       "clicked",
+                        GTK_SIGNAL_FUNC(sort_keys_email), sk);
+
+    hbox = gtk_hbox_new (FALSE, 8);
+    gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+    showall_btn = gtk_button_new_with_label (_(" List all keys "));
+    gtk_widget_show (showall_btn);
+    gtk_box_pack_start (GTK_BOX (hbox), showall_btn, FALSE, FALSE, 0);
+
+    gtk_signal_connect (GTK_OBJECT (showall_btn), "clicked",
+                        GTK_SIGNAL_FUNC (showall_btn_cb), sk);
+
+    gtkut_button_set_create (&bbox, 
+                             &select_btn, _("Select"),
+                             &cancel_btn, _("Cancel"),
+                             &other_btn,  _("Other"));
+    gtk_box_pack_end (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);
+    gtk_widget_grab_default (select_btn);
+
+    gtk_signal_connect (GTK_OBJECT (select_btn), "clicked",
+                        GTK_SIGNAL_FUNC (select_btn_cb), sk);
+    gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
+                        GTK_SIGNAL_FUNC (cancel_btn_cb), sk);
+    gtk_signal_connect (GTK_OBJECT (other_btn), "clicked",
+                        GTK_SIGNAL_FUNC (other_btn_cb), sk);
+
+    vbox2 = gtk_vbox_new (FALSE, 4);
+    gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
+
+    gtk_widget_show_all (window);
+
+    sk->window = window;
+    sk->toplabel = GTK_LABEL (label);
+    sk->clist  = GTK_CLIST (clist);
+}
+
+
+static void
+open_dialog (struct select_keys_s *sk)
+{
+    if (!sk->window)
+        create_dialog (sk);
+    manage_window_set_transient (GTK_WINDOW (sk->window));
+    sk->okay = 0;
+    sk->sort_column = N_COL_TITLES; /* use an invalid value */
+    sk->sort_type = GTK_SORT_ASCENDING;
+    gtk_widget_show (sk->window);
+}
+
+
+static void
+close_dialog (struct select_keys_s *sk)
+{
+    g_return_if_fail (sk);
+    gtk_widget_destroy (sk->window);
+    sk->window = NULL;
+}
+
+
+static gint
+delete_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
+{
+    struct select_keys_s *sk = data;
+
+    sk->okay = 0;
+    gtk_main_quit ();
+
+    return TRUE;
+}
+
+
+static void 
+key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+    struct select_keys_s *sk = data;
+
+    g_return_if_fail (sk);
+    if (event && event->keyval == GDK_Escape) {
+        sk->okay = 0;
+        gtk_main_quit ();
+    }
+}
+
+
+static void 
+select_btn_cb (GtkWidget *widget, gpointer data)
+{
+    struct select_keys_s *sk = data;
+    int row;
+    GpgmeKey key;
+
+    g_return_if_fail (sk);
+    if (!sk->clist->selection) {
+        debug_print ("** nothing selected");
+        return;
+    }
+    row = GPOINTER_TO_INT(sk->clist->selection->data);
+    key = gtk_clist_get_row_data(sk->clist, row);
+    if (key) {
+        const char *s = gpgme_key_get_string_attr (key,
+                                                   GPGME_ATTR_FPR,
+                                                   NULL, 0 );
+        if ( gpgme_key_get_ulong_attr (key, GPGME_ATTR_VALIDITY, NULL, 0 )
+             < GPGME_VALIDITY_FULL ) {
+            debug_print ("** FIXME: we are faking the trust calculation");
+        }
+        if (!gpgme_recipients_add_name_with_validity (sk->rset, s,
+                                                      GPGME_VALIDITY_FULL) ) {
+            sk->okay = 1;
+            gtk_main_quit ();
+        }
+    }
+}
+
+
+static void 
+cancel_btn_cb (GtkWidget *widget, gpointer data)
+{
+    struct select_keys_s *sk = data;
+
+    g_return_if_fail (sk);
+    sk->okay = 0;
+    if (sk->select_ctx)
+        gpgme_cancel (sk->select_ctx);
+    gtk_main_quit ();
+}
+
+
+static void
+other_btn_cb (GtkWidget *widget, gpointer data)
+{
+    struct select_keys_s *sk = data;
+    char *uid;
+
+    g_return_if_fail (sk);
+    uid = input_dialog ( _("Add key"),
+                         _("Enter another user or key ID:"),
+                         NULL );
+    if (!uid)
+        return;
+    fill_clist (sk, uid);
+    update_progress (sk, 0, sk->pattern);
+    g_free (uid);
+}
+
+static void
+showall_btn_cb (GtkWidget *widget, gpointer data)
+{
+    struct select_keys_s *sk = data;
+    char *uid;
+
+    g_return_if_fail (sk);
+    uid = "";
+       
+    fill_clist (sk, uid);
+    update_progress (sk, 0, sk->pattern);
+}
+
+static gint 
+cmp_attr (gconstpointer pa, gconstpointer pb, GpgmeAttr attr)
+{
+    GpgmeKey a = ((GtkCListRow *)pa)->data;
+    GpgmeKey b = ((GtkCListRow *)pb)->data;
+    const char *sa, *sb;
+    
+    sa = a? gpgme_key_get_string_attr (a, attr, NULL, 0 ) : NULL;
+    sb = b? gpgme_key_get_string_attr (b, attr, NULL, 0 ) : NULL;
+    if (!sa)
+        return !!sb;
+    if (!sb)
+        return -1;
+    return strcasecmp(sa, sb);
+}
+
+static gint 
+cmp_name (GtkCList *clist, gconstpointer pa, gconstpointer pb)
+{
+    return cmp_attr (pa, pb, GPGME_ATTR_NAME);
+}
+
+static gint 
+cmp_email (GtkCList *clist, gconstpointer pa, gconstpointer pb)
+{
+    return cmp_attr (pa, pb, GPGME_ATTR_EMAIL);
+}
+
+static void
+sort_keys ( struct select_keys_s *sk, enum col_titles column)
+{
+    GtkCList *clist = sk->clist;
+
+    switch (column) {
+      case COL_NAME:
+        gtk_clist_set_compare_func (clist, cmp_name);
+        break;
+      case COL_EMAIL:
+        gtk_clist_set_compare_func (clist, cmp_email);
+        break;
+      default:
+        return;
+    }
+
+    /* column clicked again: toggle as-/decending */
+    if ( sk->sort_column == column) {
+        sk->sort_type = sk->sort_type == GTK_SORT_ASCENDING ?
+                        GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
+    }
+    else
+        sk->sort_type = GTK_SORT_ASCENDING;
+
+    sk->sort_column = column;
+    gtk_clist_set_sort_type (clist, sk->sort_type);
+    gtk_clist_sort (clist);
+}
+
+static void
+sort_keys_name (GtkWidget *widget, gpointer data)
+{
+    sort_keys ((struct select_keys_s*)data, COL_NAME);
+}
+
+static void
+sort_keys_email (GtkWidget *widget, gpointer data)
+{
+    sort_keys ((struct select_keys_s*)data, COL_EMAIL);
+}
+
+#endif /*USE_GPGME*/
diff --git a/src/plugins/pgpmime/select-keys.h b/src/plugins/pgpmime/select-keys.h
new file mode 100644 (file)
index 0000000..009afc1
--- /dev/null
@@ -0,0 +1,29 @@
+/* select-keys.h - GTK+ based key selection
+ *      Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GPGMEGTK_SELECT_KEYS_H
+#define GPGMEGTK_SELECT_KEYS_H
+
+#include <glib.h>
+#include <gpgme.h>
+
+
+GpgmeRecipients gpgmegtk_recipient_selection (GSList *recp_names);
+
+
+#endif /* GPGMEGTK_SELECT_KEYS_H */