[Gpa-commits] r959 - trunk/src

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Mar 4 09:47:51 CET 2009


Author: werner
Date: 2009-03-04 09:47:46 +0100 (Wed, 04 Mar 2009)
New Revision: 959

Added:
   trunk/src/membuf.c
   trunk/src/membuf.h
Modified:
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/cardman.c
Log:
Add an application selection button.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2009-03-03 18:25:30 UTC (rev 958)
+++ trunk/src/ChangeLog	2009-03-04 08:47:46 UTC (rev 959)
@@ -1,3 +1,15 @@
+2009-03-04  Werner Koch  <wk at g10code.com>
+
+	* cardman.c (struct _GpaCardManager): Add field APP_SELECTOR.
+	(setup_app_selector, setup_app_selector_data_cb): New.
+	(gpa_card_manager_init): Call setup_app_selector.
+	(card_reload): Implement application selection.
+	(update_card_widget): Add arg ERROR_DESCRIPTION and change all
+	callers.
+
+	* membuf.c, membuf.h: New.  Taken from GnuPG and modified for use
+	with Glib.
+
 2009-03-03  Werner Koch  <wk at g10code.com>
 
 	* convert.c (gpa_sex_char_to_string): Make strings a salutation.

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2009-03-03 18:25:30 UTC (rev 958)
+++ trunk/src/Makefile.am	2009-03-04 08:47:46 UTC (rev 959)
@@ -138,6 +138,7 @@
 	      strlist.h strlist.c \
 	      gpg-stuff.h gpg-stuff.c \
 	      convert.c convert.h \
+              membuf.c membuf.h \
 	      utils.c $(gpa_w32_sources) $(gpa_cardman_sources)
 
 dndtest_SOURCES = dndtest.c

Modified: trunk/src/cardman.c
===================================================================
--- trunk/src/cardman.c	2009-03-03 18:25:30 UTC (rev 958)
+++ trunk/src/cardman.c	2009-03-04 08:47:46 UTC (rev 959)
@@ -38,6 +38,7 @@
 #include "icons.h"
 #include "cardman.h"
 #include "convert.h"
+#include "membuf.h"
 
 #include "gpagenkeycardop.h"
 
@@ -62,11 +63,12 @@
 
   GtkUIManager *ui_manager;
 
+
+  GtkWidget *app_selector;    /* Combo Box to select the application.  */
   
   GtkWidget *card_container;  /* The container holding the card widget.  */
   GtkWidget *card_widget;     /* The widget to display a card applciation.  */
 
-
   /* Labels in the status bar.  */
   GtkWidget *status_label;
   GtkWidget *status_text;
@@ -99,7 +101,7 @@
 
 /* Local prototypes */
 static void start_ticker (GpaCardManager *cardman);
-static void update_card_widget (GpaCardManager *cardman);
+static void update_card_widget (GpaCardManager *cardman, const char *err_desc);
 
 static void gpa_card_manager_finalize (GObject *object);
 
