[svn] GnuPG - r4850 - in trunk: agent doc po scd

svn author wk cvs at cvs.gnupg.org
Tue Oct 14 20:18:27 CEST 2008


Author: wk
Date: 2008-10-14 20:18:21 +0200 (Tue, 14 Oct 2008)
New Revision: 4850

Modified:
   trunk/agent/ChangeLog
   trunk/agent/call-scd.c
   trunk/agent/gpg-agent.c
   trunk/doc/gpgsm.texi
   trunk/po/be.po
   trunk/po/ca.po
   trunk/po/cs.po
   trunk/po/da.po
   trunk/po/de.po
   trunk/po/el.po
   trunk/po/eo.po
   trunk/po/es.po
   trunk/po/et.po
   trunk/po/fi.po
   trunk/po/gl.po
   trunk/po/hu.po
   trunk/po/id.po
   trunk/po/it.po
   trunk/po/ja.po
   trunk/po/nb.po
   trunk/po/pl.po
   trunk/po/pt.po
   trunk/po/pt_BR.po
   trunk/po/ro.po
   trunk/po/ru.po
   trunk/po/sk.po
   trunk/po/sv.po
   trunk/po/tr.po
   trunk/po/zh_CN.po
   trunk/po/zh_TW.po
   trunk/scd/ChangeLog
   trunk/scd/apdu.c
   trunk/scd/apdu.h
   trunk/scd/command.c
   trunk/scd/sc-copykeys.c
   trunk/scd/scdaemon.c
Log:
SCD changes for PC/SC under W32.


[The diff below has been truncated]

Modified: trunk/agent/ChangeLog
===================================================================
--- trunk/agent/ChangeLog	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/agent/ChangeLog	2008-10-14 18:18:21 UTC (rev 4850)
@@ -1,3 +1,8 @@
+2008-10-14  Werner Koch  <wk at g10code.com>
+
+	* gpg-agent.c (get_agent_scd_notify_event): Need to use a manual
+	reset event.
+
 2008-09-29  Werner Koch  <wk at g10code.com>
 
 	* agent.h (GCRY_MD_USER): Rename to GCRY_MODULE_ID_USER.

Modified: trunk/scd/ChangeLog
===================================================================
--- trunk/scd/ChangeLog	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/ChangeLog	2008-10-14 18:18:21 UTC (rev 4850)
@@ -1,3 +1,45 @@
+2008-10-14  Werner Koch  <wk at g10code.com>
+
+
+	* apdu.c (reader_table_s): Add fields connect_card and
+	disconnect_card.
+	(new_reader_slot): Set them to NULL.
+	(apdu_connect, apdu_disconnect): New.
+	(apdu_close_reader, apdu_shutdown_reader): Call apdu_disconnect.
+	(connect_pcsc_card, disconnect_pcsc_card): new.
+	(reset_pcsc_reader_direct): Implement in terms of
+	disconnect_pcsc_card and connect_pcsc_card.
+	(apdu_get_atr): Return NULL if there is no ATR.
+	* sc-copykeys.c (main): Add call to apdu_connect.
+	* command.c (open_card): Ditto.
+
+	* apdu.h (SW_HOST_ALREADY_CONNECTED): New.
+	(APDU_CARD_USABLE, APDU_CARD_PRESENT, APDU_CARD_ACTIVE): New.
+	* apdu.c: Replace constants by the new macros.
+	(open_pcsc_reader): Factor  code out to ...
+	(open_pcsc_reader_direct, open_pcsc_reader_wrapped): New.
+	(reset_pcsc_reader): Factor code out to ...
+	(reset_pcsc_reader_direct, reset_pcsc_reader_wrapped): New.
+	(pcsc_get_status): Factor code out to ...
+	(pcsc_get_status_direct, pcsc_get_status_wrapped): New.
+	(pcsc_send_apdu): Factor code out to ...
+	(pcsc_send_apdu_direct, pcsc_send_apdu_wrapped): New.
+	(close_pcsc_reader): Factor code out to ...
+	(close_pcsc_reader_direct, close_pcsc_reader_wrapped): New.
+
+	* command.c (update_reader_status_file): Open the reader if not
+	yet done.
+
+	* scdaemon.c (TIMERTICK_INTERVAL_SEC, TIMERTICK_INTERVAL_USEC):
+	New to replace TIMERTICK_INTERVAL.  Chnage from 2s (4 under W32)
+	to 250ms.
+
+2008-10-13  Werner Koch  <wk at g10code.com>
+
+	* command.c (option_handler) [W32]: Use strtoul with base 16.
+	(update_reader_status_file) [W32]: Set Event.
+	(scd_command_handler): Use INT2FD to silent warning.
+
 2008-09-29  Werner Koch  <wk at g10code.com>
 
 	* scdaemon.h (GCRY_MD_USER): Rename to GCRY_MODULE_ID_USER.

Modified: trunk/agent/call-scd.c
===================================================================
--- trunk/agent/call-scd.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/agent/call-scd.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -378,8 +378,10 @@
     char buf[100];
 
 #ifdef HAVE_W32_SYSTEM
-    snprintf (buf, sizeof buf, "OPTION event-signal=%lx", 
-              (unsigned long)get_agent_scd_notify_event ());
+    /* Use estream snprintf due to a bug in mingw32 related to the l
+       modifier.  */
+    estream_snprintf (buf, sizeof buf, "OPTION event-signal=%lx", 
+                      (unsigned long)get_agent_scd_notify_event ());
 #else
     snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
 #endif

Modified: trunk/agent/gpg-agent.c
===================================================================
--- trunk/agent/gpg-agent.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/agent/gpg-agent.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -1268,12 +1268,34 @@
 
   if (!the_event)
     {
+      HANDLE h, h2;
       SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
 
-      the_event = CreateEvent ( &sa, FALSE, FALSE, NULL);
-      if (!the_event)
+      /* We need to use manual reset evet object due to the way our
+         w32-pth wait function works: If we would use an automatic
+         reset event we are not able to figure out which handle has
+         been signaled because at the time we single out the signaled
+         handles using WFSO the event has already been reset due to
+         the WFMO.  */
+      h = CreateEvent (&sa, TRUE, FALSE, NULL);
+      if (!h)
         log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
+      else if (!DuplicateHandle (GetCurrentProcess(), h,
+                                 GetCurrentProcess(), &h2,
+                                 EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0)) 
+        {
+          log_error ("setting syncronize for scd notify event failed: %s\n",
+                     w32_strerror (-1) );
+          CloseHandle (h);
+        }
+      else
+        {
+          CloseHandle (h);
+          the_event = h2;
+        }
     }
