<commit_before>/******************************************************************

        MUSCLE SmartCard Development ( http://www.linuxnet.com )
            Title  : winscard_scf.c
            Package: pcsc-lite
            Author : <NAME>
                     <NAME>
            Date   : 6/24/02
            License: Copyright (C) 2002 <NAME>
                     <<EMAIL>>
            Purpose: This provides PC/SC to SCF shimming.. 
                     Copy this file to pcsc-lite../src/winscard_clnt.c
********************************************************************/

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/un.h>
#include <smartcard/scf.h>

#include "wintypes.h"
#include "pcsclite.h"
#include "winscard.h"
#include "debuglog.h"

#define USE_THREAD_SAFETY
#ifdef USE_THREAD_SAFETY
#include "thread_generic.h"
#endif

#include "readerfactory.h"
#include "eventhandler.h"
#include "sys_generic.h"

#define TRUE 1
#define FALSE 0

#define PCSC_SCF_MAX_READERS 2
#define PCSC_SCF_MAX_ATR_BUFFER_LENGTH 32
#define PCSC_SCF_MAX_RECV_LEN 265

/* Global session to manage Readers, Card events. */
static SCF_Session_t  g_hSession = NULL;

/* Have to define this because they are defined in pcsclite.h as externs */
SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci;

static struct _psTransmitMap {
  BYTE Buffer[266];
  int isResponseCached;
  BYTE bufferLength;
} psTransmitMap[PCSCLITE_MAX_CONTEXTS];


/* Channel Map to manage Card Connections. */
static struct _psChannelMap {
  SCARDHANDLE  PCSC_hCard;
  SCARDCONTEXT hContext;
  SCF_Session_t  hSession;
  SCF_Terminal_t hTerminal;
  SCF_Card_t     SCF_hCard;
  short haveLock;
  short isReset;
  int ReaderIndice;
} psChannelMap[PCSCLITE_MAX_CONTEXTS];

/* Context Map to manage contexts and sessions. */
static struct _psContextMap {
  SCARDCONTEXT hContext;
  SCF_Session_t  hSession;
  DWORD        contextBlockStatus;
} psContextMap[PCSCLITE_MAX_CONTEXTS];

/* Reader Map to handle Status and GetStatusChange. */
static struct _psReaderMap {
  SCF_Terminal_t hTerminal;
  LPSTR ReaderName;
  short SharedRefCount;
  DWORD dwCurrentState;
  BYTE bAtr[PCSC_SCF_MAX_ATR_BUFFER_LENGTH];
  DWORD dwAtrLength;
  SCF_ListenerHandle_t lHandle;
} psReaderMap[PCSC_SCF_MAX_READERS];


#ifdef USE_THREAD_SAFETY
static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;

/*
 * Mutex for the Smardcard Event Handling, different from client Mutex
 * because event reporting from the ocfserver is done using a single thread,
 * so to get lock on the clientMutex may affect the performance of the ocf server.
 */
static PCSCLITE_MUTEX EventMutex = PTHREAD_MUTEX_INITIALIZER;
#endif

static LONG isOCFServerRunning();
LONG SCardLockThread();
LONG SCardUnlockThread();
LONG SCardEventLock();
LONG SCardEventUnlock();
static LONG PCSC_SCF_Initialize();
static void EventCallback(SCF_Event_t eventType, SCF_Terminal_t hTerm,
			  void * cbdata);
static LONG PCSC_SCF_getATR(SCF_Card_t hCard, LPBYTE pcbAtr, 
			    LPDWORD pcbAtrLen);

static LONG ConvertStatus(SCF_Status_t status);
static LONG SCardGetReaderIndice(LPCSTR ReaderName);
static LONG getNewContext(SCARDCONTEXT *phContext);
static LONG SCardAddContext(SCARDCONTEXT hContext,SCF_Session_t  hSession );
static SCF_Session_t getSessionForContext(SCARDCONTEXT hContext );
static LONG SCardRemoveContext ( SCARDCONTEXT hContext );
static LONG SCardGetContextIndice ( SCARDCONTEXT hContext );

static LONG getNewHandle(SCARDCONTEXT hContext,LPCSTR szReader,
			 SCARDHANDLE *phCard, DWORD);
static LONG  getCardForHandle(SCARDHANDLE PSCS_hCard, SCF_Card_t *SCF_hCard);
static LONG SCardRemoveHandle(SCARDHANDLE hCard);
static LONG SCardAddHandle(SCARDHANDLE PCSC_hCard, SCARDCONTEXT hContext,
			   SCF_Session_t  hSession,  SCF_Terminal_t hTerminal,
			   SCF_Card_t  SCF_hCard, int , DWORD);
static LONG SCardGetHandleIndice(SCARDHANDLE hCard);


static LONG SCardEstablishContextTH( DWORD dwScope, LPCVOID pvReserved1, 
				     LPCVOID pvReserved2, 
				     LPSCARDCONTEXT phContext) {
  LONG rv = 0;   

  
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  rv = PCSC_SCF_Initialize();
  
  if(SCARD_S_SUCCESS != rv)
    return rv;

  if (NULL == phContext) {
    return SCARD_E_INVALID_PARAMETER;
  } else {
    *phContext = 0;
  }
   
  if ( dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
       dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL ) {
     
    *phContext = 0;     
    return SCARD_E_INVALID_VALUE;
  }   
  rv = getNewContext(phContext);
  return rv;

}

LONG SCardEstablishContext( DWORD dwScope, LPCVOID pvReserved1, 
			    LPCVOID pvReserved2, LPSCARDCONTEXT phContext) {
  long rv;

  SCardLockThread();
  rv =  SCardEstablishContextTH( dwScope,  pvReserved1, 
				 pvReserved2,  phContext);
  SCardUnlockThread();
    
    
  return rv;
    
}

static LONG SCardReleaseContextTH( SCARDCONTEXT hContext ) {

  LONG rv;
  /* Zero out everything */
 
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  rv = 0;

  /* Remove the local context from the stack */
  rv = SCardRemoveContext( hContext );

  return rv;
}

LONG SCardReleaseContext( SCARDCONTEXT hContext ) {
  long rv;
    
  SCardLockThread();
  rv = SCardReleaseContextTH( hContext );
  SCardUnlockThread();
    
  return rv;
}


static LONG SCardListReadersTH( SCARDCONTEXT hContext, LPCSTR mszGroups, 
			 LPSTR mszReaders, LPDWORD pcchReaders ) {
  static int first_time = 1;
  int i=0;
  static DWORD dwReadersLen=0;
  LONG retIndice = 0;
  char *tempPtr;
  
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
/* Check for NULL parameters */
  if ( pcchReaders == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }
  /*Check for Context validity*/
  retIndice = SCardGetContextIndice(hContext);
  if(0> retIndice)
    return SCARD_E_INVALID_HANDLE;
  
  /*Calculate the the buffer length reuired only once.
  */
  if(first_time) {
    for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
      if(NULL != psReaderMap[i].ReaderName) 
	dwReadersLen += strlen(psReaderMap[i].ReaderName) +1;
    }
    dwReadersLen++;
    first_time = 0;
  }
  /*There are no readers available*/
  if(1 >= dwReadersLen)
    return SCARD_E_READER_UNAVAILABLE;
  
  
  if ( mszReaders == 0 ) {
    *pcchReaders = dwReadersLen;
    return SCARD_S_SUCCESS;
  } else if ( *pcchReaders == 0 ) {
    *pcchReaders = dwReadersLen;
    return SCARD_S_SUCCESS;
  } else if ( *pcchReaders < dwReadersLen ) {
    *pcchReaders = dwReadersLen;
    return SCARD_E_INSUFFICIENT_BUFFER;
  }
  
  tempPtr = mszReaders;
  for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
    if(NULL != psReaderMap[i].ReaderName) {
      memcpy(tempPtr, psReaderMap[i].ReaderName, 
	     strlen(psReaderMap[i].ReaderName)+1);
      tempPtr += (strlen(psReaderMap[i].ReaderName) + 1);
    }
  }
  /*the extra NULL character as per the PCSC specs.*/
  tempPtr[0] = '\0';
  *pcchReaders = dwReadersLen;
  
  return SCARD_S_SUCCESS;
}


