// wmsoapauthsvc.cpp : Implementation of WinMain

#include "stdafx.h"
#include "resource.h"
#include <stdio.h>

#include <initguid.h>
#include "..\soap_source\xmlparser.h"
#include "..\soap_source\xmldocument.h"
#include <time.h>

#define WATCHDOG_TIMER_ID 999

VOID CALLBACK ListenerTimerProc(HWND hWnd, UINT uMsg, UINT uID, DWORD dwTickCount)
{
	_AtlModule.OnWatchdogTimer();
}

HRESULT CwmsoapauthsvcModule::PreMessageLoop(int nShowCmd)
{
    HRESULT hr = __super::PreMessageLoop(nShowCmd);

	// get configuration settings
	LoadSettings();
	// initialize cs
	InitializeCriticalSection(&m_CSNonces);
	// start watchdog timer (60 seconds)
	m_uWatchDogTimerID = SetTimer(NULL, WATCHDOG_TIMER_ID, 60000L, ListenerTimerProc);
	if (m_uWatchDogTimerID == 0)
	{
		_AtlModule.LogEvent(/*EVENTLOG_ERROR_TYPE,*/ "Attempt to create Watchdog Timer failed!");
	}
    return hr;
}

HRESULT CwmsoapauthsvcModule::PostMessageLoop()
{
	// kill timer
	if (m_uWatchDogTimerID != 0)
	{
		KillTimer(NULL, m_uWatchDogTimerID);
	}
	// empty nonce map
	EnterCriticalSection(&m_CSNonces);
	map<string, WMNonce *>::iterator iter;
	for (iter = m_mapNonces.begin(); iter != m_mapNonces.end(); iter++)
	{
		WMNonce *pNonce = (*iter).second;
		if (pNonce != NULL)
		{
			delete pNonce;
		}
	}
	LeaveCriticalSection(&m_CSNonces);
	// done with cs
	DeleteCriticalSection(&m_CSNonces);
    return __super::PostMessageLoop();
}

void CwmsoapauthsvcModule::OnWatchdogTimer()
{
	EnterCriticalSection(&m_CSNonces);
	// check nonce map for stale nonces
	map<string, WMNonce *>::iterator iter;
	for (iter = m_mapNonces.begin(); iter != m_mapNonces.end(); iter++)
	{
		WMNonce *pNonce = (*iter).second;
		if (pNonce != NULL)
		{
			time_t t = pNonce->Time;
			// stale if nonce life is exceeded
			if ((time(NULL) - t) > m_nNonceLife)
			{
				// delete it
				_AtlModule.LogEvent(/*EVENTLOG_ERROR_TYPE,*/ "Deleted stale server nonce!");
				delete pNonce;
				// remove from map
				iter = m_mapNonces.erase(iter);
				if (iter == m_mapNonces.end())
				{
					// done
					break;
				}
				else
				{
					// back up
					--iter;
				}
			}
		}
	}
	LeaveCriticalSection(&m_CSNonces);
}

bool CwmsoapauthsvcModule::LoadSettings()
{
    WMXMLDocument doc;
    // read it in
    char szBuffer[256];
    GetModuleFileName(NULL, szBuffer, 256);
    szBuffer[255] = 0;
    string strPath = szBuffer;
    string::size_type pos = strPath.rfind("\\");
    strPath = strPath.substr(0, pos);
    strPath += "\\auth-config.xml";
    if (doc.Read(strPath) == false)
    {
        return FALSE;
    }
    m_strConfigFilePath = strPath;
    map<wstring, wstring> mapNS;
    WMXMLElement *pValue;
    if (doc.SelectElems(wstring(L"/defaultRealm"), mapNS) == true)
    {
        pValue = doc.NextElem();
        if (doc.DeserializeString(m_strDefaultRealm, pValue) == false)
        {
            // bad data
            return FALSE;
        }
    }
    if (doc.SelectElems(wstring(L"/nonceLife"), mapNS) == false)
    {
        // default to 120
        m_nNonceLife = 120;
    }
    else
    {
        pValue = doc.NextElem();
        if (doc.DeserializeInt(m_nNonceLife, pValue) == false)
        {
            // bad data
            return FALSE;
        }
    }
    if (doc.SelectElems(wstring(L"/soapServices/service"), mapNS) == true)
    {
        for (WMXMLElement *pValue = doc.NextElem(); pValue != NULL; pValue = doc.NextElem())
        {
            WMXMLElement *pSvc = pValue->GetChildElement(wstring(L""), wstring(L"name"));
            WMXMLElement *pRealm = pValue->GetChildElement(wstring(L""), wstring(L"realm"));
            if (pSvc == NULL || pRealm == NULL)
            {
                continue;
            }
            string strSvc, strRealm;
            if (doc.DeserializeString(strSvc, pSvc) == false ||
                doc.DeserializeString(strRealm, pRealm) == false)
            {
                // bad data
                continue;
            }
            m_mapServices.insert(map<string, string>::value_type(strSvc, strRealm));
        }
    }
    if (doc.SelectElems(wstring(L"/authRealms/realm"), mapNS) == true)
    {
        for (WMXMLElement *pValue = doc.NextElem(); pValue != NULL; pValue = doc.NextElem())
        {
            WMXMLElement *pName = pValue->GetChildElement(wstring(L""), wstring(L"name"));
            if (pName == NULL)
            {
                continue;
            }
            string strRealmName;
            if (doc.DeserializeString(strRealmName, pName) == false)
            {
                // bad data
                continue;
            }
            WMXMLDocFragment frag(*pValue);
            if (frag.SelectElems(wstring(L"/users/user"), mapNS) == true)
            {
                for (WMXMLElement *pUser = frag.NextElem(); pUser != NULL; pUser = frag.NextElem())
                {
                    WMXMLElement *pId = pUser->GetChildElement(wstring(L""), wstring(L"userId"));
                    WMXMLElement *pPass = pUser->GetChildElement(wstring(L""), wstring(L"password"));
                    if (pId == NULL || pPass == NULL)
                    {
                        continue;
                    }
                    string strId, strPass;
                    if (doc.DeserializeString(strId, pId) == false ||
                        doc.DeserializeString(strPass, pPass) == false)
                    {
                        // bad data
                        continue;
                    }
                    string strKey(strRealmName);
                    strKey += ':';
                    strKey += strId;
                    m_mapUsers.insert(map<string, string>::value_type(strKey, strPass));
                }
            }
        }
    }
	return true;
}

CwmsoapauthsvcModule _AtlModule;

//
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    return _AtlModule.WinMain(nShowCmd);
}

