#ifndef _CPGUI_H_
#define _CPGUI_H_

#include "WinCryptEx.h"
#include "CPCryptEx.h"
#include "reader/support.h"
#include "reader/support_utf8.h"
#include "wnd_utils.h"
#include "compiler_attributes.h"
#include "visualizer.h"

/*
  Если хочется править структуры или функции в этом файле, то:
  1. Исправляется cpgui.h (этот файл). Исправляется WinCryptEx.h - весьма вероятно, через CryptoApi хотя бы часть структур пробрасывается.
  2. Исправляется CSP\src\RuNetCSP\NewCarrier\message.c (или car_find.c) (место использования в провайдере).
  3. Исправляется CSP\src\RuNetCSP\csptypes.idl так, чтобы новую структуру можно было передавать. Перекомпилируется проект, чтобы сделался csptypes.h
  4. При необходимости меняется CSP\src\RuNetCSP\sescsp.idl - если изменились пробрасываемые функции. Перекомпилируется проект, чтобы сделался sescsp.h
  5. Меняется CSP\src\RuNetCSP\sescp-cp.c - чтобы корректно переделывать структуры из транспортного уровня. 
  После этих шагов должен собраться cpcspi
  
  6. Производятся необходимые изменения в проекте cpui. Пока не соберется.

  7. Меняется CSP\src\RuNetCSP\rmcp-ses.cpp - чтобы корректно переделывать структуры в транспортный уровень.
  После этого должен собраться cpcspr

  8. Копируем новый csptypes.h в CSP/src/fenix.
     Изменяем файлы:
  
  9. Меняем файлы CSP\src\fenix\test\march-ms\march-ms-c.c, CSP\src\fenix\test\march-ms\march-ms-s.c.
  После этого должен собраться march-ms.

  10. Меняем функции ручного маршаллинга в CSP\src\fenix\wirecp_m.c.
  11. Меняем файлы CSP\src\fenix\test\march-wire\march-wire-s.c, CSP\src\fenix\test\march-wire\march-wire-c.c.
  12. Меняем файл CSP\src\fenix\sup-callback.c, при необходимости - соседние хидеры.
  После этого должен собраться march-wire и cpcsphc.

  13. Меняем файлы CSP\src\fenix\impl-wire_c.c, CSP\src\fenix\wirecp-cpc.c, CSP\src\fenix\wirecp-cpc.c.
  После этого должна собираться папка fenix под unix.

  14. Меняем файлы в папке CSP/cpui/Win32.not/ - чтобы запустилось окно под unix.
 */

/*! \internal
* \ingroup grp_carrier_wind_real
* \brief Элемент - описание контейнера
*/
typedef struct CPUISelectItem_ {
    TCHAR name[MAX_CONTAINER_NAME_LEN + 1]; /*!< короткое имя контейнера */
    TCHAR unique[MAX_INPUT_CONTAINER_STRING_LEN + 1]; /*!< полное уникальное имя контейнера */
    TCHAR reader_name[MAX_READER_NAME_LEN + 1]; /*!< "красивое" имя считывателя */
    TCHAR nickname[MAX_READER_NAME_LEN + 1]; /*!< настоящее имя считывателя */
    TCHAR connect[256]; /*!< имя соединения */
    TCHAR friendly_name[256]; /*!< дружественное имя контейнера */
    BYTE property_version;
    BYTE property_flags;
} CPUISelectItem;


typedef HRESULT WINAPI cpui_enum_containers_open(void *arg, void **ctx, DWORD flags) ATTR_USERES;

typedef HRESULT WINAPI cpui_enum_containers_next(void *arg, void *ctx, CPUISelectItem* item) ATTR_USERES;

typedef HRESULT WINAPI cpui_enum_containers_close(void *arg, void *ctx) ATTR_USERES;

/*! \internal
* \ingroup grp_carrier_wind_real
* \brief Настройки окна выбора контейнера
*/
typedef struct CRYPTOAPI_SELECT_WND_CONFIG_ {
    DWORD size_of;
    DWORD flags; /*!< [in] Флаги перечисления контейнеров. */
    void * enum_containers_arg;
    cpui_enum_containers_open * enum_containers_open;
    cpui_enum_containers_next * enum_containers_next;
    cpui_enum_containers_close * enum_containers_close;
} CRYPTOAPI_SELECT_WND_CONFIG;

/*! \internal
* \ingroup grp_carrier_wind_real
* \brief Результаты окна выбора контейнера
*/
typedef struct CRYPTOAPI_SELECT_WND_OUT_
{
    TCHAR container_name[MAX_INPUT_CONTAINER_STRING_LEN + 1]; /*!< [out] Результирующая строка, в которую будет записано имя выбранного контейнера. */
} CRYPTOAPI_SELECT_WND_OUT;

#ifdef __cplusplus
extern "C" {
#endif
    HRESULT WINAPI CPSelectContainer(
    /* in */ HWND parent,
    /* in */ CRYPTOAPI_SELECT_WND_CONFIG * info,
    /* out */ CRYPTOAPI_SELECT_WND_OUT * out) ATTR_USERES;
#ifdef __cplusplus
}
#endif

#define CRYPTOAPI_MESSAGE_BTN_OK	1
#define CRYPTOAPI_MESSAGE_BTN_CANCEL	2
#define CRYPTOAPI_MESSAGE_DEF_CANCEL	4
#define CRYPTOAPI_MESSAGE_BTN_LIC	8
#define CRYPTOAPI_MESSAGE_BTN_PRESS_BUY	16
#define CRYPTOAPI_MESSAGE_2001_KEY	128

