From: Claws Mail Team Date: Fri, 8 Oct 2004 17:19:46 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'gtk2'. X-Git-Tag: gtk2_win32_last_merge~139 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=6abf0f72886167289031835f8a4b06af14dfbb8f;ds=sidebyside This commit was manufactured by cvs2svn to create branch 'gtk2'. 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 --- diff --git a/src/plugins/pgpmime/passphrase.c b/src/plugins/pgpmime/passphrase.c new file mode 100644 index 000000000..adf762620 --- /dev/null +++ b/src/plugins/pgpmime/passphrase.c @@ -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 +#endif + +#if USE_GPGME + +#include +#include +#include +#include +#include +#include /* GDK_DISPLAY() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..5556a50c1 --- /dev/null +++ b/src/plugins/pgpmime/passphrase.h @@ -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 +#include + +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 index 000000000..d6c367b0c --- /dev/null +++ b/src/plugins/pgpmime/prefs_gpg.c @@ -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 + +#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 index 000000000..055f22756 --- /dev/null +++ b/src/plugins/pgpmime/prefs_gpg.h @@ -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 index 000000000..00da2e045 --- /dev/null +++ b/src/plugins/pgpmime/select-keys.c @@ -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 +#endif + +#ifdef USE_GPGME +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..009afc109 --- /dev/null +++ b/src/plugins/pgpmime/select-keys.h @@ -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 +#include + + +GpgmeRecipients gpgmegtk_recipient_selection (GSList *recp_names); + + +#endif /* GPGMEGTK_SELECT_KEYS_H */