//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//																	  ||
//	Copyright (C) 2001 Feitian Tech. Co. Ltd. All rights reserved.																  ||	
//	Filename: 	StdAfx.h
//	Author:		Xuying
//	Purpose:	Sample console editor for ePass1000.
//
//	Revision:
//										 	
//																	 //	
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

EPAS_HANDLE g_hToken = NULL;

long FileIDIsValid(char* CharBuf, int LenthBuf)
{
	for (int i=0; i<LenthBuf; i++)
	{
		if(!( (CharBuf[i]>='0' && CharBuf[i]<='9') || (CharBuf[i]>='a' && CharBuf[i]<='f') || (CharBuf[i]>='A' && CharBuf[i]<='F') ))
			return FT_INVALID_PARAMETER;
	}
	return FT_SUCCESS;
}

int WaitForUserInput()
{
	printf("\nInput selection:");
	fflush(stdin);
	int ic = getchar();
	//printf("%c\n",ic);
	return toupper(ic);
}

void ShowMainCmdMenu()
{
	printf("\n\nMain Menu:\n");
	printf("-------------------------------------------------------------\n");
	printf(	"  Open[F]irst  LED[O]n   [P]in     [L]ist       File[M]enu\n"
			"  Open[N]ext   LE[D]Off  [S]oPin   [G]enRandom  Cr[y]ptMenu\n"
			"  [R]eOpen     Rese[t]   [A]ccess               Set[u]pMenu\n"
			"  [C]lose      E[x]it\n");
}

void ShowBanner()
{
	unsigned long version = 0;
	printf("\nFeitian ePass1000 Editor v 3.2.3.1013\nCreate at " __DATE__ ", " __TIME__ "\n\n" );

	version = epas_GetDriverVersion();
	printf( "Driver version %d.%d.%d\n",
			HIBYTE(HIWORD(version)), LOBYTE(HIWORD(version)), LOWORD(version));

	version = epas_GetLibVersion();
	printf( "Library version %d.%d.%d\n",
			HIBYTE(HIWORD(version)), LOBYTE(HIWORD(version)), LOWORD(version));
}

void ShowErrInfo(EPAS_STATUS retval)
{
	switch(retval)
	{
	case FT_SUCCESS					 :
		printf(" Success!\n");
		return;
	case FT_CANNOT_OPEN_DRIVER		 :
		printf("Err: failed to open the driver!");
		break;
	case FT_INVALID_DRVR_VERSION	 :
		printf("Err: Invalid driver version!");
		break;
	case FT_INVALID_COMMAND          :
		printf("Err: Invalid command!");
		break;
	case FT_ACCESS_DENIED            :
		printf("Err: access denied!");
		break;
	case FT_UNIT_NOT_FOUND           :
		printf("Err: unit was not found!");
		break;
	case FT_DEVICE_REMOVED           :
		printf("Err: the device was removed!");
		break;
	case FT_COMMUNICATIONS_ERROR     :
		printf("Err: communication terminated abnormally!");
		break;
	case FT_DIR_NOT_FOUND            :
		printf("Err: The directory was not found!");
		break;
	case FT_FILE_NOT_FOUND           :
		printf("Err: The file was not found!");
		break;
	case FT_MEM_CORRUPT              :
		printf("Err: Memory inside the token was corrupted!");
		break;
	case FT_INTERNAL_HW_ERROR        :
		printf("Err: Internal hardware error occured!");
		break;
	case FT_INVALID_RESP_SIZE        :
		printf("Err: Abnormal response received from the token!");
		break;
	case FT_PIN_EXPIRED              :
		printf("Err: The PIN retry counter register return zero!");
		break;
	case FT_ALREADY_EXISTS           :
		printf("Err: The item already exist!");
		break;
	case FT_NOT_ENOUGH_MEMORY        :
		printf("Err: Insufficient memory to perform the command!");
		break;
	case FT_INVALID_PARAMETER        :
		printf("Err: Invalid parameter was assigned to the function!");
		break;
	case FT_INPUT_TOO_LONG           :
		printf("Err: The length of the input data is too long!");
		break;
	case FT_INVALID_FILE_SELECTED    :
		printf("Err: The selected file is invalid!");
		break;
	case FT_DEVICE_IN_USE            :
		printf("Err: The device is currently used by another application!");
		break;
	case FT_INVALID_API_VERSION      :
		printf("Err: The version of the API library is invalid!");
		break;
	case FT_TIME_OUT_ERROR           :
		printf("Err: The operation time out!");
		break;
	case FT_ITEM_NOT_FOUND           :
		printf("Err: The item was not found!");
		break;
	case FT_COMMAND_ABORTED          :
		printf("Err: Command aborted abnormally!");
		break;
	case FT_INVALID_STATUS           :
		printf("Err: Invalid return value received from the token!");
		break;
	case FT_INPUT_INVALID           :
		printf("Err: Invalid input value!");
		break;		
	default							 :
		printf("Err: Unknown error occured!");
		break;
	}
	printf("(0x%X)\n",retval);
}