/* Настройки окна вывода сообщения */
typedef struct CRYPTOAPI_MESSAGE_WND_CONFIG_ {
    DWORD size_of;
    DWORD num; /*!< Номер строки в ресурсе. */
    DWORD buttons; /*!< Флаги наличия кнопок. */
    TCHAR containername [256]; /*!< Имя контейнера "с проблемой" */
    TCHAR* message; // message 
    DWORD message_len; //message len
} CRYPTOAPI_MESSAGE_WND_CONFIG;

/* Результаты окна сообщения */
typedef struct CRYPTOAPI_MESSAGE_WND_OUT_ {
    DWORD ok;
} CRYPTOAPI_MESSAGE_WND_OUT;


/* Настройки окна вывода сообщения */
typedef struct CRYPTOAPI_MESSAGE_WND_CONFIG_EX_ {
    HWND parent;    /*!< хендл родительского окна */
    WORD language; /*!< язык окна */
    WORD buttons; /*!< Флаги наличия кнопок */
    char * header; /*!< заголовок окна, NULL для заголовка по умолчанию */
    char * text; /*!< сообщение */
} CRYPTOAPI_MESSAGE_WND_CONFIG_EX;

/* Колбек получения события
ctx - контекст окна сообщения
parent - хендл окна диалога, из которого вызвана функция
some_event - возвращаемый код события
*/
typedef HRESULT WINAPI cpui_message_event(/* [in] */ const HDISPMESSAGECONTEXT ctx, const TAutoWindowParams* window_params,  /* [out] */ void * some_event) ATTR_USERES;


/* Настройки окна вывода сообщения */
typedef struct CRYPTOAPI_MESSAGE_WND_CONFIG_AUTO_ {
    HWND parent;    /*!< хендл родительского окна */
    WORD language; /*!< язык окна */
    WORD buttons; /*!< Флаги наличия кнопок */
    char * header; /*!< заголовок окна, NULL для заголовка по умолчанию */
    char * text; /*!< сообщение */
    cpui_message_event * fun_event; /*!< колбек, возвращающий событие */
    TAutoWindowParams window_params;
} CRYPTOAPI_MESSAGE_WND_CONFIG_AUTO;

/*Функция вызова окна сообщений

Принимает на вход структуру с настройками.
Настройки: 
parent - хендл родительского окна;
language - язык, на котором будет отображаться диалог;
buttons: 
Флаги CRYPTOAPI_MESSAGE_BTN_OK, CRYPTOAPI_MESSAGE_BTN_CANCEL, CRYPTOAPI_MESSAGE_BTN_LIC задают отображение соответствующих кнопок в диалоге.
Флаг CRYPTOAPI_MESSAGE_DEF_CANCEL устанавливает курсор на CANCEL.
Флаг CRYPTOAPI_MESSAGE_BTN_PRESS_BUY сразу выводит окно ввода лицензии.
Флаг CRYPTOAPI_MESSAGE_2001_KEY говорит о предупреждении о ключе 2001 года. 
header - заголовок окна. NULL, если используется стандартный заголовок из оконной библиотеки;
text - отображаемое сообщение в utf8;
Функция возвращает ERROR_CANCELLED, если был передан флаг, в диалоге выбрана опция "отложить предупреждения на 1 месяц", и нажата S_OK.
Функция возвращает ERROR_RETRY, если был передан флаг CRYPTOAPI_MESSAGE_BTN_LIC, в случае успеха при нажатой кнопке BUY;
Иначе в случае, если нажата OK, функция возвращает S_OK;
Функция возвращает NTE_FAIL, если был передан флаг CRYPTOAPI_MESSAGE_BTN_LIC, в случае неуспеха при нажатой кнопке BUY.
Функция возвращает SCARD_W_CANCELLED_BY_USER, если пользователь нажал CANCEL;
Функция может возвращать другие ошибки CryptoApi.
*/
#ifdef __cplusplus
extern "C" {
#endif
    HRESULT WINAPI CPDisplayMessage(
    /* [in] */ HWND parent,
    /* [in] */ CRYPTOAPI_MESSAGE_WND_CONFIG *info,
    /* [out] */ CRYPTOAPI_MESSAGE_WND_OUT * out) ATTR_USERES;
    HRESULT WINAPI CPDisplayMessageEx( /* [in] */ CRYPTOAPI_MESSAGE_WND_CONFIG_EX *info) ATTR_USERES;
    HRESULT WINAPI CPDisplayMessageAuto( /* [in] */ const HDISPMESSAGECONTEXT ctx, /* [in] */ CRYPTOAPI_MESSAGE_WND_CONFIG_AUTO *info) ATTR_USERES;

#ifdef __cplusplus
}
#endif

/* Во всех строках char* лежат строки в кодировке UTF8*/