+
+  log_debug  ("returning notify handle %p\n", the_event);
   return the_event;
 }
 #endif /*HAVE_W32_SYSTEM*/

Modified: trunk/doc/gpgsm.texi
===================================================================
--- trunk/doc/gpgsm.texi	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/doc/gpgsm.texi	2008-10-14 18:18:21 UTC (rev 4850)
@@ -226,7 +226,7 @@
 @opindex delete-keys
 Delete the keys matching @var{pattern}.  Note that there is no command
 to delete the secret part of the key directly.  In case you need to do
-this, you should run the command @code{gpg --dump-secret-keys KEYID}
+this, you should run the command @code{gpgsm --dump-secret-keys KEYID}
 before you delete the key, copy the string of hex-digits in the
 ``keygrip'' line and delete the file consisting of these hex-digits
 and the suffix @code{.key} from the @file{private-keys-v1.d} directory

Modified: trunk/po/be.po  [not shown]
Modified: trunk/po/ca.po  [not shown]
Modified: trunk/po/cs.po  [not shown]
Modified: trunk/po/da.po  [not shown]
Modified: trunk/po/de.po  [not shown]
Modified: trunk/po/el.po  [not shown]
Modified: trunk/po/eo.po  [not shown]
Modified: trunk/po/es.po  [not shown]
Modified: trunk/po/et.po  [not shown]
Modified: trunk/po/fi.po  [not shown]
Modified: trunk/po/gl.po  [not shown]
Modified: trunk/po/hu.po  [not shown]
Modified: trunk/po/id.po  [not shown]
Modified: trunk/po/it.po  [not shown]
Modified: trunk/po/ja.po  [not shown]
Modified: trunk/po/nb.po  [not shown]
Modified: trunk/po/pl.po  [not shown]
Modified: trunk/po/pt.po  [not shown]
Modified: trunk/po/pt_BR.po  [not shown]
Modified: trunk/po/ro.po  [not shown]
Modified: trunk/po/ru.po  [not shown]
Modified: trunk/po/sk.po  [not shown]
Modified: trunk/po/sv.po  [not shown]
Modified: trunk/po/tr.po  [not shown]
Modified: trunk/po/zh_CN.po  [not shown]
Modified: trunk/po/zh_TW.po  [not shown]
Modified: trunk/scd/apdu.c
===================================================================
--- trunk/scd/apdu.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/apdu.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -103,6 +103,8 @@
   unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
 
   /* Function pointers intialized to the various backends.  */
+  int (*connect_card)(int);
+  int (*disconnect_card)(int);
   int (*close_reader)(int);
   int (*shutdown_reader)(int);
   int (*reset_reader)(int);
@@ -291,6 +293,7 @@
 
 /*  Prototypes.  */
 static int pcsc_get_status (int slot, unsigned int *status);
+static int reset_pcsc_reader (int slot);
 
 
 
@@ -327,6 +330,8 @@
       reader_table[reader].lock_initialized = 1;
     }
 #endif /*USE_GNU_PTH*/
+  reader_table[reader].connect_card = NULL;
+  reader_table[reader].disconnect_card = NULL;
   reader_table[reader].close_reader = NULL;
   reader_table[reader].shutdown_reader = NULL;
   reader_table[reader].reset_reader = NULL;
@@ -386,6 +391,7 @@
     case SW_HOST_NO_READER: return "no reader";
     case SW_HOST_ABORTED: return "aborted";
     case SW_HOST_NO_KEYPAD: return "no keypad"; 
+    case SW_HOST_ALREADY_CONNECTED: return "already connected"; 
     default: return "unknown host status error";
     }
 }
@@ -536,10 +542,10 @@
 static int
 ct_get_status (int slot, unsigned int *status)
 {
-  *status = 1|2|4;  /* FIXME */
+  /* The status we returned is wrong but we don't care becuase ctAPI
+     is not anymore required.  */
+  *status = APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE;
   return 0;
-
-  return SW_HOST_NOT_SUPPORTED;
 }
 
 /* Actually send the APDU of length APDULEN to SLOT and return a
@@ -767,178 +773,87 @@
 static void
 dump_pcsc_reader_status (int slot)
 {
-  log_info ("reader slot %d: active protocol:", slot);
-  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T0))
-    log_printf (" T0");
-  else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
-    log_printf (" T1");
-  else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_RAW))
-    log_printf (" raw");
-  log_printf ("\n");
+  if (reader_table[slot].pcsc.card)
+    {
+      log_info ("reader slot %d: active protocol:", slot);
+      if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T0))
+        log_printf (" T0");
+      else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
+        log_printf (" T1");
+      else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_RAW))
+        log_printf (" raw");
+      log_printf ("\n");
+    }
+  else
+    log_info ("reader slot %d: not connected\n", slot);
 }
 
 
-/* Send an PC/SC reset command and return a status word on error or 0
-   on success. */
+#ifndef NEED_PCSC_WRAPPER
 static int
-reset_pcsc_reader (int slot)
+pcsc_get_status_direct (int slot, unsigned int *status)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
-  reader_table_t slotp;
-  size_t len;
-  int i, n;
-  unsigned char msgbuf[9];
-  unsigned int dummy_status;
-  int sw = SW_HOST_CARD_IO_ERROR;
+  struct pcsc_readerstate_s rdrstates[1];
 
