COpenOTPCredential::COpenOTPCredential():
    _cRef(1),
    _pCredProvCredentialEvents(NULL),
	_openotp_is_challenge_request(false),
	_user_name(NULL),
	_domain_name(NULL)
{
    DllAddRef();

    ZERO(_rgCredProvFieldDescriptors);
    ZERO(_rgFieldStatePairs);
    ZERO(_rgFieldStrings);

	ZERO(_openotp_server_url);
	ZERO(_openotp_cert_file);
	ZERO(_openotp_cert_password);
	ZERO(_openotp_ca_file);
	ZERO(_openotp_client_id);
	ZERO(_openotp_default_domain);
	ZERO(_openotp_user_settings);
	ZERO(_openotp_login_text);

	_openotp_login_request = *openotp_login_req_new();

	_openotp_login_response.code    = 0;
	_openotp_login_response.timeout = 0;
	_openotp_login_response.data    = NULL;
	_openotp_login_response.message = NULL;
	_openotp_login_response.session = NULL;

	_openotp_challenge_response.code    = 0;
	_openotp_challenge_response.data    = NULL;
	_openotp_challenge_response.message = NULL;

	// Read OpenOTP config
	readRegistryValueString(CONF_SERVER_URL, sizeof(_openotp_server_url), _openotp_server_url);
	readRegistryValueString(CONF_CERT_FILE, sizeof(_openotp_cert_file), _openotp_cert_file);
	readRegistryValueString(CONF_CERT_PASSWORD, sizeof(_openotp_cert_password), _openotp_cert_password);
	readRegistryValueString(CONF_CA_FILE, sizeof(_openotp_ca_file), _openotp_ca_file);
	readRegistryValueString(CONF_CLIENT_ID, sizeof(_openotp_client_id), _openotp_client_id);	
	readRegistryValueString(CONF_DEFAULT_DOMAIN, sizeof(_openotp_default_domain), _openotp_default_domain);
	readRegistryValueString(CONF_USER_SETTINGS, sizeof(_openotp_user_settings), _openotp_user_settings);

	//readRegistryValueString(CONF_LOGIN_TEXT, sizeof(_openotp_login_text), _openotp_login_text);
	if (readRegistryValueString(CONF_LOGIN_TEXT, sizeof(_openotp_login_text), _openotp_login_text) <= 2) // 2 = size of a wchar_t NULL-terminator in byte
		strcpy_s(_openotp_login_text, sizeof(_openotp_login_text), OPENOTP_DEFAULT_LOGIN_TEXT);

	readRegistryValueInteger(CONF_SOAP_TIMEOUT, &_openotp_soap_timeout);
	// END Read OpenOTP config
}
HRESULT CLMSFilter::Filter(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus, DWORD dwFlags, GUID* rgclsidProviders, BOOL* rgbAllow, DWORD cProviders)
{
	LPOLESTR clsid;//PWSTR
	int isRDP;
	int onlyRDP = 0;//Local and RDP

	if (DEVELOP_MODE) PrintLn("========== MultiotpProvider::Applying CLMSFilter::Filter ==========");

	isRDP = IsRemoteSession();
	if (!isRDP) {
		if (readRegistryValueInteger(CONF_RDP_ONLY, onlyRDP)) {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter: Only RDP is OTP protected!!!");
			//isRDP = FALSE;
			return S_OK;
		}
		else {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter: RDP and Local OTP protection");
			isRDP = TRUE;
		}
	} else if (DEVELOP_MODE) {
		PrintLn("MultiotpProvider::CLMSFilter::Filter: RDP connection");
	}

	switch (cpus)
	{
	case CPUS_LOGON:
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter CPUS_LOGON");
	case CPUS_UNLOCK_WORKSTATION:
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter CPUS_UNLOCK_WORKSTATION");
		for (DWORD i = 0; i < cProviders; i++)
		{
			if (i < dwFlags) {}

			if (IsEqualGUID(rgclsidProviders[i], CLSID_Multiotp)) {
				rgbAllow[i] = isRDP;// TRUE;
			}
			else {
				rgbAllow[i] = !isRDP;// FALSE;
			}
			if (DEVELOP_MODE) {
				StringFromCLSID(rgclsidProviders[i], &clsid);
				if (rgbAllow[i] == FALSE) {
					PrintLn(L"\t-", clsid);
				}
				else {
					PrintLn(L"\t+", clsid);
				}
				CoTaskMemFree(clsid);
			}
		}
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter End of CPUS_UNLOCK_WORKSTATION");
		return S_OK;
	case CPUS_CREDUI: //issue #1
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter CPUS_CREDUI");
	case CPUS_CHANGE_PASSWORD:
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter CPUS_CHANGE_PASSWORD");
		return E_NOTIMPL;
	default:
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::CLMSFilter::Filter default");
		return E_INVALIDARG;
	}

}
// Sets pdwCount to the number of tiles that we wish to show at this time.
// Sets pdwDefault to the index of the tile which should be used as the default.
// The default tile is the tile which will be shown in the zoomed view by default. If
// more than one provider specifies a default the last used cred prov gets to pick
// the default. If *pbAutoLogonWithDefault is TRUE, LogonUI will immediately call
// GetSerialization on the credential you've specified as the default and will submit
// that credential for authentication without showing any further UI.
HRESULT MultiotpProvider::GetCredentialCount(
    _Out_ DWORD *pdwCount,
    _Out_ DWORD *pdwDefault,
    _Out_ BOOL *pbAutoLogonWithDefault)
{
	if (DEVELOP_MODE) PrintLn("MultiotpProvider::GetCredentialCount");

    *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
    *pbAutoLogonWithDefault = FALSE;

    if (_fRecreateEnumeratedCredentials)
    {
        _fRecreateEnumeratedCredentials = false;
        _ReleaseEnumeratedCredentials();
        _CreateEnumeratedCredentials();
    }
	DWORD dwUserCount = 1;
	HRESULT hr;

	if (_pCredProviderUserArray != nullptr) {
		hr = _pCredProviderUserArray->GetCount(&dwUserCount);
		if (hr == 0) {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::UserArrayCount:(%d)", dwUserCount);
		}
		else {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::UserArray.GetCount Error");
			dwUserCount = 1;
		}
	}
	else {
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::Unassigned UserArray");
		dwUserCount = 1;
	}

	if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
		dwUserCount += 1;//display additional empty tile
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::Count +1 (empty tile)");
	}

	if (DEVELOP_MODE) PrintLn("MultiotpProvider::User count:(%d)", dwUserCount);

	if (IsRemoteSession()) {
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::GetCredentialCount: RDP connection");

		*pdwCount = dwUserCount;//1
		
		//get RDP port from registry
		int RDPPort = 3389;//default RDPPort
//		HRESULT hr;

		RDPPort = readRegistryValueInteger(CONF_RDP_PORT, RDPPort);
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::RDP connection on port: %d", RDPPort);
	}

	else {
		if (DEVELOP_MODE) PrintLn("MultiotpProvider::Local connection");
		//logfile << "Local connection\n";

		if (readRegistryValueInteger(CONF_RDP_ONLY, 0)) {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::Only RDP is OTP protected!!!");
			*pdwCount = 0;//no filtering no OTP tile
		}
		else {
			if (DEVELOP_MODE) PrintLn("MultiotpProvider::RDP and Local OTP protection");
			*pdwCount = dwUserCount;//show OTP tile
		}

		if (DEVELOP_MODE) {
			PrintLn("MultiotpProvider::OTP tile always visible");
			*pdwCount = dwUserCount;//development - don't force but allow OTP in all scenarios
		}
	}

    return S_OK;
}