/*Начальное состояние окна аутентификации.

Окно всегда вызывается для ввода или смены какой-то аутентификации, назовем ее main. При этом в процессе работы окна может потребоваться 
для разблокировки main (M) вторая аутентификация - unblocking (U). При инициализации окна передается информация об M, и, если это нужно,
информация об U.

Окно может содержать поле ввода пароля, и два поля ввода нового пароля. В окне либо присутствует только поле ввода пароля, либо только два поля 
ввода нового пароля, либо все три поля сразу. Если обозначить аутентификацию, вводимую в блоке ввода пароля, первой буквой, а аутентификацию, 
вводимую в блоке смены пароля - второй буквой, а 0 - отсутствие отображения какого-то блока, то возможны следующие состояния окна: 
ca_sspf_ask = M0,
ca_sspf_change = 0M,
ca_sspf_unblock = UM,
ca_sspf_ask_change = MM.

В процессе работы окна возможны переходы из одного состояния в другое:
ca_sspf_ask -> ca_sspf_unblock, при условии can_ask_unblocking == 1, при получении ошибки SCARD_W_CHV_BLOCKED.
ca_sspf_change -> ca_sspf_unblock, при условии can_ask_unblocking == 1, при получении ошибки SCARD_W_CHV_BLOCKED.
ca_sspf_change -> ca_sspf_ask_change, при условии can_ask_main == 1, при получении ошибки SCARD_W_CARD_NOT_AUTHENTICATED.
Переходы по ошибке не обратимы.

Флаг can_ask_main может зажигаться в состоянии ca_sspf_ask. Сейчас его можно игнорировать.
Флаг can_ask_main зажигается в состоянии ca_sspf_change, когда подразумевается смена пароля, а не задание нового пароля.
Флаг can_ask_unblocking зажигается в состоянии ca_sspf_ask, когда существует протокол разблокировки пароля. Окно переходит в подразумеваемое состояние "разблокировка пароля".
Флаг can_ask_unblocking зажигается в состоянии ca_sspf_change, когда подразумевается задание нового пароля, но может потребоваться административная аутентификация.

Если окно вызвано в состоянии ca_sspf_ask, то успешное завершение возможно в случае успешного выполнения основной аутентификации и только тогда.
Если окно вызвано в состоянии ca_sspf_change, то успешное завершение возможно в случае успешного выполнения колбека смены аутентификации и только тогда.
Если окно вызвано в состоянии ca_sspf_unblock, то успешное завершение возможно в случае успешного выполнения колбека смены аутентификации и только тогда.
Окно в состоянии ca_sspf_ask_change не вызывается.
*/
typedef enum
{
    ca_sspf_ask = 1,	    /*состояние "запрос пароля"*/
    ca_sspf_change = 2,	    /*состояние "смена пароля" или "задание нового пароля"*/
    ca_sspf_unblock = 3,    /*состояние "разблокировка пароля" или "задание пароля с административным"*/
    ca_sspf_ask_change = 4  /*состояние "смена пароля с предварительным вводом для аутентификации"*/
} PWDFKC_WINDOW_START_STATES;

/* индексы строк заголовков в массиве строк заголовков, задающих заголовки в зависимости от состояния окна */
#define PWDFKC_PASSWORD_ASK_INDEX 0
#define PWDFKC_PASSWORD_CHANGE_INDEX 1
#define PWDFKC_PASSWORD_UNBLOCK_INDEX 2
#define PWDFKC_PASSWORD_ASK_CHANGE_INDEX 3
#define PWDFKC_PASSWORD_INDEX_NUMBER 4


/* Колбек установки нового пароля.
parent - хендл окна диалога, из которого вызвана функция

set_info->auth_type содержит идентификатор аутентификации, которая изменяется данной функцией. должен быть равен main_pass.auth_type из входной структуры.
set_info->password - блоб пароля
set_info->flags.save_in_cache - должен быть установлен в 0, не обрабатывается.
set_info->flags.save_in_registry - должен быть установлен в 0, не обрабатывается.
set_info->reserved может содержать в себе предъявляемую аутентификацию.

Возвращает ошибки:
1. Ошибки CryptoAPI - окно может их отобразить пользователю, после чего завершается.
2. SCARD_W_CARD_NOT_AUTHENTICATED - Необходима предварительная основная аутентификация. Может возникать в состоянии ca_sspf_change (в значении смены аутентификации).
При получении ошибки окно должно перейти в состояние ca_sspf_ask_change, если это разрешено (признак can_ask_main).
3. SCARD_W_CHV_BLOCKED - Необходима предварительная разблокирующая аутентификация. Может возникать в состоянии  ca_sspf_change (в значении задания новой аутентификации).
При получении ошибки окно должно перейти в состояние ca_sspf_unblock, если это разрешено (признак can_ask_unblocking).
4. ERROR_INVALID_STATE - в случае, если во время работы окна состояние контейнера/носителя изменилось, и окно неактуально.
*/
typedef HRESULT WINAPI cpui_pwdfkc_change_auth(const PWDFKC_CONTEXT* ctx, HWND parent, const CRYPT_PIN_WND_SOURCE_PARAM* set_info) ATTR_USERES;

/* Колбек проведения аутентификации.
parent - хендл окна диалога, из которого вызвана функция

set_info->auth_type содержит идентификатор аутентификации, которая проводится данной функцией (может быть как unblocking_pass.auth_type, так и main_pass.auth_type из входной структуры).
set_info->password - блоб пароля
set_info->flags.once - должен быть установлен в 0, не обрабатывается.
set_info->flags.save - сохранение пароля в реестре. 1, если надо сохранить, 0 иначе.
set_info->reserved должен быть равен {0,NULL}.

Возвращает ошибки:
1. Ошибки CryptoAPI - окно может их отобразить пользователю, после чего завершается.
2. SCARD_W_CHV_BLOCKED - Необходима предварительная разблокирующая аутентификация. Может возникать в состоянии ca_sspf_ask, если основная аутентификация заблокирована.
При получении ошибки окно должно перейти в состояние ca_sspf_unblock, если это разрешено (признак can_ask_unblocking).
3. ERROR_INVALID_STATE - в случае, если во время работы окна состояние контейнера/носителя изменилось, и окно неактуально.
*/
typedef HRESULT WINAPI cpui_pwdfkc_auth(const PWDFKC_CONTEXT* ctx, HWND parent, const CRYPT_PIN_WND_SOURCE_PARAM * pass) ATTR_USERES;

/* Неопределенное значение счетчика оставшихся попыток. 
   Такое значение передается провайдером, если носитель не умеет возвращать корректное
   оставшееся число попыток. В этом случае надо показывать окно без указания оставшихся попыток.*/
#define AUTH_INFO_TRYES_UNDEFINED 0x8000  

