/*
    Big bad tester application that runs against CT-API library.
    Handles up to four card-terminal interfaces simultaneously.
    It issues commands for both synchronous and asynchronous cards.
 
    This file is part of the Unix driver for Towitoko smartcard readers
    Copyright (C) 2000 Carlos Prados <cprados@yahoo.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if !defined DEBUG_IO && !defined DEBUG_IFD && !defined DEBUG_ICC && !defined DEBUG_PROTOCOL && !defined DEBUG_CTAPI
/* Define if you want multi-thread. Disabled by default if we are debugging  */
#define MULTI_THREAD 
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "ctapi.h"
#include "ctbcs.h"
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
#include <pthread.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif


/* Default Class byte */
#define CLASS 0x00

/* Status of each card-terminal */
struct
{
  unsigned short pn;            /* Serial port (1..4), 0 if not assigned */
  char port[16];		/* Descripton of port, printed in prompt */
  int status;                   /* -1 void, 0 sync, 1 async */
  unsigned char atr[33];        /* ATR bytes */
  unsigned short atr_size;      /* ATR size */
  unsigned char cla;		/* Class byte for commands */
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
  pthread_t thread;             /* Monitoring thread for this ctn */
  pthread_mutex_t mutex;        /* Mutex for accessin this element */
#endif
}
ct_list[4];

/* Menu loop */
void menu_loop (void);

/* Event handlers */
void Initialize (void);
unsigned short Change (unsigned short);
void Close (unsigned short);
void SelectClass (unsigned short);
void SelectFile (unsigned short);
void GetResponse (unsigned short);
void UpdateBinary (unsigned short);
void ReadBinary (unsigned short);
void VerifyKey (unsigned short);
void SendPPS (unsigned short);
void EnterPin (unsigned short);
void ChangePin (unsigned short);
void ReadData (unsigned short);
void WriteData (unsigned short);

#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
/* Asynchronous monitoring thread function */
void *Monitor (void *);
#else
/* Synchronous polling function */
unsigned short GetSmartcard (unsigned short);
#endif

/* Print status */
void PrintReport (void);

/* Read bus and port */
unsigned short ReadPort (char port[16]);

/* Calculate length of memory card */
unsigned GetMemoryLength(unsigned char * atr, unsigned length);

/* Print array of bytes */
void PrintArray (unsigned char * buffer, unsigned length);

int
main (int argc, char *argv[])
{
  unsigned short ctn;

  /* Initialize status of ct's */
  for (ctn = 0; ctn < 4; ctn++)
    {
      ct_list[ctn].pn = 0;
      ct_list[ctn].status = -1;
      ct_list[ctn].cla = CLASS;
      memset (ct_list[ctn].port, 0, 16);
      memset (ct_list[ctn].atr, 0, 33);
      ct_list[ctn].atr_size = 0;
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
      pthread_mutex_init (&(ct_list[ctn].mutex), NULL);
#endif
    }

  /* Start menu loop */
  menu_loop ();

  /* Close all open ct's */
  for (ctn = 0; ctn < 4; ctn++)
    {
      if (ct_list[ctn].pn != 0)
        {
          Close (ctn);
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
          pthread_mutex_destroy (&(ct_list[ctn].mutex));
#endif
        }
    }
    
  return 0;
}