@@ -258,7 +260,11 @@
 card_reload (GpaCardManager *cardman)
 {
   gpg_error_t err;
+  const char *application;
+  char *command_buf = NULL;
   const char *command;
+  const char *err_desc = NULL;
+  int auto_app;
 
   if (!cardman->gpgagent)
     return;  /* No support for GPGME_PROTOCOL_ASSUAN.  */
@@ -279,22 +285,80 @@
          command; this makes sure that scdaemon initalizes the card if
          that has not yet been done.  */
       command = "SCD SERIALNO";
+      if (cardman->app_selector 
+          && (gtk_combo_box_get_active 
+              (GTK_COMBO_BOX (cardman->app_selector)) > 0)
+          && (application = gtk_combo_box_get_active_text
+              (GTK_COMBO_BOX (cardman->app_selector))))
+        {
+          command_buf = g_strdup_printf ("%s %s", command, application);
+          command = command_buf;
+          auto_app = 0;
+        }
+      else
+        auto_app = 1;
       err = gpgme_op_assuan_transact (cardman->gpgagent,
                                       command,
                                       scd_data_cb, NULL,
                                       scd_inq_cb, NULL,
                                       scd_status_cb, cardman);
       if (!err)
-        err = gpgme_op_assuan_result (cardman->gpgagent)->err;
+        {
+          err = gpgme_op_assuan_result (cardman->gpgagent)->err;
+          if (!auto_app
+              && gpg_err_source (err) == GPG_ERR_SOURCE_SCD
+              && gpg_err_code (err) == GPG_ERR_CONFLICT)
+            {
+              /* Not in auto select mode and the scdaemon told us
+                 about a conflicting use.  We now do a restart and try
+                 again to display an application selection conflict
+                 error only if it is not due to our own connection to
+                 the scdaemon.  */
+              if (!gpgme_op_assuan_transact (cardman->gpgagent,
+                                             "SCD RESTART",
+                                             NULL, NULL, NULL, NULL,
+                                             NULL, NULL)
+                  && !gpgme_op_assuan_result (cardman->gpgagent)->err)
+                {
+                  err = gpgme_op_assuan_transact (cardman->gpgagent,
+                                                  command,
+                                                  scd_data_cb, NULL,
+                                                  scd_inq_cb, NULL,
+                                                  scd_status_cb, cardman);
+                  if (!err)
+                    err = gpgme_op_assuan_result (cardman->gpgagent)->err;
+                }
+            }
+        }
 
+
       if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
         ;
+      else if (gpg_err_source (err) == GPG_ERR_SOURCE_SCD
+               && gpg_err_code (err) == GPG_ERR_CONFLICT)
+        {
+          err_desc = auto_app
+            ? _("The selected card application is currently not available.")
+            : _("Another process is using a different card application "
+                "than the selected one.\n\n"
+                "You may change the application selection mode to "
+                "\"Auto\" to select the active application.");
+        }
+      else if (!auto_app
+               && gpg_err_source (err) == GPG_ERR_SOURCE_SCD
+               && gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
+        {
+          err_desc = 
+            _("The selected card application is not available.");
+        }
       else if (err)
         {
           g_debug ("assuan command `%s' failed: %s <%s>\n", 
                    command, gpg_strerror (err), gpg_strsource (err));
+          err_desc = _("Error accessing the card.");
           statusbar_update (cardman, _("Error accessing card"));
         }
+      g_free (command_buf);
 
  
       if (!err)
@@ -329,7 +393,7 @@
         }
 
       
-      update_card_widget (cardman);
+      update_card_widget (cardman, err_desc);
       update_title (cardman);
       
       update_info_visibility (cardman);
@@ -626,7 +690,7 @@
 
 
 static void
-update_card_widget (GpaCardManager *cardman)
+update_card_widget (GpaCardManager *cardman, const char *error_description)
 {
   if (cardman->card_widget)
     {
@@ -654,7 +718,13 @@
     }
   else
     {
-      cardman->card_widget = gtk_label_new (_("No card found."));
+      if (!error_description)
+        {
+          error_description = cardman->cardtype
+            ? _("This card application is not yet supported.")
+            : _("No card found.");
+        }
+      cardman->card_widget = gtk_label_new (error_description);
     }
 
   gtk_scrolled_window_add_with_viewport 
@@ -664,11 +734,82 @@
 }
 
 
+/* Handler for the "changed" signal of the application selector.  */
 static void
+app_selector_changed_cb (GtkComboBox *cbox, void *opaque)
+{
+  GpaCardManager *cardman = opaque;
+
+  g_object_ref (cardman);
+  g_idle_add (card_reload_idle_cb, cardman);
+}
+
+
+/* Assuan data callback used by setup_app_selector.  */
+static gpg_error_t
+setup_app_selector_data_cb (void *opaque, const void *data, size_t datalen)
+{
+  membuf_t *mb = opaque;
+
+  put_membuf (mb, data, datalen);
+
+  return 0;
+}
+
+
+/* Fill the app_selection box with the available applications.  */
+static void
+setup_app_selector (GpaCardManager *cardman)
+{
+  gpg_error_t err;
+  membuf_t mb;
+  char *string;
+  char *p, *p0, *p1;
+
+  if (!cardman->gpgagent || !cardman->app_selector)
+    return;
+
+  init_membuf (&mb, 256);
+
+  err = gpgme_op_assuan_transact (cardman->gpgagent,
+                                  "SCD GETINFO app_list",
+                                  setup_app_selector_data_cb, &mb,
+                                  NULL, NULL, NULL, NULL);
+  if (err || gpgme_op_assuan_result (cardman->gpgagent)->err)
+    {
+      g_free (get_membuf (&mb, NULL));
+      return;
+    }
+  /* Make sure the data is a string and get it. */
+  put_membuf (&mb, "", 1);
+  string = get_membuf (&mb, NULL);
+  if (!string)
+    return; /* Out of core.  */
+
+  for (p=p0=string; *p; p++)
+    {
+      if (*p == '\n')
+        {
+          *p = 0;
+          p1 = strchr (p0, ':');
+          if (p1)
+            *p1 = 0;
+          gtk_combo_box_append_text 
+            (GTK_COMBO_BOX (cardman->app_selector), p0);
+          if (p[1])
+            p0 = p+1;
+        }
+    }
+
+  g_free (string);
+}
+
+
+static void
 construct_widgets (GpaCardManager *cardman)
 {
   GtkWidget *vbox;
-  GtkWidget *hbox;
+  GtkWidget *hbox, *hbox1, *hbox2;
   GtkWidget *label;
   GtkWidget *icon;
   gchar *markup;
@@ -691,22 +832,39 @@
   gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0);
 
   /* Add a fancy label that tells us: This is the card manager.  */
-  hbox = gtk_hbox_new (FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
+  hbox1 = gtk_hbox_new (FALSE, 0);
   
   icon = gtk_image_new_from_stock (GPA_STOCK_CARDMAN, GTK_ICON_SIZE_DND);
-  gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox1), icon, FALSE, TRUE, 0);
 
   label = gtk_label_new (NULL);
   markup = g_strdup_printf ("<span font_desc=\"16\">%s</span>",
                             _("Card Manager"));
   gtk_label_set_markup (GTK_LABEL (label), markup);
   g_free (markup);