/* код ошибки "при чтении счетчиков ошибок не произошло" */
#define AUTH_INFO_ERROR_NO	0

/* код ошибки "основная аутентификация заблокирована" */
#define AUTH_INFO_ERROR_BLOCKED_MAIN	1

/* код ошибки "разблокирующая аутентификация заблокирована" */
#define AUTH_INFO_ERROR_BLOCKED_UNBLOCKING	2

/* код ошибки "заблокированы обе аутентификации" */
#define AUTH_INFO_ERROR_BLOCKED_BOTH	(AUTH_INFO_ERROR_BLOCKED_MAIN | AUTH_INFO_ERROR_BLOCKED_UNBLOCKING)

/* код "для смены основной аутентификации нужно сначала провести основную аутентификацию " */
#define AUTH_INFO_ERROR_NEED_MAIN		4

/* код "для смены основной аутентификации нужно провести разблокирующую аутентификацию " */
#define AUTH_INFO_ERROR_NEED_UNBLOCKING		8

/* код "основная аутентификация временно заблокирована, нужно подождать" */
#define AUTH_INFO_ERROR_BLOCKED_MAIN_TEMP	16

/* функция получает информацию об аутентификации во втором параметре.
Функция получает значения счетчиков для первой и второй аутентификаций и ошибки для отображения на экране.
Возвращаемые значения в структуре out_info: 
1. Счетчики аутентификаций и операций, в случае проведения основной аутентификации в контейнере.
2. Флаги состояния аутентификации out_info->error. (Поле может содержать несколько флагов). Равна 
2.1. AUTH_INFO_ERROR_BLOCKED_MAIN  - если заблокирована основная аутентификация, для разблокирования надо провести разблокирующую аутентификацию.
2.2. AUTH_INFO_ERROR_BLOCKED_UNBLOCKING  - заблокирована (исчерпаны попытки ввода) разблокирующая аутентификация, но основная аутентификация заблокирована. Данная ситуация возможна при
                                  наличии разблокирующей аутентификации, в которой, однако, все попытки ввода исчерпаны. Переход в состояние разблокировки 
				  в этом случае невозможен.
2.3. AUTH_INFO_ERROR_BLOCKED_BOTH - если заблокированы обе аутентификации. Дальнейшая работа окна бессмысленна.
2.4. AUTH_INFO_ERROR_NEED_MAIN	- если для смены основной аутентификации требуется предъявление основной аутентификации. Данный флаг не сочетается с 
				  AUTH_INFO_ERROR_BLOCKED_MAIN, AUTH_INFO_ERROR_BLOCKED_UNBLOCKING.
2.5. AUTH_INFO_ERROR_NEED_UNBLOCKING - если для смены основной аутентификации требуется предъявление разблокирующей аутентификации. Данный флаг не сочетается с 
				  AUTH_INFO_ERROR_BLOCKED_UNBLOCKING.
2.6. AUTH_INFO_ERROR_NO -	  все аутентификации окна доступны для работы.
При возникновении ошибки AUTH_INFO_ERROR_BLOCKED_MAIN окно должно осуществлять попытку перехода в состояние разблокировки.
При возкниновении ошибки AUTH_INFO_ERROR_BLOCKED_BOTH окно должно завершаться с ошибкой SCARD_W_CHV_BLOCKED.
При возникновении ошибки AUTH_INFO_ERROR_BLOCKED_UNBLOCKING окно должно завершаться с ошибкой SCARD_W_CHV_BLOCKED в случае, если только что завершился вызов 
одной из функций аутентификации с ошибкой SCARD_W_CHV_BLOCKED.

Код возврата:
1. ERROR_SUCCESS - если получение счетчиков прошло успешно.
2. Ошибки CryptoAPI - окно завершается, передавая в качестве ответа эту ошибку.
3. ERROR_INVALID_STATE - в случае, если во время работы окна состояние контейнера/носителя изменилось, и окно неактуально.
*/
typedef HRESULT WINAPI cpui_pwdfkc_get_auth_info(const PWDFKC_CONTEXT* ctx, HWND parent, CRYPT_WND_INFO_PARAM* out_info) ATTR_USERES;

/*стартовое описание счетчиков.*/
typedef struct
{
    BOOL exist; /* признак, что данный счетчик используется и отображается в окне */
    char * name;    /*имя счетчика. если NULL и счетчик используется, то значение строка-название счетчика меняется на эту */
} PWDFKC_INIT_COUNTER;


/* флаги описания поля */
typedef struct
{
    unsigned show : 1;	 /* флаг, означающий демонстрацию данного поля при старте */
    unsigned change : 1; /* флаг, означающий возможность изменения */
    unsigned set1 : 1;	 /* флаг, означающий установку данного параметра в 1 (для бинарных значений) */
} PWDFKC_FIELD_FLAGS;


/* структура передачи параметров ввода пароля */
typedef struct
{
    DWORD auth_type;		/* Тип аутентификации в CSP. Передается в колбэки. */
    struct
    {
	char * term;		/* термин пароля */
	char * not_same;	/* сообщение о несовпадающих паролях */
    } strings;			/* строки */
    char * example;		    /* пример пароля. не используется, unused */
    SHORT min_length;		    /* минимальная длина */
    SHORT max_length;		    /* максимальная длина */
    DATA_BLOB enc;		    /* данные для зашифрования пароля. unused */
} PWDFKC_PASSWORD_INPUT;