void
menu_loop (void)
{
  char option[32];
  unsigned short ctn = 0, i;
  int dummy;

  while (1)
    {
      PrintReport ();
      printf ("Select option:\n");

      /* Common menu */
      printf ("in: Initialize new terminal\n");
      printf ("ch: Change current terminal\n");
      printf ("cl: Close current terminal\n");

      /* Port is open */
      if (ct_list[ctn].pn != 0)
        {
          /* Processor cards menu */
          if (ct_list[ctn].status == 1)
            {
              printf ("sc: Select Class Byte (current: %02X)\n", ct_list[ctn].cla);
              printf ("sf: Select File\n");
              printf ("gr: Get Response\n");
              printf ("vk: Verify Key (Cryptoflex)\n");
              printf ("rb: Read Binary\n");
              printf ("ub: Update Binary\n");
	      printf ("pps: Send PPS\n");
            }

          /* Memory card menu */
          else if (ct_list[ctn].status == 0)
            {
              printf ("ep: Enter PIN\n");
              printf ("cp: Change PIN\n");
              printf ("rd: Read Data\n");
              printf ("wd: Write Data\n");
            }
        }

      printf ("*: Refresh Menu\n");
      printf ("q: Quit\n");

      if (ct_list[ctn].pn != 0)
        printf ("%s$ ", ct_list[ctn].port);
      else
        printf ("$ ");

      /* Get  menu option */
      scanf ("%s", option);
      dummy = getchar ();

      /* Convert input to lowercase */
      for (i = 0; option[i]; i++)
        option[i] = tolower ((int) option[i]);

      /* Common options */
      if (strcmp (option, "q") == 0)
        break;

      else if (strcmp (option, "in") == 0)
        Initialize ();

      else if (strcmp (option, "ch") == 0)
        ctn = Change (ctn);

      else if (strcmp (option, "cl") == 0)
        Close (ctn);

      /* Processor card options */
      if (ct_list[ctn].status == 1)
        {
          if (strcmp (option, "sc") == 0)
            SelectClass (ctn);

	  else if (strcmp (option, "sf") == 0)
            SelectFile (ctn);

          else if (strcmp (option, "gr") == 0)
            GetResponse (ctn);

          else if (strcmp (option, "vk") == 0)
            VerifyKey (ctn);

          else if (strcmp (option, "rb") == 0)
            ReadBinary (ctn);

          else if (strcmp (option, "ub") == 0)
            UpdateBinary (ctn);

	  else if (strcmp (option, "pps") == 0)
	    SendPPS (ctn);
        }

      /* Memory card options */
      else if (ct_list[ctn].status == 0)
        {
          if (strcmp (option, "ep") == 0)
            EnterPin (ctn);

          else if (strcmp (option, "cp") == 0)
            ChangePin (ctn);

          else if (strcmp (option, "rd") == 0)
            ReadData (ctn);

          else if (strcmp (option, "wd") == 0)
            WriteData (ctn);
        }
    }
}

void
PrintReport (void)
{
  unsigned short ctn, num, i;

  num = 0;
  for (ctn = 0; ctn < 4; ctn++)
    if (ct_list[ctn].pn != 0)
      num++;

  printf
   
 ("**********************************************************************\n");
  printf ("Towitoko CT-API tester utility\n");
  printf ("Copyright (C) 2000 2001 Carlos Prados <cprados@yahoo.com>\n");
  printf ("Initilized CardTerminals: %d\n", num);

  for (ctn = 0; ctn < 4; ctn++)
    {
      if (ct_list[ctn].pn != 0)
        {
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
          pthread_mutex_lock (&(ct_list[ctn].mutex));
#endif
          printf
           
 ("**********************************************************************\n");
          printf ("%s\n", ct_list[ctn].port);

          printf ("Status: %s",
                  ct_list[ctn].status == 0 ? "Memory smartcard present" :
                  ct_list[ctn].status == 1 ? "Processor smartcard present" :
                  "No smartcard present (type * to refresh)");

	  if (ct_list[ctn].status == 0)
		  printf (". Memory size: %d bytes\n", 
		  GetMemoryLength(ct_list[ctn].atr, ct_list[ctn].atr_size));
	  else
		  printf("\n");

          if (ct_list[ctn].status != -1)
            {
              printf ("ATR: ");
              for (i = 0; i < ct_list[ctn].atr_size; i++)
                printf ("%02X ", ct_list[ctn].atr[i]);
              printf ("\n");
            }
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
          pthread_mutex_unlock (&(ct_list[ctn].mutex));
#endif
        }
    }

  printf
   
 ("**********************************************************************\n");
}