void ShowBinHex(unsigned char* pBin, long len)
{
	// Show 16 bytes each line.

	long lLines = len / 16;
	long lCharInLastLine = 0;
	if(0 != len % 16)
	{
		lCharInLastLine = len - lLines * 16;
//		++lLines;
	}

	for(long i = 0; i < lLines; ++i)
	{
		for(int j = 0; j < 16; ++j)
		{
			printf("%02X ", pBin[16 * i + j]);

			if(j == 7)
				printf("- ");
		}

		printf("    ");

		for(j = 0; j < 16; ++j)
		{
			if(isprint(pBin[16 * i + j]))
				printf("%c", pBin[16 * i + j]);
			else
				printf(".");
		}

		printf("\n");
	}

	if(0 != lCharInLastLine)
	{
		for(int j = 0; j < lCharInLastLine; ++j)
		{
			printf("%02X ", pBin[16 * i + j]);

			if(j == 7 && lCharInLastLine > 8)
				printf("- ");
		}

		int k = 0;

		k += ((16 - lCharInLastLine) * 3);

		if(lCharInLastLine <= 8)
		{
			k += 2;
		}

		for(int kk = 0; kk < k; ++kk)
			printf(" ");

		printf("    ");

		for(j = 0; j < lCharInLastLine; ++j)
		{
			if(isprint(pBin[16 * i + j]))
				printf("%c", pBin[16 * i + j]);
			else
				printf(".");
		}

		printf("\n");
	}

//	for(long i = 0; i < len; ++i)
//	{
//		unsigned char t = pBin[i];
//		printf("%X", t >> 4);
//		printf("%X ", t & 0x0F);
//	}
	printf("\n");
}

char* TransAccessBit2Text(unsigned char bFlag)
{
	switch(bFlag)
	{
	case EPAS_ACCESS_OFFICER:
		return "SO    ";
	case EPAS_ACCESS_ANYONE:
		return "ANYONE";
	case EPAS_ACCESS_USER:
		return "USER  ";
	case EPAS_ACCESS_NONE:
		return "NONE  ";
	}
	return "      ";
}

char* TransFileType2Text(unsigned char type)
{
	switch(type)
	{
	case EPAS_FILETYPE_KEY:
		return "KEY ";
	case EPAS_FILETYPE_DATA:
		return "DATA";
	case EPAS_FILETYPE_DIR:
		return "DIR ";
	case EPAS_FILETYPE_UNUSED:
		return "FREE";
	}
	return "N/A ";
}

char* TransBool2Text(unsigned long bb)
{
	return bb ? "Yes":"No";
}

// Open device and show token information.
void OpenToken(unsigned long flags)
{
	EPAS_STATUS retval = FT_SUCCESS;
	
	printf("Open device:");
	retval = epas_OpenDevice(g_hToken, flags, NULL);
	ShowErrInfo(retval);
	if(FT_SUCCESS != retval)
		return;

	EPAS_VERSIONINFO version = {0};

	retval = epas_GetProperty(g_hToken, EPAS_PROP_VERSIONINFO,
			NULL, &version,sizeof(EPAS_VERSIONINFO));
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Firmware Version: %d.%d\n=>> Product Code: %X",
				version.ucFwVerMajor,
				version.ucFwVerMinor,
				version.ucProductCode);
	}
	
	unsigned long capa = 0;
	retval = epas_GetProperty(g_hToken, EPAS_PROP_CAPABILITIES,
			NULL, &capa, sizeof(capa));
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Capabilities: %X",capa);
	}
	
	unsigned long memSize = 0;
	retval = epas_GetProperty(g_hToken, EPAS_PROP_MEM_SIZE, NULL,
			&memSize, sizeof(memSize));
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Total memory size: %d byte%s",
				memSize, memSize > 1 ? "s" : "");
	}

	EPAS_SYSINFO sysInfo = {0};
	retval = epas_GetProperty(g_hToken, EPAS_PROP_SYSINFO,
			NULL, &sysInfo, sizeof(EPAS_SYSINFO));
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Free memory space: %d byte%s",
				sysInfo.ulFreeSpace, sysInfo.ulFreeSpace > 1 ? "s" : "");
		printf("\n=>> Max directory levels: %d",sysInfo.ucMaxDirLevels);
		printf("\n=>> File system type: %d",sysInfo.ucFileSysType);
	}
	
	char fName[EPAS_FRIENDLY_NAME_SIZE+1] = {0};
	retval = epas_GetProperty(g_hToken, EPAS_PROP_FRIENDLY_NAME,
			NULL, fName, EPAS_FRIENDLY_NAME_SIZE);
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Friendly token name: %s", fName);
	}
	
	unsigned long sn[2] = {0};
	retval = epas_GetProperty(g_hToken,EPAS_PROP_SERNUM,NULL,sn,sizeof(sn));
	if(FT_SUCCESS == retval)
	{
		printf("\n=>> Hardware serial number: 0x%08lX%08lX", sn[1], sn[0]);
	}
}