-  slotp = reader_table + slot;
-
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
-    {
-      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return sw;
-    }
-
-  msgbuf[0] = 0x05; /* RESET command. */
-  len = 0;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
-    {
-      log_error ("error sending PC/SC RESET request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC RESET response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  if (len > DIM (slotp->atr))
-    {
-      log_error ("PC/SC returned a too large ATR (len=%lx)\n",
-                 (unsigned long)len);
-      sw = SW_HOST_GENERAL_ERROR;
-      goto command_failed;
-    }
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  memset (rdrstates, 0, sizeof *rdrstates);
+  rdrstates[0].reader = reader_table[slot].rdrname;
+  rdrstates[0].current_state = PCSC_STATE_UNAWARE;
+  err = pcsc_get_status_change (reader_table[slot].pcsc.context,
+                                0,
+                                rdrstates, 1);
+  if (err == PCSC_E_TIMEOUT)
+    err = 0; /* Timeout is no error error here. */
   if (err)
     {
-      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
+      log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
-      /* If the error code is no smart card, we should not considere
-         this a major error and close the wrapper.  */
-      sw = pcsc_error_to_sw (err);
-      if (err == PCSC_E_NO_SMARTCARD)
-        return sw;
-      goto command_failed;
-    }
-
-  /* The open function may return a zero for the ATR length to
-     indicate that no card is present.  */
-  n = len;
-  if (n)
-    {
-      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
-        {
-          log_error ("error receiving PC/SC RESET response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
-        }
-    }
-  slotp->atrlen = len;
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
-
-  return 0;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return sw;
-
-#else /* !NEED_PCSC_WRAPPER */
-  long err;
-  char reader[250];
-  unsigned long nreader, atrlen;
-  unsigned long card_state, card_protocol;
-
-  if (reader_table[slot].pcsc.card)
-    {
-      err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
-      if (err)
-        {
-          log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
-                     pcsc_error_string (err), err);
-          return SW_HOST_CARD_IO_ERROR;
-        }
-      reader_table[slot].pcsc.card = 0;
-    }
-
-  err = pcsc_connect (reader_table[slot].pcsc.context,
-                      reader_table[slot].rdrname,
-                      PCSC_SHARE_EXCLUSIVE,
-                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
-                      &reader_table[slot].pcsc.card,
-                      &reader_table[slot].pcsc.protocol);
-  if (err)
-    {
-      log_error ("pcsc_connect failed: %s (0x%lx)\n",
-                  pcsc_error_string (err), err);
-      reader_table[slot].pcsc.card = 0;
       return pcsc_error_to_sw (err);
     }
 
+  /*   log_debug  */
+  /*     ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
 
-  atrlen = DIM(reader_table[0].atr);
-  nreader = sizeof reader - 1;
-  err = pcsc_status (reader_table[slot].pcsc.card,
-                     reader, &nreader,
-                     &card_state, &card_protocol,
-                     reader_table[slot].atr, &atrlen);
-  if (err)
-    {
-      log_error ("pcsc_status failed: %s (0x%lx)\n",
-                  pcsc_error_string (err), err);
-      reader_table[slot].atrlen = 0;
-      return pcsc_error_to_sw (err);
-    }
-  if (atrlen > DIM (reader_table[0].atr))
-    log_bug ("ATR returned by pcsc_status is too large\n");
-  reader_table[slot].atrlen = atrlen;
-  reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
+  *status = 0;
+  if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
+    *status |= APDU_CARD_PRESENT;
+  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+    *status |= APDU_CARD_ACTIVE;
+#ifndef HAVE_W32_SYSTEM
+  /* We indicate a useful card if it is not in use by another
+     application.  This is because we only use exclusive access
+     mode.  */
+  if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+       == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
+       && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
+    *status |= APDU_CARD_USABLE;
+#else
+  /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
+     time when we are the only user (SCM SCR335) under Windows.  */
+  if ((*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+      == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+    *status |= APDU_CARD_USABLE;
+#endif
 
   return 0;
-#endif /* !NEED_PCSC_WRAPPER */
 }
+#endif /*!NEED_PCSC_WRAPPER*/
 
 
+#ifdef NEED_PCSC_WRAPPER
 static int
-pcsc_get_status (int slot, unsigned int *status)
+pcsc_get_status_wrapped (int slot, unsigned int *status)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len, full_len;
@@ -1030,7 +945,6 @@
   /* We are lucky: The wrapper already returns the data in the
      required format. */
   *status = buffer[3];
-
   return 0;
 
  command_failed:
@@ -1042,74 +956,63 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return sw;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#else /*!NEED_PCSC_WRAPPER*/
 
+static int
+pcsc_get_status (int slot, unsigned int *status)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return pcsc_get_status_wrapped (slot, status);
+#else
+  return pcsc_get_status_direct (slot, status);
+#endif
+}
+
+
+#ifndef NEED_PCSC_WRAPPER
+static int
+pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
+                       unsigned char *buffer, size_t *buflen, 
+                       struct pininfo_s *pininfo)
+{
   long err;
-  struct pcsc_readerstate_s rdrstates[1];
+  struct pcsc_io_request_s send_pci;
+  unsigned long recv_len;
 
-  memset (rdrstates, 0, sizeof *rdrstates);
-  rdrstates[0].reader = reader_table[slot].rdrname;
-  rdrstates[0].current_state = PCSC_STATE_UNAWARE;
-  err = pcsc_get_status_change (reader_table[slot].pcsc.context,
-                                0,
-                                rdrstates, 1);
-  if (err == PCSC_E_TIMEOUT)
-    err = 0; /* Timeout is no error error here. */
-  if (err)
-    {
-      log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      return pcsc_error_to_sw (err);
-    }
+  if (!reader_table[slot].atrlen
+      && (err = reset_pcsc_reader (slot)))
+    return err;
 
+  if (DBG_CARD_IO)
+    log_printhex ("  PCSC_data:", apdu, apdulen);
 
-  /*   log_debug  */
-  /*     ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
-  /*      (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
+  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
+      send_pci.protocol = PCSC_PROTOCOL_T1;
+  else
+      send_pci.protocol = PCSC_PROTOCOL_T0;
+  send_pci.pci_len = sizeof send_pci;
+  recv_len = *buflen;
+  err = pcsc_transmit (reader_table[slot].pcsc.card,
+                       &send_pci, apdu, apdulen,
+                       NULL, buffer, &recv_len);
+  *buflen = recv_len;
+  if (err)
+    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
+               pcsc_error_string (err), err);
 
-  *status = 0;
-  if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
-    *status |= 2;
-  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
-    *status |= 4;
-#ifndef HAVE_W32_SYSTEM
-  /* We indicate a useful card if it is not in use by another
-     application.  This is because we only use exclusive access
-     mode.  */
-  if ( (*status & 6) == 6
-       && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
-    *status |= 1;
-#else
-  /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
-     time when we are the only user (SCM SCR335) under Windows.  */
-  if ((*status & 6) == 6)
-    *status |= 1;
-#endif
-
-  return 0;
+  return pcsc_error_to_sw (err);
+}
 #endif /*!NEED_PCSC_WRAPPER*/
-}
 
 
-/* Actually send the APDU of length APDULEN to SLOT and return a
-   maximum of *BUFLEN data in BUFFER, the actual returned size will be
-   set to BUFLEN.  Returns: CT API error code. */
+#ifdef NEED_PCSC_WRAPPER
 static int
-pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen, 
-                struct pininfo_s *pininfo)
+pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
+                        unsigned char *buffer, size_t *buflen, 
+                        struct pininfo_s *pininfo)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len, full_len;
@@ -1215,43 +1118,43 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return sw;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#else /*!NEED_PCSC_WRAPPER*/
 