#if !defined HAVE_PTHREAD_H || !defined MULTI_THREAD
unsigned short
GetSmartcard (unsigned short ctn)
{
  unsigned char cmd[11], res[256], sad, dad;
  unsigned short lr, count;
  char ret;
#ifdef HAVE_NANOSLEEP
  struct timespec req_ts;

  req_ts.tv_sec = 1;
  req_ts.tv_nsec = 0;
#endif

  for (count = 0; count < 60; count ++)
    {
      /* Check if card is inserted */
      cmd[0] = CTBCS_CLA;
      cmd[1] = CTBCS_INS_STATUS;
      cmd[2] = CTBCS_P1_CT_KERNEL;
      cmd[3] = CTBCS_P2_STATUS_ICC;
      cmd[4] = 0x00;

      dad = 1;
      sad = 2;
      lr = 256;

      ret = CT_data (ctn, &dad, &sad, 11, cmd, &lr, res);

      if ((ret != OK) || (res[lr-2] != 0x90))
        {
          fprintf (stderr, "\nError getting status of terminal: %d\n", ret);
          return 0;
        }
 
      if (res[0] == CTBCS_DATA_STATUS_CARD_CONNECT)
        {            
          if (count > 1)                
            printf("\n");
            
          printf ("Activating card...\n");

          /* Activate card */
          cmd[0] = CTBCS_CLA;
          cmd[1] = CTBCS_INS_REQUEST;
          cmd[2] = CTBCS_P1_INTERFACE1;
          cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
          cmd[4] = 0x00;

          dad = 0x01;
          sad = 0x02;
          lr = 256;

          ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, res);

          if ((ret != OK) || (res[lr - 2] != 0x90))
            {
              fprintf (stderr, "Error activating card: %d\n", ret);
              return 0;
            }

          /* Store the type of card */
          ct_list[ctn].status = res[lr - 1];

          /* Store ATR */
          memcpy (ct_list[ctn].atr, res, lr - 2);
          ct_list[ctn].atr_size = lr - 2;
          return 1;
        }
        
      else
        {
          if (count > 0)
            {
              printf (".");
              fflush (stdout);
            }
          else
            printf ("Please insert a smartcard in the terminal\n");
        }
#ifdef HAVE_NANOSLEEP
          nanosleep (&req_ts, NULL);
#else
          usleep (999999);
#endif                                                                          
 
    }

  printf ("\nTimeout waiting for smartcard insertion\n");
  return 0;
}

#else

void *
Monitor (void *arg)
{
  unsigned char cmd[5], res[256], sad, dad;
  unsigned short lr, ctn;
  char ret;
#ifdef HAVE_NANOSLEEP
  struct timespec req_ts;

  req_ts.tv_sec = 1;
  req_ts.tv_nsec = 0;
#endif

  ctn = *(unsigned short *) arg;
  free (arg);

  while (ct_list[ctn].pn != 0)
    {
      /* Check if card is inserted */
      cmd[0] = CTBCS_CLA;
      cmd[1] = CTBCS_INS_STATUS;
      cmd[2] = CTBCS_P1_CT_KERNEL;
      cmd[3] = CTBCS_P2_STATUS_ICC;
      cmd[4] = 0x00;

      dad = 1;
      sad = 2;
      lr = 256;

      ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, res);

      if ((ret != OK) || (res[lr-2] != 0x90))
        continue;
      
      pthread_mutex_lock (&(ct_list[ctn].mutex));
      
      if (res[0] == CTBCS_DATA_STATUS_CARD_CONNECT)
        {            
          if (ct_list[ctn].status == -1)
            {
              /* Activate card */
              cmd[0] = CTBCS_CLA;
              cmd[1] = CTBCS_INS_REQUEST;
              cmd[2] = CTBCS_P1_INTERFACE1;
              cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
              cmd[4] = 0x00;

              dad = 0x01;
              sad = 0x02;
              lr = 256;

              ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, res);

              if ((ret != OK) || (res[lr - 2] != 0x90))
                {
                  pthread_mutex_unlock (&(ct_list[ctn].mutex));
                  continue;
                }   
              
              /* Store the type of card */
              ct_list[ctn].status = res[lr - 1];

              /* Store ATR */
              memcpy (ct_list[ctn].atr, res, lr - 2);
              ct_list[ctn].atr_size = lr - 2;
              
              pthread_mutex_unlock (&(ct_list[ctn].mutex));
            }
        }

      else
        {
          if (ct_list[ctn].status != -1)
            {
              ct_list[ctn].status = -1;
              memset (ct_list[ctn].atr, 0, 33);
              ct_list[ctn].atr_size = 0;
            }
        }
      
      pthread_mutex_unlock (&(ct_list[ctn].mutex));