void ListDir(unsigned long parDid)
{
	EPAS_STATUS retval = FT_SUCCESS;
	EPAS_FILEINFO fi = {0};

	retval = epas_ChangeDir(g_hToken, EPAS_DIR_BY_LONG_ID, parDid, NULL);
	if(FT_SUCCESS != retval)
	{
		printf("\n\n");
		ShowErrInfo(retval);
		return;
	}

	for(int i = 0; i < 255; ++i)
	{
		retval = epas_Directory(g_hToken, 0, i, &fi, sizeof(EPAS_FILEINFO));
		if(FT_SUCCESS != retval)
			break;

		printf("\n%08X %08X %s %s %s %s %-7ld",
				parDid, fi.ulID,
				TransFileType2Text(fi.ucFileType),
				TransAccessBit2Text(fi.ucReadAccess),
				TransAccessBit2Text(fi.ucWriteAccess),
				TransAccessBit2Text(fi.ucCryptAccess),
				fi.ulFileSize
			);
		if(EPAS_FILETYPE_DIR == fi.ucFileType)
		{
			epas_ChangeDir(g_hToken, EPAS_DIR_BY_LONG_ID, fi.ulID, NULL);
			unsigned char AName[EPAS_APP_NAME_SIZE] = {0};
			if(FT_SUCCESS == epas_GetProperty(g_hToken, EPAS_PROP_APP_NAME,
					NULL, AName, sizeof(AName)))
			{
				printf("\n                  ");
				printf("Name: \"%s\"", AName);
			}
			
			epas_ChangeDir(g_hToken, EPAS_DIR_BY_LONG_ID, fi.ulID, NULL);
			GUID guid = {0};
			if(FT_SUCCESS == epas_GetProperty(g_hToken, EPAS_PROP_APP_GUID,
					NULL, (unsigned char*)&guid, sizeof(GUID)))
			{
				GUID guidTemp = {0};
				if(0 != memcmp(&guid, &guidTemp, sizeof(GUID)))
				{
					printf("\n                  ");
					printf("GUID: ");
					printf("{%08X-%04X-%04X-",guid.Data1,guid.Data2,guid.Data3);
					printf("%02X%02X-",guid.Data4[0],guid.Data4[1]);
					for(int i = 2; i < 8; ++i)
					{
						printf("%02X",guid.Data4[i]);
					}
					printf("}");
				}
			}
			epas_ChangeDir(g_hToken,EPAS_DIR_BY_LONG_ID,parDid,NULL);
		}
		
		if(EPAS_FILETYPE_DIR == fi.ucFileType)
		{
			ListDir(fi.ulID);
			retval = epas_ChangeDir(g_hToken,EPAS_DIR_BY_LONG_ID,parDid,NULL);
			if(FT_SUCCESS!=retval)
			{
				printf("\n\n");
				ShowErrInfo(retval);
				return;
			}
		}

		if(EPAS_FILETYPE_UNUSED == fi.ucFileType)
			break;
	}
}