LONG SCardListReaders( SCARDCONTEXT hContext, LPCSTR mszGroups, 
		       LPSTR mszReaders, LPDWORD pcchReaders ) {

  long rv;
    
  SCardLockThread();
  rv = SCardListReadersTH( hContext, mszGroups, mszReaders, pcchReaders );
  SCardUnlockThread();
    
  return rv;    
}
/* by najam */


static LONG SCardConnectTH( SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
			    DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
			    LPDWORD pdwActiveProtocol ) {    
  LONG rv;
   
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  /* Zero out everything   */
  rv=0;
  
  /* Check for NULL parameters */
  if ( phCard == 0 || pdwActiveProtocol == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  } else {
    *phCard = 0;
  }
  
  /* Make sure this context has been opened */
  if ( SCardGetContextIndice( hContext ) == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  if ( szReader == 0 ) {
    return SCARD_E_UNKNOWN_READER;
  }

  /* Check for uninitialized strings */
  if ( strlen(szReader) > MAX_READERNAME ) {
    return SCARD_E_INVALID_VALUE;
  } 

  if ( !(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_ANY) ) {

    return SCARD_E_INVALID_VALUE;
  }
  
  if((SCARD_SHARE_SHARED != dwShareMode) &&
     (SCARD_SHARE_EXCLUSIVE != dwShareMode) &&
     (SCARD_SHARE_DIRECT != dwShareMode) ){
    return SCARD_E_INVALID_VALUE;
  }
  /* TODO Which Protocols have to be supported */
  /* Ignoring protocols for now */
  /* Make sure this handle has been opened */

  rv = getNewHandle(hContext,szReader,phCard,dwShareMode);
  
  if(SCARD_S_SUCCESS != rv) {
    return rv;
  }
  
  *pdwActiveProtocol = SCARD_PROTOCOL_T0;
  return SCARD_S_SUCCESS;
}

LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
		  DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
		  LPDWORD pdwActiveProtocol) 
{
  long rv;
    
  SCardLockThread();
  rv = SCardConnectTH(hContext, szReader, dwShareMode,
		      dwPreferredProtocols, phCard, pdwActiveProtocol);
  SCardUnlockThread();
  return rv;
    
}

static LONG SCardDisconnectTH( SCARDHANDLE hCard, DWORD dwDisposition ) {
     
  long rv;
  LONG retIndice = 0;
  
  SCF_Status_t status;
  
  /*check ocfserver availibility*/
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  if ( dwDisposition != SCARD_LEAVE_CARD &&
       dwDisposition != SCARD_RESET_CARD &&
       dwDisposition != SCARD_UNPOWER_CARD &&
       dwDisposition != SCARD_EJECT_CARD ) {
    return SCARD_E_INVALID_VALUE;
  }
  /*CHECK HANDLE VALIDITY*/
  retIndice = SCardGetHandleIndice(hCard);
  if ((retIndice == -1) || (NULL == psChannelMap[retIndice].SCF_hCard)) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  /* TODO Take Care of the Disposition...  */
  /* Resetting the card for SCARD_RESET_CARD | 
     SCARD_UNPOWER_CARD | SCARD_EJECT_CARD */
  if(SCARD_LEAVE_CARD != dwDisposition) {
    /*must acquire the lock to reset card*/ 
    status = SCF_Card_lock(psChannelMap[retIndice].SCF_hCard, 0);
    if((SCF_STATUS_SUCCESS == status) || (SCF_STATUS_DOUBLELOCK == status )) {
      status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard);
      SCF_Card_unlock(psChannelMap[retIndice].SCF_hCard);
      /*a usleep here will allow the RESET_EVENT to be reported and 
	the Maps to be updated*/
      SYS_USleep(10);
    }
  }
  
  rv = SCardRemoveHandle(hCard);
     
  return rv;
  
}

static LONG SCardReconnectTH( SCARDHANDLE hCard, DWORD dwShareMode,
		       DWORD dwPreferredProtocols, DWORD dwInitialization,
		       LPDWORD pdwActiveProtocol ) {    
     
  SCARDCONTEXT hContext;
  LPSTR ReaderName;
  SCARDHANDLE tempHandle;
  LONG rv;
     
  int retIndice = 0;
   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
   if ( pdwActiveProtocol == 0 ){
    return SCARD_E_INVALID_PARAMETER;
  }
  if ( dwInitialization != SCARD_LEAVE_CARD &&
       dwInitialization != SCARD_RESET_CARD &&
       dwInitialization != SCARD_UNPOWER_CARD &&
       dwInitialization != SCARD_EJECT_CARD ) {  
    return SCARD_E_INVALID_VALUE;
  }
     
  retIndice = SCardGetHandleIndice(hCard);
    
  if(-1 == retIndice) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  hContext = psChannelMap[retIndice].hContext;
  ReaderName = psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName;

  SCardDisconnectTH(hCard, dwInitialization);
  
  /* get a new handle*/
  rv = SCardConnectTH(hContext, ReaderName, dwShareMode, 
		      dwPreferredProtocols, &tempHandle, pdwActiveProtocol);
  if(SCARD_S_SUCCESS != rv) {
    return rv;
  }
     
  retIndice = SCardGetHandleIndice(tempHandle);
  if(-1 == retIndice) {
    return SCARD_E_NO_MEMORY;
  }
     
  /*set PCSC hCard to old Handle */
  SCardEventLock();
  psChannelMap[retIndice].PCSC_hCard = hCard;
  SCardEventUnlock();
  
  return SCARD_S_SUCCESS;
     
}

LONG SCardReconnect( SCARDHANDLE hCard, DWORD dwShareMode,
		     DWORD dwPreferredProtocols, DWORD dwInitialization,
		     LPDWORD pdwActiveProtocol ) {
    long rv;
    
    SCardLockThread();
    rv = SCardReconnectTH(hCard, dwShareMode, dwPreferredProtocols,
			  dwInitialization, pdwActiveProtocol);
    SCardUnlockThread();
    return rv;
    
}

LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition ) {

  long rv;
    
  SCardLockThread();
  rv = SCardDisconnectTH(hCard, dwDisposition);
  SCardUnlockThread();
  return rv;
    
}


LONG SCardBeginTransaction( SCARDHANDLE hCard ) {
     
  LONG rv;
  
  SCF_Card_t SCF_hCard;
  SCF_Status_t   status;
  /* Zero out everything   */
  rv=0;
     
  SCardLockThread();
  if(SCARD_S_SUCCESS != isOCFServerRunning()) {
    SCardUnlockThread();
    return SCARD_E_NO_SERVICE;
  }
   rv = getCardForHandle(hCard, &SCF_hCard);
  if(SCARD_S_SUCCESS != rv) {
    SCardUnlockThread();
    return rv;
  }
  SCardUnlockThread();
     
  status = SCF_Card_lock(SCF_hCard, SCF_TIMEOUT_MAX);
     
  if(SCF_STATUS_DOUBLELOCK == status)
    return SCARD_S_SUCCESS;

  rv = ConvertStatus(status);

  return rv;
     
}