-  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
+  gtk_box_pack_start (GTK_BOX (hbox1), label, TRUE, TRUE, 10);
   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
 
-  /* Create a container (a scolled windows) which will take the actual
-     card widgte.  This container is required so that we can easily
+  /* Add a application selection box.  */
+  hbox2 = gtk_hbox_new (FALSE, 0);
+  label = gtk_label_new (_("Application selection:"));
+  gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 5);
+  cardman->app_selector = gtk_combo_box_new_text ();
+  gtk_combo_box_append_text (GTK_COMBO_BOX (cardman->app_selector),
+                             _("Auto"));
+  gtk_combo_box_set_active (GTK_COMBO_BOX (cardman->app_selector), 0);
+  gtk_box_pack_start (GTK_BOX (hbox2), cardman->app_selector, FALSE, TRUE, 0);
+
+  /* Put Card Manager label and application selector into the same line.  */
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), hbox1, FALSE, FALSE, 0);
+  gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
+
+
+  /* Create a container (a scolled window) which will take the actual
+     card widget.  This container is required so that we can easily
      change to a differet card widget. */
   cardman->card_container = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy 
@@ -715,7 +873,7 @@
   gtk_box_pack_start (GTK_BOX (vbox), cardman->card_container, TRUE, TRUE, 0);
 
   /* Update the container using the current card application.  */
-  update_card_widget (cardman);
+  update_card_widget (cardman, NULL);
 
   statusbar = statusbar_new (cardman);
   gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 0);
@@ -777,6 +935,13 @@
       gpgme_release (cardman->gpgagent);
       cardman->gpgagent = NULL;
     }
