// Compilieren mit folgender Kommandozeile:
//
//		 g++ -I/usr/include/PCSC modify_pin_direct.cpp -lpcsclite -o modify_pin_direct
// g++ -framework PCSC -I/Users/sct/reinser-sct/5final.SP03/pcsc-cyberjack-3.99.5final.SP03/include/macosx/PCSC  modify_pin_direct.cpp -o modify_pin_direct

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>

#define CALLCONVENTION

#include <PCSC/wintypes.h>
#include <PCSC/pcsclite.h>
#include <PCSC/winscard.h>
#include <reader.h>

#define KP_DEBUG 0

int main(int argc, char** argv)
{
	SCARDHANDLE hCard;
	DWORD cardProtocol;
	SCARDCONTEXT hContext;
	long res;
	char *mszReaders;
	DWORD dwReaders = 1000;
	char *mszGroups;

	res = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);

	if (res != SCARD_S_SUCCESS) {
		printf("Fehler bei sCardEstablishContext: %p\n", (void*)res);
		return -1;
	}

	printf("Testing SCardListReaders\t: ");
	mszGroups = NULL;
	mszReaders = (char *)calloc(dwReaders, sizeof(char));
	res = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders);
	if (res != SCARD_S_SUCCESS) {
		printf("Fehler bei SCardListReaders: %p\n", (void*)res);
		return -1;
	}
	/*
	 * Have to understand the multi-string here
	 */
	for (int i = 0; i + 1 < dwReaders; i++) {
		printf("Reader %s\n", &mszReaders[i]);
		while (mszReaders[++i] != 0) ;
	}


	for (int loopnr = 1; loopnr <= 1; ++loopnr) {
		int i = 0;
		sleep(1); // es ist egal, ob hier sleep steht, oder nicht, insofern kein Timing-Problem
		//SCARD_SHARE_EXCLUSIVE,

		//"REINER SCT cyberJack pp_a (5475474673) 00 00",
		//"REINER SCT cyberJack ecom_a (1521134321) 00 00",
		res = SCardConnect(hContext,
				   &mszReaders[0],
				   SCARD_SHARE_SHARED,
				   SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
				   &hCard,
				   &cardProtocol);

		if (res != SCARD_S_SUCCESS) {
			printf("sCardConnect %03d: Fehler %p ****\n", loopnr, (void*)res);
		} else {
			SCARD_IO_REQUEST pioRecvPci;
			SCARD_IO_REQUEST pioSendPci;
			unsigned char bSendBuffer[MAX_BUFFER_SIZE];
			unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
			DWORD send_length, length;
		printf("cardProtocol=0x%08x SCARD_PROTOCOL_T1=0x%08x\n",cardProtocol,SCARD_PROTOCOL_T1);
			switch (cardProtocol) {
			case SCARD_PROTOCOL_T0:
				pioSendPci = *SCARD_PCI_T0;
				break;
			case SCARD_PROTOCOL_T1:
				pioSendPci = *SCARD_PCI_T1;
				break;
			case SCARD_PROTOCOL_RAW:
				pioSendPci = *SCARD_PCI_RAW;
				break;
			default:
				printf("Unknown protocol\n");
				return -1;
			}

			/* APDU select file */
			printf("Select file:");
			send_length = 8;
			memcpy(bSendBuffer, "\x00\xA4\x00\x00\x02\x3F\x00\x00", send_length);
			for (i = 0; i < send_length; i++)
				printf(" %02X", bSendBuffer[i]);
			printf("\n");
			length = sizeof(bRecvBuffer);

			printf("Testing SCardTransmit\t\t: ");
			res = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
					    &pioRecvPci, bRecvBuffer, &length);
			printf("res=%ld\n", res);
			for (i = 0; i < length; i++)
				printf(" %02X", bRecvBuffer[i]);

			sleep(1);

			{
				char buffer[1024] = { 0x02 };
				DWORD cbRecvLength = sizeof(buffer);
				DWORD fr_fmpd = 0;
				DWORD dwControlCode = 0x00313520;

				printf("\ntesting SCardControl CM_IOCTL_GET_FEATURE_REQUEST\n");
#if 0
        /* Is this a proper Windows smart card ioctl? */
        if ((dwControlCode & 0xffff0000) == (49 << 16))
        {
                /* Translate to local encoding */
                dwControlCode = (dwControlCode & 0x3ffc) >> 2;
                dwControlCode = SCARD_CTL_CODE(dwControlCode);
        }
        else
        {
                printf("Bogus smart card control code 0x%08x\n", dwControlCode);
        }
#endif

				send_length = 0;
				PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)buffer;
				//res = SCardControl(hCard, dwControlCode, NULL, 0, buffer, sizeof(buffer), &cbRecvLength);
printf("CM_IOCTL_GET_FEATURE_REQUEST 0x%08x", CM_IOCTL_GET_FEATURE_REQUEST);
				res = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, bSendBuffer, send_length, buffer, sizeof(buffer), &cbRecvLength);
				//res = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, bRecvBuffer, sizeof(bRecvBuffer), &length);