#ifdef HAVE_NANOSLEEP
      nanosleep (&req_ts, NULL);
#else
      usleep(999999);
#endif
    }

  return NULL;
}
#endif

unsigned short
ReadPort(char port[16])
{
  unsigned short pn;

  scanf("%6s", port);

  if(strncasecmp(port,"COM",3) == 0)
  {
	  sscanf(port+3,"%hu",&pn);
	  snprintf(port,16,"COM%hu",pn);
  }

  else if (strncasecmp(port,"USB",3) == 0)
  {
	  sscanf(port+3,"%hu",&pn);
	  snprintf(port,16,"USB%hu",pn);
	  pn += 32768;
  }
  else
  {
	  sscanf(port,"%hu",&pn);
	  snprintf(port,16,"COM%hu",pn);
  }

  return pn;
}

unsigned 
GetMemoryLength(unsigned char * atr, unsigned length)
{
	if (length < 2)
		return 0;

	/* This line is dedicated to Rene Puls ;-) */
	return( 1 << (((int)(atr[1] & 120) >> 3)+6) * 1 << (int)(atr[1] & 7) / 8);
}

void 
PrintArray (unsigned char * buffer, unsigned length)
{
	unsigned i;

	if (length > 16)
		printf ("\n");

	for (i=0; i<length; i++)
	{
		printf ("%02X ", buffer[i]);
		if (i%16 == 15)
			printf ("\n");
	}

	if (i%16 != 0)
		printf ("\n");
}

void
Initialize (void)
{
  unsigned short int pn, ctn;
  char port[16];
  char ret;

  printf ("Port (COM[1..n] or USB[1..n]): ");

  pn = ReadPort(port);

  for (ctn = 0; ctn < 4; ctn++)
    {
      if ((ct_list[ctn].pn == pn))
        {
          printf ("Port already open\n");
          return;
        }
      else if (ct_list[ctn].pn == 0)
        break;
    }

  if (ctn > 4)
    {
      printf ("Maximum number of ports open\n");
      return;
    }

  printf ("Initializing terminal at %s...\n",port);

#ifndef CTAPI_WIN32_COM
  ret = CT_init (ctn, pn - 1);
#else
  ret = CT_init (ctn, pn);
#endif

  if (ret != OK)
    {
      fprintf (stderr, "Error on port allocation: %d\n", ret);
      return;
    }

  strncpy(ct_list[ctn].port,port,16);
  ct_list[ctn].pn = pn;
  
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
    {
      unsigned short *arg;

      arg = (unsigned short *) malloc (sizeof (unsigned short));
      (*arg) = ctn;

      printf ("Starting terminal monitoring job...\n");

      pthread_create (&(ct_list[ctn].thread), NULL, Monitor, (void *) arg);

      {
        /* Wait 0.1 seconds before returning to the menu loop
          to give time the monitor thread to adquire the mutex */

#ifdef HAVE_NANOSLEEP
        struct timespec req_ts;

        req_ts.tv_sec = 0;
        req_ts.tv_nsec = 100000000;

        nanosleep (&req_ts, NULL);
#else
        usleep(100000);
#endif
      }
    }
#else
  if (!GetSmartcard (ctn))
    Close (ctn);
#endif
}

unsigned short
Change (unsigned short ctn)
{
  unsigned short pn, i;
  char port[16];

  /* Show the list of open ports */
  printf ("Port number (");

  for (i = 0; i < 4; i++)
    {
      if (ct_list[i].pn != 0)
        printf ("%s", ct_list[i].port);
      if (i + 1 < 4)
        {
          if (ct_list[i + 1].pn != 0)
            printf (", ");
        }
      else
        printf ("): ");
    }

  pn = ReadPort(port);

  /* Search the ctn */
  for (i = 0; i < 4; i++)
    {
      if (ct_list[i].pn == pn)
        break;
    }

  if (i >= 4)
    {
      printf ("Invalid port number\n");
      return ctn;
    }

  return i;
}