-  long err;
-  struct pcsc_io_request_s send_pci;
-  unsigned long recv_len;
+/* Send the APDU of length APDULEN to SLOT and return a maximum of
+   *BUFLEN data in BUFFER, the actual returned size will be stored at
+   BUFLEN.  Returns: A status word. */
+static int
+pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen, 
+                struct pininfo_s *pininfo)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return pcsc_send_apdu_wrapped (slot, apdu, apdulen, buffer, buflen, pininfo);
+#else
+  return pcsc_send_apdu_direct (slot, apdu, apdulen, buffer, buflen, pininfo);
+#endif
+}
 
-  if (!reader_table[slot].atrlen
-      && (err = reset_pcsc_reader (slot)))
-    return err;
 
-  if (DBG_CARD_IO)
-    log_printhex ("  PCSC_data:", apdu, apdulen);
-
-  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
-      send_pci.protocol = PCSC_PROTOCOL_T1;
-  else
-      send_pci.protocol = PCSC_PROTOCOL_T0;
-  send_pci.pci_len = sizeof send_pci;
-  recv_len = *buflen;
-  err = pcsc_transmit (reader_table[slot].pcsc.card,
-                       &send_pci, apdu, apdulen,
-                       NULL, buffer, &recv_len);
-  *buflen = recv_len;
-  if (err)
-    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
-               pcsc_error_string (err), err);
-
-  return pcsc_error_to_sw (err);
+#ifndef NEED_PCSC_WRAPPER
+static int
+close_pcsc_reader_direct (int slot)
+{
+  pcsc_release_context (reader_table[slot].pcsc.context);
+  xfree (reader_table[slot].rdrname);
+  reader_table[slot].rdrname = NULL;
+  reader_table[slot].used = 0;
+  return 0;
+}
 #endif /*!NEED_PCSC_WRAPPER*/
-}
 
 
+#ifdef NEED_PCSC_WRAPPER
 static int
-close_pcsc_reader (int slot)
+close_pcsc_reader_wrapped (int slot)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len;
@@ -1313,25 +1216,349 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return 0;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#else /*!NEED_PCSC_WRAPPER*/
 
-  pcsc_release_context (reader_table[slot].pcsc.context);
-  xfree (reader_table[slot].rdrname);
-  reader_table[slot].rdrname = NULL;
-  reader_table[slot].used = 0;
+static int
+close_pcsc_reader (int slot)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return close_pcsc_reader_wrapped (slot);
+#else
+  return close_pcsc_reader_direct (slot);
+#endif
+}
+
+
+/* Connect a PC/SC card.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+connect_pcsc_card (int slot)
+{
+  long err;
+
+  assert (slot >= 0 && slot < MAX_READER);
+
+  if (reader_table[slot].pcsc.card)
+    return SW_HOST_ALREADY_CONNECTED;
+
+  reader_table[slot].atrlen = 0;
+  reader_table[slot].last_status = 0;
+  reader_table[slot].is_t0 = 0;
+
+  err = pcsc_connect (reader_table[slot].pcsc.context,
+                      reader_table[slot].rdrname,
+                      PCSC_SHARE_EXCLUSIVE,
+                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
+                      &reader_table[slot].pcsc.card,
+                      &reader_table[slot].pcsc.protocol);
+  if (err)
+    {
+      reader_table[slot].pcsc.card = 0;
+      if (err != PCSC_E_NO_SMARTCARD) 
+        log_error ("pcsc_connect failed: %s (0x%lx)\n",
+                   pcsc_error_string (err), err);
+    }
+  else
+    {
+      char reader[250];
+      unsigned long readerlen, atrlen;
+      unsigned long card_state, card_protocol;
+
+      atrlen = DIM (reader_table[0].atr);
+      readerlen = sizeof reader -1 ;
+      err = pcsc_status (reader_table[slot].pcsc.card,
+                         reader, &readerlen,
+                         &card_state, &card_protocol,
+                         reader_table[slot].atr, &atrlen);
+      if (err)
+        log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
+                   pcsc_error_string (err), err, readerlen);
+      else
+        {
+          if (atrlen > DIM (reader_table[0].atr))
+            log_bug ("ATR returned by pcsc_status is too large\n");
+          reader_table[slot].atrlen = atrlen;
+          /* If we got to here we know that a card is present
+             and usable.  Remember this.  */
+          reader_table[slot].last_status = (   APDU_CARD_USABLE
+                                             | APDU_CARD_PRESENT
+                                             | APDU_CARD_ACTIVE
+                                             | 0x8000);
+          reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
+        }
+    }
+
+  dump_reader_status (slot);
+  return pcsc_error_to_sw (err);
+}
+#endif /*!NEED_PCSC_WRAPPER*/
+
+
+/* Disconnect a PC/SC card.  Note that this succeeds even if the card
+   is not connected.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+disconnect_pcsc_card (int slot)
+{
+  long err;
+
+  assert (slot >= 0 && slot < MAX_READER);
+
+  if (!reader_table[slot].pcsc.card)
+    return 0; 
+
+  err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
+  if (err)
+    {
+      log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return SW_HOST_CARD_IO_ERROR;
+    }
+  reader_table[slot].pcsc.card = 0;
   return 0;
+}
 #endif /*!NEED_PCSC_WRAPPER*/