#if KP_DEBUG
       if (res != SCARD_S_SUCCESS) {
                printf("Fehler bei SCardControl: %p CM_IOCTL_GET_FEATURE_REQUEST=0x%08x dwControlCode=0x%08x\n", (void*)res,CM_IOCTL_GET_FEATURE_REQUEST,dwControlCode);
                return -1;
        }

				if (cbRecvLength && (SCARD_S_SUCCESS == res)) {
					for (i = 0; i < cbRecvLength; i++)
						printf("0x%02x ", buffer[i]);
					printf(" ");
				}else  {
					printf("Fehler bei SCardControl: %p\n", (void*)res);
					return 1;
				}
				printf("\n");
#endif
				for (int len = 0; len < cbRecvLength; len++) {
					//printf("tag=0x%08x FEATURE_MODIFY_PIN_DIRECT=0x%08x\n",pcsc_tlv->tag,FEATURE_MODIFY_PIN_DIRECT);
					switch (pcsc_tlv->tag) {
					case FEATURE_MODIFY_PIN_DIRECT:
						printf("FEATURE_MODIFY_PIN_DIRECT found\n");
						printf("pcsc_tlv->value = %08x\n", ntohl(pcsc_tlv->value));
						fr_fmpd = ntohl(pcsc_tlv->value);
						break;
#if KP_DEBUG
					case FEATURE_VERIFY_PIN_DIRECT:
						printf("FEATURE_VERIFY_PIN_DIRECT found\n");
						printf("pcsc_tlv->value = %08x\n", ntohl(pcsc_tlv->value));
						break;
					default:
						printf("unknown FEATURE found\n");
						printf("pcsc_tlv->value = %08x\n", ntohl(pcsc_tlv->value));
#endif
					}
					pcsc_tlv++;
					len += sizeof(PCSC_TLV_STRUCTURE);
				}


				if (fr_fmpd) {
					printf("\ntesting SCardControl FEATURE_MODIFY_PIN_DIRECT\n");
					send_length = 28;
					memcpy(bSendBuffer, "\x00\x00\x82\x08\x00\x00\x00\x08\x04\x03\x02\x03\x04\x07\x00\x01\x02\x00\x00\x00\x04\x00\x00\x00\x00\x24\x00\x03", send_length);
					for (i = 0; i < send_length; i++)
						printf(" %02X", bSendBuffer[i]);
					printf("\n");
					length = sizeof(bRecvBuffer);

					res = SCardControl(hCard, fr_fmpd, bSendBuffer, send_length, buffer, sizeof(buffer), &cbRecvLength);
					if (cbRecvLength && (SCARD_S_SUCCESS == res)) {
						for (i = 0; i < cbRecvLength; i++)
							printf("%c", buffer[i]);
						printf(" ");
					}else  {
						printf("Fehler bei SCardControl: %p\n", (void*)res);
						return 1;
					}
				}
			}

			SCardDisconnect(hCard, SCARD_RESET_CARD); // ohne diesen disconnect gehen alle Folgeaufrufe schief
		}
	}

	return 0;
}