static LONG SCardEndTransactionTH( SCARDHANDLE hCard, DWORD dwDisposition ) {

  LONG rv;
  LONG retIndice = 0;
  SCF_Card_t SCF_hCard;
  SCF_Status_t   status;

   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  /* Zero out everything   */
  rv=0;
  if ( dwDisposition != SCARD_LEAVE_CARD &&
       dwDisposition != SCARD_RESET_CARD &&
       dwDisposition != SCARD_UNPOWER_CARD &&
       dwDisposition != SCARD_EJECT_CARD ) {
	   
    return SCARD_E_INVALID_VALUE;
  }
  retIndice = SCardGetHandleIndice(hCard);
  if ( retIndice == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }    
       
  rv = getCardForHandle(hCard, &SCF_hCard);
  if(rv != SCARD_S_SUCCESS)
    return rv;
  
  /* TODO Take Care of the Disposition... */
  if(SCARD_LEAVE_CARD != dwDisposition) {
    status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard);
    if(SCF_STATUS_SUCCESS == status) {
      /* reset the isReset for this card */
      SYS_USleep(10);
      SCardEventLock();
      psChannelMap[retIndice].isReset = 0;
      SCardEventUnlock();
    }	   
  }
  
  status = SCF_Card_unlock(SCF_hCard);
       
  return ConvertStatus(status);
}

LONG SCardEndTransaction( SCARDHANDLE hCard, DWORD dwDisposition ) {

  long rv;
    
  SCardLockThread();
  rv = SCardEndTransactionTH(hCard, dwDisposition);
  SCardUnlockThread();
  return rv;
}

static LONG SCardCancelTransactionTH( SCARDHANDLE hCard ) {
   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
   
  /* TODO */
  return SCARD_S_SUCCESS;
}

LONG SCardCancelTransaction( SCARDHANDLE hCard ) {

  long rv;
    
  SCardLockThread();
  rv = SCardCancelTransactionTH(hCard);
  SCardUnlockThread();
  return rv;
}
static LONG SCardStatusTH( SCARDHANDLE hCard, LPSTR mszReaderNames, 
		    LPDWORD pcchReaderLen, LPDWORD pdwState, 
		    LPDWORD pdwProtocol, LPBYTE pbAtr,
		    LPDWORD pcbAtrLen ) {
  LONG retIndice, rv;
  int i;
  DWORD dwReaderLen;
  SCF_Card_t SCF_hCard;

   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  /* Zero out everything   */
  retIndice=0; dwReaderLen=0; rv=0; i=0;
  /* Check for NULL parameters */

  if ( pcchReaderLen == 0 || pdwState == 0 || 
       pdwProtocol == 0 || pcbAtrLen == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }

  
  retIndice = SCardGetHandleIndice(hCard);
  
  rv = getCardForHandle(hCard, &SCF_hCard);
  if(SCARD_S_SUCCESS != rv)
    return rv;
  
  dwReaderLen = strlen(psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName);
  
   if (mszReaderNames == 0) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0;
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_S_SUCCESS;
  }

   if (*pcchReaderLen == 0) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0; 
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_S_SUCCESS;
  }

  if (*pcchReaderLen < dwReaderLen) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0; 
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_E_INSUFFICIENT_BUFFER;
  }
  
  *pcchReaderLen = dwReaderLen;
  strcpy(mszReaderNames, 
	 psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName);
  *pdwProtocol = SCARD_PROTOCOL_T0;
  
  SCardEventLock();
  if(!(psReaderMap[psChannelMap[retIndice].ReaderIndice].dwCurrentState & SCARD_STATE_PRESENT)) {
    *pdwState = SCARD_ABSENT;
    SCardEventUnlock();
    return SCARD_S_SUCCESS;
  }
  
  *pdwState = SCARD_NEGOTIABLE | SCARD_POWERED |  SCARD_PRESENT;
  rv = PCSC_SCF_getATR(SCF_hCard, pbAtr, pcbAtrLen); 
  if(SCARD_S_SUCCESS == rv) {
    /*referesh the Atr in the reader Map*/
    psReaderMap[psChannelMap[retIndice].ReaderIndice].dwAtrLength = *pcbAtrLen;
    memcpy(psReaderMap[psChannelMap[retIndice].ReaderIndice].bAtr,
	   pbAtr, *pcbAtrLen);
  }
  
  SCardEventUnlock();
  return SCARD_S_SUCCESS;
}

LONG SCardStatus( SCARDHANDLE hCard, LPSTR mszReaderNames, 
		  LPDWORD pcchReaderLen, LPDWORD pdwState, 
		  LPDWORD pdwProtocol, LPBYTE pbAtr,
                  LPDWORD pcbAtrLen ) {
  long rv;
    
  SCardLockThread();
  rv = SCardStatusTH(hCard, mszReaderNames, pcchReaderLen, pdwState,
		     pdwProtocol, pbAtr, pcbAtrLen);
  SCardUnlockThread();
  return rv;
}