/* главная структура-конфигуратор окна */
typedef struct
{
    HWND parent;	    /* указатель на родительское окно */
    WORD language; 	    /* язык окна */
    PWDFKC_WINDOW_START_STATES start_state;	    /* состояние текущего окна (что в нём выполняется) */
    struct
    {
	unsigned can_ask_main : 1;	/* разрешение расширения текущего состояния основной аутентификацией (см. описание PWDFKC_WINDOW_START_STATES ) */
	unsigned can_ask_unblocking : 1;	/* разрешение расширения текущего состояния разблокирующей аутентификацией (см. описание PWDFKC_WINDOW_START_STATES ) */
    } flags;	    /* флаги вызова */
    PWDFKC_FIELD_FLAGS	save_in_cache;	/* возможность поля "сохранение пароля в кэше" */
    PWDFKC_FIELD_FLAGS	save_in_system;	/* возможность поля "сохранение пароля в реестре" */
    char * header; /* заголовок окна */
    char * text[PWDFKC_PASSWORD_INDEX_NUMBER]; /* массив фраз заголовка */
    char * add_text;	/*Дополнительная строка (например, приветствие УЭК) */
    struct
    {
	char* group;	    /* Имя группы имени */
	char* reader_term;	    /* название первого имени */
	char* reader_value;	    /* значение первого имени */
	char* unique_term;	    /* название второго имени */
	char* unique_value;	    /* значение второго имени */
	char* container_term;	    /* название третьего имени */
	char* container_value;	    /* значение третьего имени */
	BOOL unique_exists;
    } name; /* место проведения аутентификации */
    PWDFKC_PASSWORD_INPUT  main_pass;	    /* свойства пароля */
    PWDFKC_PASSWORD_INPUT  unblocking_pass;	    /* дополнительные свойства пароля, используются только когда включен флаг two_pass, для пароля, разрешающего задание основного */
    PWDFKC_INIT_COUNTER main_counters[CPCAR_COUNTER_CONTAINER_NUMBER];	/* признаки использования и имена счетчиков для основной аутентификации */
    PWDFKC_INIT_COUNTER unblocking_counters[CPCAR_COUNTER_ROOT_NUMBER];		/* признаки использования и имена счетчиков для разблокирующей аутентификации */

    cpui_pwdfkc_get_auth_info*	fun_info;	/* callback для получения информации аутентификаций */
    cpui_pwdfkc_auth*		fun_auth;	/* callback для проведения аутентификации */
    cpui_pwdfkc_change_auth*	fun_change;	/* callback для смены (установки) аутентификации */
}  CRYPTOAPI_PASSWORD_FKC_WND_CONFIG;

/*Функция вызова окна аутентификации.

В начале исполнения отрисовывает окно в соответствии с начальными установками. Может быть в трех различных начальных состояниях (см. PWDFKC_WINDOW_START_STATES).
В начальном состоянии ca_sspf_ask отрисовывает блок ввода пароля для основной аутентификации.
В начальном состоянии ca_sspf_change отрисовывает блок смены аутентификации для основной аутентификации.
В начальном состоянии ca_sspf_unblock отрисовывает блок ввода пароля для аутентификации B и смены аутентификации для основной аутентификации.

В ca_sspf_ask добавляет галочку "смена пароля", если can_ask_main. При нажатии на нее переходит в состояние ca_sspf_ask_change, причем возможность снятия галочки остается.
В зависимости от show_properties либо скрывает блоки счетчиков носителя и ограничений, либо показывает их при старте.

Модифицируются имена отображаемых счетчиков, и скрываются неотображаемые, в зависимости от  установок a_counters, b_counters.
Если выставлен признак times_exist, отображаются значения сроков действия ключей time_private_key, time_public_key.
Иначе строки отображения сроков действия ключей скрываются.

Если все счетчики носителя отсутствуют, и отсутствуют сроки действия ключей, вне зависимости от значения show_properties кнопка "подробнее" скрывается, блоки ограничений и
счетчиков носителя не демонстрируются.

Устанавливается заголовок, равный header.
В зависимости от текущего состояния выводится в верху окна строка text[i], где i - номер состояния. (Например, для ca_sspf_ask - PWDFKC_PASSWORD_ASK_INDEX).
Если add_text != 0, под первой строкой выводится add_text.
Если name.group!=0, значение по умолчанию блока описания контейнера заменяется на name.group.
Если name.reader_term!=0, значение по умолчанию описания имени считывателя заменяется на name.reader_term.
Если name.reader_value!=0, оно устанавливается в качестве имени считывателя.
Если name.unique_term!=0, значение по умолчанию описания имени носителя заменяется на name.unique_term.
Если name.unique_value!=0, оно устанавливается в качестве имени носителя.
Если name.container_term!=0, значение по умолчанию описания имени контейнера заменяется на name.container_term.
Если name.container_value!=0, оно устанавливается в качестве имени контейнера.
Если name.unique_exists == FALSE, то окно может установить строки имени носителя, либо не показывать

В описаниях паролей, где требуется термин пароля, он берется из описания соответствующей аутентификации.

Функция использует колбек информации ауетнтификации для получения текущих значений счетчиков с некоторой периодичностью.
Начальные значения счетчиков также получаются этим колбеком.
Если из колбека информации получена ошибка error!=0, сначала выводится сообщение на экран, соответствующее error, вне зависимости от того, с ошибкой или нет завершился
колбек.
Если код возврата колбека не равен ERROR_SUCCESS, и не требует смены состояния окна, окно завершается с полученным из колбека кодом возврата.
Если код возврата колбека требует смены состояния окна, то если возможна смена состояния (установлены соответствующие флаги разрешения), смена состояния происходит;
если же смена состояния не разрешена, окно завершается с полученным из колбека кодом возврата.

Функция использует колбек смены аутентификации для смены аутентификационной информации A или для полного создания контейнера (в случае введения новой аутентификации).
Смена аутентификации заввершается установкой этой аутентификации внутри колбека смены.

Функция использует колбек проведения аутентификации для основной аутентификации или по B.

1. Если окно вызвано в состоянии ca_sspf_ask, то при отсутствии переходов успешным завершением считается успешное выполнение колбека:
1.1. Основная аутентификация.

1.2. Если в ходе работы была смена состояние на ca_sspf_unblock, то последовательность вызова колбеков, соответствующая успешному завершению окна:
 1.2.1 Разблокирующая аутентификация.
 1.2.2 Смена основной.
1.3. Если в ходе работы была смена состояния на ca_sspf_ask_change, то последовательность колбеков:
 1.3.1. Основная аутентификация.
 1.3.2. Смена основной.

2. Если окно вызвано в состоянии ca_sspf_change, то при отсутствии переходов успешным завершением считается успешное выполнение колбека:
2.1. Смена основной.
2.2. Если в процессе работы окна была смена состояния на ca_sspf_unblock, то последовательность вызова колбеков, соответствующая успешному завершению окна:
 2.2.1. Разблокирующая аутентификация.
 2.2.2. Смена основной.
2.3. Если в процессе работы была смена состояния на ca_sspf_ask_change, то последовательность вызова колбеков, соответствующая успешному завершению окна:
 2.3.1. Основная аутентификация.
 2.3.2. Смена основной.

3. Если окно вызвано в состоянии ca_sspf_unblock, то успешное завершение возможно в случае успешного выполнения последовательности:
3.1. Разблокирующая аутентификация.
3.2. Смена основной.

Функция возвращает ошибки CryptoAPI и транслирует ошибки SCARD_W_CARD_NOT_AUTHENTICATED, SCARD_W_CHV_BLOCKED, ERROR_INVALID_STATE, полученные из колбеков,
если не может их обработать самостоятельно.
*/
#ifdef __cplusplus
extern "C" {
#endif
HRESULT WINAPI CPQueryPinEx(const PWDFKC_CONTEXT* ctx, const CRYPTOAPI_PASSWORD_FKC_WND_CONFIG* info) ATTR_USERES;
#ifdef __cplusplus
}
#endif