void
Close (unsigned short ctn)
{
  char ret;

  if ((ct_list[ctn].pn == 0) && (ct_list[ctn].status == -1))
  {
	  printf ("Port not open\n");
	  return;
  }

#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
  pthread_mutex_lock (&(ct_list[ctn].mutex));
#endif
  ct_list[ctn].pn = 0;
  ct_list[ctn].status = -1;
  memset (ct_list[ctn].atr, 0, 33);
  ct_list[ctn].atr_size = 0;
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
  pthread_mutex_unlock (&(ct_list[ctn].mutex));
  
  printf ("Waiting for terminal monitoring job to stop...\n");
  pthread_join(ct_list[ctn].thread ,NULL);
#endif

  printf ("Closing terminal at %s\n", ct_list[ctn].port);

  ret = CT_close (ctn);
  if (ret != OK)
    printf ("Error closing terminal at %s\n", ct_list[ctn].port);
}

void
SelectClass (unsigned short ctn)
{
  unsigned char buffer[32];
  int dummy;

  printf ("Class byte (current is %02X): ", ct_list[ctn].cla);
  scanf ("%X", (unsigned int *) buffer);
  dummy = getchar ();

#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
    pthread_mutex_lock (&(ct_list[ctn].mutex));
#endif
  ct_list[ctn].cla = buffer[0];
#if defined HAVE_PTHREAD_H && defined MULTI_THREAD
  pthread_mutex_unlock (&(ct_list[ctn].mutex));
#endif
}