LONG SCardGetStatusChange( SCARDCONTEXT hContext, DWORD dwTimeout, 
			   LPSCARD_READERSTATE_A rgReaderStates, 
                           DWORD cReaders ) {

  LONG rv, retIndice;
   PSCARD_READERSTATE_A currReader;
  PREADER_STATES rContext;
  LPSTR lpcReaderName;
  DWORD dwTime;
  DWORD dwState;
  DWORD dwBreakFlag;
  int i, j;

   
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
   /* Zero out everything */
  rv=0; rContext=0; lpcReaderName=0; dwTime=0; j=0;
  dwState=0; i=0; currReader=0; retIndice=0; dwBreakFlag=0;
  
   if ( rgReaderStates == 0 && cReaders > 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }
  if ( cReaders < 0 ) {
    return SCARD_E_INVALID_VALUE;
  }
  /* change by najam */
  SCardLockThread();
  retIndice = SCardGetContextIndice( hContext );
  /* change by najam */
  SCardUnlockThread();
  if ( retIndice == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }
  
   /* Application is waiting for a reader -
     return the first available reader 
  */
  if ( cReaders == 0 ) {
      for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
	if(psReaderMap[i].ReaderName) 
	  return SCARD_S_SUCCESS;
      }
      return SCARD_E_READER_UNAVAILABLE;
  } else if(cReaders >PCSC_SCF_MAX_READERS) {
    return SCARD_E_INVALID_VALUE;
  }
   /* Check the integrity of the reader states structures */
  for ( j=0; j < cReaders; j++ ) {
    currReader = &rgReaderStates[j];
    if ( currReader->szReader == 0 ) {
      return SCARD_E_INVALID_VALUE;
    }
  }
  /* End of search for readers */
  
 /* Clear the event state for all readers */
  for ( j=0; j < cReaders; j++ ) {
    currReader = &rgReaderStates[j];
    currReader->dwEventState = 0;
  }

  /* Now is where we start our event checking loop */

  psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_BLOCKING;
  j=0;
  
  do {
    SYS_USleep(10);
    if(SCARD_S_SUCCESS != isOCFServerRunning())
      return SCARD_E_NO_SERVICE;

    currReader    = &rgReaderStates[j];
   
    /************ Look for IGNORED readers ****************************/

    if ( currReader->dwCurrentState & SCARD_STATE_IGNORE ) {
      currReader->dwEventState = SCARD_STATE_IGNORE;
    } else {
      /************ Looks for correct readernames *********************/
      
      lpcReaderName = (char *)currReader->szReader;
      
      retIndice = SCardGetReaderIndice(lpcReaderName);
      /* The requested reader name is not recognized */
      if(0> retIndice) {
	if ( currReader->dwCurrentState & SCARD_STATE_UNKNOWN ) {
	  currReader->dwEventState = SCARD_STATE_UNKNOWN;
	} else {
	  currReader->dwEventState = 
	    SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
	  /* Spec says use SCARD_STATE_IGNORE but a removed USB reader
	     with eventState fed into currentState will be ignored forever */
	  dwBreakFlag = 1;
	}
      } else {
		/* The reader has come back after being away */
	if ( currReader->dwCurrentState & SCARD_STATE_UNKNOWN ) {
	  currReader->dwEventState |= SCARD_STATE_CHANGED;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  dwBreakFlag = 1;
	}
	
	/*****************************************************************/
	SCardEventLock();
	/* Now we check all the Reader States */
	dwState = psReaderMap[retIndice].dwCurrentState;
	
	/*********** Check if the reader is in the correct state ********/
	if ( dwState & SCARD_STATE_UNKNOWN ) {
	  /* App thinks reader is in bad state and it is */
	  if ( currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE ) {
	    currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
	  } else {
	    /* App thinks reader is in good state and it is not */
	    currReader->dwEventState = SCARD_STATE_CHANGED |
	      SCARD_STATE_UNAVAILABLE;
	    dwBreakFlag = 1;
	  }
	} else {
	  /* App thinks reader in bad state but it is not */
	  if ( currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE ) {
	    currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  } 
	}	
	
	/********** Check for card presence in the reader **************/

	if ( dwState & SCARD_STATE_PRESENT ) {
	  currReader->cbAtr = psReaderMap[retIndice].dwAtrLength;
	  memcpy( currReader->rgbAtr, psReaderMap[retIndice].bAtr, 
		  currReader->cbAtr );
	} else {
	   currReader->cbAtr = 0;
	}
		/* Card is now absent                   */
	if ( dwState & SCARD_STATE_EMPTY ) {
	  currReader->dwEventState |= SCARD_STATE_EMPTY;
	  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
	  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
	  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
	  currReader->dwEventState &= ~SCARD_STATE_MUTE;
	  currReader->dwEventState &= ~SCARD_STATE_INUSE;
	  /* After present the rest are assumed */
	  if ( currReader->dwCurrentState & SCARD_STATE_PRESENT ||
	       currReader->dwCurrentState & SCARD_STATE_ATRMATCH ||
	       currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE ||
	       currReader->dwCurrentState & SCARD_STATE_INUSE ) 
	    {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;	
	      dwBreakFlag = 1;
	    }
	   /* Card is now present              */
	} else if ( dwState & SCARD_STATE_PRESENT ) {
	  currReader->dwEventState |= SCARD_STATE_PRESENT;
	  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
	  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
	  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	  currReader->dwEventState &= ~SCARD_STATE_MUTE;
	  
	  if ( currReader->dwCurrentState & SCARD_STATE_EMPTY ) {
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  }	
	  /* TODO */
	  if ( 0 && dwState & SCARD_SWALLOWED ) {
	    if ( currReader->dwCurrentState & SCARD_STATE_MUTE ) {
	      currReader->dwEventState |= SCARD_STATE_MUTE;
	    } else {
	      currReader->dwEventState |= SCARD_STATE_MUTE;
              if ( currReader->dwCurrentState != SCARD_STATE_UNAWARE ) {
	        currReader->dwEventState |= SCARD_STATE_CHANGED;
              }
	      dwBreakFlag = 1;
	    }
	  } else {
	    /* App thinks card is mute but it is not */
	    if ( currReader->dwCurrentState & SCARD_STATE_MUTE ) {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;
	      dwBreakFlag = 1;
	    }
	  }	    
	}
	
	if(-1 == psReaderMap[retIndice].SharedRefCount) {
	  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
	  currReader->dwEventState &= ~SCARD_STATE_INUSE;
	  if ( !currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE ) {
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  }
	} else if (psReaderMap[retIndice].SharedRefCount >= 1) {
	 /* A card must be inserted for it to be INUSE */
	  if ( dwState & SCARD_STATE_PRESENT ) {
	    currReader->dwEventState |= SCARD_STATE_INUSE;
	    currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
	    if ( !currReader->dwCurrentState & SCARD_STATE_INUSE ) {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;
	      dwBreakFlag = 1;
	    }
	  }
	}
	SCardEventUnlock();
	if ( currReader->dwCurrentState == SCARD_STATE_UNAWARE ) {
	  /* Break out of the while .. loop and return status 
	     once all the status's for all readers is met */
	  dwBreakFlag = 1;
	}
	SYS_USleep( PCSCLITE_STATUS_WAIT );
	
      }  /* End of SCARD_STATE_UNKNOWN */
      
    }    /* End of SCARD_STATE_IGNORE */
    
     /* Counter and resetter */
    j = j + 1;
    if ( j == cReaders ) { j=0; }
    
    if ( dwTimeout != INFINITE && dwTimeout != 0 ) {
      dwTime += PCSCLITE_STATUS_WAIT;
      
      /* If time is greater than timeout and all readers have been 
	 checked
      */
      if ( ( dwTime >= (dwTimeout*1000) )&&
	   ( j == 0 ) ) 
	{
        return SCARD_E_TIMEOUT;
      }
    }

 /* Declare all the break conditions */
    /* TODO think about this */
       if ( psContextMap[retIndice].contextBlockStatus == 
	 BLOCK_STATUS_RESUME ) {
      break;
    }
    
 /* Break if UNAWARE is set and all readers have been checked */
    if ( ( dwBreakFlag == 1 ) && ( j == 0 ) ) {
      break;
    }
  } while ( 1 ); /* end of do */

  if ( psContextMap[retIndice].contextBlockStatus == 
         BLOCK_STATUS_RESUME ) {
      return SCARD_E_CANCELLED;
    }
  
  return SCARD_S_SUCCESS;
}


LONG SCardControl( SCARDHANDLE hCard, LPCBYTE pbSendBuffer, DWORD cbSendLength,
                   LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength ) {

  /* TODO */
  return SCARD_S_SUCCESS;
}

