Re: display support

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Re: display support

Andreas Steffen-2
Hi Martin,

here are my patches which allow the use of the Kobil Kaan Professional
reader's display and key pad via the

  opensc-tool --output

and

  opensc-tool --input

function calls. The Kaan's display size is currently hardcoded into
opensc-tool.c:

  const int display_len = 32; /* size of the Kobil Kaan display */

Regards

Andreas

Martin Paljak wrote:
> Hello!
>
> I heard you are dealing with display support for opensc-openct. As I
> develop something related to it (namely pinpad support in opensc and
> related UI issues) i'd like to know what you are doing and how, so
> that both worlds would fit together.
>
> peace,
> m.

=======================================================================
Andreas Steffen                   e-mail: [hidden email]
strongSec GmbH                    home:   http://www.strongsec.com
Alter Z├╝richweg 20                phone:  +41 1 730 80 64
CH-8952 Schlieren (Switzerland)   fax:    +41 1 730 80 65
==========================================[strong internet security]===

diff -urN openct-0.6.5/src/ct/client.c openct-0.6.5-strongswan/src/ct/client.c
--- openct-0.6.5/src/ct/client.c 2005-05-10 22:08:02.000000000 +0200
+++ openct-0.6.5-strongswan/src/ct/client.c 2005-06-06 18:43:03.000000000 +0200
@@ -142,6 +142,40 @@
 }
 
 /*
+ * Put a prompt on the reader's display and get input via the pin pad
+ */
+int
+ct_reader_input(ct_handle *h, const char *message,
+ void *recv_buf, size_t recv_len)
+{
+ ct_tlv_parser_t tlv;
+ unsigned char buffer[256];
+ ct_buf_t args, resp;
+ int rc;
+ int i;
+
+ ct_buf_init(&args, buffer, sizeof(buffer));
+ ct_buf_init(&resp, buffer, sizeof(buffer));
+
+ ct_buf_putc(&args, CT_CMD_INPUT);
+ ct_buf_putc(&args, CT_UNIT_READER);
+
+ /* Add arguments if given */
+ if (message)
+ ct_args_string(&args, CT_TAG_MESSAGE, message);
+
+ rc = ct_socket_call(h->sock, &args, &resp);
+ if (rc < 0)
+ return rc;
+
+ rc = ct_tlv_parse(&tlv, &resp);
+ if (rc < 0)
+ return rc;
+
+ return ct_tlv_get_bytes(&tlv, CT_TAG_DATA, recv_buf, recv_len);
+}
+
+/*
  * Get card status
  */
 int
diff -urN openct-0.6.5/src/ct/tlv.c openct-0.6.5-strongswan/src/ct/tlv.c
--- openct-0.6.5/src/ct/tlv.c 2005-03-22 09:02:16.000000000 +0100
+++ openct-0.6.5-strongswan/src/ct/tlv.c 2005-06-06 18:43:03.000000000 +0200
@@ -48,7 +48,7 @@
  len = (len << 8) | p[header++];
  }
 
- if (len == 0 || header + len > avail)
+ if (header + len > avail)
  return -1;
 
  parser->val[tag] = p + header;
diff -urN openct-0.6.5/src/ifd/ctbcs.c openct-0.6.5-strongswan/src/ifd/ctbcs.c
--- openct-0.6.5/src/ifd/ctbcs.c 2005-03-22 09:02:12.000000000 +0100
+++ openct-0.6.5-strongswan/src/ifd/ctbcs.c 2005-06-06 18:43:03.000000000 +0200
@@ -59,6 +59,26 @@
 }
 
 /*
+ * Put a prompt on the reader's display in order to get input via the pin pad
+ */
+int
+ctbcs_build_input(unsigned char *cmd, size_t size, const char *message)
+{
+ ct_buf_t buf;
+ int len;
+
+ if (message == NULL)
+ return IFD_ERROR_INVALID_ARG;
+
+ ct_buf_init(&buf, cmd, size);
+ ctbcs_begin(&buf, 0x16, 0x50, 0x01);
+ ctbcs_add_message(&buf, message);
+ len = ctbcs_finish(&buf);
+ ct_buf_putc(&buf, 0x00);  /* le */
+ return len + 1;
+}
+
+/*
  * Generic Verify APDU
  */
 int
