/**
*********************************************************************************************************************
* @file		SmartCard.cpp
* @brief	EMV Library for Windows(95/98/NT/2000/XP).
* @brief	Selection Smart Readers and sending APDU commands to smart-card.
* @author	Konstantin Yalin
* @author	Email: Yalin@yalko.ru 
* @author	Website: http://www.yalko.ru 
* @version	1.0
* @date		2010
*********************************************************************************************************************
*/
/**
***************** Modification Section: *****************************************************************************
$Archive: /SmartReader/SmartCard/SmartCard.cpp $
$Author: Yalin $
$Date: 17.08.09 16:49 $
$Revision: 23 $
$Header: /SmartReader/SmartCard/SmartCard.cpp 23    17.08.09 16:49 Yalin $
$Modtime: 6.08.09 16:19 $
*********************************************************************************************************************
*/
#include "stdafx.h"

TCHAR MainFname[256];
TCHAR AppDir [256];
TCHAR test_name[256];

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
			break;
		case DLL_THREAD_ATTACH:			
			break;
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;

    }
    return TRUE;
}
WORD hex2code(WORD h) 
{
    if (h<='9') return h-'0';
    else return h-'A'+10;
}

BYTE code2hex(BYTE c) 
{
    if (c<=9) return c+'0';
    else return c-10+'A';
}

void hex2bin( BYTE * hex, BYTE * bin, DWORD BYTE_amn) 
{
    WORD x,y;
    while (BYTE_amn>0) {
        x=hex2code((WORD)*hex++)<<4;
        y=hex2code((WORD)*hex++);
        *bin++ =(BYTE)(x+y);
        BYTE_amn--;
    }
}

void bin2hex( BYTE * bin, BYTE * hex, DWORD BYTE_amn) 
{
    while (BYTE_amn>0) {
        *hex++ = code2hex((BYTE)(*bin>>4));
        *hex++ = code2hex((BYTE)(*bin&0xf));
        bin++;
        BYTE_amn--;
    }
}

BYTE WINAPI SelectReader(LPSTR rname,DWORD rname_size)
{	
    //emv_ker.dll: RFU Reserved for Future Use
	return 1;/*TRUE*/
}
BYTE WINAPI OpenReader(LPSTR rname)
{		
    //emv_ker.dll: RFU Reserved for Future Use
	return 0;/*TRUE;*/
}
BYTE WINAPI CloseReader(void)
{
    //emv_ker.dll: RFU Reserved for Future Use
    return 0;/*TRUE;*/
}

 unsigned short apdu_data_len;
 byte apdu_cmd[5];
 byte apdu_data[356];

 unsigned short apdu_sw;
 byte apdu_answer[356];
 unsigned short apdu_answer_len;