+
+
+#ifndef NEED_PCSC_WRAPPER
+static int
+reset_pcsc_reader_direct (int slot)
+{
+  int sw;
+
+  sw = disconnect_pcsc_card (slot);
+  if (!sw)
+    sw = connect_pcsc_card (slot);
+
+  return sw;
 }
+#endif /*NEED_PCSC_WRAPPER*/
 
-/* Note:  It is a pitty that we can't return proper error codes.  */
+
+#ifdef NEED_PCSC_WRAPPER
 static int
-open_pcsc_reader (const char *portstr)
+reset_pcsc_reader_wrapped (int slot)
 {
+  long err;
+  reader_table_t slotp;
+  size_t len;
+  int i, n;
+  unsigned char msgbuf[9];
+  unsigned int dummy_status;
+  int sw = SW_HOST_CARD_IO_ERROR;
+
+  slotp = reader_table + slot;
+
+  if (slotp->pcsc.req_fd == -1
+      || slotp->pcsc.rsp_fd == -1
+      || slotp->pcsc.pid == (pid_t)(-1) )
+    {
+      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
+      return sw;
+    }
+
+  msgbuf[0] = 0x05; /* RESET command. */
+  len = 0;
+  msgbuf[1] = (len >> 24);
+  msgbuf[2] = (len >> 16);
+  msgbuf[3] = (len >>  8);
+  msgbuf[4] = (len      );
+  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
+    {
+      log_error ("error sending PC/SC RESET request: %s\n",
+                 strerror (errno));
+      goto command_failed;
+    }
+
+  /* Read the response. */
+  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
+    {
+      log_error ("error receiving PC/SC RESET response: %s\n",
+                 i? strerror (errno) : "premature EOF");
+      goto command_failed;
+    }
+  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  if (msgbuf[0] != 0x81 || len < 4)
+    {
+      log_error ("invalid response header from PC/SC received\n");
+      goto command_failed;
+    }
+  len -= 4; /* Already read the error code. */
+  if (len > DIM (slotp->atr))
+    {
+      log_error ("PC/SC returned a too large ATR (len=%lx)\n",
+                 (unsigned long)len);
+      sw = SW_HOST_GENERAL_ERROR;
+      goto command_failed;
+    }
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  if (err)
+    {
+      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      /* If the error code is no smart card, we should not considere
+         this a major error and close the wrapper.  */
+      sw = pcsc_error_to_sw (err);
+      if (err == PCSC_E_NO_SMARTCARD)
+        return sw;
+      goto command_failed;
+    }
+
+  /* The open function may return a zero for the ATR length to
+     indicate that no card is present.  */
+  n = len;
+  if (n)
+    {
+      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
+        {
+          log_error ("error receiving PC/SC RESET response: %s\n",
+                     i? strerror (errno) : "premature EOF");
+          goto command_failed;
+        }
+    }
+  slotp->atrlen = len;
+
+  /* Read the status so that IS_T0 will be set. */
+  pcsc_get_status (slot, &dummy_status);
+
+  return 0;
+
+ command_failed:
+  close (slotp->pcsc.req_fd);
+  close (slotp->pcsc.rsp_fd);
+  slotp->pcsc.req_fd = -1;
+  slotp->pcsc.rsp_fd = -1;
+  kill (slotp->pcsc.pid, SIGTERM);
+  slotp->pcsc.pid = (pid_t)(-1);
+  slotp->used = 0;
+  return sw;
+}
+#endif /* !NEED_PCSC_WRAPPER */
+
+
+/* Send an PC/SC reset command and return a status word on error or 0
+   on success. */
+static int
+reset_pcsc_reader (int slot)
+{
 #ifdef NEED_PCSC_WRAPPER
+  return reset_pcsc_reader_wrapped (slot);
+#else
+  return reset_pcsc_reader_direct (slot);
+#endif
+}
+
+
+/* Open the PC/SC reader without using the wrapper.  Returns -1 on
+   error or a slot number for the reader.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+open_pcsc_reader_direct (const char *portstr)
+{
+  long err;
+  int slot;
+  char *list = NULL;
+  unsigned long nreader, listlen;
+  char *p;
+
+  slot = new_reader_slot ();
+  if (slot == -1)
+    return -1;
+
+  /* Fixme: Allocating a context for each slot is not required.  One
+     global context should be sufficient.  */
+  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
+                                &reader_table[slot].pcsc.context);
+  if (err)
+    {
+      log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+
+  err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                           NULL, NULL, &nreader);
+  if (!err)
+    {
+      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
+      if (!list)
+        {
+          log_error ("error allocating memory for reader list\n");
+          pcsc_release_context (reader_table[slot].pcsc.context);
+          reader_table[slot].used = 0;
+          return -1 /*SW_HOST_OUT_OF_CORE*/;
+        }
+      err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                               NULL, list, &nreader);
+    }
+  if (err)
+    {
+      log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      xfree (list);
+      return -1;
+    }
+
+  listlen = nreader;
+  p = list;
+  while (nreader)
+    {
+      if (!*p && !p[1])
+        break;
+      if (*p)
+        log_info ("detected reader `%s'\n", p);
+      if (nreader < (strlen (p)+1))
+        {
+          log_error ("invalid response from pcsc_list_readers\n");
+          break;
+        }
+      nreader -= strlen (p)+1;
+      p += strlen (p) + 1;
+    }
+
+  reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
+  if (!reader_table[slot].rdrname)
+    {
+      log_error ("error allocating memory for reader name\n");
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
+  xfree (list);
+  list = NULL;
+
+  reader_table[slot].pcsc.card = 0;
+  reader_table[slot].atrlen = 0;
+  reader_table[slot].last_status = 0;
+
+  reader_table[slot].connect_card = connect_pcsc_card;
+  reader_table[slot].disconnect_card = disconnect_pcsc_card;
+  reader_table[slot].close_reader = close_pcsc_reader;
+  reader_table[slot].reset_reader = reset_pcsc_reader;
+  reader_table[slot].get_status_reader = pcsc_get_status;
+  reader_table[slot].send_apdu_reader = pcsc_send_apdu;
+  reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
+
+  dump_reader_status (slot);
+  return slot;
+}
+#endif /*!NEED_PCSC_WRAPPER */
+
+
 /* Open the PC/SC reader using the pcsc_wrapper program.  This is
    needed to cope with different thread models and other peculiarities
    of libpcsclite. */