void ShowSetupMenu()
{
	EPAS_STATUS retval = FT_SUCCESS;
	while(1)
	{
		printf("\n\nSetup Menu:\n");
		printf("-------------------------------------------------------------\n");
		printf("  [P]IN       [S]oPIN           [T]okenName       [C]leanup\n");
		printf("  [U]lockPIN  [A]ccessSettings  [D]eleteAll       E[x]it\n\n");

		switch(WaitForUserInput())
		{
		case 'P':
			{
				char oldPin[80] = {0};
				char newPin[80] = {0};
				printf("\nChange User Pin:\n");
				printf("Input Old User Pin:");
				fflush(stdin);
				gets(oldPin);
				printf("Input new User Pin:");
				fflush(stdin);
				gets(newPin);
				retval = epas_ChangeCode(
						g_hToken, EPAS_CHANGE_USER_PIN | EPAS_CHANGE_HASH_UPIN,
											(unsigned char*)oldPin,
											lstrlen(oldPin),
											(unsigned char*)newPin,
											lstrlen(newPin));
				ShowErrInfo(retval);
			}
			break;
		case 'S':
			{
				char oldSO[80] = {0};
				char newSO[80] = {0};
				printf("\nChange SO Pin:\n");
				printf("Input Old SO Pin:");
				fflush(stdin);
				gets(oldSO);
				printf("Input new SO Pin:");
				fflush(stdin);
				gets(newSO);
				retval = epas_ChangeCode(	g_hToken,
											EPAS_CHANGE_SO_PIN,
											(unsigned char*)oldSO,
											lstrlen(oldSO),
											(unsigned char*)newSO,
											lstrlen(newSO));
				ShowErrInfo(retval);
			}
			break;
		case 'T':
			{
				printf("Input new Token Name:");
				char ntName[40] = {0};
				fflush(stdin);
				gets(ntName);
				retval = epas_SetProperty(	g_hToken,
											EPAS_PROP_FRIENDLY_NAME,
											NULL,
											ntName,
											lstrlen(ntName));
				ShowErrInfo(retval);
			}
			break;
		case 'C':
			printf("Cleanup   ");
			retval = epas_Cleanup(g_hToken, 0);
			ShowErrInfo(retval);
			break;
		case 'U':
			{
				EPAS_ACCESSINFO ai = {0};
				char SOPin[80] = {0};
				char nPin[80] = {0};
				printf("\nChange User Pin:\n");
				printf("Input SO Pin:");
				fflush(stdin);
				gets(SOPin);
				printf("Input new User Pin:");
				fflush(stdin);
				gets(nPin);
				retval = epas_ChangeCode(	g_hToken,
											EPAS_UNBLOCK_USER_PIN | EPAS_VERIFY_HASH_UPIN,
											(unsigned char*)SOPin,
											lstrlen(SOPin),
											(unsigned char*)nPin,
											lstrlen(nPin));
				if(retval == FT_SUCCESS)
				{
					if( 0 ==epas_GetProperty(	g_hToken,
												EPAS_PROP_ACCESSINFO,
												NULL,
												&ai,
												sizeof(ai)))
					{
						ai.ucCurPinCounter = ai.ucMaxPinRetries;

						epas_SetProperty(	g_hToken,
													EPAS_PROP_ACCESSINFO,
													NULL,
													&ai,
													sizeof(ai));
					}
				}
				ShowErrInfo(retval);
			}
			break;
		case 'A':
			{
				EPAS_ACCESSINFO ai = {0};
				char tBuf[32] = {0};
				int tv = 0;
				printf("Create access(0=Anyone 1=PIN 2=SOPIN 7=None):");
				fflush(stdin);
				gets(tBuf);
				sscanf(tBuf,"%ld",&tv);

				// add by liutiezheng for bug 0011102
				int tag = 0;
				switch(tv)
				{
				case 0:
					break;
				case 1:
					break;
				case 2:
					break;
				case 7:
					break;
				default:
					{
						tag = 1;
						break;
					}
				}

				if (1 == tag)
				{
					tag = 0;
					ShowErrInfo(FT_INPUT_INVALID);
					break;
				}
				// add end

				ai.ucCreateAccess = tv;
				printf("Delete access(0=Anyone 1=PIN 2=SOPIN 7=None):");
				fflush(stdin);
				gets(tBuf);
				sscanf(tBuf,"%ld",&tv);

				// add by liutiezheng for bug 0011102
				switch(tv)
				{
				case 0:
					break;
				case 1:
					break;
				case 2:
					break;
				case 7:
					break;
				default:
					{
						tag = 1;
						break;
					}
				}

				if (1 == tag)
				{
					tag = 0;
					ShowErrInfo(FT_INPUT_INVALID);
					break;
				}
				// add end

				ai.ucDeleteAccess = tv;
				printf("Max User Pin retry counter(0-15):");
				fflush(stdin);
				gets(tBuf);
				sscanf(tBuf,"%ld",&tv);

				// add by liutiezheng for bug 0011102
				
				if ((tv > 15) || (tv < 0))
				{
					ShowErrInfo(FT_INPUT_INVALID);
					break;
				}
				// add end
				

				ai.ucMaxPinRetries = tv;
				
				printf("Current User Pin retry counter(0-15):");
				fflush(stdin);
				gets(tBuf);
				sscanf(tBuf,"%ld",&tv);

				// add by liutiezheng for bug 0011102
				
				if ((tv > 15) || (tv < 0))
				{
					ShowErrInfo(FT_INPUT_INVALID);
					break;
				}
				// add end

				ai.ucCurPinCounter = tv;

				retval = epas_SetProperty(	g_hToken,
											EPAS_PROP_ACCESSINFO,
											NULL,
											&ai,
											sizeof(ai));
				ShowErrInfo(retval);
			}
			break;
		case 'D':
			printf("Delete all the files and directories!\n");
			retval = epas_DeleteDir(g_hToken,EPAS_DIR_BY_LONG_ID,EPAS_ROOT_DIR,NULL);
			ShowErrInfo(retval);
			break;
		case 'X':
			return;
		default:
			break;
		}
	}
}