#define VISUALIZER_CONTROL_FLAG_ASK_PASSWORD 1 /* флаг, показывающий, что требуется запрос пароля а не просто подтверждение подписи */

/* главная структура-конфигуратор окна запроса разрешения на подпись */
typedef struct
{
    CRYPTOAPI_PASSWORD_FKC_WND_CONFIG * info;	/* Здесь хранится общая информация об окне, поля в точности повторяют семантику вызова CPQueryPinEx. */
    PHS_SIGNING_DATA signing_data;		/* Структура для хранения документа, передаваемого на подпись. */
    PHS_ADDITIONAL_DATA additional_data;	/* Структура, содержащая ссылки на дополнительные данные, хэш которых содержится в signing_data. */
    DWORD context_flags;			/* Здесь хранятся флаги контекста, из которого вызвали запрос. В том числе CRYPT_SILENT. Подтверждение
						   может отображаться на устройстве, игнорирующем этот флаг. */
    DWORD control_flags;			/* Здесь хранятся флаги, описывающие вызов. В частности, VISUALIZER_CONTROL_FLAG_ASK_PASSWORD. */
}  CRYPTOAPI_VISUALIZER_WND_CONFIG;

/*Функция вызова окна запроса разрешения на подпись.
Если (control_flags & VISUALIZER_CONTROL_FLAG_ASK_PASSWORD) != 0, то отображает документы, переданные в signing_data и additional_data, после чего для 
подтверждения подписи запрашивает пароль в соответствии с параметрами, переданными в info.
Если (control_flags & VISUALIZER_CONTROL_FLAG_ASK_PASSWORD) == 0, то отображаются документы, переданные в signing_data и additional_data, и запрашивается разрешение 
на их подпись.
При отображении ввода пароля вызов окна в состоянии ca_sspf_change считается ошибочным(?)

Функция возвращает ошибки CryptoAPI и транслирует ошибки SCARD_W_CARD_NOT_AUTHENTICATED, SCARD_W_CHV_BLOCKED, ERROR_INVALID_STATE, полученные из колбеков,
если не может их обработать самостоятельно, в случае, если отображался ввод пароля.
Функция возвращает ERROR_SUCCESS, если пользователь согласился с документами.
Функция возвращает NTE_SILENT_CONTEXT, если не может выполнить запрос, потому что контекст помечен, как тихий.
Функция возвращает SCARD_W_CANCELLED_BY_USER, если пользователь отклонил запрос подписи.
Функция возвращает NTE_BAD_DATA, если данные некорректные. 
Функция возвращает ERROR_UNSUPPORTED_TYPE, если данные не удалось отобразить.
*/
#ifdef __cplusplus
extern "C" {
#endif
    HRESULT WINAPI CPAskForSign(const PWDFKC_CONTEXT* ctx, const CRYPTOAPI_VISUALIZER_WND_CONFIG* info) ATTR_USERES;
#ifdef __cplusplus
}
#endif


/*! 
Структуры и функция для вывода legacy-окна ввода пароля
*/

typedef struct _CRYPTOAPI_CARRIER_INFO {
    DWORD login_type;
    short max_length;
    short min_length;
    /* [string][full] */ TCHAR *reader_name;
    /* [string][full] */ TCHAR *nickname;
    /* [string][full] */ TCHAR *passwd_term;
    unsigned char flags;
} CRYPTOAPI_CARRIER_INFO;

typedef struct _CRYPTOAPI_CARRIER_LIST {
    short n;
    /* [size_is] */ CRYPTOAPI_CARRIER_INFO *parts;
} CRYPTOAPI_CARRIER_LIST;

typedef struct _CRYPTOAPI_RDR_PIN_FLAGS {
    unsigned char use_double;
    unsigned char same_double;
    unsigned char save_passwd;
    unsigned char disable_save_passwd;
} CRYPTOAPI_RDR_PIN_FLAGS;

