#include "test_common.h"

//#define MANUAL_INIT_TOKEN_TEST

CK_SLOT_ID SlotId;
CK_UTF8CHAR *new_user_pin = "22222222";
CK_UTF8CHAR *new_so_pin = "88888888";
CK_UTF8CHAR *sopin = NULL;
CK_UTF8CHAR *userpin = NULL;
CK_SLOT_ID_PTR SlotList = NULL;
CK_ULONG SlotCount = 0;
//CK_UTF8CHAR prompt_and_pin_buf[80];

int main(int argc, char *argv[]){

	CK_RV rc; // Return Code

#ifndef MANUAL_INIT_TOKEN_TEST
	CK_FLAGS flags = 0;
	CK_SESSION_HANDLE sess;
#endif
	int i;
	CK_UTF8CHAR *label = "Rutoken Lite 5";
	CK_UTF8CHAR label32[32];

   // parse the command line parameters
	for (i=1; i<argc; i++) {
		if (strcmp("-api", argv[i]) == 0) {
			i++;
			api_path = argv[i];
		} else if (strcmp("-user_pin", argv[i]) == 0) {
			i++;
			user_pin = argv[i];
		}
	}

	//сначала всё сотрем

	printf("==>> init...\n");
	rc = init(api_path, &funcs, NULL);
	if (rc != CKR_OK) {
		printf("==>> init failed\n\n");
		return rc;
	}
	printf("==>> init Ok\n\n");

	printf("==>> get_slot_list...\n");
	rc = get_slot_list(funcs,
                    &SlotList,
                    &SlotCount);
	if (rc != CKR_OK) {
		printf("==>> get_slot_list failed, rc = 0x%x\n\n", rc );
		return rc;
	}
	printf("==>> get_slot_list Ok\n\n");

	printf("==>> find_slot_with_token...\n");
	rc = find_slot_with_token(funcs,
                           SlotList,
                           SlotCount,
                           &SlotId);
	if (rc != CKR_OK) {
		printf(
			"==>> find_slot_with_token failed, rc = 0x%x\n\n", rc );
		return rc;
	}
	printf("==>> find_slot_with_token Ok\n\n");

	userpin = hw_user_pin;
	sopin = hw_so_pin;

	display_token_info(funcs, SlotId);
	printf("==>> C_InitToken...\n");
	// Если токен не был инициализирован, то SO PIN не проверяется,
	// а впервые назначается, поэтому в любом случае после успешного
	// выполнения данной функции на токене будет установлен заданный sopin,
	// а USER PIN установлен не будет.
	memset(label32, ' ', sizeof(label32));
	memcpy(label32, label, strlen(label));  
	rc = funcs->C_InitToken(SlotId, sopin, strlen(sopin), label32);
	if (rc != CKR_OK) {
		printf("==>> C_InitToken failed\n\n");
		return rc;
	}
	printf("==>> C_InitToken Ok\n\n");
	display_token_info(funcs, SlotId);

	flags = CKF_SERIAL_SESSION | CKF_RW_SESSION;

// Открытие сессии с указанием колбэка для ввода PIN и буфера для 
// обмена данными между библиотекой и колбэком. Библиотека формирует 
// в буфере запрос на ввод PIN, а колбэк возвращает PIN в этом же буфере. 
// Библиотека сама очищает значение PIN в буфере после его использования.
//	rc = funcs->C_OpenSession( 
//		SlotId, flags, prompt_and_pin_buf, pin_callback, &sess );

	rc = funcs->C_OpenSession( SlotId, flags, NULL, NULL, &sess );
	if (rc != CKR_OK) {
		printf("C_OpenSession failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_OpenSession success\n");

	display_token_info(funcs, SlotId);

	rc = funcs->C_Login(sess, CKU_SO, sopin, strlen(sopin));
	if (rc != CKR_OK) {
		printf("C_Login failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Login (CKU_SO) success\n");	

	rc = funcs->C_InitPIN(sess, new_user_pin, strlen(new_user_pin));
	if (rc != CKR_OK) {
		printf("C_InitPIN failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_InitPIN success\n");

	rc = funcs->C_SetPIN(sess, sopin, strlen(sopin), 
		new_so_pin, strlen(new_so_pin));
	if (rc != CKR_OK) {
		printf("C_SetPIN failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_SetPIN (CKU_SO) success\n");

	rc = funcs->C_Logout(sess);
	if (rc != CKR_OK) {
		printf("C_Logout failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Logout (CKU_SO) success\n");

	rc = funcs->C_Login(sess, CKU_SO, 
		new_so_pin, strlen(new_so_pin));
	if (rc != CKR_OK) {
		printf("C_Login failed, rc = 0x%x\n", rc );
		display_token_info(funcs, SlotId);
		return rc;
	}
	printf("C_Login (CKU_SO) success\n");

	rc = funcs->C_SetPIN(sess, new_so_pin, strlen(new_so_pin), 
		sopin, strlen(sopin));
	if (rc != CKR_OK) {
		printf("C_SetPIN failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_SetPIN back (CKU_SO) success\n");

	rc = funcs->C_Logout(sess);
	if (rc != CKR_OK) {
		printf("C_Logout failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Logout (CKU_SO) success\n");

	rc = funcs->C_Login(sess, CKU_SO, sopin, strlen(sopin));
	if (rc != CKR_OK) {
		printf("C_Login failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Login (CKU_SO) success\n");

	rc = funcs->C_Logout(sess);
	if (rc != CKR_OK) {
		printf("C_Logout failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Logout (CKU_SO) success\n");

	// Здесь будет использоваться колбэк для ввода PIN,
	// если он задан в C_OpenSession.
	//	rc = funcs->C_Login(sess, CKU_USER, NULL, 0);

	rc = funcs->C_Login(sess, CKU_USER, 
		new_user_pin, strlen(new_user_pin));
	if (rc != CKR_OK) {
		printf("C_Login failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Login (CKU_USER) success\n");

	rc = funcs->C_SetPIN(sess, 
		new_user_pin, strlen(new_user_pin), 
		userpin, strlen(userpin));
	if (rc != CKR_OK) {
		printf("C_SetPIN failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_SetPIN (CKU_USER) success\n");

	rc = funcs->C_Logout(sess);
	if (rc != CKR_OK) {
		printf("C_Logout failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_Logout (CKU_USER) success\n");

	rc = funcs->C_CloseSession(sess);
	if (rc != CKR_OK) {
		printf("C_CloseSession failed, rc = 0x%x\n", rc );
		return rc;
	}
	printf("C_CloseSession success\n");

	display_token_info(funcs, SlotId);

	printf("==>> test c_init_token Ok\n");

	return rc;

}