diff -urN openct-0.6.5/src/ifd/ctbcs.h openct-0.6.5-strongswan/src/ifd/ctbcs.h
--- openct-0.6.5/src/ifd/ctbcs.h 2005-03-22 09:02:12.000000000 +0100
+++ openct-0.6.5-strongswan/src/ifd/ctbcs.h 2005-06-06 18:43:03.000000000 +0200
@@ -10,6 +10,8 @@
 
 extern int ctbcs_build_output(unsigned char *cmd, size_t size,
        const char *message);
+extern int ctbcs_build_input(unsigned char *cmd, size_t size,
+       const char *message);
 extern int ctbcs_build_perform_verify_apdu(
  unsigned char *cmd, size_t size,
  unsigned int slot, const char *prompt,
diff -urN openct-0.6.5/src/ifd/ifd-kaan.c openct-0.6.5-strongswan/src/ifd/ifd-kaan.c
--- openct-0.6.5/src/ifd/ifd-kaan.c 2005-03-22 09:02:13.000000000 +0100
+++ openct-0.6.5-strongswan/src/ifd/ifd-kaan.c 2005-06-06 18:43:03.000000000 +0200
@@ -584,15 +584,15 @@
  * Output a string to the display
  */
 static int
-kaan_display(ifd_reader_t *reader, const char *string)
+kaan_display(ifd_reader_t *reader, const char *message)
 {
- unsigned char buffer[256] = { 0x20, 0x17, 0x40, 00 };
+ unsigned char buffer[256] = { 0x20, 0x17, 0x40, 0x00 };
  int rc, n;
 
  if (!(reader->flags & IFD_READER_DISPLAY))
  return 0;
 
- n = ctbcs_build_output(buffer, sizeof(buffer), string);
+ n = ctbcs_build_output(buffer, sizeof(buffer), message);
  if (n < 0)
  return n;
 
@@ -601,6 +601,44 @@
 }
 
 /*
+ * Put a prompt on the reader's display and get input via the pin pad
+ */
+static int
+kaan_input(ifd_reader_t *reader, const char *message,
+  unsigned char *resp, size_t resp_len)
+{
+ unsigned char buffer[256] = { 0x20, 0x16, 0x50, 0x01 };
+ int n;
+ unsigned short sw;
+
+ if (!((reader->flags & IFD_READER_DISPLAY)
+ && (reader->flags & IFD_READER_KEYPAD)))
+ return 0;
+
+ n = ctbcs_build_input(buffer, sizeof(buffer), message);
+ if (n < 0)
+ return n;
+
+ n = kaan_apdu_xcv(reader, buffer, n, resp, resp_len, 0);
+ if (n < 0) {
+ ct_error("kaan_input failed: %s", ct_strerror(n));
+ }
+
+ if ((n = kaan_get_sw(resp, n, &sw)) < 0)
+ return n;
+
+ switch (sw) {
+ case 0x6400:
+ ct_error("kaan_input failed: timeout");
+ return IFD_ERROR_USER_TIMEOUT;
+ case 0x6401:
+ ct_error("kaan_input failed: user pressed cancel");
+ return IFD_ERROR_USER_ABORT;
+ }
+ return n;
+}
+
+/*
  * Perform a PIN verification
  */
 static int
@@ -1037,6 +1075,7 @@
  kaan_driver.card_reset = kaan_card_reset;
  kaan_driver.card_request = kaan_card_request;
  kaan_driver.output= kaan_display;
+ kaan_driver.input= kaan_input;
  kaan_driver.perform_verify = kaan_perform_verify;
  kaan_driver.send= kaan_send;
  kaan_driver.recv= kaan_recv;
@@ -1052,6 +1091,7 @@
  b1_driver.card_reset = kaan_card_reset;
  b1_driver.card_request = kaan_card_request;
  b1_driver.output= kaan_display;
+ b1_driver.input= kaan_input;
  b1_driver.perform_verify = kaan_perform_verify;
  b1_driver.send= kaan_send;
  b1_driver.recv= kaan_recv;
diff -urN openct-0.6.5/src/ifd/process.c openct-0.6.5-strongswan/src/ifd/process.c
--- openct-0.6.5/src/ifd/process.c 2005-03-22 09:02:12.000000000 +0100
+++ openct-0.6.5-strongswan/src/ifd/process.c 2005-06-06 18:43:03.000000000 +0200
@@ -59,6 +59,8 @@
  ct_tlv_parser_t *, ct_tlv_builder_t *);
 static int do_output(ifd_reader_t *, int,
  ct_tlv_parser_t *, ct_tlv_builder_t *);