void ShowCryptMenu()
{
	EPAS_STATUS retval = FT_SUCCESS;
	unsigned long fid1 = 0;
	unsigned long fid2 = 0;
	while(1)
	{
		printf("\n\nCrypt Menu:\n");
		printf("-------------------------------------------------------------\n");
		printf("  [H]MAC  [M]akeHMACKeys   E[x]it\n");
		switch(WaitForUserInput())
		{
		case 'H':
			{
				printf("\nUsing two key files for MD5-HMAC authentication.\n\n");

				char tBuf[32] = {0};
ID1:			printf("Input ID of the first key file(0-FFFF):");
				fflush(stdin);
				gets(tBuf);
				retval=FileIDIsValid(tBuf,lstrlen(tBuf));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID1;
				}
				sscanf(tBuf,"%lx",&fid1);
ID2:			printf("Input ID of the second key file(0-FFFF):");
				fflush(stdin);
				gets(tBuf);
				retval=FileIDIsValid(tBuf,lstrlen(tBuf));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID2;
				}
				sscanf(tBuf,"%lx",&fid2);
				char text[80] = {0};
				fflush(stdin);
				printf("Input random data for MD5-HMAC authentication(MAX 55 bytes):");
				gets(text);
				unsigned char Dig1[16] = {0};
				retval = epas_MD5_HMAC(	g_hToken,
										fid1,
										fid2,
										(unsigned char*)text,
										lstrlen(text),
										Dig1);
				ShowBinHex(Dig1,16);
				unsigned char Dig2[16] = {0};
				printf("\n\nPlease input the secret MD5-HMAC key to verify:");
				char skey[80] = {0};
				fflush(stdin);
				gets(skey);
				MD5_HMAC((unsigned char*)text,lstrlen(text),(unsigned char*)skey,lstrlen(skey),NULL,NULL,Dig2);
				printf("Software MD5-HMAC compute result:\n");
				ShowBinHex(Dig2,16);
				
				if(memcmp(Dig1,Dig2,16))
				{
					printf("Verification FAILED!");
				}
				else
				{
					printf("Verification SUCCESSFUL!");
				}
			}
			break;
		case 'M':
			{
				printf("\n Create two key files for MD5-HMAC authentication.\n\n");
				char tmpBuf[32] = {0};
ID3:			printf("Input ID of the first key file(0-FFFF):");
				fflush(stdin);
				gets(tmpBuf);
				retval=FileIDIsValid(tmpBuf,lstrlen(tmpBuf));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID3;
				}
				sscanf(tmpBuf,"%lx",&fid1);
ID4:			printf("Input ID of the second key file(0-FFFF):");
				fflush(stdin);
				gets(tmpBuf);
				retval=FileIDIsValid(tmpBuf,lstrlen(tmpBuf));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID4;
				}
				sscanf(tmpBuf,"%lx",&fid2);
				
				printf("Input the secret MD5-HMAC key:");
				char hkey[80] = {0};
				fflush(stdin);
				gets(hkey);
				
				unsigned char key1[16] = {0};
				unsigned char key2[16] = {0};
				unsigned char tDig[16] = {0};
				MD5_HMAC(NULL,0,(unsigned char*)hkey,lstrlen(hkey),key1,key2,tDig);

				printf("First MD5-HMAC key file content:\n");
				ShowBinHex(key1,16);
				printf("Second MD5-HMAC key file content:\n");
				ShowBinHex(key2,16);

				EPAS_FILEINFO fi = {0};
				retval = epas_OpenFile(g_hToken,EPAS_FILE_WRITE,fid1,&fi,sizeof(fi));
				if(FT_FILE_NOT_FOUND == retval)
				{
					memset(&fi, 0, sizeof(fi));

					fi.ulID = fid1;
					fi.ulFlags = 0;
					fi.ulFileSize = 16;
					fi.ucFileType = EPAS_FILETYPE_KEY;
					fi.ucWriteAccess = EPAS_ACCESS_OFFICER;
					fi.ucCryptAccess = EPAS_ACCESS_ANYONE;
					fi.ucReadAccess = EPAS_ACCESS_NONE;

					retval = epas_CreateFile(g_hToken,0,&fi,sizeof(fi));
				}

				unsigned long tlen = 0;
				if(FT_SUCCESS == retval)
				{
					retval = epas_Write(g_hToken,0,0,key1,16,&tlen);
				}

				if(FT_SUCCESS == retval)
				{
					retval = epas_OpenFile(g_hToken,EPAS_FILE_WRITE,fid2,&fi,sizeof(fi));
					if(FT_FILE_NOT_FOUND == retval)
					{
						memset(&fi, 0, sizeof(fi));

						fi.ulID = fid2;
						fi.ulFlags = 0;
						fi.ulFileSize = 16;
						fi.ucFileType = EPAS_FILETYPE_KEY;
						fi.ucWriteAccess = EPAS_ACCESS_OFFICER;
						fi.ucReadAccess = EPAS_ACCESS_NONE;
						fi.ucCryptAccess = EPAS_ACCESS_ANYONE;

						retval = epas_CreateFile(g_hToken,0,&fi,sizeof(fi));
					}
					if(FT_SUCCESS == retval)
						retval = epas_Write(g_hToken,0,0,key2,16,&tlen);

					epas_CloseFile(g_hToken);
				}
				ShowErrInfo(retval);
			}
			break;
		case 'X':
			return;
		default:
			break;
		}
	}
}