static LONG SCardTransmitTH( SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
		      LPCBYTE pbSendBuffer, DWORD cbSendLength,
		      LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, 
		      LPDWORD pcbRecvLength ) {
 
  BYTE Buffer[256];<commit_msg>Solve the problem of never exiting the loop when a smartcard is already inserted in the reader, thus blocking the application.<commit_after>/******************************************************************

        MUSCLE SmartCard Development ( http://www.linuxnet.com )
            Title  : winscard_scf.c
            Package: pcsc-lite
            Author : <NAME>
                     <NAME>
            Date   : 6/24/02
            License: Copyright (C) 2002 <NAME>
                     <<EMAIL>>
            Purpose: This provides PC/SC to SCF shimming.. 
                     Copy this file to pcsc-lite../src/winscard_clnt.c
********************************************************************/

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/un.h>
#include <smartcard/scf.h>

#include "wintypes.h"
#include "pcsclite.h"
#include "winscard.h"
#include "debuglog.h"

#define USE_THREAD_SAFETY
#ifdef USE_THREAD_SAFETY
#include "thread_generic.h"
#endif

#include "readerfactory.h"
#include "eventhandler.h"
#include "sys_generic.h"

#define TRUE 1
#define FALSE 0

#define PCSC_SCF_MAX_READERS 2
#define PCSC_SCF_MAX_ATR_BUFFER_LENGTH 32
#define PCSC_SCF_MAX_RECV_LEN 265

/* Global session to manage Readers, Card events. */
static SCF_Session_t  g_hSession = NULL;

/* Have to define this because they are defined in pcsclite.h as externs */
SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci;

static struct _psTransmitMap {
  BYTE Buffer[266];
  int isResponseCached;
  BYTE bufferLength;
} psTransmitMap[PCSCLITE_MAX_CONTEXTS];


/* Channel Map to manage Card Connections. */
static struct _psChannelMap {
  SCARDHANDLE  PCSC_hCard;
  SCARDCONTEXT hContext;
  SCF_Session_t  hSession;
  SCF_Terminal_t hTerminal;
  SCF_Card_t     SCF_hCard;
  short haveLock;
  short isReset;
  int ReaderIndice;
} psChannelMap[PCSCLITE_MAX_CONTEXTS];

/* Context Map to manage contexts and sessions. */
static struct _psContextMap {
  SCARDCONTEXT hContext;
  SCF_Session_t  hSession;
  DWORD        contextBlockStatus;
} psContextMap[PCSCLITE_MAX_CONTEXTS];

/* Reader Map to handle Status and GetStatusChange. */
static struct _psReaderMap {
  SCF_Terminal_t hTerminal;
  LPSTR ReaderName;
  short SharedRefCount;
  DWORD dwCurrentState;
  BYTE bAtr[PCSC_SCF_MAX_ATR_BUFFER_LENGTH];
  DWORD dwAtrLength;
  SCF_ListenerHandle_t lHandle;
} psReaderMap[PCSC_SCF_MAX_READERS];


#ifdef USE_THREAD_SAFETY
static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;

/*
 * Mutex for the Smardcard Event Handling, different from client Mutex
 * because event reporting from the ocfserver is done using a single thread,
 * so to get lock on the clientMutex may affect the performance of the ocf server.
 */
static PCSCLITE_MUTEX EventMutex = PTHREAD_MUTEX_INITIALIZER;
#endif

static LONG isOCFServerRunning();
LONG SCardLockThread();
LONG SCardUnlockThread();
LONG SCardEventLock();
LONG SCardEventUnlock();
static LONG PCSC_SCF_Initialize();
static void EventCallback(SCF_Event_t eventType, SCF_Terminal_t hTerm,
			  void * cbdata);
static LONG PCSC_SCF_getATR(SCF_Card_t hCard, LPBYTE pcbAtr, 
			    LPDWORD pcbAtrLen);

static LONG ConvertStatus(SCF_Status_t status);
static LONG SCardGetReaderIndice(LPCSTR ReaderName);
static LONG getNewContext(SCARDCONTEXT *phContext);
static LONG SCardAddContext(SCARDCONTEXT hContext,SCF_Session_t  hSession );
static SCF_Session_t getSessionForContext(SCARDCONTEXT hContext );
static LONG SCardRemoveContext ( SCARDCONTEXT hContext );
static LONG SCardGetContextIndice ( SCARDCONTEXT hContext );

static LONG getNewHandle(SCARDCONTEXT hContext,LPCSTR szReader,
			 SCARDHANDLE *phCard, DWORD);
static LONG  getCardForHandle(SCARDHANDLE PSCS_hCard, SCF_Card_t *SCF_hCard);
static LONG SCardRemoveHandle(SCARDHANDLE hCard);
static LONG SCardAddHandle(SCARDHANDLE PCSC_hCard, SCARDCONTEXT hContext,
			   SCF_Session_t  hSession,  SCF_Terminal_t hTerminal,
			   SCF_Card_t  SCF_hCard, int , DWORD);
static LONG SCardGetHandleIndice(SCARDHANDLE hCard);


static LONG SCardEstablishContextTH( DWORD dwScope, LPCVOID pvReserved1, 
				     LPCVOID pvReserved2, 
				     LPSCARDCONTEXT phContext) {
  LONG rv = 0;   

  
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  rv = PCSC_SCF_Initialize();
  
  if(SCARD_S_SUCCESS != rv)
    return rv;

  if (NULL == phContext) {
    return SCARD_E_INVALID_PARAMETER;
  } else {
    *phContext = 0;
  }
   
  if ( dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
       dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL ) {
     
    *phContext = 0;     
    return SCARD_E_INVALID_VALUE;
  }   
  rv = getNewContext(phContext);
  return rv;

}

LONG SCardEstablishContext( DWORD dwScope, LPCVOID pvReserved1, 
			    LPCVOID pvReserved2, LPSCARDCONTEXT phContext) {
  long rv;

  SCardLockThread();
  rv =  SCardEstablishContextTH( dwScope,  pvReserved1, 
				 pvReserved2,  phContext);
  SCardUnlockThread();
    
    
  return rv;
    
}

static LONG SCardReleaseContextTH( SCARDCONTEXT hContext ) {

  LONG rv;
  /* Zero out everything */
 
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  rv = 0;

  /* Remove the local context from the stack */
  rv = SCardRemoveContext( hContext );

  return rv;
}

LONG SCardReleaseContext( SCARDCONTEXT hContext ) {
  long rv;
    
  SCardLockThread();
  rv = SCardReleaseContextTH( hContext );
  SCardUnlockThread();
    
  return rv;
}


static LONG SCardListReadersTH( SCARDCONTEXT hContext, LPCSTR mszGroups, 
			 LPSTR mszReaders, LPDWORD pcchReaders ) {
  static int first_time = 1;
  int i=0;
  static DWORD dwReadersLen=0;
  LONG retIndice = 0;
  char *tempPtr;
  
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
/* Check for NULL parameters */
  if ( pcchReaders == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }
  /*Check for Context validity*/
  retIndice = SCardGetContextIndice(hContext);
  if(0> retIndice)
    return SCARD_E_INVALID_HANDLE;
  
  /*Calculate the the buffer length reuired only once.
  */
  if(first_time) {
    for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
      if(NULL != psReaderMap[i].ReaderName) 
	dwReadersLen += strlen(psReaderMap[i].ReaderName) +1;
    }
    dwReadersLen++;
    first_time = 0;
  }
  /*There are no readers available*/
  if(1 >= dwReadersLen)
    return SCARD_E_READER_UNAVAILABLE;
  
  
  if ( mszReaders == 0 ) {
    *pcchReaders = dwReadersLen;
    return SCARD_S_SUCCESS;
  } else if ( *pcchReaders == 0 ) {
    *pcchReaders = dwReadersLen;
    return SCARD_S_SUCCESS;
  } else if ( *pcchReaders < dwReadersLen ) {
    *pcchReaders = dwReadersLen;
    return SCARD_E_INSUFFICIENT_BUFFER;
  }
  
  tempPtr = mszReaders;
  for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
    if(NULL != psReaderMap[i].ReaderName) {
      memcpy(tempPtr, psReaderMap[i].ReaderName, 
	     strlen(psReaderMap[i].ReaderName)+1);
      tempPtr += (strlen(psReaderMap[i].ReaderName) + 1);
    }
  }
  /*the extra NULL character as per the PCSC specs.*/
  tempPtr[0] = '\0';
  *pcchReaders = dwReadersLen;
  
  return SCARD_S_SUCCESS;
}