static void CardSimulator()
{
    char sCmd[100];
    char sData[514];

    memset(sCmd,0,sizeof(sCmd));
    memset(sData,0,sizeof(sData));

    bin2hex(apdu_cmd,(BYTE*)sCmd,5);

    if(apdu_data_len > 0 && apdu_data_len < sizeof(sData)/2)
    {
        bin2hex(apdu_data, (BYTE *)sData,apdu_data_len);

        //MessageBox(NULL,sCmd,sData,MB_OK);
        if (strcmp(sCmd,"00A404000E") == 0 && strcmp(sData,"315041592E5359532E4444463031") == 0)
        {
            apdu_sw = 0x6A82;
        } else
            if (strcmp(sCmd,"00A4040007") == 0 && strcmp(sData,"A0000000031010") == 0)
            {
                apdu_sw = 0x9000;
                char sAnswer[] = "6F318407A0000000031010A526500B56495341204352454449549F120F4352454449544F20444520564953418701019F110101";
                apdu_answer_len = strlen(sAnswer) / 2;
                hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
            }
            else
                if (strcmp(sCmd,"80A8000002") == 0 && strcmp(sData,"8300") == 0)
                {
                    apdu_sw = 0x9000;
                    char sAnswer[] = "800E5C00080101001001030018010201";
                    apdu_answer_len = strlen(sAnswer) / 2;
                    hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                }
                else
                    if (strcmp(sCmd,"80AE80001D") == 0)// && sData.Equals("00000001000000000000000008404000048000064313083100E9C4B090"))
                    {
                        apdu_sw = 0x9000;
                        char sAnswer[] = "80128000018B5911CDEBC190F506010A03900000";
                        apdu_answer_len = strlen(sAnswer) / 2;
                        hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                    }
                    else
                        if (strcmp(sCmd,"008200000A") == 0)// && sData.Equals("993680ED37FC09533030"))
                        {
                            apdu_sw = 0x9000;
                        }
                        else
                            if (strcmp(sCmd,"80AE40001F") == 0)// && sData.Equals("3030000000010000000000000000084040000480000643130831006D4B0149"))
                            {
                                apdu_sw = 0x9000;
                                char sAnswer[] = "8012400001492136F956F8B83006010A03600000";
                                apdu_answer_len = strlen(sAnswer) / 2;
                                hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                            }
                            else
                                if (strncmp(sCmd,"00A404000",9) == 0)
                                {
                                    apdu_sw = 0x6A82;
                                } else
                                {
                                    MessageBox(NULL,"No Equals","No Equals",MB_OK);
                                }

    } else {
        if (strcmp(sCmd,"00B2010C00") == 0)
        {
            apdu_sw = 0x9000;
            char sAnswer[] = "70435F201A564953412041435155495245522054455354204341524420303157114761739001010010D101220111438780899F1F1031313433383030373830303030303030";
            apdu_answer_len = strlen(sAnswer) / 2;
            hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
        }
        else
            if (strcmp(sCmd,"00B2011400") == 0)
            {
                apdu_sw = 0x9000;
                char sAnswer[] = "7081939081908B3901F6253048A8B2CB08974A4245D90E1F0C4A2A69BCA469615A71DB21EE7B3AA94200CFAEDCD6F0A7D9AD0BF79213B6A418D7A49D234E5C9715C9140D87940F2E04D6971F4A204C927A455D4F8FC0D6402A79A1CE05AA3A526867329853F5AC2FEB3C6F59FF6C453A7245E39D73451461725795ED73097099963B82EBF7203C1F78A529140C182DBBE6B42AE00C02";
                apdu_answer_len = strlen(sAnswer) / 2;
                hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
            }
            else
                if (strcmp(sCmd,"00B2021400") == 0)
                {
                    apdu_sw = 0x9000;
                    char sAnswer[] = "702D8F01959F320103922433F5E4447D4A32E5936E5A1339329BB4E8DD8BF0044CE4428E24D0866FAEFD2348809D71";
                   apdu_answer_len = strlen(sAnswer) / 2;
                    hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                }
                else
                    if (strcmp(sCmd,"00B2031400") == 0)
                    {
                        apdu_sw = 0x9000;
                        char sAnswer[] = "708193938190919D6C210B3981D1C99B3AD55EDF36A138FFAD54D838FA40622AB97046E05EA6E6230AB89D5BE871114EB5431B97403B8C3D2D4CA9BB625AC13FD8C6B825433656CB56557AAC396D945F6D4014FB6E71E8DBEA74B285E9CF3FCEABDFA61D5A4BE16DAAA433F7F2644B178A7DD93DA98BB9D10E84298BDB6B6AE02D04E6E5558C77E79F82C9E046DF821DD0277AB9D00C";
                        apdu_answer_len = strlen(sAnswer) / 2;
                        hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                    }
                    else
                        if (strcmp(sCmd,"00B2011C00") == 0)
                        {
                            apdu_sw = 0x9000;
                            char sAnswer[] = "700E5A0847617390010100105F340101";
                            apdu_answer_len = strlen(sAnswer) / 2;
                            hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                        }
                        else
                            if (strcmp(sCmd,"00B2021C00") == 0)
                            {
                                apdu_sw = 0x9000;
                                char sAnswer[] = "707D9F420208405F25039507015F24031012319F0802008C5F280208405F300202019F0702FF008E0E00000000000000001E0302031F008C159F02069F03069F1A0295055F2A029A039C019F37048D178A029F02069F03069F1A0295055F2A029A039C019F37049F0D05F0400088009F0E0500100000009F0F05F040009800";
                                apdu_answer_len = strlen(sAnswer) / 2;
                                hex2bin((BYTE*)sAnswer, apdu_answer, apdu_answer_len);
                            }
                            else
                            {
                                MessageBox(NULL,"No Equals","No Equals",MB_OK);
                            }
    }
}

/**
**********************************************************************************************
*	@fn BYTE WINAPI Atr(BYTE *atr, DWORD * max_len, BYTE * protocol) 
*  @b Назначение:							\n
*	@brief Получает ATR, используется EMV ядром.	\n
*  @author  Ilya Yalin
**********************************************************************************************
*  @b Выполняет:
*	@code
*  1.) Посылает ридеру команду подать питание на карточку.
*  2.) Получает от карточки ATR.
*	@endcode
**********************************************************************************************
*  @param Вход: \n
*  @b DWORD * max_len;	- Максимальный размер буфера для приёма данных ATR.
*
*  @param Выход: \n
*  @b BYTE *atr	- Указатель на буфер для данных ATR.
*  @b DWORD * max_len;	- Размер полученных данных.
*  @b BYTE * protocol;	- Адрес для получения протокола. Для моторизованных ридеров всегда 0.
**********************************************************************************************
*  @return 
*  @b BYTE;	- Статус выполнения операций.
*	@b 1 – операция завершилась успешно.
*	@b 0 – операция завершилась не удачей.
**********************************************************************************************
*/

