[Gpa-commits] r974 - in trunk: . src
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Tue Mar 24 11:50:59 CET 2009
Author: werner
Date: 2009-03-24 11:50:53 +0100 (Tue, 24 Mar 2009)
New Revision: 974
Modified:
trunk/TODO
trunk/src/ChangeLog
trunk/src/cardman.c
trunk/src/cm-netkey.c
trunk/src/cm-openpgp.c
trunk/src/gpa-key-details.c
trunk/src/gpa.c
trunk/src/gpa.h
trunk/src/gpgmetools.c
trunk/src/gpgmetools.h
Log:
Various cardman related updates.
Modified: trunk/TODO
===================================================================
--- trunk/TODO 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/TODO 2009-03-24 10:50:53 UTC (rev 974)
@@ -1,4 +1,4 @@
--*- outline -*-
+-*- org -*-
In no particular order:
@@ -55,6 +55,14 @@
We might also want to have a scheduled refresh mode. But that might
be better implemented in gpg.
+* Cardman
+
+** We don't care about duplicate keys
+ In particular with X.509 it is common to use the same key (keygrip)
+ with several certificates. GpaKeyDetails can't cope with that but
+ uses the first key found.
+
+
* MB:
** Support getting plaintext from verify operation (should emit "created file"
then). Done for clipboard. Also needed for normal file ops and server.
@@ -116,6 +124,7 @@
When doing multi-file verify/decrypt, we may ignore more errors as
to make more progress. This seems more useful than the current
behavior.
+
** FileChooser Dialog with pseudo-random window size
When clicking "import" in the keyring manager, the FileChooser pops
up in a tiny window most of the time -- sometimes the window size is just right.
@@ -130,3 +139,4 @@
It seems, GPA windows have no icon set. Besides: GTK+ has a rather
nice key icon in it's stock: GTK_STOCK_AUTHENTICATION_DIALOG. Using
that would probably look more natural in a GNOME environment.
+
Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/ChangeLog 2009-03-24 10:50:53 UTC (rev 974)
@@ -1,3 +1,14 @@
+2009-03-23 Werner Koch <wk at g10code.com>
+
+ * gpgmetools.c (gpg_simple_stderr_cb): Use GString and skip
+ non-status lines.
+
+ * gpa.h (disable_ticker): New.
+ * gpa.c: Add hidden option --disable-ticker.
+ * cardman.c (start_ticker): Implement option.
+ (ticker_cb): Ignore tick while reloading.
+ (watcher_cb): Avoid reload already here.
+
2009-03-22 Moritz <moritz at gnu.org>
* cardman.c (cardman_action_new): Call
@@ -4,6 +15,33 @@
gtk_action_group_set_translation_domain before
gtk_action_group_add_actions.
+2009-03-19 Werner Koch <wk at g10code.com>
+
+ * gpgmetools.c (gpa_backup_key): Replace g_assert for the gpg path
+ test by a cleaner return_if_fail.
+ (gpa_start_simple_gpg_command): New.
+
+2009-03-18 Werner Koch <wk at g10code.com>
+
+ * cardman.c (construct_widgets): Do not update the card widget here.
+ (card_reload_finish_idle_cb): New.
+ (card_reload): Decrement card via idle handler.
+
+ * cm-netkey.c (reload_more_data_idle_cb, reload_more_data)
+ (reload_more_data_cb): New.
+ (reload_data): Call reload_more_data.
+ (construct_data_widget): Add a keys frame.
+ (reload_data): Clear the frame.
+
+2009-03-17 Werner Koch <wk at g10code.com>
+
+ * cm-openpgp.c (show_admin_pin_notice): New.
+ (save_attr): Call it.
+
+ * gpa-key-details.c (gpa_key_details_update): Keep track of the
+ current key.
+ (signatures_uid_changed): Select sigs according to current key.
+
2009-03-16 Werner Koch <wk at g10code.com>
* cm-openpgp.c (construct_data_widget): Use an expander for the
Modified: trunk/src/cardman.c
===================================================================
--- trunk/src/cardman.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/cardman.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -259,6 +259,19 @@
}
+/* Idle queue callback to mark a relaod operation finished. */
+static gboolean
+card_reload_finish_idle_cb (void *user_data)
+{
+ GpaCardManager *cardman = user_data;
+
+ cardman->in_card_reload--;
+ g_object_unref (cardman);
+
+ return FALSE; /* Remove us from the idle queue. */
+}
+
+
/* This function is called to trigger a card-reload. */
static void
card_reload (GpaCardManager *cardman)
@@ -275,7 +288,6 @@
/* Start the ticker if not yet done. */
start_ticker (cardman);
-
if (!cardman->in_card_reload)
{
cardman->in_card_reload++;
@@ -336,7 +348,8 @@
}
- if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT
+ || gpg_err_code (err) == GPG_ERR_CARD_REMOVED)
{
err_desc = _("No card found.");
}
@@ -387,8 +400,9 @@
scd_status_cb, cardman);
if (!err)
err = gpgme_op_assuan_result (cardman->gpgagent)->err;
-
- if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+
+ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT
+ || gpg_err_code (err) == GPG_ERR_CARD_REMOVED)
statusbar_update (cardman, _("No card"));
else if (err)
{
@@ -403,12 +417,12 @@
update_title (cardman);
update_info_visibility (cardman);
- /* Fixme: We should decrement the sentinel only after finishing
- the operation, so that we don't run them over and over if the
- user clicks too often. Note however that the primary reason
- for this sentinel is to avoid concurrent reloads triggered by
- the user and by the file watcher. */
- cardman->in_card_reload--;
+ /* We decrement our lock using a idle handler with lo priority.
+ This gives us a better chance not to do a reload a second
+ time on behalf of the file watcher or ticker. */
+ g_object_ref (cardman);
+ g_idle_add_full (G_PRIORITY_LOW,
+ card_reload_finish_idle_cb, cardman, NULL);
}
}
@@ -469,7 +483,7 @@
return 0;
}
-/* This fucntion is called by the timerout ticker started by
+/* This function is called by the timeout ticker started by
start_ticker. It is used to poll scdaemon to detect a card status
change. */
static gboolean
@@ -477,7 +491,8 @@
{
GpaCardManager *cardman = user_data;
- if (!cardman || !cardman->ticker_timeout_id || !cardman->gpgagent)
+ if (!cardman || !cardman->ticker_timeout_id || !cardman->gpgagent
+ || cardman->in_card_reload)
return TRUE; /* Keep on ticking. */
/* Note that we are single threaded and thus there is no need to
@@ -497,6 +512,9 @@
static void
start_ticker (GpaCardManager *cardman)
{
+ if (disable_ticker)
+ return;
+
if (!cardman->ticker_timeout_id)
{
#if GTK_CHECK_VERSION (2, 14, 0)
@@ -571,7 +589,7 @@
{
GpaCardManager *cardman = opaque;
- if (cardman && strchr (reason, 'w') )
+ if (cardman && strchr (reason, 'w') && !cardman->in_card_reload)
{
card_reload (cardman);
}
Modified: trunk/src/cm-netkey.c
===================================================================
--- trunk/src/cm-netkey.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/cm-netkey.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -29,6 +29,7 @@
#include "gpa.h"
#include "gtktools.h"
#include "convert.h"
+#include "gpa-key-details.h"
#include "cm-object.h"
#include "cm-netkey.h"
@@ -77,6 +78,8 @@
GtkWidget *warning_frame; /* The frame used to display warnings etc. */
+ GtkWidget *keys_frame; /* The frame containing the keys. */
+
GtkWidget *entries[ENTRY_LAST];
GtkWidget *change_pin_btn; /* The button to change the PIN for NKS. */
@@ -98,6 +101,7 @@
/* Local prototypes */
+static void learn_keys_clicked_cb (GtkButton *widget, void *user_data);
static void gpa_cm_netkey_finalize (GObject *object);
@@ -223,14 +227,188 @@
any_isnull,
tbl[idx].is_puk, tbl[idx].widget);
+ gtk_widget_set_no_show_all (card->warning_frame, FALSE);
if (any_isnull)
gtk_widget_show_all (card->warning_frame);
else
- gtk_widget_hide_all (card->warning_frame);
+ {
+ gtk_widget_hide_all (card->warning_frame);
+ gtk_widget_set_no_show_all (card->warning_frame, TRUE);
+ }
}
+/* Structure form comminucation between reload_more_data and
+ reload_more_data_cb. */
+struct reload_more_data_parm
+{
+ GpaCMNetkey *card; /* self */
+ gpgme_ctx_t ctx; /* A prepared context for relaod_more_data_cb. */
+ int any_unknown; /* Set if at least one key is not known. */
+};
+
+/* Helper for relaod_more_data. This is actually an Assuan status
+ callback */
+static gpg_error_t
+reload_more_data_cb (void *opaque, const char *status, const char *args)
+{
+ struct reload_more_data_parm *parm = opaque;
+ gpgme_key_t key = NULL;
+ const char *s;
+ char pattern[100];
+ int idx;
+ gpg_error_t err;
+ const char *keyid;
+ int any = 0;
+
+ if (strcmp (status, "KEYPAIRINFO") )
+ return 0;
+
+ idx = 0;
+ pattern[idx++] = '&';
+ for (s=args; hexdigitp (s) && idx < sizeof pattern - 1; s++)
+ pattern[idx++] = *s;
+ pattern[idx] = 0;
+ if (!spacep (s) || (s - args != 40))
+ return 0; /* Invalid formatted keygrip. */
+ while (spacep (s))
+ s++;
+ keyid = s;
+
+ if (!(err=gpgme_op_keylist_start (parm->ctx, pattern, 0)))
+ {
+ if (!(err=gpgme_op_keylist_next (parm->ctx, &key)))
+ {
+ GtkWidget *vbox, *expander, *details, *hbox, *label;
+
+ vbox = gtk_bin_get_child (GTK_BIN (parm->card->keys_frame));
+ if (!vbox)
+ g_debug ("Ooops, vbox missing in key frame");
+ else
+ {
+ expander = gtk_expander_new (keyid);
+ details = gpa_key_details_new ();
+ gtk_container_add (GTK_CONTAINER (expander), details);
+ gpa_key_details_update (details, key, 1);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ label = gtk_label_new (NULL);
+ gtk_label_set_width_chars (GTK_LABEL (label), 22);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), expander, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ any = 1;
+ }
+ gpgme_key_unref (key);
+ }
+ }
+ gpgme_op_keylist_end (parm->ctx);
+ if (!any)
+ parm->any_unknown = 1;
+ return 0;
+}
+
+
+/* Reload more data. This function is called from the idle handler. */
+static void
+reload_more_data (GpaCMNetkey *card)
+{
+ gpg_error_t err;
+ gpgme_ctx_t gpgagent;
+ GtkWidget *vbox;
+ struct reload_more_data_parm parm;
+
+ gpgagent = GPA_CM_OBJECT (card)->agent_ctx;
+ g_return_if_fail (gpgagent);
+ g_return_if_fail (card->keys_frame);
+
+ /* We remove any existing children of the keys frame and then we add
+ a new vbox to be filled with new widgets by the callback. */
+ vbox = gtk_bin_get_child (GTK_BIN (card->keys_frame));
+ if (vbox)
+ gtk_widget_destroy (vbox);
+ vbox = gtk_vbox_new (FALSE, 5);
+ gtk_container_add (GTK_CONTAINER (card->keys_frame), vbox);
+
+ /* Create a context for key listings. */
+ parm.any_unknown = 0;
+ parm.card = card;
+ err = gpgme_new (&parm.ctx);
+ if (err)
+ {
+ /* We don't want an error window because we are run from an idle
+ handler and the information is not that important. */
+ g_debug ("failed to create a context: %s", gpg_strerror (err));
+ return;
+ }
+ gpgme_set_protocol (parm.ctx, GPGME_PROTOCOL_CMS);
+ /* We include ephemeral keys in the listing. */
+ gpgme_set_keylist_mode (parm.ctx, GPGME_KEYLIST_MODE_EPHEMERAL);
+
+ err = gpgme_op_assuan_transact (gpgagent,
+ "SCD LEARN --keypairinfo",
+ NULL, NULL, NULL, NULL,
+ reload_more_data_cb, &parm);
+ if (!err)
+ err = gpgme_op_assuan_result (gpgagent)->err;
+ if (err)
+ g_debug ("SCD LEARN failed: %s", gpg_strerror (err));
+
+ if (parm.any_unknown)
+ {
+ GtkWidget *button, *align;
+
+ align = gtk_alignment_new (0.5, 0, 0, 0);
+ button = gtk_button_new_with_label (_("Learn keys"));
+ gpa_add_tooltip
+ (button, _("For some or all of the keys available on the card, "
+ "the GnuPG crypto engine does not yet know the "
+ "corresponding certificates.\n"
+ "\n"
+ "If you click this button, GnuPG will be asked to "
+ "\"learn\" "
+ "this card and import all certificates stored on the "
+ "card into its own certificate store. This is not done "
+ "automatically because it may take several seconds to "
+ "read all certificates from the card.\n"
+ "\n"
+ "If you are unsure what to do, just click the button."));
+ gtk_container_add (GTK_CONTAINER (align), button);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
+ gtk_box_reorder_child (GTK_BOX (vbox), align, 0);
+
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (learn_keys_clicked_cb), card);
+ }
+
+ gpgme_release (parm.ctx);
+ gtk_widget_show_all (card->keys_frame);
+ return;
+}
+
+
+/* Idle queue callback to reload more data. */
+static gboolean
+reload_more_data_idle_cb (void *user_data)
+{
+ GpaCMNetkey *card = user_data;
+
+ if (card->reloading)
+ return TRUE; /* Just in case we are still reloading, wait for the
+ next idle slot. */
+
+ card->reloading++;
+ reload_more_data (card);
+ g_object_unref (card);
+ card->reloading--;
+
+ return FALSE; /* Remove us from the idle queue. */
+}
+
+
struct scd_getattr_parm
{
GpaCMNetkey *card; /* The object. */
@@ -297,6 +475,8 @@
g_return_if_fail (gpgagent);
card->reloading++;
+
+ /* Show all attributes. */
parm.card = card;
for (attridx=0; attrtbl[attridx].name; attridx++)
{
@@ -333,11 +513,96 @@
break;
}
}
+ if (!err)
+ {
+ g_object_ref (card);
+ g_idle_add (reload_more_data_idle_cb, card);
+ }
card->reloading--;
}
+/* A structure used to pass data to the learn_keys_gpg_status_cb. */
+struct learn_keys_gpg_status_parm
+{
+ GpaCMNetkey *card;
+ GtkWidget *button;
+ GtkProgressBar *pbar;
+};
+
+
+/* Helper for learn_keys_clicked_cb. */
+static gboolean
+learn_keys_gpg_status_cb (void *opaque, char *line)
+{
+ struct learn_keys_gpg_status_parm *parm = opaque;
+
+ if (!line)
+ {
+ /* We are finished with the command. */
+ g_debug ("learn_keys_gpg_status_cb: cleanup");
+ /* Trigger a reload of the key data. */
+ g_object_ref (parm->card);
+ g_idle_add (reload_more_data_idle_cb, parm->card);
+ /* Cleanup. */
+ gtk_widget_destroy (parm->button);
+ g_object_unref (parm->button);
+ g_object_unref (parm->card);
+ xfree (parm);
+ return FALSE; /* (The return code does not matter here.) */
+ }
+
+ g_debug ("learn_keys_gpg_status_cb: `%s'", line);
+ if (!strncmp (line, "PROGRESS", 8))
+ gtk_progress_bar_pulse (parm->pbar);
+
+ return TRUE; /* Keep on running. */
+}
+
+
+/* Fire up the learn command. */
static void
+learn_keys_clicked_cb (GtkButton *button, void *user_data)
+{
+ GpaCMNetkey *card = user_data;
+ GtkWidget *widget;
+ gpg_error_t err;
+ struct learn_keys_gpg_status_parm *parm;
+
+ parm = xcalloc (1, sizeof *parm);
+
+ g_debug ("learn keys clicked");
+ gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+ widget = gtk_bin_get_child (GTK_BIN (button));
+ if (widget)
+ gtk_widget_destroy (widget);
+
+ widget = gtk_progress_bar_new ();
+ gtk_container_add (GTK_CONTAINER (button), widget);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (widget),
+ _("Learning keys ..."));
+ gtk_widget_show_all (GTK_WIDGET (button));
+
+ g_object_ref (card);
+ parm->card = card;
+ g_object_ref (button);
+ parm->button = GTK_WIDGET (button);
+ parm->pbar = GTK_PROGRESS_BAR (widget);
+
+ err = gpa_start_simple_gpg_command
+ (learn_keys_gpg_status_cb, parm, GPGME_PROTOCOL_CMS,
+ "--learn-card", "-v", NULL);
+ if (err)
+ {
+ g_debug ("error starting gpg: %s", gpg_strerror (err));
+ learn_keys_gpg_status_cb (parm, NULL);
+ return;
+ }
+}
+
+
+/* Run the dialog to change the NullPIN. */
+static void
change_nullpin (GpaCMNetkey *card)
{
gpg_error_t err;
@@ -652,6 +917,22 @@
G_CALLBACK (set_initial_pin_clicked_cb), card);
+ /* Keys frame. */
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+ label = gtk_label_new (_("<b>Keys</b>"));
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+
+ /* There is only a label widget yet in the frame for now. The real
+ widgets are added while figuring out the keys of the card. */
+ label = gtk_label_new (_("scanning ..."));
+ gtk_container_add (GTK_CONTAINER (frame), label);
+
+ gtk_box_pack_start (GTK_BOX (card), frame, FALSE, TRUE, 0);
+ card->keys_frame = frame;
+
+
/* PIN frame. */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
@@ -696,7 +977,6 @@
G_CALLBACK (change_pin_clicked_cb), card);
gtk_box_pack_start (GTK_BOX (card), frame, FALSE, TRUE, 0);
-
}
Modified: trunk/src/cm-openpgp.c
===================================================================
--- trunk/src/cm-openpgp.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/cm-openpgp.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -104,8 +104,6 @@
/* The parent class. */
static GObjectClass *parent_class;
-
-
/* Local prototypes */
static void gpa_cm_openpgp_finalize (GObject *object);
@@ -137,6 +135,52 @@
}
+/* If not yet done show a warning to tell the user about the Admin
+ PIN. Returns true if the operation shall continue. */
+static int
+show_admin_pin_notice (GpaCMOpenpgp *card)
+{
+ static int shown;
+ GtkWidget *dialog;
+ const char *string;
+ int okay;
+
+ if (shown)
+ return 1;
+
+ string = _("<b>Admin-PIN Required</b>\n"
+ "\n"
+ "Depending on the previous operations you may now "
+ "be asked for the Admin-PIN. Entering a wrong value "
+ "for the Admin-PIN decrements the corresponding retry counter. "
+ "If the retry counter is down to zero, the Admin-PIN can't "
+ "be restored anymore and thus the data on the card can't be "
+ "modified.\n"
+ "\n"
+ "Unless changed, a fresh standard card has set the Admin-PIN "
+ "to the value <i>12345678</i>. "
+ "However, the issuer of your card might "
+ "have initialized the card with a different Admin-PIN and "
+ "that Admin-PIN might only be known to the issuer. "
+ "Please check the instructions of your issuer.\n"
+ "\n"
+ "This notice will be shown only once per session.");
+
+ /* FIXME: How do we figure out our GtkWindow? */
+ dialog = gtk_message_dialog_new_with_markup (NULL /*GTK_WINDOW (card)*/,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK_CANCEL,
+ NULL);
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), string);
+ okay = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ if (okay)
+ shown = 1;
+ return okay;
+}
+
+
/* Clears the info contained in the card widget. */
static void
clear_card_data (GpaCMOpenpgp *card)
@@ -521,6 +565,9 @@
gpgagent = GPA_CM_OBJECT (card)->agent_ctx;
g_return_val_if_fail (gpgagent,gpg_error (GPG_ERR_BUG));
+ if (!show_admin_pin_notice (card))
+ return gpg_error (GPG_ERR_CANCELED);
+
if (is_escaped)
command = g_strdup_printf ("SCD SETATTR %s %s", name, value);
else
Modified: trunk/src/gpa-key-details.c
===================================================================
--- trunk/src/gpa-key-details.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/gpa-key-details.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -75,6 +75,10 @@
/* The widgets in the subkeys list. */
GtkWidget *subkeys_page;
GtkWidget *subkeys_list;
+
+ /* The key currently shown or NULL. */
+ gpgme_key_t current_key;
+
};
@@ -99,13 +103,11 @@
signatures_uid_changed (GtkComboBox *combo, gpointer user_data)
{
GpaKeyDetails *kdt = user_data;
- gpgme_key_t key;
- /* FIXME key = keyring_editor_current_key (kdt);*/ key = NULL;
/* Note that we need to subtract one, as the first entry (with index
0 means) "all user names". */
gpa_siglist_set_signatures
- (kdt->signatures_list, key,
+ (kdt->signatures_list, kdt->current_key,
gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) - 1);
}
@@ -450,9 +452,6 @@
kdt->subkeys_page = vbox;
gtk_notebook_append_page (GTK_NOTEBOOK (kdt), kdt->subkeys_page,
gtk_label_new (_("Subkeys")));
-/* FIXME gtk_widget_show_all (kdt->notebook_details); */
-/* keyring_update_details_notebook (editor); */
-/* idle_update_details (editor); */
}
@@ -531,17 +530,23 @@
static void
gpa_key_details_init (GTypeInstance *instance, void *class_ptr)
{
- GpaKeyDetails *obj = GPA_KEY_DETAILS (instance);
+ GpaKeyDetails *kdt = GPA_KEY_DETAILS (instance);
- construct_main_widget (obj);
+ construct_main_widget (kdt);
}
static void
gpa_key_details_finalize (GObject *object)
{
-/* GpaKeyDetails *obj = GPA_KEY_DETAILS (object); */
+ GpaKeyDetails *kdt = GPA_KEY_DETAILS (object);
+ if (kdt->current_key)
+ {
+ gpgme_key_unref (kdt->current_key);
+ kdt->current_key = NULL;
+ }
+
parent_class->finalize (object);
}
@@ -598,8 +603,15 @@
g_return_if_fail (GPA_IS_KEY_DETAILS (keydetails));
kdt = GPA_KEY_DETAILS (keydetails);
+ if (kdt->current_key)
+ {
+ gpgme_key_unref (kdt->current_key);
+ kdt->current_key = NULL;
+ }
if (key && keycount == 1)
{
+ gpgme_key_ref (key);
+ kdt->current_key = key;
details_page_fill_key (kdt, key);
signatures_page_fill_key (kdt, key);
subkeys_page_fill_key (kdt, key);
Modified: trunk/src/gpa.c
===================================================================
--- trunk/src/gpa.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/gpa.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -54,7 +54,10 @@
/* True if CMS hack mode is enabled. */
gboolean cms_hack;
+/* True if the ticker used for card operations should not be started. */
+gboolean disable_ticker;
+
/* Local variables. */
typedef struct
{
@@ -108,6 +111,8 @@
N_("Read options from file"), "FILE" },
{ "cms", 'x', 0, G_OPTION_ARG_NONE, &cms_hack,
"Enable CMS/X.509 support", NULL },
+ { "disable-ticker", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE,
+ &disable_ticker, NULL, NULL },
{ NULL }
};
Modified: trunk/src/gpa.h
===================================================================
--- trunk/src/gpa.h 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/gpa.h 2009-03-24 10:50:53 UTC (rev 974)
@@ -52,8 +52,8 @@
extern GList *global_defaultRecipients;
extern gchar *gnupg_homedir;
extern gboolean cms_hack;
+extern gboolean disable_ticker;
-
/* Show the keyring editor dialog. */
void gpa_open_keyring_editor (GtkAction *action, void *data);
Modified: trunk/src/gpgmetools.c
===================================================================
--- trunk/src/gpgmetools.c 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/gpgmetools.c 2009-03-24 10:50:53 UTC (rev 974)
@@ -1,6 +1,6 @@
/* gpgmetools.h - Additional gpgme support functions for GPA.
Copyright (C) 2002 Miguel Coca.
- Copyright (C) 2005, 2008 g10 Code GmbH.
+ Copyright (C) 2005, 2008, 2009 g10 Code GmbH.
This file is part of GPA
@@ -25,6 +25,8 @@
#include <errno.h>
#include <ctype.h>
+#include <stdarg.h>
+
#include "gpa.h"
#include "gtktools.h"
#include "gpgmetools.h"
@@ -433,7 +435,7 @@
}
-/* Retrieve the path to the GnuPG executable. */
+/* Retrieve the path to the GPG executable. */
static const gchar *
get_gpg_path (void)
{
@@ -450,6 +452,24 @@
}
+/* Retrieve the path to the GPGSM executable. */
+static const gchar *
+get_gpgsm_path (void)
+{
+ gpgme_engine_info_t engine;
+
+ gpgme_get_engine_info (&engine);
+ while (engine)
+ {
+ if (engine->protocol == GPGME_PROTOCOL_CMS)
+ return engine->file_name;
+ engine = engine->next;
+ }
+ return NULL;
+}
+
+
+
/* Backup a key. It exports both the public and secret keys to a file.
Returns TRUE on success and FALSE on error. It displays errors to
the user. */
@@ -476,9 +496,10 @@
const gchar *path;
mode_t mask;
- /* Get the gpg path */
+ /* Get the gpg path. */
path = get_gpg_path ();
- g_assert (path != NULL);
+ g_return_val_if_fail (path && *path, FALSE);
+
/* Add the executable to the arg arrays */
header_argv[0] = (gchar*) path;
pub_argv[0] = (gchar*) path;
@@ -1232,3 +1253,163 @@
return 0; /* No gpg-engine available. */
}
+
+/* Structure used to communicate with gpg_simple_stderr_cb. */
+struct gpg_simple_stderr_parm_s
+{
+ gboolean (*cb)(void *opaque, char *line);
+ void *cb_arg;
+ GString *string;
+};
+
+/* Helper for gpa_start_simple_gpg_command. */
+static gboolean
+gpg_simple_stderr_cb (GIOChannel *channel, GIOCondition condition,
+ void *user_data)
+{
+ struct gpg_simple_stderr_parm_s *parm = user_data;
+ GIOStatus status;
+ char *line, *p;
+
+ if ((condition & G_IO_IN))
+ {
+ /* We don't use a while but an if because that allows to update
+ progress bars nicely. A bit slower, but no real problem. */
+ if ((status = g_io_channel_read_line_string
+ (channel, parm->string, NULL, NULL)) == G_IO_STATUS_NORMAL)
+ {
+ line = parm->string->str;
+
+ /* We care only about status lines. */
+ if (!strncmp (line, "[GNUPG:] ", 9))
+ {
+ line += 9;
+
+ /* Strip line terminator. */
+ p = strchr (line, '\n');
+ if (p)
+ {
+ if (p > line && p[-1] == '\r')
+ p[-1] = 0;
+ else
+ *p = 0;
+ }
+
+ /* Call user callback. */
+ if (parm->cb && !parm->cb (parm->cb_arg, line))
+ {
+ g_debug ("User requested EOF");
+ goto cleanup;
+ }
+ }
+ }
+ if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN )
+ {
+ /* Error or EOF. */
+ g_debug ("Received %s", status==G_IO_STATUS_EOF? "EOF":"ERROR");
+ goto cleanup;
+ }
+ }
+ if ((condition & G_IO_HUP))
+ {
+ g_debug ("Received HUP");
+ goto cleanup;
+ }
+
+ return TRUE; /* Keep on watching this channel. */
+
+ cleanup:
+ if (parm->cb)
+ parm->cb (parm->cb_arg, NULL); /* Tell user about EOF. */
+ g_string_free (parm->string, TRUE);
+ xfree (parm);
+ g_io_channel_unref (channel); /* Close channel. */
+ return FALSE; /* Remove us from the watch list. */
+}
+
+
+/* Run gpg asynchronously with the given arguments and return a gpg
+ error code on error. The list of arguments are all of type (const
+ char*) and end with a NULL argument (FIRST_ARG may already be NULL,
+ but that does not make any sense). STDIN and STDOUT are connected
+ to /dev/null. No more than 20 arguments may be given.
+
+ If the function returns success the provided callback CB is called
+ for each line received on STDERR. EOF is send to this callback by
+ passing a LINE argument of NULL. The callback may use this for
+ cleanup. If the callback returns FALSE, an EOF is forced with the
+ result that the callback is called once more with LINE set to NULL. */
+gpg_error_t
+gpa_start_simple_gpg_command (gboolean (*cb)(void *opaque, char *line),
+ void *cb_arg, gpgme_protocol_t protocol,
+ const char *first_arg, ...)
+{
+ char *argv[24];
+ int argc;
+ int fd_stderr;
+ GIOChannel *channel;
+ struct gpg_simple_stderr_parm_s *parm = NULL;
+
+ if (protocol == GPGME_PROTOCOL_OpenPGP)
+ argv[0] = (char*)get_gpg_path ();
+ else if (protocol == GPGME_PROTOCOL_CMS)
+ argv[0] = (char*)get_gpgsm_path ();
+ else
+ argv[0] = NULL;
+ g_return_val_if_fail (argv[0], gpg_error (GPG_ERR_INV_ARG));
+ argc = 1;
+ argv[argc++] = (char*)"--status-fd";
+ argv[argc++] = (char*)"2";
+ argv[argc++] = (char*)first_arg;
+ if (first_arg)
+ {
+ va_list arg_ptr;
+ const char *s;
+
+ va_start (arg_ptr, first_arg);
+ while (argc < DIM (argv)-1 && (s=va_arg (arg_ptr, const char *)))
+ argv[argc++] = (char*)s;
+ va_end (arg_ptr);
+ argv[argc] = NULL;
+ g_return_val_if_fail (argc < DIM (argv), gpg_error (GPG_ERR_INV_ARG));
+ }
+
+ parm = g_try_malloc (sizeof *parm);
+ if (!parm)
+ return gpg_error_from_syserror ();
+ parm->cb = cb;
+ parm->cb_arg = cb_arg;
+ parm->string = g_string_sized_new (200);
+
+ if (!g_spawn_async_with_pipes (NULL, argv, NULL,
+ (G_SPAWN_STDOUT_TO_DEV_NULL),
+ NULL, NULL, NULL,
+ NULL, NULL, &fd_stderr, NULL))
+ {
+ gpa_window_error (_("Calling the crypto engine program failed."), NULL);
+ xfree (parm);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+#ifdef G_OS_WIN32
+ channel = g_io_channel_win32_new_fd (fd_stderr);
+#else
+ channel = g_io_channel_unix_new (fd_stderr);
+#endif
+ g_io_channel_set_encoding (channel, NULL, NULL);
+ /* Note that we need a buffered channel, so that we can use the read
+ line function. */
+ g_io_channel_set_close_on_unref (channel, TRUE);
+
+ /* Create a watch for the channel. */
+ if (!g_io_add_watch (channel, (G_IO_IN|G_IO_HUP),
+ gpg_simple_stderr_cb, parm))
+ {
+ g_debug ("error creating watch for gpg command");
+ g_io_channel_unref (channel);
+ xfree (parm);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+ return 0;
+}
+
Modified: trunk/src/gpgmetools.h
===================================================================
--- trunk/src/gpgmetools.h 2009-03-22 16:17:54 UTC (rev 973)
+++ trunk/src/gpgmetools.h 2009-03-24 10:50:53 UTC (rev 974)
@@ -194,5 +194,13 @@
/* Return true if the gpg engine has at least version NEED_VERSION. */
int is_gpg_version_at_least (const char *need_version);
+/* Run a simple gpg command. */
+gpg_error_t gpa_start_simple_gpg_command (gboolean (*cb)
+ (void *opaque, char *line),
+ void *cb_arg,
+ gpgme_protocol_t protocol,
+ const char *first_arg, ...)
+ G_GNUC_NULL_TERMINATED;
+
#endif /*GPGMETOOLS_H*/
More information about the Gpa-commits
mailing list