LONG SCardListReaders( SCARDCONTEXT hContext, LPCSTR mszGroups, 
		       LPSTR mszReaders, LPDWORD pcchReaders ) {

  long rv;
    
  SCardLockThread();
  rv = SCardListReadersTH( hContext, mszGroups, mszReaders, pcchReaders );
  SCardUnlockThread();
    
  return rv;    
}
/* by najam */


static LONG SCardConnectTH( SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
			    DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
			    LPDWORD pdwActiveProtocol ) {    
  LONG rv;
   
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  /* Zero out everything   */
  rv=0;
  
  /* Check for NULL parameters */
  if ( phCard == 0 || pdwActiveProtocol == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  } else {
    *phCard = 0;
  }
  
  /* Make sure this context has been opened */
  if ( SCardGetContextIndice( hContext ) == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  if ( szReader == 0 ) {
    return SCARD_E_UNKNOWN_READER;
  }

  /* Check for uninitialized strings */
  if ( strlen(szReader) > MAX_READERNAME ) {
    return SCARD_E_INVALID_VALUE;
  } 

  if ( !(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
       !(dwPreferredProtocols & SCARD_PROTOCOL_ANY) ) {

    return SCARD_E_INVALID_VALUE;
  }
  
  if((SCARD_SHARE_SHARED != dwShareMode) &&
     (SCARD_SHARE_EXCLUSIVE != dwShareMode) &&
     (SCARD_SHARE_DIRECT != dwShareMode) ){
    return SCARD_E_INVALID_VALUE;
  }
  /* TODO Which Protocols have to be supported */
  /* Ignoring protocols for now */
  /* Make sure this handle has been opened */

  rv = getNewHandle(hContext,szReader,phCard,dwShareMode);
  
  if(SCARD_S_SUCCESS != rv) {
    return rv;
  }
  
  *pdwActiveProtocol = SCARD_PROTOCOL_T0;
  return SCARD_S_SUCCESS;
}

LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
		  DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
		  LPDWORD pdwActiveProtocol) 
{
  long rv;
    
  SCardLockThread();
  rv = SCardConnectTH(hContext, szReader, dwShareMode,
		      dwPreferredProtocols, phCard, pdwActiveProtocol);
  SCardUnlockThread();
  return rv;
    
}

static LONG SCardDisconnectTH( SCARDHANDLE hCard, DWORD dwDisposition ) {
     
  long rv;
  LONG retIndice = 0;
  
  SCF_Status_t status;
  
  /*check ocfserver availibility*/
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
  if ( dwDisposition != SCARD_LEAVE_CARD &&
       dwDisposition != SCARD_RESET_CARD &&
       dwDisposition != SCARD_UNPOWER_CARD &&
       dwDisposition != SCARD_EJECT_CARD ) {
    return SCARD_E_INVALID_VALUE;
  }
  /*CHECK HANDLE VALIDITY*/
  retIndice = SCardGetHandleIndice(hCard);
  if ((retIndice == -1) || (NULL == psChannelMap[retIndice].SCF_hCard)) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  /* TODO Take Care of the Disposition...  */
  /* Resetting the card for SCARD_RESET_CARD | 
     SCARD_UNPOWER_CARD | SCARD_EJECT_CARD */
  if(SCARD_LEAVE_CARD != dwDisposition) {
    /*must acquire the lock to reset card*/ 
    status = SCF_Card_lock(psChannelMap[retIndice].SCF_hCard, 0);
    if((SCF_STATUS_SUCCESS == status) || (SCF_STATUS_DOUBLELOCK == status )) {
      status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard);
      SCF_Card_unlock(psChannelMap[retIndice].SCF_hCard);
      /*a usleep here will allow the RESET_EVENT to be reported and 
	the Maps to be updated*/
      SYS_USleep(10);
    }
  }
  
  rv = SCardRemoveHandle(hCard);
     
  return rv;
  
}

static LONG SCardReconnectTH( SCARDHANDLE hCard, DWORD dwShareMode,
		       DWORD dwPreferredProtocols, DWORD dwInitialization,
		       LPDWORD pdwActiveProtocol ) {    
     
  SCARDCONTEXT hContext;
  LPSTR ReaderName;
  SCARDHANDLE tempHandle;
  LONG rv;
     
  int retIndice = 0;
   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
   if ( pdwActiveProtocol == 0 ){
    return SCARD_E_INVALID_PARAMETER;
  }
  if ( dwInitialization != SCARD_LEAVE_CARD &&
       dwInitialization != SCARD_RESET_CARD &&
       dwInitialization != SCARD_UNPOWER_CARD &&
       dwInitialization != SCARD_EJECT_CARD ) {  
    return SCARD_E_INVALID_VALUE;
  }
     
  retIndice = SCardGetHandleIndice(hCard);
    
  if(-1 == retIndice) {
    return SCARD_E_INVALID_HANDLE;
  }
  
  hContext = psChannelMap[retIndice].hContext;
  ReaderName = psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName;

  SCardDisconnectTH(hCard, dwInitialization);
  
  /* get a new handle*/
  rv = SCardConnectTH(hContext, ReaderName, dwShareMode, 
		      dwPreferredProtocols, &tempHandle, pdwActiveProtocol);
  if(SCARD_S_SUCCESS != rv) {
    return rv;
  }
     
  retIndice = SCardGetHandleIndice(tempHandle);
  if(-1 == retIndice) {
    return SCARD_E_NO_MEMORY;
  }
     
  /*set PCSC hCard to old Handle */
  SCardEventLock();
  psChannelMap[retIndice].PCSC_hCard = hCard;
  SCardEventUnlock();
  
  return SCARD_S_SUCCESS;
     
}

LONG SCardReconnect( SCARDHANDLE hCard, DWORD dwShareMode,
		     DWORD dwPreferredProtocols, DWORD dwInitialization,
		     LPDWORD pdwActiveProtocol ) {
    long rv;
    
    SCardLockThread();
    rv = SCardReconnectTH(hCard, dwShareMode, dwPreferredProtocols,
			  dwInitialization, pdwActiveProtocol);
    SCardUnlockThread();
    return rv;
    
}

LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition ) {

  long rv;
    
  SCardLockThread();
  rv = SCardDisconnectTH(hCard, dwDisposition);
  SCardUnlockThread();
  return rv;
    
}


LONG SCardBeginTransaction( SCARDHANDLE hCard ) {
     
  LONG rv;
  
  SCF_Card_t SCF_hCard;
  SCF_Status_t   status;
  /* Zero out everything   */
  rv=0;
     
  SCardLockThread();
  if(SCARD_S_SUCCESS != isOCFServerRunning()) {
    SCardUnlockThread();
    return SCARD_E_NO_SERVICE;
  }
   rv = getCardForHandle(hCard, &SCF_hCard);
  if(SCARD_S_SUCCESS != rv) {
    SCardUnlockThread();
    return rv;
  }
  SCardUnlockThread();
     
  status = SCF_Card_lock(SCF_hCard, SCF_TIMEOUT_MAX);
     
  if(SCF_STATUS_DOUBLELOCK == status)
    return SCARD_S_SUCCESS;

  rv = ConvertStatus(status);

  return rv;
     
}