BYTE WINAPI Atr (BYTE *atr, DWORD * max_len,BYTE * protocol)
{
    char sAtr[] = "3B620000811F";
    if (strlen(sAtr)/2 < *max_len)
    {
        *max_len = strlen(sAtr)/2;
        hex2bin((BYTE*)sAtr,atr,*max_len);
        *protocol = 0;
    }
    return 1;//ok
}

/**
**********************************************************************************************
*	@fn WORD WINAPI SendApduIn(BYTE *Cmd,BYTE * Data,WORD *Data_len,BYTE *answer,WORD answer_max_len)
*  @b Назначение:							\n
*	@brief Посылает APDU команду с данными и получает ответ. Используется EMV ядром.	\n
*  @author  
**********************************************************************************************
*  @b Выполняет:
*	@code
*  1.) Посылает APDU команду и получает ответ.
*  2.) Возвращает данные в буфер.
*	@endcode
**********************************************************************************************
*  @param Вход: \n
*  @b BYTE * Cmd;	– Буфер, содержащий APDU команду.
*  @b BYTE * Data;	– Буфер, содержащий данные.
*  @b WORD *Data_len;	- Длина даннных.
*  @b WORD answer_max_len;	- Размер буфера для ответа.
*
*  @param Выход: \n
*  @b BYTE * answer;	– Буфер для ответа от карты на APDU команду.
*  @b WORD *Data_len;	- Длина полученых от карты даннных.
**********************************************************************************************
*  @return 
*  @b WORD;	- Статус, полученный от карты на APDU команду.
**********************************************************************************************
*/
WORD WINAPI SendApduIn(BYTE *cmd,BYTE * data,WORD *data_len,BYTE *answer,WORD answer_max_len)
{
    memcpy(apdu_cmd, cmd, 5);
    apdu_data_len = *data_len;
    if (apdu_data_len < sizeof(apdu_data))
    {
        memcpy(apdu_data, data, apdu_data_len);

        apdu_sw = 0;
        apdu_answer_len = 0;
        memset(apdu_answer, 0, sizeof(apdu_answer));

        CardSimulator();

        if (apdu_answer_len > 0 && answer_max_len > apdu_answer_len)
        {
            memcpy(answer, apdu_answer, apdu_answer_len);
            *data_len = apdu_answer_len;
        }
        return apdu_sw;
    } else {
        return 0;
    }
}

/**
**********************************************************************************************
*	@fn WORD WINAPI SendApduOut(BYTE *Cmd,WORD *Stat,BYTE *answer,WORD answer_max_len)
*  @b Назначение:						\n
*	@brief Посылает APDU команду и получает ответ. Используется EMV ядром.	\n
*  @author  
**********************************************************************************************
*  @b Выполняет:
*	@code
*  1.) Посылает APDU команду и получает ответ.
*  2.) Возвращает данные в буфер.
*	@endcode
**********************************************************************************************
*  @param Вход: \n
*  @b BYTE * Cmd;	– Буфер, содержащий APDU команду.
*  @b WORD answer_max_len;	- Размер буфера для ответа.
*
*  @param Выход: \n
*  @b WORD * Stat;	– Возвращается статус, полученный от карты на APDU команду.
*  @b BYTE * answer;	– Буфер для ответа от карты на APDU команду.
**********************************************************************************************
*  @return 
*  @b WORD;	- Длинна полученного ответа от карты.
**********************************************************************************************
*/
WORD WINAPI SendApduOut(BYTE * cmd, WORD * stat, BYTE * answer, WORD answer_max_len)
{	
    memcpy(apdu_cmd, cmd, 5);

    apdu_data_len = 0;
    apdu_sw = 0;
    apdu_answer_len = 0;
    memset(apdu_answer, 0, sizeof(apdu_answer));

    CardSimulator();

    if (apdu_answer_len > 0 && answer_max_len > apdu_answer_len)
    {
        memcpy(answer, apdu_answer, apdu_answer_len);
        * stat = apdu_sw;
        return apdu_answer_len;
    } else {
        return 0;
    }
}

/**
**********************************************************************************************
*	@fn BYTE WINAPI CheckConnect()
*  @b Назначение:							\n
*	@brief Проверяет наличие карты в ридере.	\n
*  @author  
**********************************************************************************************
*  @b Выполняет:
*	@code
*  1.) Проверяет флаг наличия карты в ридере. Флаг выставляется после выполнения TakeCard(), если была подача карты.
*	@endcode
**********************************************************************************************
*  @param Вход: \n
*  @b None
*
*  @param Выход: \n
*  @b None
**********************************************************************************************
*  @return 
*  @b BYTE;	- Результат выполнения.
*  @b 1	- Карта присутствует.
*  @b 0	- Карта отсуттствует.
**********************************************************************************************
*/
BYTE WINAPI CheckConnect()
{
    //emv_ker.dll call it time from time
    return 1;//TRUE
}