+static int do_input(ifd_reader_t *, int,
+ ct_tlv_parser_t *, ct_tlv_builder_t *);
 static int do_lock(ct_socket_t *, ifd_reader_t *, int,
  ct_tlv_parser_t *, ct_tlv_builder_t *);
 static int do_unlock(ct_socket_t *, ifd_reader_t *, int,
@@ -124,6 +126,10 @@
  rc = do_output(reader, unit, &args, &resp);
  break;
 
+ case CT_CMD_INPUT:
+ rc = do_input(reader, unit, &args, &resp);
+ break;
+
  case CT_CMD_RESET:
  case CT_CMD_REQUEST_ICC:
  rc = do_reset(reader, unit, &args, &resp);
@@ -226,6 +232,32 @@
 }
 
 /*
+ * Put a prompt on the reader's display and get input via the pin pad
+ */
+int
+do_input(ifd_reader_t *reader, int unit,
+ ct_tlv_parser_t *args, ct_tlv_builder_t *resp)
+{
+ char msgbuf[128];
+ const char *message = NULL;
+ int rc;
+
+ if (unit > CT_UNIT_READER)
+ return IFD_ERROR_INVALID_ARG;
+
+ /* See if we have message parameter */
+ if (ct_tlv_get_string(args, CT_TAG_MESSAGE, msgbuf, sizeof(msgbuf)) > 0)
+ message = msgbuf;
+
+ rc = ifd_input(reader, message, (unsigned char *) msgbuf, sizeof(msgbuf));
+ if (rc < 0)
+ return rc;
+
+ ct_tlv_put_opaque(resp, CT_TAG_DATA, (const unsigned char *) msgbuf, rc);
+ return 0;
+}
+
+/*
  * Lock/unlock card
  */
 int
diff -urN openct-0.6.5/src/ifd/reader.c openct-0.6.5-strongswan/src/ifd/reader.c
--- openct-0.6.5/src/ifd/reader.c 2005-03-22 09:02:12.000000000 +0100
+++ openct-0.6.5-strongswan/src/ifd/reader.c 2005-06-06 18:43:03.000000000 +0200
@@ -169,6 +169,21 @@
 }
 
 /*
+ * Put a prompt on the reader's display and get input via the pin pad
+ */
+int
+ifd_input(ifd_reader_t *reader, const char *message,
+  void *rbuf, size_t rlen)
+{
+ const ifd_driver_t *drv = reader->driver;
+
+ if (!drv || !drv->ops || !drv->ops->input)
+ return IFD_ERROR_NOT_SUPPORTED;
+
+ return drv->ops->input(reader, message, rbuf, rlen);
+}
+
+/*
  * Detect card status
  */
 int
diff -urN openct-0.6.5/src/include/openct/driver.h openct-0.6.5-strongswan/src/include/openct/driver.h
--- openct-0.6.5/src/include/openct/driver.h 2005-03-22 09:02:14.000000000 +0100
+++ openct-0.6.5-strongswan/src/include/openct/driver.h 2005-06-06 18:43:03.000000000 +0200
@@ -33,6 +33,8 @@
  time_t, const char *);
 
  int (*output)(ifd_reader_t *, const char *);