static LONG SCardEndTransactionTH( SCARDHANDLE hCard, DWORD dwDisposition ) {

  LONG rv;
  LONG retIndice = 0;
  SCF_Card_t SCF_hCard;
  SCF_Status_t   status;

   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  /* Zero out everything   */
  rv=0;
  if ( dwDisposition != SCARD_LEAVE_CARD &&
       dwDisposition != SCARD_RESET_CARD &&
       dwDisposition != SCARD_UNPOWER_CARD &&
       dwDisposition != SCARD_EJECT_CARD ) {
	   
    return SCARD_E_INVALID_VALUE;
  }
  retIndice = SCardGetHandleIndice(hCard);
  if ( retIndice == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }    
       
  rv = getCardForHandle(hCard, &SCF_hCard);
  if(rv != SCARD_S_SUCCESS)
    return rv;
  
  /* TODO Take Care of the Disposition... */
  if(SCARD_LEAVE_CARD != dwDisposition) {
    status = SCF_Card_reset(psChannelMap[retIndice].SCF_hCard);
    if(SCF_STATUS_SUCCESS == status) {
      /* reset the isReset for this card */
      SYS_USleep(10);
      SCardEventLock();
      psChannelMap[retIndice].isReset = 0;
      SCardEventUnlock();
    }	   
  }
  
  status = SCF_Card_unlock(SCF_hCard);
       
  return ConvertStatus(status);
}

LONG SCardEndTransaction( SCARDHANDLE hCard, DWORD dwDisposition ) {

  long rv;
    
  SCardLockThread();
  rv = SCardEndTransactionTH(hCard, dwDisposition);
  SCardUnlockThread();
  return rv;
}

static LONG SCardCancelTransactionTH( SCARDHANDLE hCard ) {
   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
   
  /* TODO */
  return SCARD_S_SUCCESS;
}

LONG SCardCancelTransaction( SCARDHANDLE hCard ) {

  long rv;
    
  SCardLockThread();
  rv = SCardCancelTransactionTH(hCard);
  SCardUnlockThread();
  return rv;
}
static LONG SCardStatusTH( SCARDHANDLE hCard, LPSTR mszReaderNames, 
		    LPDWORD pcchReaderLen, LPDWORD pdwState, 
		    LPDWORD pdwProtocol, LPBYTE pbAtr,
		    LPDWORD pcbAtrLen ) {
  LONG retIndice, rv;
  int i;
  DWORD dwReaderLen;
  SCF_Card_t SCF_hCard;

   if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  /* Zero out everything   */
  retIndice=0; dwReaderLen=0; rv=0; i=0;
  /* Check for NULL parameters */

  if ( pcchReaderLen == 0 || pdwState == 0 || 
       pdwProtocol == 0 || pcbAtrLen == 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }

  
  retIndice = SCardGetHandleIndice(hCard);
  
  rv = getCardForHandle(hCard, &SCF_hCard);
  if(SCARD_S_SUCCESS != rv)
    return rv;
  
  dwReaderLen = strlen(psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName);
  
   if (mszReaderNames == 0) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0;
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_S_SUCCESS;
  }

   if (*pcchReaderLen == 0) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0; 
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_S_SUCCESS;
  }

  if (*pcchReaderLen < dwReaderLen) {
    *pcchReaderLen    = dwReaderLen;
    *pcbAtrLen        = 0; 
    *pdwState         = 0;
    *pdwProtocol      = 0;
    return SCARD_E_INSUFFICIENT_BUFFER;
  }
  
  *pcchReaderLen = dwReaderLen;
  strcpy(mszReaderNames, 
	 psReaderMap[psChannelMap[retIndice].ReaderIndice].ReaderName);
  *pdwProtocol = SCARD_PROTOCOL_T0;
  
  SCardEventLock();
  if(!(psReaderMap[psChannelMap[retIndice].ReaderIndice].dwCurrentState & SCARD_STATE_PRESENT)) {
    *pdwState = SCARD_ABSENT;
    SCardEventUnlock();
    return SCARD_S_SUCCESS;
  }
  
  *pdwState = SCARD_NEGOTIABLE | SCARD_POWERED |  SCARD_PRESENT;
  rv = PCSC_SCF_getATR(SCF_hCard, pbAtr, pcbAtrLen); 
  if(SCARD_S_SUCCESS == rv) {
    /*referesh the Atr in the reader Map*/
    psReaderMap[psChannelMap[retIndice].ReaderIndice].dwAtrLength = *pcbAtrLen;
    memcpy(psReaderMap[psChannelMap[retIndice].ReaderIndice].bAtr,
	   pbAtr, *pcbAtrLen);
  }
  
  SCardEventUnlock();
  return SCARD_S_SUCCESS;
}

LONG SCardStatus( SCARDHANDLE hCard, LPSTR mszReaderNames, 
		  LPDWORD pcchReaderLen, LPDWORD pdwState, 
		  LPDWORD pdwProtocol, LPBYTE pbAtr,
                  LPDWORD pcbAtrLen ) {
  long rv;
    
  SCardLockThread();
  rv = SCardStatusTH(hCard, mszReaderNames, pcchReaderLen, pdwState,
		     pdwProtocol, pbAtr, pcbAtrLen);
  SCardUnlockThread();
  return rv;
}