+#ifdef NEED_PCSC_WRAPPER
+static int
+open_pcsc_reader_wrapped (const char *portstr)
+{
   int slot;
   reader_table_t slotp;
   int fd, rp[2], wp[2];
@@ -1358,8 +1585,8 @@
     return -1;
   slotp = reader_table + slot;
 
-  /* Fire up the pcsc wrapper.  We don't use any fork/exec code from
-     the common directy but implement it direclty so that this file
+  /* Fire up the PC/SCc wrapper.  We don't use any fork/exec code from
+     the common directy but implement it directly so that this file
      may still be source copied. */
 
   if (pipe (rp) == -1)
@@ -1449,7 +1676,7 @@
 #endif
   while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
     ;
-#undef X
+#undef WAIT
 
   /* Now send the open request. */
   msgbuf[0] = 0x01; /* OPEN command. */
@@ -1509,7 +1736,10 @@
         }
       /* If we got to here we know that a card is present
          and usable.  Thus remember this.  */
-      slotp->last_status = (1|2|4| 0x8000);
+      slotp->last_status = (  APDU_CARD_USABLE
+                            | APDU_CARD_PRESENT
+                            | APDU_CARD_ACTIVE
+                            | 0x8000);
     }
   slotp->atrlen = len;
 
@@ -1517,7 +1747,6 @@
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
-  reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
   /* Read the status so that IS_T0 will be set. */
@@ -1537,146 +1766,21 @@
   /* There is no way to return SW. */
   return -1;
 
-#else /*!NEED_PCSC_WRAPPER */
-  long err;
-  int slot;
-  char *list = NULL;
-  unsigned long nreader, listlen, atrlen;
-  char *p;
-  unsigned long card_state, card_protocol;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-  slot = new_reader_slot ();
-  if (slot == -1)
-    return -1;
 
-  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
-                                &reader_table[slot].pcsc.context);
-  if (err)
-    {
-      log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      reader_table[slot].used = 0;
-      return -1;
-    }
-
-  err = pcsc_list_readers (reader_table[slot].pcsc.context,
-                           NULL, NULL, &nreader);
-  if (!err)
-    {
-      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
-      if (!list)
-        {
-          log_error ("error allocating memory for reader list\n");
-          pcsc_release_context (reader_table[slot].pcsc.context);
-          reader_table[slot].used = 0;
-          return -1 /*SW_HOST_OUT_OF_CORE*/;
-        }
-      err = pcsc_list_readers (reader_table[slot].pcsc.context,
-                               NULL, list, &nreader);
-    }
-  if (err)
-    {
-      log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      pcsc_release_context (reader_table[slot].pcsc.context);
-      reader_table[slot].used = 0;
-      xfree (list);
-      return -1 /*pcsc_error_to_sw (err)*/;
-    }
-
-  listlen = nreader;
-  p = list;
-  while (nreader)
-    {
-      if (!*p && !p[1])
-        break;
-      if (*p)
-        log_info ("detected reader `%s'\n", p);
-      if (nreader < (strlen (p)+1))
-        {
-          log_error ("invalid response from pcsc_list_readers\n");
-          break;
-        }
-      nreader -= strlen (p)+1;
-      p += strlen (p) + 1;
-    }
-
-  reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
-  if (!reader_table[slot].rdrname)
-    {
-      log_error ("error allocating memory for reader name\n");
-      pcsc_release_context (reader_table[slot].pcsc.context);
-      reader_table[slot].used = 0;
-      return -1 /*SW_HOST_OUT_OF_CORE*/;
-    }
-  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
-  xfree (list);
-  list = NULL;
-
-  err = pcsc_connect (reader_table[slot].pcsc.context,
-                      reader_table[slot].rdrname,
-                      PCSC_SHARE_EXCLUSIVE,
-                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
-                      &reader_table[slot].pcsc.card,
-                      &reader_table[slot].pcsc.protocol);
-  if (err == PCSC_E_NO_SMARTCARD) 
-    reader_table[slot].pcsc.card = 0;
-  else if (err)
-    {
-      log_error ("pcsc_connect failed: %s (0x%lx)\n",
-                  pcsc_error_string (err), err);
-      pcsc_release_context (reader_table[slot].pcsc.context);
-      xfree (reader_table[slot].rdrname);
-      reader_table[slot].rdrname = NULL;
-      reader_table[slot].used = 0;
-      return -1 /*pcsc_error_to_sw (err)*/;
-    }
-
-  reader_table[slot].atrlen = 0;
-  reader_table[slot].last_status = 0;
-  if (!err)
-    {
-      char reader[250];
-      unsigned long readerlen;
-
-      atrlen = DIM (reader_table[0].atr);
-      readerlen = sizeof reader -1 ;
-      err = pcsc_status (reader_table[slot].pcsc.card,
-                         reader, &readerlen,
-                         &card_state, &card_protocol,
-                         reader_table[slot].atr, &atrlen);
-      if (err)
-        log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
-                   pcsc_error_string (err), err, readerlen);
-      else
-        {
-          if (atrlen > DIM (reader_table[0].atr))
-            log_bug ("ATR returned by pcsc_status is too large\n");
-          reader_table[slot].atrlen = atrlen;
-          /* If we got to here we know that a card is present
-             and usable.  Thus remember this.  */
-          reader_table[slot].last_status = (1|2|4| 0x8000);
-          reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
-        }
-    }
-
-  reader_table[slot].close_reader = close_pcsc_reader;
-  reader_table[slot].reset_reader = reset_pcsc_reader;
-  reader_table[slot].get_status_reader = pcsc_get_status;
-  reader_table[slot].send_apdu_reader = pcsc_send_apdu;
-  reader_table[slot].check_keypad = NULL;
-  reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
-
-/*   log_debug ("state    from pcsc_status: 0x%lx\n", card_state); */
-/*   log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
-
-  dump_reader_status (slot);
-  return slot;
-#endif /*!NEED_PCSC_WRAPPER */
+static int
+open_pcsc_reader (const char *portstr)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return open_pcsc_reader_wrapped (portstr);
+#else
+  return open_pcsc_reader_direct (portstr);
+#endif
 }
 
 