+ int (*input)(ifd_reader_t *, const char *,
+ unsigned char *, size_t);
  int (*perform_verify)(ifd_reader_t *,
        int, unsigned int, const char *,
  const unsigned char *, size_t,
diff -urN openct-0.6.5/src/include/openct/openct.h openct-0.6.5-strongswan/src/include/openct/openct.h
--- openct-0.6.5/src/include/openct/openct.h 2005-03-22 09:02:15.000000000 +0100
+++ openct-0.6.5-strongswan/src/include/openct/openct.h 2005-06-06 18:43:03.000000000 +0200
@@ -31,6 +31,9 @@
 #define IFD_CARD_PRESENT        0x0001
 #define IFD_CARD_STATUS_CHANGED 0x0002
 
+#define IFD_READER_DISPLAY 0x0100
+#define IFD_READER_KEYPAD 0x0200
+
 /* Lock types
  *  - shared locks allow concurrent access from
  *    other applications run by the same user.
@@ -61,6 +64,9 @@
 extern int ct_reader_info(unsigned int, ct_info_t *);
 extern ct_handle * ct_reader_connect(unsigned int);
 extern void ct_reader_disconnect(ct_handle *);
+extern int ct_reader_output(ct_handle *h, const char *message);
+extern int ct_reader_input(ct_handle *h, const char *message,
+ void *recv_buf, size_t recv_len);
 extern int ct_reader_status(ct_handle *, ct_info_t *);
 extern int ct_card_status(ct_handle *h, unsigned int slot, int *status);
 extern int ct_card_set_protocol(ct_handle *h, unsigned int slot,

diff -urN opensc-0.9.6/docs/opensc-tool.1 opensc-0.9.6-strongswan/docs/opensc-tool.1
--- opensc-0.9.6/docs/opensc-tool.1 2005-04-14 11:02:17.000000000 +0200
+++ opensc-0.9.6-strongswan/docs/opensc-tool.1 2005-06-06 18:50:08.000000000 +0200
@@ -31,6 +31,15 @@
 .BR \-\-list\-rdrivers ", " \-R
 Lists all installed reader drivers
 .TP
+.BR "\-\-output " \fImessage\fP, " \-o " \fImessage\fP
+Outputs a message string on the reader's display.
+\'\\n\' in the message string is interpreted as a newline character.
+.TP
+.BR "\-\-input "  \fIprompt\fP ", " \-i " \fIprompt\fP
+Displays a prompt string on the reader's display and returns
+the characters entered via the reader's key pad on stdout.
+\'\\n\' in the prompt string is interpreted as a newline character.
+.TP
 .BR "\-\-reader " \fInum\fP ", \-r " \fInum\fP
 Use the given reader number.  The default is 0, the first reader
 in the system.
diff -urN opensc-0.9.6/src/libopensc/opensc.h opensc-0.9.6-strongswan/src/libopensc/opensc.h
--- opensc-0.9.6/src/libopensc/opensc.h 2005-04-14 11:02:16.000000000 +0200
+++ opensc-0.9.6-strongswan/src/libopensc/opensc.h 2005-06-06 18:50:19.000000000 +0200
@@ -370,6 +370,9 @@
  * deallocate the private data.  Other fields will be
  * freed by OpenSC. */
  int (*release)(struct sc_reader *reader);
+        int (*output)(struct sc_reader *reader, const char *message);
+        int (*input)(struct sc_reader *reader, const char *message,
+     u8 *recvbuf, size_t *recvsize);
 
  int (*detect_card_presence)(struct sc_reader *reader,
     struct sc_slot_info *slot);
diff -urN opensc-0.9.6/src/libopensc/pkcs15-pin.c opensc-0.9.6-strongswan/src/libopensc/pkcs15-pin.c
--- opensc-0.9.6/src/libopensc/pkcs15-pin.c 2005-04-14 11:02:15.000000000 +0200
+++ opensc-0.9.6-strongswan/src/libopensc/pkcs15-pin.c 2005-06-06 18:50:38.000000000 +0200
@@ -216,9 +216,9 @@
  /* XXX need some sort of internationalization here */
  args.flags |= SC_PIN_CMD_USE_PINPAD;
  if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
- args.pin1.prompt = "Please enter SO PIN";
+ args.pin1.prompt = "Please enter SO\nPIN ";
  else
- args.pin1.prompt = "Please enter PIN";
+ args.pin1.prompt = "Please enter PIN\n";
  }
 
  r = sc_pin_cmd(card, &args, &pin->tries_left);
diff -urN opensc-0.9.6/src/libopensc/reader-openct.c opensc-0.9.6-strongswan/src/libopensc/reader-openct.c
--- opensc-0.9.6/src/libopensc/reader-openct.c 2005-04-14 11:02:16.000000000 +0200
+++ opensc-0.9.6-strongswan/src/libopensc/reader-openct.c 2005-06-06 18:50:46.000000000 +0200
@@ -36,6 +36,9 @@
 static int openct_add_reader(struct sc_context *ctx, unsigned int num, ct_info_t *info);
 static int openct_reader_finish(struct sc_context *ctx, void *priv_data);
 static int openct_reader_release(struct sc_reader *reader);
