/*************************************************************************
* Rutoken                                                                *
* Copyright (c) 2003-2017, CJSC Aktiv-Soft. All rights reserved.         *
* Подробная информация:  http://www.rutoken.ru                           *
*------------------------------------------------------------------------*
* В данном файле содержится реализация следующих вспомогательных         *
* функций для работы с Рутокен при помощи программы Cert2Cont:           *
*  - получения массива имен криптопровайдеров;                           *
*  - выбора криптопровайдера для дальнейшей работы.                      *
*************************************************************************/


#include "stdafx.h"
#include "CSPs.h"
#include "Cert2Cont.h"
#include "Util_Funcs.h"


/************************************************************************
* Получить массив имен криптопровайдеров                                *
************************************************************************/
BOOL EnumCSPs(OUT LPWSTR lpszCSPs[],
              OUT DWORD pdwCSPsTypes[],
              OUT DWORD* pdwCSPsCount)
{
	BOOL bResult = TRUE;                     // Вспомогательная переменная для хранения результата выполнения функции

	DWORD dwIndex = 0;                       // Счетчик цикла
	DWORD dwError = ERROR_SUCCESS;           // Вспомогательная переменная для хранения кода возврата

	LPWSTR lpszCurCSP = NULL;                // Указатель на строку с именем текущего криптопровайдера
	DWORD dwCurCSPNameLen = 0;               // Количество символов в имени криптопровайдера
	DWORD dwCurCSPType = 0;                  // Тип криптопровайдера


	for (dwIndex = 0; dwIndex < C2C_MAX_ENUM_COUNT; ++dwIndex) {
		/************************************************************************
		* Получить имена всех криптопровайдеров                                 *
		* (перебор производится в цикле)                                        *
		************************************************************************/
		bResult = CryptEnumProvidersW(dwIndex,
		                              NULL,
		                              0,
		                              &dwCurCSPType,
		                              NULL,
		                              &dwCurCSPNameLen);
		if (!bResult) {
			dwError = GetLastError();
			if (dwError == ERROR_NO_MORE_ITEMS) {
				bResult = TRUE;
				break;
			} else {
				PrintErrorText(L"CryptEnumProvidersW",
				               dwError);
				break;
			}
		}

		lpszCurCSP = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, dwCurCSPNameLen);


		/************************************************************************
		* Получить тип выбранного криптопровайдера на текущем шаге              *
		************************************************************************/
		bResult = CryptEnumProvidersW(dwIndex,
		                              NULL,
		                              0,
		                              &dwCurCSPType,
		                              lpszCurCSP,
		                              &dwCurCSPNameLen);
		if (!bResult) {
			dwError = GetLastError();
			LocalFree(lpszCurCSP);
			if (dwError == ERROR_NO_MORE_ITEMS) {
				bResult = TRUE;
				break;
			} else {
				PrintErrorText(L"CryptEnumProvidersW",
				               dwError);
				break;
			}
		}

		/************************************************************************
		* Поместить в выходные массивы имя и тип для текущего                   *
		* выбранного криптопровайдера                                           *
		************************************************************************/
		*pdwCSPsCount = dwIndex + 1;
		lpszCSPs[dwIndex] = lpszCurCSP;
		pdwCSPsTypes[dwIndex] = dwCurCSPType;
	}

	return bResult;
}

/************************************************************************
* Получить порядковый номер элемента в массиве имен криптопровайдеров,  *
* для которого имя криптопровайдера из массива совпадает с именем       *
* криптопровайдера, переданным пользователем                            *
************************************************************************/
DWORD SelectCSP(IN LPCWSTR lpszPreferredCSP,
                IN LPWSTR lpszCSPs[],
                IN DWORD* pdwCSPsTypes,
                IN DWORD dwCSPsCount)
{
	DWORD dwSelectedCSP = C2C_BAD_SELECT;   // Возвращаемое значение. Порядковый номер криптопровайдера в массиве
	DWORD dwIndex = 0;                      // Счетчик цикла

	if (lpszPreferredCSP) {
		/************************************************************************
		* Если пользователь передал в командной строке имя криптопровайдера,    *
		* выполнить следующие действия:                                         *
		*  - сравнить имя криптопровайдера, переданное пользователем, с именами *
		*    криптопровайдеров, присутствующими в массиве имен;                 *
		*  - вернуть индекс элемента массива, совпадающего с тем,               *
		*    который передал пользователь.                                      *
		************************************************************************/
		for (dwIndex = 0; dwIndex < dwCSPsCount; ++dwIndex) {
			if (wcscmp(lpszPreferredCSP,
			           lpszCSPs[dwIndex])
			    == 0) {
				dwSelectedCSP = dwIndex;
				break;
			}
		}
	} else {
		/************************************************************************
		* Если пользователь не передал в командной строке имя криптопровайдера, *
		* выполнить следующие действия:                                         *
		*  - распечатать пронумерованный список имен криптопровайдеров;         *
		*  - запросить у пользователя номер криптопровайдера,                   *
		*    с которым будет производиться дальнейшая работа.                   *
		************************************************************************/
		wprintf(L"Select CSP:\n");
		for (dwIndex = 0; dwIndex < dwCSPsCount; ++dwIndex) {
			wprintf(L"[%d] - %s\n", dwIndex, lpszCSPs[dwIndex]);
		}

		if (wscanf(L"%d", &dwSelectedCSP) != 1
		    ||  dwSelectedCSP + 1 > dwCSPsCount) {
			wprintf(L"Input error.\n");
			dwSelectedCSP = C2C_BAD_SELECT;
			return dwSelectedCSP;
		}
	}

	if (dwSelectedCSP == C2C_BAD_SELECT) {
		wprintf(L"Error: no such CSP in the system.\n");
	} else {
		wprintf(L"Selected CSP: \"%s\".\n", lpszCSPs[dwSelectedCSP]);
		wprintf(L"CSP type is %X.\n", pdwCSPsTypes[dwSelectedCSP]);
	}

	return dwSelectedCSP;
}