void ShowFileMenu()
{
	EPAS_STATUS retval = FT_SUCCESS;

	while(1)
	{
		printf("\n\nFile Menu:\n");
		printf("-------------------------------------------------------------\n");
		printf(	"  C[h]Dir    [L]ist   Create[D]ir   Create[F]ile   Create[A]pp\n"
				"  DelD[i]r   D[e]leteFile\n"
				"  [O]pen     [R]ead   [W]rite      [C]lose\n"
				"  Cr[y]ptMenu         Set[u]pMenu   E[x]it\n" );
		switch(WaitForUserInput())
		{
		case 'H':
			{
ID5:			printf("Input ID of the dir to change in(0-FFFF):");
				char iBuf1[80] = {0};
				fflush(stdin);
				gets(iBuf1);
				retval=FileIDIsValid(iBuf1,lstrlen(iBuf1));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID5;
				}
				unsigned long did = 0;
				sscanf(iBuf1,"%lx",&did);
				retval = epas_ChangeDir(g_hToken,EPAS_DIR_BY_LONG_ID,did,NULL);
				ShowErrInfo(retval);
			}
			break;
		case 'L':
			printf("\nDir ID   File ID  Type Read   Write  Crypt  Size");
			printf("\n-------- -------- ---- ------ ------ ------ -----");
			ListDir(0);
			break;
		case 'D':
			{
				EPAS_DIRINFO di = {0};
ID6:			printf("Input ID of the Dir to be created(0-FFFF):");
				char iBuf2[80] = {0};
				fflush(stdin);
				gets(iBuf2);
				retval=FileIDIsValid(iBuf2,lstrlen(iBuf2));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID6;
				}
				sscanf(iBuf2,"%lx",&di.ulID);
				retval = epas_CreateDir(g_hToken,0,NULL,NULL,&di,sizeof(di));
				ShowErrInfo(retval);
			}
			break;
		case 'F':
			{
				EPAS_FILEINFO fi1 = {0};
				fi1.ulFlags = 0;
ID7:			printf("Input ID of the file to be created(0-FFFF): ");
				char iBuf3[80] = {0};
				fflush(stdin);
				gets(iBuf3);
				retval=FileIDIsValid(iBuf3,lstrlen(iBuf3));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID7;
				}
				sscanf(iBuf3,"%lx",&fi1.ulID);
				
				printf("Input size of the file(in byte): ");
				fflush(stdin);
				gets(iBuf3);
				sscanf(iBuf3,"%ld",&fi1.ulFileSize);
				
				printf("Input file type(2=DATA,4=KEY): ");
				fflush(stdin);
				gets(iBuf3);
				sscanf(iBuf3,"%ld",&fi1.ucFileType);

				fi1.ucReadAccess  = EPAS_ACCESS_ANYONE;
				fi1.ucCryptAccess = EPAS_ACCESS_ANYONE;

				if(EPAS_FILETYPE_DATA == fi1.ucFileType)
				{
					printf("Input read access (0=Anyone 1=User 2=SO 3=None): ");
					fflush(stdin);
					gets(iBuf3);
					sscanf(iBuf3,"%ld",&fi1.ucReadAccess);
				}

				printf("Input write access (0=Anyone 1=User 2=SO 3=None): ");
				fflush(stdin);
				gets(iBuf3);
				sscanf(iBuf3,"%ld",&fi1.ucWriteAccess);

				if(EPAS_FILETYPE_KEY == fi1.ucFileType)
				{
					printf("Input crypt access (0=Anyone 1=User 2=SO 3=None): ");
					fflush(stdin);
					gets(iBuf3);
					sscanf(iBuf3,"%ld",&fi1.ucCryptAccess);
				}

				retval = epas_CreateFile(g_hToken,0,&fi1,sizeof(fi1));
				ShowErrInfo(retval);
			}
			break;
		case 'A':
			{
				EPAS_DIRINFO di2 = {0};
				unsigned char AName[EPAS_APP_NAME_SIZE] = {0};
				unsigned char DGuid[64] = {0};
				unsigned long dtype = 0;

				printf("Inpute App Name of the Dir(0-32chars):");
				fflush(stdin);
				gets((char*)AName);
				printf("Input GUID of the Dir{xxxx-xxxx...}:");
				fflush(stdin);
				gets((char*)DGuid);
				
				if(AName[0])
					dtype = EPAS_DIR_BY_NAME | EPAS_CREATE_AUTO_ID;
				if(DGuid[0])
					dtype = EPAS_DIR_BY_GUID_STR | EPAS_CREATE_AUTO_ID;

				retval = epas_CreateDir(g_hToken,
										dtype,
										AName[0]?AName:NULL,
										DGuid[0]?DGuid:NULL,
										&di2,
										sizeof(di2));
				ShowErrInfo(retval);
			}
			break;
		case 'I':
			{
ID8:			printf("Input ID of the Dir to delete(0-FFFF):");
				unsigned long did2 = 0;
				char iBuf4[80] = {0};
				fflush(stdin);
				gets(iBuf4);
				retval=FileIDIsValid(iBuf4,lstrlen(iBuf4));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID8;
				}
				sscanf(iBuf4,"%lx",&did2);
				retval = epas_DeleteDir(g_hToken,EPAS_DIR_BY_LONG_ID,did2,NULL);
				ShowErrInfo(retval);
			}
			break;
		case 'E':
			{
ID9:			printf("Input ID of the file to delete(0-FFFF):");
				unsigned long fid2 = 0;
				char iBuf5[80] = {0};
				fflush(stdin);
				gets(iBuf5);
				retval=FileIDIsValid(iBuf5,lstrlen(iBuf5));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID9;
				}
				sscanf(iBuf5,"%lx",&fid2);
				retval = epas_DeleteFile(g_hToken,0,fid2);
				ShowErrInfo(retval);
			}
			break;
		case 'O':
			{
				EPAS_FILEINFO fi3 = {0};
				unsigned long fid3 = 0;
				char iBuf6[80] = {0};
ID10:			printf("Input ID of the file to open(0-FFFF):");
				fflush(stdin);
				gets(iBuf6);
				retval=FileIDIsValid(iBuf6,lstrlen(iBuf6));
				if(FT_SUCCESS!=retval)
				{
					ShowErrInfo(retval);
					goto ID10;
				}
				sscanf(iBuf6,"%lx",&fid3);
				retval = epas_OpenFile(g_hToken,0,fid3,&fi3,sizeof(fi3));
				ShowErrInfo(retval);
				if(FT_SUCCESS == retval)
				{
					printf("\n File size: %ld",fi3.ulFileSize);
					printf("\n File type: %s",TransFileType2Text(fi3.ucFileType));

					printf("\n File Crypt Access: %s",TransBool2Text(fi3.ucGrantedAccess&EPAS_ACCESS_CRYPT));
					printf("\n File Read Access: %s",TransBool2Text(fi3.ucGrantedAccess&EPAS_ACCESS_READ));
					printf("\n File Write Access: %s",TransBool2Text(fi3.ucGrantedAccess&EPAS_ACCESS_WRITE));
				}
			}
			break;
		case 'R':
			{
				unsigned char iBuf7[80] = {0};
				unsigned long offs = 0;
				printf("Input offset to begin read(0-65500):");
				fflush(stdin);
				gets((char*)iBuf7);
				sscanf((char*)iBuf7,"%ld",&offs);
				printf("Input number of byte to read(0-65500):");
				unsigned long rLen = 0;
				fflush(stdin);
				gets((char*)iBuf7);
				sscanf((char*)iBuf7,"%ld",&rLen);
				unsigned char rBuff[100000] = {0};
				ZeroMemory(rBuff,100000);
				retval = epas_Read(g_hToken,0,offs,rBuff,rLen,&rLen);
				ShowErrInfo(retval);
				if(FT_SUCCESS == retval)
				{
					printf("\n =>> %ld (0x%X) byte%s read.\n", rLen, rLen, rLen > 1 ? "s" : "");
					ShowBinHex(rBuff,rLen);
				}
			}
			break;
		case 'W':
			{
				unsigned long off2 = 0;
				unsigned char iBuf8[80] = {0};
				printf("Input offset to begin write(0-65500):");
				fflush(stdin);
				gets((char*)iBuf8);
				sscanf((char*)iBuf8,"%ld",&off2);
				printf("Input data to write:");
				fflush(stdin);
				gets((char*)iBuf8);
				unsigned long rLen2 = 0;
				rLen2 = lstrlen((char*)iBuf8);
				printf("\n =>> %ld byte%s to write.\n",rLen2, rLen2 > 1 ? "s" : "");
				ShowBinHex(iBuf8,rLen2);
				 
				retval = epas_Write(g_hToken,0,off2,iBuf8,rLen2,&rLen2);
				ShowErrInfo(retval);
				if(FT_SUCCESS == retval)
				{
					printf("\n =>> %ld byte%s written successfully!",rLen2, rLen2 > 1 ? "s" : "");
				}
			}
			break;
		case 'C':
			printf("Close File\n");
			retval = epas_CloseFile(g_hToken);
			ShowErrInfo(retval);
			break;
		case 'Y':
			ShowCryptMenu();
			break;
		case 'U':
			ShowSetupMenu();
			break;
		case 'X':
			return;
		}
	}
}