typedef struct _CRYPTOAPI_PIN_WND_CONFIG {
    DWORD size_of;
    CRYPTOAPI_CARRIER_INFO context;
    /* [full][string] */ TCHAR *header;
    /* [full][string] */ TCHAR *text;
    /* [full][string] */ TCHAR *input;
    /* [full][string] */ TCHAR *input2;
    /* [full][string] */ TCHAR *default_passwd;
    /* [full][string] */ TCHAR *not_same;
    /* [full][string] */ TCHAR *save_text;
    /* [full][string] */ TCHAR *container_name;
    CRYPTOAPI_RDR_PIN_FLAGS flags;
    int try_number;
    DWORD idd;
    DWORD container_flags;
    DWORD action;
#ifndef NO_NK
    short n;
    short k;
    short max_n;
    short max_k;
#endif // NO_NK
} CRYPTOAPI_PIN_WND_CONFIG;

typedef struct _CRYPTOAPI_PIN_WND_OUT {
    TCHAR passwd[256];
    TCHAR passwd2[256];
#ifndef NO_NK
    TCHAR container[256];
    short n;
    short k;
    char create_container;
#endif // NO_NK
    char save_passwd;
} CRYPTOAPI_PIN_WND_OUT;

#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
    HRESULT WINAPI CPQueryPin(
	/* [in] */ HWND parent,
	/* [in] */ CRYPTOAPI_PIN_WND_CONFIG *info,
	/* [in] */ CRYPTOAPI_SELECT_WND_CONFIG * select_info,
	/* [out] */ CRYPTOAPI_PIN_WND_OUT * out) ATTR_USERES;
#ifdef __cplusplus
}
#endif //__cplusplus


/*
 * Структура для получения в оконном интерфейсе одного элемента считывателя
 * За структурой в буфер пишутся:
 * utf8z строка имени считывателя или '\0', если имя считывателя отсутствует;
 * utf8z строка названия апплетов на носителе или '\0', если отсутствует;
 * для i = 0..CRYPTOAPI_SELECT_READER_MAX_APPLET_COUNT-1:
 * utf8z строка unique[i], или '\0', если unique[i] отсутствует;
 * utf8z строка info[i], или '\0', если info[i] отсутствует;
 * ---------------------------------- version 2 ----------------------------------
 * utf8z строка прозвища считывателя или '\0', если прозвище считывателя отсутствует;
 * DWORD флаги считывателя;
 */
typedef struct _CRYPT_SELECT_READER_ITEM
{
    HSELREADER	context; 	/*! \brief Контекст считывателя/носителя */
    ULONGLONG	icon_count;	/*! \brief Количество иконок */
    HSELREADERICON icons[CRYPTOAPI_SELECT_READER_ICONS_NUMBER]; /*! \brief Хендлы иконок */
    ULONGLONG	unique_count;	/*! \brief Количество аплетов */
    DWORD	retcode[CRYPTOAPI_SELECT_READER_MAX_APPLET_COUNT]; /*! \brief Коды возврата аплетов */
} CRYPT_SELECT_READER_ITEM;

/* Колбек открытия списка доступных считывателей.
 * Для контекста ctx, переданного из окна parent, возвращает контекст списка list_context.
 */
typedef HRESULT WINAPI cpui_selreader_list_open (HSELREADERINITDATA ctx, HWND parent, HSELREADERLISTCONTEXT * list_context) ATTR_USERES;

/* Колбек получения очередного элемента списка считывателей.
 * Для контекста ctx, переданного из окна parent, возвращает очередной элемент.
 * list_context - контекст списка, открытый также в (ctx, parent).
 * item_size - на входе - размер передаваемого буфера out_item. На выходе - количество реально записанных байт в случае успеха и out_item!=NULL,
 * или требуемый размер буфера, если out_item == NULL,
 * или требуемый размер буфера, если размера буфера недостаточно для записи элемента.
 * Колбек должен вызываться сначала для получения длины, с NULL в качестве буфера, а потом с буфером требуемой длины.
 * out_item - буфер с описанием очередного считывателя.
 */
typedef HRESULT WINAPI cpui_selreader_list_next(HSELREADERINITDATA ctx, HWND parent, HSELREADERLISTCONTEXT list_context, size_t * item_size, CRYPT_SELECT_READER_ITEM * out_item) ATTR_USERES;

/*Колбек закрытия списка считывателей.
 * Для контекста ctx, переданного из окна parent, закрывает ранее открытый список list_context.
 */
typedef HRESULT WINAPI cpui_selreader_list_free(HSELREADERINITDATA ctx, HWND parent, HSELREADERLISTCONTEXT list_context) ATTR_USERES;

/* Колбек установки ответа диалога (контекст считывателя и номер аплета).
 * Для контекста ctx, переданного из окна parent, устанавливает выбранные пользователем контекст считывателя reader и номер аплета current_applet. 
 */
typedef HRESULT WINAPI cpui_selreader_set_answer (HSELREADERINITDATA ctx, HWND parent, HSELREADER reader, unsigned int current_applet) ATTR_USERES;

/* Колбек установки считывателя по умолчанию.
 * Для контекста ctx, переданного из окна parent, устанавливает считыватель по умолчанию defcontext.
 */
/* borodin разъяснил, что не надо требовать проверки кода возврата. 2020-jan-23 */
typedef HRESULT WINAPI cpui_selreader_set_default(HSELREADERINITDATA ctx, HWND parent, HSELREADER defcontext);

/* Колбек освобождения контекста считывателя.
 * Для контекста ctx, переданного из окна parent, освобождает контекст reader.
 * Все контексты, переданные окну колбеком cpui_selreader_list_next, должны быть освобождены этим колбеком в течение работы окна, кроме 
 * контекста, выбранного пользователем.
 */