-
 
 #ifdef HAVE_LIBUSB
 /*
@@ -1738,9 +1842,9 @@
     return -1;
 
   if (bits == 0)
-    *status = 1|2|4;
+    *status = (APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE);
   else if (bits == 1)
-    *status = 2;
+    *status = APDU_CARD_PRESENT;
   else
     *status = 0;
 
@@ -1836,7 +1940,10 @@
     {
       /* If we got to here we know that a card is present
          and usable.  Thus remember this.  */
-      reader_table[slot].last_status = (1|2|4| 0x8000);
+      reader_table[slot].last_status = (APDU_CARD_USABLE
+                                        | APDU_CARD_PRESENT
+                                        | APDU_CARD_ACTIVE 
+                                        | 0x8000);
     }
 
   reader_table[slot].close_reader = close_ccid_reader;
@@ -2335,7 +2442,11 @@
       pcsc_api_loaded = 1;
     }
 
+#ifdef NEED_PCSC_WRAPPER
+  return open_pcsc_reader_wrapped (portstr);
+#else
   return open_pcsc_reader (portstr);
+#endif
 }
 
 
@@ -2378,21 +2489,31 @@
 int
 apdu_close_reader (int slot)
 {
+  int sw;
+
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
+  sw = apdu_disconnect (slot);
+  if (sw)
+    return sw;
   if (reader_table[slot].close_reader)
     return reader_table[slot].close_reader (slot);
   return SW_HOST_NOT_SUPPORTED;
 }
 
 /* Shutdown a reader; that is basically the same as a close but keeps
-   the handle ready for later use. A apdu_reset_reader should be used
-   to get it active again. */
+   the handle ready for later use. A apdu_reset_reader or apdu_connect
+   should be used to get it active again. */
 int
 apdu_shutdown_reader (int slot)
 {
+  int sw;
+
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
+  sw = apdu_disconnect (slot);
+  if (sw)
+    return sw;
   if (reader_table[slot].shutdown_reader)
     return reader_table[slot].shutdown_reader (slot);
   return SW_HOST_NOT_SUPPORTED;
@@ -2410,6 +2531,58 @@
   return 0;
 }
 
+
+/* Connect a card.  This is used to power up the card and make sure
+   that an ATR is available.  */
+int
+apdu_connect (int slot)
+{
+  int sw;
+
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+
+  /* Only if the access method provides a connect function we use it.
+     If not, we expect that the card has been implicitly connected by
+     apdu_open_reader.  */
+  if (reader_table[slot].connect_card)
+    {
+      sw = lock_slot (slot);
+      if (!sw)
+        {
+          sw = reader_table[slot].connect_card (slot);
+          unlock_slot (slot);
+        }
+    }
+  else
+    sw = 0;
+  return sw;
+}
+
+int
+apdu_disconnect (int slot)
+{
+  int sw;
+
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+
+  if (reader_table[slot].disconnect_card)
+    {
+      sw = lock_slot (slot);
+      if (!sw)
+        {
+          sw = reader_table[slot].disconnect_card (slot);
+          unlock_slot (slot);
+        }
+    }
+  else
+    sw = 0;
+  return sw;
+}
+
+
+
 /* Do a reset for the card in reader at SLOT. */
 int
 apdu_reset (int slot)
@@ -2430,7 +2603,10 @@
     {
       /* If we got to here we know that a card is present
          and usable.  Thus remember this.  */
-      reader_table[slot].last_status = (1|2|4| 0x8000);
+      reader_table[slot].last_status = (APDU_CARD_USABLE
+                                        | APDU_CARD_PRESENT
+                                        | APDU_CARD_ACTIVE 
+                                        | 0x8000);
     }
 
   unlock_slot (slot);
@@ -2474,7 +2650,10 @@
                 {
                   /* If we got to here we know that a card is present
                      and usable.  Thus remember this.  */
-                  reader_table[slot].last_status = (1|2|4| 0x8000);
+                  reader_table[slot].last_status = (APDU_CARD_USABLE
+                                                    | APDU_CARD_PRESENT
+                                                    | APDU_CARD_ACTIVE
+                                                    | 0x8000);
                 }
             }
         }
@@ -2493,7 +2672,8 @@
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return NULL;
-
+  if (!reader_table[slot].atrlen)
+    return NULL;
   buf = xtrymalloc (reader_table[slot].atrlen);
   if (!buf)
     return NULL;
@@ -2508,12 +2688,12 @@
    card to become available if HANG is set to true. On success the
    bits in STATUS will be set to
 
-     bit 0 = card present and usable
-     bit 1 = card present
-     bit 2 = card active
-     bit 3 = card access locked [not yet implemented]
+     APDU_CARD_USABLE  (bit 0) = card present and usable
+     APDU_CARD_PRESENT (bit 1) = card present
+     APDU_CARD_ACTIVE  (bit 2) = card active
+                       (bit 3) = card access locked [not yet implemented]
 
-   For must application, testing bit 0 is sufficient.
+   For must applications, testing bit 0 is sufficient.
 
    CHANGED will receive the value of the counter tracking the number
    of card insertions.  This value may be used to detect a card