void
SelectFile (unsigned short ctn)
{
  unsigned char select_file[8] = { CLASS, 0xA4, 0x00, 0x00, 0x02, 0x3f, 0x00, 0x00 };
  unsigned char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int dummy;
  char ret;

  select_file[0] = ct_list[ctn].cla;

  printf ("File ID: ");
  scanf ("%X %X", (unsigned int *) buffer, (unsigned int *) buffer + 1);
  dummy = getchar ();

  select_file[5] = buffer[0];
  select_file[6] = buffer[1];

  dad = 0;
  sad = 2;
  lr = 256;

  printf ("Command: ");
  PrintArray (select_file, 8);

  ret = CT_data (ctn, &dad, &sad, 8, select_file, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error in SELECT FILE: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
GetResponse (unsigned short ctn)
{
  unsigned char get_response[5] = { CLASS, 0xC0, 0x00, 0x00, 0x00 };
  char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int dummy;
  char ret;

  get_response[0] = ct_list[ctn].cla;

  printf ("Response size (hexadecimal): ");
  scanf ("%X", (unsigned int *) buffer);
  dummy = getchar ();
  get_response[4] = buffer[0];

  dad = 0;
  sad = 2;
  lr = 256;

  printf ("Command: ");
  PrintArray (get_response, 5);

  ret = CT_data (ctn, &dad, &sad, 5, get_response, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on GET RESPONSE: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
UpdateBinary (unsigned short ctn)
{
  unsigned char update_binary[260] = { CLASS, 0xD6, 0x00, 0x00, 0x00 };
  char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int size, dummy;
  char ret;

  update_binary[0] =  ct_list[ctn].cla;

  printf ("File size (0..255): ");
  scanf ("%d", &size);
  dummy = getchar ();
  update_binary[4] = (unsigned char) (size % 256);

  printf ("Data: ");
  scanf ("%02X", (unsigned int *) buffer);
  dummy = getchar ();

  memset(update_binary + 5, buffer[0], update_binary[4]);

  dad = 0;
  sad = 2;
  lr = 256;

  printf ("Command: ");
  PrintArray (update_binary, update_binary[4] + 5);

  ret = CT_data (ctn, &dad, &sad, (int) update_binary[4] + 5, update_binary, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on UPDATE BYNARY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
ReadBinary (unsigned short ctn)
{
  unsigned char read_binary[5] = { CLASS, 0xB0, 0x00, 0x00, 0x00 };
  char buffer[32];
  unsigned char res[258];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int dummy;
  char ret;

  read_binary[0] = ct_list[ctn].cla;

  /* Read binary */
  printf ("File size: ");
  scanf ("%X", (unsigned int *) buffer);
  dummy = getchar ();
  read_binary[4] = buffer[0];

  dad = 0;
  sad = 2;
  lr = 258;

  printf ("Command: ");
  PrintArray (read_binary, 5);

  ret = CT_data (ctn, &dad, &sad, 5, read_binary, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on READ BYNARY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
VerifyKey (unsigned short ctn)
{
  unsigned char verify_key[13] =
    { CLASS, 0x2A, 0x00, 0x01, 0x08, 0x47, 0x46, 0x58, 0x49, 0x32, 0x56, 0x78, 0x40 };
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  char ret;

  verify_key[0] = ct_list[ctn].cla;

  dad = 0;
  sad = 2;
  lr = 256;
  printf ("Command: ");
  PrintArray (verify_key, 13);

  ret = CT_data (ctn, &dad, &sad, 13, verify_key, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on VERIFY KEY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
SendPPS (unsigned short ctn)
{
  unsigned char reset[9] = {0x20, 0x11, 0x01, 0x01, 0x03, 0xFF, 0x00, 0x00, 0x00};
  unsigned char buffer[32], res[256];
  unsigned char dad, sad;
  unsigned short lr;
  int dummy;
  char ret;

  printf ("PPS request (PPSS PPS0 PPS1): ");
  scanf ("%X %X %X", (unsigned int *) buffer, (unsigned int *) buffer + 1, (unsigned int *) buffer + 2);
  dummy = getchar ();

  reset[5] = buffer[0];
  reset[6] = buffer[1];
  reset[7] = buffer[2];

  dad = 0x01;
  sad = 0x02;
  lr = 256;

  printf ("Command: ");
  PrintArray (reset, 8);

  ret = CT_data (ctn, &dad, &sad, 9, reset, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on Reset CT (Send  PPS): %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
EnterPin (unsigned short ctn)
{
  unsigned char verify[8] = { 0x00, 0x20, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 };
  unsigned char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int dummy;
  char ret;

  printf ("PIN (3 bytes): ");
  scanf ("%X %X %X", (unsigned int *) buffer, (unsigned int *) buffer + 1, (unsigned int *) buffer + 2);
  dummy = getchar ();

  verify[5] = buffer[0];
  verify[6] = buffer[1];
  verify[7] = buffer[2];

  dad = 0;
  sad = 2;
  lr = 256;

  printf ("Command: ");
  PrintArray (verify, 8);

  ret = CT_data (ctn, &dad, &sad, 8, verify, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on VERIFY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
ChangePin (unsigned short ctn)
{
  unsigned char change[11] =
    { 0x00, 0x24, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  unsigned char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr;
  int dummy;
  char ret;

  printf ("PIN (3 bytes): ");
  scanf ("%X %X %X", (unsigned int *) buffer, (unsigned int *) buffer + 1, (unsigned int *) buffer + 2);
  dummy = getchar ();

  change[5] = buffer[0];
  change[6] = buffer[1];
  change[7] = buffer[2];

  printf ("New PIN (3 bytes): ");
  scanf ("%X %X %X", (unsigned int *) buffer, (unsigned int *) buffer + 1, (unsigned int *) buffer + 2);
  dummy = getchar ();

  change[8] = buffer[0];
  change[9] = buffer[1];
  change[10] = buffer[2];

  dad = 0;
  sad = 2;
  lr = 256;

  printf ("Command: ");
  PrintArray (change, 11);

  ret = CT_data (ctn, &dad, &sad, 11, change, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on CHANGE VERIFICATION DATA: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}

void
ReadData (unsigned short ctn)
{
  unsigned char select_file[7] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };
  unsigned char read_binary[6] = { 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00 };
  int address;
  int size, total_size;
  unsigned char * res;
  unsigned char dad;
  unsigned char sad;
  unsigned short lr, lc;
  int dummy;
  char ret;

  printf ("Address: ");
  scanf ("%d", &address);
  dummy = getchar ();

  read_binary[2] = (unsigned char) (address >> 8);
  read_binary[3] = (unsigned char) (address & 0x00FF);

  total_size  = GetMemoryLength(ct_list[ctn].atr, ct_list[ctn].atr_size);

  printf ("Size (0..%d): ", total_size);
  scanf ("%d", &size);
  dummy = getchar ();

  if (size < 256)
  {
	read_binary[4] = (unsigned char) size;
	lc = 5;
  }
  else
  {
	read_binary[4] = 0;
	read_binary[5] = (unsigned char) (size >> 8);
	read_binary[6] = (unsigned char) (size & 0x00FF);
	lc = 7;
  }

  printf ("Command: ");
  PrintArray (select_file, 7);

  dad = 0;
  sad = 2;
  res  = calloc ((lr = 2), sizeof (unsigned char));

  /* Select MF */
  ret = CT_data (ctn, &dad, &sad, 7, select_file, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on SELECT FILE: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);

  free (res);

  printf ("Command: ");
  PrintArray (read_binary, lc);

  dad = 0;
  sad = 2;
  if (size != 0)
  	res = calloc ((lr = size + 2), sizeof (unsigned char));
  else
	res  = calloc ((lr = total_size + 2), sizeof (unsigned char));

  if (res == NULL)
	  return;

  /* Read binary */
  ret = CT_data (ctn, &dad, &sad, lc, read_binary, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on READ BINARY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);

  free  (res);
}

void
WriteData (unsigned short ctn)
{
  unsigned char select_file[7] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };
  unsigned char * update_binary;
  int address;
  int size, total_size;
  unsigned char buffer[32];
  unsigned char res[256];
  unsigned char dad;
  unsigned char sad;
  unsigned short lr, lc;
  int dummy;
  char ret;

  printf ("Address: ");
  scanf ("%d", &address);
  dummy = getchar ();

  total_size  = GetMemoryLength(ct_list[ctn].atr, ct_list[ctn].atr_size);

  printf ("Size (0..%d): ", total_size);
  scanf ("%d", &size);
  dummy = getchar ();

  printf ("Data: ");
  scanf ("%X", (unsigned int *) buffer);
  dummy = getchar ();

  if  (size < 256)
  {
	update_binary = calloc (size +5, sizeof (unsigned char));

	if (update_binary == NULL)
		return;

	update_binary[0] = 0x00;
	update_binary[1] = 0xD6;
	update_binary[2] = (unsigned char) (address >> 8);
	update_binary[3] = (unsigned char) (address & 0x00FF);
	update_binary[4] = size;
	memset (update_binary+5, buffer[0], size);
	lc = size + 5;
  }
  else
  {
	update_binary = calloc (size +7, sizeof (unsigned char));

	if (update_binary == NULL)
		return;

	update_binary[0] = 0x00;
	update_binary[1] = 0xD6;
	update_binary[2] = (unsigned char) (address >> 8);
	update_binary[3] = (unsigned char) (address & 0x00FF);
	update_binary[4] = 0;
	update_binary[5] = (unsigned char) (size >> 8);
	update_binary[6] = (unsigned char) (size & 0x00FF);
	memset (update_binary+7, buffer[0], size);
	lc = size +7;
  }

  printf ("Command: ");
  PrintArray (select_file, 7);

  dad = 0;
  sad = 2;
  lr = 256;

  /* Select MF */
  ret = CT_data (ctn, &dad, &sad, 7, select_file, &lr, res);

  if (ret != OK)
    {
      fprintf (stderr, "Error on SELECT FILE: %d\n", ret);
      free (update_binary);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);

  printf ("Command: ");
  PrintArray (update_binary, lc);

  dad = 0;
  sad = 2;
  lr = 256;

  /* Update binary */
  ret = CT_data (ctn, &dad, &sad, lc, update_binary, &lr, res);

  free (update_binary);

  if (ret != OK)
    {
      fprintf (stderr, "Error on UPDATE BINARY: %d\n", ret);
      return;
    }

  printf ("Response: ");
  PrintArray (res, lr);
}



syntax highlighted by Code2HTML, v. 0.9.1