int main(int argc, char* argv[])
{
	EPAS_STATUS retval = FT_SUCCESS;

	ShowBanner();
	
	printf("Create Context:");
	retval = epas_CreateContext(&g_hToken,0,EPAS_API_VERSION);
	ShowErrInfo(retval);
	if(FT_SUCCESS != retval)
		return 1;

	while(1)
	{
		ShowMainCmdMenu();
		switch(WaitForUserInput())
		{
		case 'F':
			OpenToken(EPAS_OPEN_FIRST);
			break;
		case 'O':
			printf("\nTurn LED on:");
			retval = epas_SetProperty(g_hToken,EPAS_PROP_LED_ON,NULL,NULL,0);
			ShowErrInfo(retval);
			break;
		case 'P':
			{
				char s[80] = {0};
				printf("Input Pin:");
				fflush(stdin);
				gets(s);
				retval = epas_Verify(g_hToken,EPAS_VERIFY_USER_PIN|EPAS_VERIFY_HASH_UPIN,(unsigned char*)s,lstrlen(s));
				ShowErrInfo(retval);
			}
			break;
		case 'L':
			printf("\nDir ID   File ID  Type Read   Write  Crypt  Size");
			printf("\n-------- -------- ---- ------ ------ ------ -----");
			ListDir(0);
			break;
		case 'M':
			ShowFileMenu();
			break;
		case 'N':
			OpenToken(EPAS_OPEN_NEXT);
			break;
		case 'D':
			printf("\nTurn LED off:");
			retval = epas_SetProperty(g_hToken,EPAS_PROP_LED_OFF,NULL,NULL,0);
			ShowErrInfo(retval);
			break;
		case 'S':
			{
				char s[80] = {0};
				printf("Input SO-Pin:");
				fflush(stdin);
				gets(s);
				retval = epas_Verify(g_hToken,EPAS_VERIFY_SO_PIN,(unsigned char*)s,lstrlen(s));
				ShowErrInfo(retval);
			}
			break;
		case 'G':
			{
				printf("Generate Random");
				unsigned char rBuf[16] = {0};
				retval = epas_GenRandom(g_hToken,0,rBuf,16);
				ShowErrInfo(retval);
				ShowBinHex(rBuf,16);
			}
			break;
		case 'Y':
			ShowCryptMenu();
			break;
		case 'R':
			OpenToken(EPAS_OPEN_CURRENT);
			break;
		case 'T':
			printf("Reset token:");
			retval = epas_ResetSecurityState(g_hToken,EPAS_SCOPE_MF);
			ShowErrInfo(retval);
			break;
		case 'A':
			{
				EPAS_ACCESSINFO aInfo = {0};
				retval = epas_GetProperty(g_hToken,EPAS_PROP_ACCESSINFO,NULL,&aInfo,sizeof(aInfo));
				ShowErrInfo(retval);
				if(FT_SUCCESS == retval)
				{
					printf("\n=>> Item create access: %s",TransAccessBit2Text(aInfo.ucCreateAccess));
					printf("\n=>> Item delete access: %s",TransAccessBit2Text(aInfo.ucDeleteAccess));
					printf("\n=>> Max Pin retry counter: %d",aInfo.ucMaxPinRetries);
					printf("\n=>> Current Pin retry counter: %d",aInfo.ucCurPinCounter);
				}
			}
			break;
		case 'U':
			ShowSetupMenu();
			break;
		case 'C':
			printf("\nClose Device:");
			retval = epas_CloseDevice(g_hToken);
			ShowErrInfo(retval);
			break;
		case 'X':
			epas_CloseDevice(g_hToken);
			epas_DeleteContext(g_hToken);
			return 0;
		default:
			break;
		}
	}
}