+static int opensc_reader_output(struct sc_reader *reader, const char *message);
+static int opensc_reader_input(struct sc_reader *reader, const char *message,
+ u8 *recvbuf, size_t *recvsize);
 static int openct_reader_detect_card_presence(struct sc_reader *reader,
  struct sc_slot_info *slot);
 static int openct_reader_connect(struct sc_reader *reader,
@@ -181,6 +184,66 @@
 }
 
 /*
+ * Send a message string to the reader's display
+ */
+int
+openct_reader_output(struct sc_reader *reader, const char *message)
+{
+ struct driver_data *data = (struct driver_data *) reader->drv_data;
+ int rc;
+
+ if (data->h == NULL)
+ {
+ if (!(data->h = ct_reader_connect(data->num))) {
+ sc_error(reader->ctx, "ct_reader_connect socket failed\n");
+ return SC_ERROR_READER_DETACHED;
+ }
+ }
+
+ rc = ct_reader_output(data->h, message);
+
+ if (rc == IFD_ERROR_NOT_CONNECTED) {
+ ct_reader_disconnect(data->h);
+ data->h = NULL;
+ return SC_ERROR_READER_DETACHED;
+ }
+
+ return openct_error(reader, rc);
+}
+
+/*
+ * Send a message string to the reader's display
+ */
+int
+openct_reader_input(struct sc_reader *reader, const char *message,
+     u8 *recvbuf, size_t *recvsize)
+{
+ struct driver_data *data = (struct driver_data *) reader->drv_data;
+ int rc;
+
+ if (data->h == NULL)
+ {
+ if (!(data->h = ct_reader_connect(data->num))) {
+ sc_error(reader->ctx, "ct_reader_connect socket failed\n");
+ return SC_ERROR_READER_DETACHED;
+ }
+ }
+
+ rc = ct_reader_input(data->h, message, recvbuf, *recvsize);
+
+ if (rc == IFD_ERROR_NOT_CONNECTED) {
+ ct_reader_disconnect(data->h);
+ data->h = NULL;
+ return SC_ERROR_READER_DETACHED;
+ }
+
+ if (rc >= 0)
+ *recvsize = rc;
+
+ return openct_error(reader, rc);
+}
+
+/*
  * Check whether a card was added/removed
  */
 int
@@ -440,6 +503,8 @@
  openct_ops.connect = openct_reader_connect;
  openct_ops.disconnect = openct_reader_disconnect;
  openct_ops.transmit = openct_reader_transmit;
+ openct_ops.output = openct_reader_output;
+ openct_ops.input = openct_reader_input;
  openct_ops.perform_verify = openct_reader_perform_verify;
  openct_ops.lock = openct_reader_lock;
  openct_ops.unlock = openct_reader_unlock;
diff -urN opensc-0.9.6/src/tools/opensc-tool.c opensc-0.9.6-strongswan/src/tools/opensc-tool.c
--- opensc-0.9.6/src/tools/opensc-tool.c 2005-04-14 11:02:05.000000000 +0200
+++ opensc-0.9.6-strongswan/src/tools/opensc-tool.c 2005-06-06 18:50:13.000000000 +0200
@@ -49,6 +49,8 @@
  { "list-rdrivers", 0, 0, 'R' },
  { "list-files", 0, 0, 'f' },
  { "send-apdu", 1, 0, 's' },
+ { "output", 1, 0, 'o' },
+ { "input", 1, 0, 'i' },
  { "reader", 1, 0, 'r' },
  { "card-driver", 1, 0, 'c' },
  { "wait", 0, 0, 'w' },
@@ -64,6 +66,8 @@
  "Lists all installed reader drivers",
  "Recursively lists files stored on card",
  "Sends an APDU in format AA:BB:CC:DD:EE:FF...",
+ "Sends a message string to the reader's display",
+ "Sends a prompt to the display and returns input from the key pad",
  "Uses reader number <arg> [0]",
  "Forces the use of driver <arg> [auto-detect]",
  "Wait for a card to be inserted",
@@ -122,6 +126,103 @@
  return 0;
 }
 