typedef HRESULT WINAPI cpui_selreader_delete_hselreader(HSELREADERINITDATA ctx, HWND parent, HSELREADER reader) ATTR_USERES;


/* Колбек передачи иконки для считывателя.
 * Для контекста ctx, переданного из окна parent, получает данные иконки icon размера x_icon*y_icon с приоритетом <= priority.
 * out_size - получает на вход длину буфера out_data. 
 * На выходе в out_size реальное количество записанной в буфер информации в случае успеха, или размер требуемого буфера, если out_data == NULL
 * или размер переданного буфера недостаточен для записи информации об иконке. 
 */
typedef HRESULT WINAPI cpui_selreader_icon_transmit(HSELREADERINITDATA ctx, HWND parent, HSELREADERICON icon, DWORD x_icon, DWORD y_icon, DWORD priority, size_t * out_size, LPBYTE out_data) ATTR_USERES;

/*
 * Структура для установки начальных значений в окне выбора считывателя и аплета.
 */
typedef struct
{
    HWND parent; /*!< Для Win32, главное окно. */
    WORD language; /*!< Номер языка окна */
    DWORD flags;  /*!< Флаги, открывающего контекста */

    char * header; /*!< Заголовок окна, NULL для стандартного. */
    char * text; /*!< Текст внутри окна, NULL для стандартного. */
    char * text_for_empty; /*!< Текст внутри окна для пустого списка. */
    char * defreader; /*!< Имя ридера по умолчанию */

    cpui_selreader_list_open * list_open; /*!< Функция открытия списка */
    cpui_selreader_list_next * list_next; /*!< Функция получения следующего элемента списка */
    cpui_selreader_list_free * list_free; /*!< Функция закрытия списка */
    cpui_selreader_delete_hselreader * del_reader; /*!< Функция удаления считывателя */
    cpui_selreader_set_answer * set_answer; /*!< Функция возвращения ответа окна */
    cpui_selreader_set_default * set_def;      /*!< Установки считывателя по умолчанию. */
    cpui_selreader_icon_transmit * get_icon_info; /*!< Функция получения информации о иконке. Может быть NULL. */
} CRYPTOAPI_SELECT_READER_CONFIG;

#ifdef __cplusplus
extern "C" {
#endif
    HRESULT WINAPI CPSelectReader(HSELREADERINITDATA ctx, const CRYPTOAPI_SELECT_READER_CONFIG *init_info) ATTR_USERES;
#ifdef __cplusplus
}
#endif

typedef HRESULT(WINAPI *cpuifkc_select_carrier_ptr_t)(HSELREADERINITDATA ctx, const CRYPTOAPI_SELECT_READER_CONFIG *init_info) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_query_pin_ex_ptr_t)(const PWDFKC_CONTEXT* ctx, const CRYPTOAPI_PASSWORD_FKC_WND_CONFIG* info) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_query_pin_ptr_t)(HWND parent, CRYPTOAPI_PIN_WND_CONFIG* info, CRYPTOAPI_SELECT_WND_CONFIG* select_info, CRYPTOAPI_PIN_WND_OUT* out) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_display_message_ex_ptr_t)(CRYPTOAPI_MESSAGE_WND_CONFIG_EX * info) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_display_message_ptr_t)(HWND parent, CRYPTOAPI_MESSAGE_WND_CONFIG * info, CRYPTOAPI_MESSAGE_WND_OUT * out) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_select_container_ptr_t)(HWND parent, CRYPTOAPI_SELECT_WND_CONFIG * info, CRYPTOAPI_SELECT_WND_OUT * out) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_display_message_auto_ptr_t)(const HDISPMESSAGECONTEXT ctx, CRYPTOAPI_MESSAGE_WND_CONFIG_AUTO *info) ATTR_USERES;

typedef HRESULT(WINAPI *cpui_ask_for_sign_ptr_t)(const PWDFKC_CONTEXT* ctx, const CRYPTOAPI_VISUALIZER_WND_CONFIG* info) ATTR_USERES;

#ifndef CSP_EXPORT
#define CSP_EXPORT extern
#endif /* CSP_EXPORT */

#ifdef __cplusplus
extern "C" {
#endif

#if defined _WIN32
#define UI_MODULE_NAME _TEXT("cpui.dll") 
#define DISPLAY_MESSAGE_NAME_EX "cpui_display_message_ex"
#define DISPLAY_MESSAGE_NAME_AUTO "cpui_display_message_auto"
#define DISPLAY_MESSAGE_NAME "cpui_display_message"
#define SELECT_CONTAINER_NAME "cpui_select_container"
#define QUERY_PIN_NAME "cpui_query_pin"
#define QUERY_PIN_EX_NAME "cpui_query_pin_ex"
#define SELECT_CARRIER_NAME "cpui_choice_carrier"
#define ASK_FOR_SIGN_NAME "cpui_ask_for_sign"
#else
#define UI_MODULE_NAME _TEXT("libcpui.so")
#define DISPLAY_MESSAGE_NAME_EX "CPDisplayMessageEx"
#define DISPLAY_MESSAGE_NAME_AUTO "CPDisplayMessageAuto"
#define DISPLAY_MESSAGE_NAME "CPDisplayMessage"
#define SELECT_CONTAINER_NAME "CPSelectContainer"
#define QUERY_PIN_NAME "CPQueryPin"
#define QUERY_PIN_EX_NAME "CPQueryPinEx"
#define ASK_FOR_SIGN_NAME "CPAskForSign"
#endif

#ifdef __cplusplus
}
#endif


#endif /*_CPGUI_H_*/