+
+  setup_app_selector (cardman);
+  if (cardman->app_selector)
+    g_signal_connect (cardman->app_selector, "changed",
+                      G_CALLBACK (app_selector_changed_cb), cardman);
+
+
 }
 
 

Added: trunk/src/membuf.c
===================================================================
--- trunk/src/membuf.c	2009-03-03 18:25:30 UTC (rev 958)
+++ trunk/src/membuf.c	2009-03-04 08:47:46 UTC (rev 959)
@@ -0,0 +1,104 @@
+/* membuf.c - A simple implementation of a dynamic buffer
+ *	Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "membuf.h"
+
+
+/* A simple implementation of a dynamic buffer.  Use init_membuf() to
+   create a buffer, put_membuf to append bytes and get_membuf to
+   release and return the buffer.  Allocation errors are detected but
+   only returned at the final get_membuf(), this helps not to clutter
+   the code with out of core checks.  */
+void
+init_membuf (membuf_t *mb, size_t initiallen)
+{
+  if (!initiallen)
+    initiallen = 1024;
+  mb->len = 0;
+  mb->size = initiallen;
+  mb->out_of_core = 0;
+  mb->buf = g_try_malloc (initiallen);
+  if (!mb->buf)
+    mb->out_of_core = errno;
+}
+
+
+void
+put_membuf (membuf_t *mb, const void *buf, size_t len)
+{
+  if (mb->out_of_core)
+    return;
+
+  if (mb->len + len >= mb->size)
+    {
+      char *p;
+      
+      mb->size += len + 1024;
+      p = g_try_realloc (mb->buf, mb->size);
+      if (!p)
+        {
+          mb->out_of_core = errno ? errno : ENOMEM;
+          /* Wipe out what we already accumulated.  This is required
+             in case we are storing sensitive data here.  The membuf
+             API does not provide another way to cleanup after an
+             error. */ 
+          memset (mb->buf, 0, mb->len);
+          return;
+        }
+      mb->buf = p;
+    }
+  memcpy (mb->buf + mb->len, buf, len);
+  mb->len += len;
+}
+
+
+void
+put_membuf_str (membuf_t *mb, const char *string)
+{
+  put_membuf (mb, string, strlen (string));
+}
+
+
+void *
+get_membuf (membuf_t *mb, size_t *len)
+{
+  char *p;
+
+  if (mb->out_of_core)
+    {
+      g_free (mb->buf);
+      mb->buf = NULL;
+      errno = mb->out_of_core;
+      return NULL;
+    }
+
+  p = mb->buf;
+  if (len)
+    *len = mb->len;
+  mb->buf = NULL;
+  mb->out_of_core = ENOMEM; /* Hack to make sure it won't get reused. */
+  return p;
+}

Added: trunk/src/membuf.h
===================================================================
--- trunk/src/membuf.h	2009-03-03 18:25:30 UTC (rev 958)
+++ trunk/src/membuf.h	2009-03-04 08:47:46 UTC (rev 959)
@@ -0,0 +1,46 @@
+/* membuf.h - A simple implementation of a dynamic buffer
+ *	Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GPA_MEMBUF_H
+#define GPA_MEMBUF_H
+
+/* The definition of the structure is private, we only need it here,
+   so it can be allocated on the stack. */
+struct private_membuf_s 
+{
+  size_t len;      
+  size_t size;     
+  char *buf;       
+  int out_of_core; 
+};
+
+typedef struct private_membuf_s membuf_t;
+
+/* Return the current length of the membuf.  */
+#define get_membuf_len(a)  ((a)->len)
+#define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
+#define MEMBUF_ZERO        { 0, 0, NULL, 0}
+
+void init_membuf (membuf_t *mb, size_t initiallen);
+void put_membuf  (membuf_t *mb, const void *buf, size_t len);
+void put_membuf_str (membuf_t *mb, const char *string);
+void *get_membuf (membuf_t *mb, size_t *len);
+
+
+#endif /*GPA_MEMBUF_H*/



More information about the Gpa-commits mailing list