+void parse_message(const char *message, char *buf, size_t buf_len)
+{
+ size_t last_char = buf_len - 1;
+ size_t msg_len = strlen(message);
+ char *buf_ptr = buf;
+ const char *msg_ptr = message;
+ char *esc_ptr = strchr(msg_ptr, '\\');
+
+ /* process any escape characters */
+ while (esc_ptr != NULL)
+ {
+ int len = esc_ptr - msg_ptr;
+
+ /* copy message up to escape character or end of display */
+ if (len > buf_len - 1)
+ len = buf_len - 1;
+
+ strncpy(buf_ptr, msg_ptr, len);
+
+ msg_ptr += len + 1;
+ msg_len -= len + 1;
+ buf_ptr += len;
+ buf_len -= len;
+
+ if (buf_len > 2)
+ {
+ /* insert newline or other escaped character */
+ *buf_ptr++ = (*msg_ptr == 'n')? '\n' : *msg_ptr;
+ buf_len--;
+ }
+ *msg_ptr++;
+ msg_len--;
+ esc_ptr = strchr(msg_ptr, '\\');
+ }
+
+ /* copy remaining message */
+ strncpy(buf_ptr, msg_ptr, buf_len);
+
+ /* make sure the output string is null terminated */
+ buf[last_char] = '\0';
+}
+
+int send_msg(const char *message)
+{
+ const int display_len = 32; /* size of the Kobil Kaan display */
+ int buf_len = display_len + 1;
+ char buf[buf_len];
+
+ int num = (opt_reader > 0 && opt_reader < ctx->reader_count)?
+   opt_reader : 0;
+ sc_reader_t *reader = ctx->reader[num];
+
+ if (reader == NULL)
+ return SC_ERROR_NO_READERS_FOUND;
+ if (reader->ops->output == NULL)
+ {
+ fprintf(stderr, "Output to reader display not supported!\n");
+ return SC_ERROR_NOT_SUPPORTED;
+ }
+
+ parse_message(message, buf, buf_len);
+
+ /* call thre reader's output function */
+ return reader->ops->output(reader, buf);
+}
+
+int get_input(const char *message)
+{
+ int r;
+ const size_t display_len = 32; /* size of the Kobil Kaan display */
+ size_t buf_len = display_len + 1;
+ char buf[buf_len];
+
+ int num = (opt_reader > 0 && opt_reader < ctx->reader_count)?
+   opt_reader : 0;
+ sc_reader_t *reader = ctx->reader[num];
+
+ if (reader == NULL)
+ return SC_ERROR_NO_READERS_FOUND;
+ if (reader->ops->input == NULL)
+ {
+ fprintf(stderr, "Input from reader pin pad not supported!\n");
+ return SC_ERROR_NOT_SUPPORTED;
+ }
+
+ parse_message(message, buf, buf_len);
+
+ /* call thre reader's input function */
+ r = reader->ops->input(reader, buf, buf, &buf_len);
+ if (r < 0)
+ return r;
+
+ /* output on stdout */
+ printf("%.*s\n",buf_len, buf);
+ return 0;
+}
+
 int print_file(struct sc_card *card, const struct sc_file *file, const struct sc_path *path, int depth)
 {
  int r;
@@ -355,16 +456,19 @@
  int do_list_rdrivers = 0;
  int do_list_files = 0;
  int do_send_apdu = 0;
+ int do_send_msg = 0;
+ int do_get_input = 0;
  int do_print_atr = 0;
  int do_print_name = 0;
  int action_count = 0;
  const char *opt_driver = NULL;
+ const char *opt_msg = NULL;
 
  setbuf(stderr, NULL);
  setbuf(stdout, NULL);
 
  while (1) {
- c = getopt_long(argc, argv, "nlfr:vs:DRc:aw", options, &long_optind);
+ c = getopt_long(argc, argv, "nlfr:vs:o:i:DRc:aw", options, &long_optind);
  if (c == -1)
  break;
  if (c == '?')
@@ -395,6 +499,16 @@
  action_count++;
  opt_apdu_count++;
  break;
+ case 'o':
+ do_send_msg = 1;
+ opt_msg = optarg;
+ action_count++;
+ break;
+ case 'i':
+ do_get_input = 1;
+ opt_msg = optarg;
+ action_count++;
+ break;
  case 'a':
  do_print_atr = 1;
  action_count++;
@@ -444,6 +558,22 @@
  if (action_count <= 0)
  goto end;
 
+ if (do_send_msg) {
+ if ((err = send_msg(opt_msg)))
+ goto end;
+ action_count--;
+ }
+
+ if (do_get_input) {
+ if ((err = get_input(opt_msg)))
+ goto end;
+ action_count--;
+ }
+
+ /* leave if inserted card doesn't have to be contacted */
+ if (action_count <= 0)
+ goto end;
+
  if (opt_driver != NULL) {
  err = sc_set_card_driver(ctx, opt_driver);
  if (err) {

_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc.org/cgi-bin/mailman/listinfo/opensc-devel