Modified: trunk/scd/apdu.h
===================================================================
--- trunk/scd/apdu.h	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/apdu.h	2008-10-14 18:18:21 UTC (rev 4850)
@@ -65,13 +65,20 @@
   SW_HOST_GENERAL_ERROR = 0x1000b,
   SW_HOST_NO_READER     = 0x1000c,
   SW_HOST_ABORTED       = 0x1000d,
-  SW_HOST_NO_KEYPAD     = 0x1000e
+  SW_HOST_NO_KEYPAD     = 0x1000e,
+  SW_HOST_ALREADY_CONNECTED = 0x1000f
 };
 
 
 #define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
 
 
+/* Bit flags for the card status.  */
+#define APDU_CARD_USABLE   (1)    /* Card is present and ready for use.  */
+#define APDU_CARD_PRESENT  (2)    /* Card is just present.  */
+#define APDU_CARD_ACTIVE   (4)    /* Card is active.  */
+
+
 /* Note , that apdu_open_reader returns no status word but -1 on error. */
 int apdu_open_reader (const char *portstr);
 int apdu_open_remote_reader (const char *portstr,
@@ -92,8 +99,11 @@
 const char *apdu_strerror (int rc);
 
 
-/* These apdu functions do return status words. */
+/* These APDU functions return status words. */
 
+int apdu_connect (int slot);
+int apdu_disconnect (int slot);
+
 int apdu_activate (int slot);
 int apdu_reset (int slot);
 int apdu_get_status (int slot, int hang,

Modified: trunk/scd/command.c
===================================================================
--- trunk/scd/command.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/command.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -102,8 +102,12 @@
   /* The Assuan context used by this session/server. */
   assuan_context_t assuan_ctx;
 
-  int event_signal;        /* Or 0 if not used. */
-
+#ifdef HAVE_W32_SYSTEM
+  unsigned long event_signal;   /* Or 0 if not used. */
+#else
+  int event_signal;             /* Or 0 if not used. */
+#endif
+  
   /* True if the card has been removed and a reset is required to
      continue operation. */
   int card_removed;        
@@ -165,6 +169,7 @@
       {
         sl->card_removed = value;
       }
+  /* Let the card application layer know about the removal.  */
   if (value)
     application_notify_card_removed (slot);
 }
@@ -319,10 +324,16 @@
   if (!strcmp (key, "event-signal"))
     {
       /* A value of 0 is allowed to reset the event signal. */
+#ifdef HAVE_W32_SYSTEM
+      if (!*value)
+        return gpg_error (GPG_ERR_ASS_PARAMETER);
+      ctrl->server_local->event_signal = strtoul (value, NULL, 16);
+#else
       int i = *value? atoi (value) : -1;
       if (i < 0)
         return gpg_error (GPG_ERR_ASS_PARAMETER);
       ctrl->server_local->event_signal = i;
+#endif
     }
 
  return 0;
@@ -389,7 +400,15 @@
   if (slot == -1)
     err = gpg_error (GPG_ERR_CARD);
   else
-    err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+    {
+      /* Fixme: We should move the apdu_connect call to
+         select_application.  */
+      int sw = apdu_connect (slot);
+      if (sw && sw != SW_HOST_ALREADY_CONNECTED)
+        err = gpg_error (GPG_ERR_CARD);
+      else
+        err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+    }
 
   TEST_CARD_REMOVAL (ctrl, err);
   return err;
@@ -1774,7 +1793,7 @@
     }
   else
     {
-      rc = assuan_init_socket_server_ext (&ctx, fd, 2);
+      rc = assuan_init_socket_server_ext (&ctx, INT2FD(fd), 2);
     }
   if (rc)
     {
@@ -1911,6 +1930,11 @@
   int idx;
   unsigned int status, changed;
 
+  /* Make sure that the reader has been opened.  Like get_reader_slot,
+     this part of the code assumes that there is only one reader.  */
+  if (!slot_table[0].valid)
+    (void)get_reader_slot ();
+
   /* Note, that we only try to get the status, because it does not
      make sense to wait here for a operation to complete.  If we are
      busy working with a card, delays in the status file update should
@@ -2007,11 +2031,20 @@
             if (sl->event_signal && sl->assuan_ctx)
               {
                 pid_t pid = assuan_get_pid (sl->assuan_ctx);
+
+#ifdef HAVE_W32_SYSTEM
+                HANDLE handle = (void *)sl->event_signal;
+                
+                log_info ("client pid is %d, triggering event %lx (%p)\n",
+                          pid, sl->event_signal, handle);
+                if (!SetEvent (handle))
+                  log_error ("SetEvent(%lx) failed: %s\n",
+                             sl->event_signal, w32_strerror (-1));
+#else
                 int signo = sl->event_signal;
                 
                 log_info ("client pid is %d, sending signal %d\n",
                           pid, signo);
-#ifndef HAVE_W32_SYSTEM
                 if (pid != (pid_t)(-1) && pid && signo > 0)
                   kill (pid, signo);
 #endif

Modified: trunk/scd/sc-copykeys.c
===================================================================
--- trunk/scd/sc-copykeys.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/sc-copykeys.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -142,6 +142,8 @@
   slot = apdu_open_reader (reader_port);
   if (slot == -1)
     exit (1);
+  if (apdu_connect (slot))
+    exit (1);
 
   /* FIXME: Use select_application. */
   appbuf.slot = slot;

Modified: trunk/scd/scdaemon.c
===================================================================
--- trunk/scd/scdaemon.c	2008-10-13 09:42:32 UTC (rev 4849)
+++ trunk/scd/scdaemon.c	2008-10-14 18:18:21 UTC (rev 4850)
@@ -148,15 +148,18 @@
 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
 #endif
 
-/* The timer tick used for housekeeping stuff.  For Windows we use a
-   longer period as the SetWaitableTimer seems to signal earlier than
-   the 2 seconds.  */
-#ifdef HAVE_W32_SYSTEM
-#define TIMERTICK_INTERVAL    (4)
-#else




More information about the Gnupg-commits mailing list