LONG SCardGetStatusChange( SCARDCONTEXT hContext, DWORD dwTimeout, 
			   LPSCARD_READERSTATE_A rgReaderStates, 
                           DWORD cReaders ) {

  LONG rv, retIndice;
   PSCARD_READERSTATE_A currReader;
  PREADER_STATES rContext;
  LPSTR lpcReaderName;
  DWORD dwTime;
  DWORD dwState;
  DWORD dwBreakFlag;
  int i, j;

   
  if(SCARD_S_SUCCESS != isOCFServerRunning())
    return SCARD_E_NO_SERVICE;
  
   /* Zero out everything */
  rv=0; rContext=0; lpcReaderName=0; dwTime=0; j=0;
  dwState=0; i=0; currReader=0; retIndice=0; dwBreakFlag=0;
  
   if ( rgReaderStates == 0 && cReaders > 0 ) {
    return SCARD_E_INVALID_PARAMETER;
  }
  if ( cReaders < 0 ) {
    return SCARD_E_INVALID_VALUE;
  }
  /* change by najam */
  SCardLockThread();
  retIndice = SCardGetContextIndice( hContext );
  /* change by najam */
  SCardUnlockThread();
  if ( retIndice == -1 ) {
    return SCARD_E_INVALID_HANDLE;
  }
  
   /* Application is waiting for a reader -
     return the first available reader 
  */
  if ( cReaders == 0 ) {
      for(i=0;i<PCSC_SCF_MAX_READERS;i++) {
	if(psReaderMap[i].ReaderName) 
	  return SCARD_S_SUCCESS;
      }
      return SCARD_E_READER_UNAVAILABLE;
  } else if(cReaders >PCSC_SCF_MAX_READERS) {
    return SCARD_E_INVALID_VALUE;
  }
   /* Check the integrity of the reader states structures */
  for ( j=0; j < cReaders; j++ ) {
    currReader = &rgReaderStates[j];
    if ( currReader->szReader == 0 ) {
      return SCARD_E_INVALID_VALUE;
    }
  }
  /* End of search for readers */
  
 /* Clear the event state for all readers */
  for ( j=0; j < cReaders; j++ ) {
    currReader = &rgReaderStates[j];
    currReader->dwEventState = 0;
  }

  /* Now is where we start our event checking loop */

  psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_BLOCKING;
  j=0;
  
  do {
    SYS_USleep(10);
    if(SCARD_S_SUCCESS != isOCFServerRunning())
      return SCARD_E_NO_SERVICE;

    currReader    = &rgReaderStates[j];
   
    /************ Look for IGNORED readers ****************************/

    if ( currReader->dwCurrentState & SCARD_STATE_IGNORE ) {
      currReader->dwEventState = SCARD_STATE_IGNORE;
    } else {
      /************ Looks for correct readernames *********************/
      
      lpcReaderName = (char *)currReader->szReader;
      
      retIndice = SCardGetReaderIndice(lpcReaderName);
      /* The requested reader name is not recognized */
      if(0> retIndice) {
	if ( currReader->dwCurrentState & SCARD_STATE_UNKNOWN ) {
	  currReader->dwEventState = SCARD_STATE_UNKNOWN;
	} else {
	  currReader->dwEventState = 
	    SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
	  /* Spec says use SCARD_STATE_IGNORE but a removed USB reader
	     with eventState fed into currentState will be ignored forever */
	  dwBreakFlag = 1;
	}
      } else {
		/* The reader has come back after being away */
	if ( currReader->dwCurrentState & SCARD_STATE_UNKNOWN ) {
	  currReader->dwEventState |= SCARD_STATE_CHANGED;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  dwBreakFlag = 1;
	}
	
	/*****************************************************************/
	SCardEventLock();
	/* Now we check all the Reader States */
	dwState = psReaderMap[retIndice].dwCurrentState;
	
	/*********** Check if the reader is in the correct state ********/
	if ( dwState & SCARD_STATE_UNKNOWN ) {
	  /* App thinks reader is in bad state and it is */
	  if ( currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE ) {
	    currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
	  } else {
	    /* App thinks reader is in good state and it is not */
	    currReader->dwEventState = SCARD_STATE_CHANGED |
	      SCARD_STATE_UNAVAILABLE;
	    dwBreakFlag = 1;
	  }
	} else {
	  /* App thinks reader in bad state but it is not */
	  if ( currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE ) {
	    currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  } 
	}	
	
	/********** Check for card presence in the reader **************/

	if ( dwState & SCARD_STATE_PRESENT ) {
	  currReader->cbAtr = psReaderMap[retIndice].dwAtrLength;
	  memcpy( currReader->rgbAtr, psReaderMap[retIndice].bAtr, 
		  currReader->cbAtr );
	} else {
	   currReader->cbAtr = 0;
	}
		/* Card is now absent                   */
	if ( dwState & SCARD_STATE_EMPTY ) {
	  currReader->dwEventState |= SCARD_STATE_EMPTY;
	  currReader->dwEventState &= ~SCARD_STATE_PRESENT;
	  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
	  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	  currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
	  currReader->dwEventState &= ~SCARD_STATE_MUTE;
	  currReader->dwEventState &= ~SCARD_STATE_INUSE;
	  /* After present the rest are assumed */
	  if ( currReader->dwCurrentState & SCARD_STATE_PRESENT ||
	       currReader->dwCurrentState & SCARD_STATE_ATRMATCH ||
	       currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE ||
	       currReader->dwCurrentState & SCARD_STATE_INUSE ) 
	    {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;	
	      dwBreakFlag = 1;
	    }
	   /* Card is now present              */
	} else if ( dwState & SCARD_STATE_PRESENT ) {
	  currReader->dwEventState |= SCARD_STATE_PRESENT;
	  currReader->dwEventState &= ~SCARD_STATE_EMPTY;
	  currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
	  currReader->dwEventState &= ~SCARD_STATE_IGNORE;
	  currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
	  currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
	  currReader->dwEventState &= ~SCARD_STATE_MUTE;
	  
	  if ( currReader->dwCurrentState & SCARD_STATE_EMPTY ) {
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  }	
	  /* TODO */
	  if ( 0 && dwState & SCARD_SWALLOWED ) {
	    if ( currReader->dwCurrentState & SCARD_STATE_MUTE ) {
	      currReader->dwEventState |= SCARD_STATE_MUTE;
	    } else {
	      currReader->dwEventState |= SCARD_STATE_MUTE;
              if ( currReader->dwCurrentState != SCARD_STATE_UNAWARE ) {
	        currReader->dwEventState |= SCARD_STATE_CHANGED;
              }
	      dwBreakFlag = 1;
	    }
	  } else {
	    /* App thinks card is mute but it is not */
	    if ( currReader->dwCurrentState & SCARD_STATE_MUTE ) {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;
	      dwBreakFlag = 1;
	    }
	  }	    
	}
	
	if(-1 == psReaderMap[retIndice].SharedRefCount) {
	  currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
	  currReader->dwEventState &= ~SCARD_STATE_INUSE;
	  if ( !currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE ) {
	    currReader->dwEventState |= SCARD_STATE_CHANGED;
	    dwBreakFlag = 1;
	  }
	} else if (psReaderMap[retIndice].SharedRefCount >= 1) {
	 /* A card must be inserted for it to be INUSE */
	  if ( dwState & SCARD_STATE_PRESENT ) {
	    currReader->dwEventState |= SCARD_STATE_INUSE;
	    currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
	    if ( !currReader->dwCurrentState & SCARD_STATE_INUSE ) {
	      currReader->dwEventState |= SCARD_STATE_CHANGED;
	      dwBreakFlag = 1;
	    }
	  }
	}
	SCardEventUnlock();
	if ( currReader->dwCurrentState == SCARD_STATE_UNAWARE ) {
	  /* Break out of the while .. loop and return status 
	     once all the status's for all readers is met */
	  dwBreakFlag = 1;
	}
	SYS_USleep( PCSCLITE_STATUS_WAIT );
	
      }  /* End of SCARD_STATE_UNKNOWN */
      
    }    /* End of SCARD_STATE_IGNORE */
    
     /* Counter and resetter */
    j = j + 1;
    if ( j == cReaders ) { j=0; }
    
    if ( dwTimeout != INFINITE && dwTimeout != 0 ) {
      dwTime += PCSCLITE_STATUS_WAIT;
      
      /* If time is greater than timeout and all readers have been 
	 checked
      */
      if ( ( dwTime >= (dwTimeout*1000) )&&
	   ( j == 0 ) ) 
	{
        return SCARD_E_TIMEOUT;
      }
    }

 /* Declare all the break conditions */
    /* TODO think about this */
       if ( psContextMap[retIndice].contextBlockStatus == 
	 BLOCK_STATUS_RESUME ) {
      break;
    }
    
 /* Break if UNAWARE is set and all readers have been checked */
    if ( ( dwBreakFlag == 1 ) && ( j == 0 ) ) {
      break;
    }

    /*
     * Solve the problem of never exiting the loop when a smartcard is
     * already inserted in the reader, thus blocking the application
     * (patch proposed by <NAME>)
     */
    if ((dwTimeout == 0) && (j == 0))
    {
	    break;
    }

  } while ( 1 ); /* end of do */

  if ( psContextMap[retIndice].contextBlockStatus == 
         BLOCK_STATUS_RESUME ) {
      return SCARD_E_CANCELLED;
    }
  
  return SCARD_S_SUCCESS;
}


LONG SCardControl( SCARDHANDLE hCard, LPCBYTE pbSendBuffer, DWORD cbSendLength,
                   LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength ) {

  /* TODO */
  return SCARD_S_SUCCESS;
}

static LONG SCardTransmitTH( SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
		      LPCBYTE pbSendBuffer, DWORD cbSendLength,
		      LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, 
		      LPDWORD pcbRecvLength ) {
 
  BYTE Buffer[256];
{'fraction_non_alphanumeric': 0.1052760504993405, 'fraction_numerical': 0.005577539099302808, 'mean_word_length': 3.3751854905193737, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 164, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5787977', 'n_tokens_mistral': 19468, 'n_tokens_neox': 18722, 'n_words': 3860}