// wmsoapsvcmgr2.cpp : Implementation of Cwmsoapsvcmgr2

#include "stdafx.h"
#include "wmsoapsvcmgr2.h"
#include "comdef.h"
#include "..\soap_source\wmsoaplistener.h"
#include "..\soap_source\charencode.h"
#include "..\wmsoapstruct\wmsoapstruct.h"
#include "..\wmsoapstruct\wmsoapstruct_i.c"


// Cwmsoapsvcmgr2

STDMETHODIMP Cwmsoapsvcmgr2::GetServerStats(long *NumConnects, long *NumBytesSent, long *NumHTTPErrors, long *NumNetErrors, long *NumIntErrors, VARIANT_BOOL *Result)
{
	*NumConnects = _AtlModule.m_pSOAPListener->GetNumConnectTotal();
	*NumBytesSent = _AtlModule.m_pSOAPListener->GetNumBytesSent();
	*NumHTTPErrors = _AtlModule.m_pSOAPListener->GetNumHTTPErrors();
	*NumNetErrors = _AtlModule.m_pSOAPListener->GetNumNetworkErrors();
	*NumIntErrors = _AtlModule.m_pSOAPListener->GetNumInternalErrors();
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::GetServerParams(long *ListenPort, long *NumWorkThreads, long *NumClientConn, long *ClientTimeout, long *WatchdogTimer, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	*ListenPort = _AtlModule.m_pSOAPListener->GetListenPort();
	*NumWorkThreads = _AtlModule.m_pSOAPListener->GetNumWorkThreads();
	*NumClientConn = _AtlModule.m_pSOAPListener->GetNumClientConn();
	*ClientTimeout = _AtlModule.m_pSOAPListener->GetClientTimeout();
	*WatchdogTimer = _AtlModule.m_pSOAPListener->GetWatchdogTimer();
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::GetServiceInfo(VARIANT *SvcInfo, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	// create SAFEARRAY
	SAFEARRAYBOUND Bounds[1];
	Bounds[0].lLbound = 0;
	Bounds[0].cElements = (unsigned long)_AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.size();

	SAFEARRAY *pArray = SafeArrayCreate(VT_VARIANT, 1, Bounds);
	if (pArray == NULL)
	{
		*Result = VARIANT_FALSE;
		LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
		return S_OK;
	}
	if (SvcInfo->vt & VT_BYREF)
	{
		*(SvcInfo->pparray) = pArray;
	}
	else
	{
		SvcInfo->parray = pArray;
	}
	SvcInfo->vt |= (VT_VARIANT | VT_ARRAY);
	// fill up name array
	BSTR bstrNames[10];
	bstrNames[0] = SysAllocString(L"SvcURI");
	bstrNames[1] = SysAllocString(L"SvcName");
	bstrNames[2] = SysAllocString(L"Port");
	bstrNames[3] = SysAllocString(L"WSDL_URL");
	bstrNames[4] = SysAllocString(L"SvcProgID");
	bstrNames[5] = SysAllocString(L"HdrProgIDs");
	bstrNames[6] = SysAllocString(L"Roles");
	bstrNames[7] = SysAllocString(L"NextHopURL");
	bstrNames[8] = SysAllocString(L"NodeURI");
	bstrNames[9] = SysAllocString(L"Enabled");
	// set up index for insertion
	long arrIndex[1];
	// read out SOAPAction map contents
	map<string, SOAPSvcDesc *>::iterator iM1;
	long lCounter = 0;
	_variant_t varTemp;
	string strTemp;
	// decompose service descriptions
	for (iM1 = _AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.begin();
			iM1 != _AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.end(); iM1++)
	{
		// instantiate struct object
		Iwmsoapstruct *pIwmsoapstructOut;
		HRESULT res = CoCreateInstance( CLSID_wmsoapstruct,
										NULL, CLSCTX_SERVER,
										IID_Iwmsoapstruct,
										(void **) &pIwmsoapstructOut);
		if (FAILED(res))
		{
			*Result = VARIANT_FALSE;
			LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
			return S_OK;
		}
        SOAPSvcDesc *pSvc = (*iM1).second;
		VARIANT_BOOL bResult;
		// Service URI
        string strTemp = pSvc->m_strReqURI;
        if (pSvc->m_bExtraPathEnabled == true)
        {
            strTemp += "/*";
        }
        varTemp = strTemp.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[0], varTemp, &bResult);
        // WSDL Service name
        varTemp = pSvc->m_wstrWsdlSvc.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[1], varTemp, &bResult);
        // WSDL Port name
        varTemp = pSvc->m_wstrWsdlPort.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[2], varTemp, &bResult);
        // WSDL doc URL
        varTemp = pSvc->m_strWsdlDocURL.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[3], varTemp, &bResult);
        // Body processor ProgId
        varTemp = pSvc->m_wstrBodyProcProgId.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[4], varTemp, &bResult);
        // Header processor ProgIds
	    SAFEARRAYBOUND Bounds2[1];
	    Bounds2[0].lLbound = 0;
	    Bounds2[0].cElements = pSvc->m_listHeaderProcProgIds.size();
	    SAFEARRAY *pArray2 = SafeArrayCreate(VT_VARIANT, 1, Bounds2);
        varTemp.parray = pArray2;
        varTemp.vt = (VT_ARRAY | VT_VARIANT);
        _variant_t varItem;
        long arrIndex2[1];
        int counter = 0;
        list<wstring>::iterator iL;
        for (iL = pSvc->m_listHeaderProcProgIds.begin();
            iL != pSvc->m_listHeaderProcProgIds.end();
            iL++)
        {
            varItem = (*iL).c_str();
		    arrIndex2[0] = counter++;
		    // put it away
		    SafeArrayPutElement(pArray2, arrIndex2, &varItem);
        }
		pIwmsoapstructOut->SetMember(bstrNames[5], varTemp, &bResult);
        varTemp.Clear();
        // roles
	    Bounds2[0].lLbound = 0;
	    Bounds2[0].cElements = pSvc->m_listRoles.size();
	    pArray2 = SafeArrayCreate(VT_VARIANT, 1, Bounds2);
        varTemp.parray = pArray2;
        varTemp.vt = (VT_ARRAY | VT_VARIANT);
        counter = 0;
        for (iL = pSvc->m_listRoles.begin();
            iL != pSvc->m_listRoles.end();
            iL++)
        {
            varItem = (*iL).c_str();
		    arrIndex2[0] = counter++;
		    // put it away
		    SafeArrayPutElement(pArray2, arrIndex2, &varItem);
        }
		pIwmsoapstructOut->SetMember(bstrNames[6], varTemp, &bResult);
        varTemp.Clear();
        // Next Hop URL
        varTemp = pSvc->m_wstrNextHopURL.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[7], varTemp, &bResult);
        // Node URI
        varTemp = pSvc->m_wstrNodeURI.c_str();
		pIwmsoapstructOut->SetMember(bstrNames[8], varTemp, &bResult);
        // Enabled flag
        varTemp = pSvc->m_bEnabled;
		pIwmsoapstructOut->SetMember(bstrNames[9], varTemp, &bResult);
		// now get IDispatch pointer
		IDispatch *pIDispatchOut;
		res = pIwmsoapstructOut->QueryInterface(IID_IDispatch, (void **)&pIDispatchOut);
		if (FAILED(res))
		{
			pIwmsoapstructOut->Release();
			*Result = VARIANT_FALSE;
			LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
			return S_OK;
		}
		// release
		pIwmsoapstructOut->Release();
		// set up variant
		varTemp.Clear();
		varTemp.vt = VT_DISPATCH;
		varTemp.pdispVal = pIDispatchOut;
		arrIndex[0] = lCounter++;
		// put it away
		SafeArrayPutElement(pArray, arrIndex, &varTemp);
		varTemp.Clear();
	}
	// done with names
	for (int j = 0; j < 10; j++)
	{
		SysFreeString(bstrNames[j]);
	}
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::SetServiceInfo(VARIANT SvcInfo, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	// extract info from SAFEARRAY
	SAFEARRAY *pArray = SvcInfo.parray;
	long arrIndex[1];
	// set flag to empty cache
	_AtlModule.m_pSOAPListener->SetFlushWSDLCacheFlag();
	// lock array
	SafeArrayLock(pArray);
	// fill up name array
	BSTR bstrNames[10];
	bstrNames[0] = SysAllocString(L"SvcURI");
	bstrNames[1] = SysAllocString(L"SvcName");
	bstrNames[2] = SysAllocString(L"Port");
	bstrNames[3] = SysAllocString(L"WSDL_URL");
	bstrNames[4] = SysAllocString(L"SvcProgID");
	bstrNames[5] = SysAllocString(L"HdrProgIDs");
	bstrNames[6] = SysAllocString(L"Roles");
	bstrNames[7] = SysAllocString(L"NextHopURL");
	bstrNames[8] = SysAllocString(L"NodeURI");
	bstrNames[9] = SysAllocString(L"Enabled");
	// iterate over array of structs
	for (unsigned int i = pArray->rgsabound[0].lLbound;
			i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			i++)
	{
		arrIndex[0] = i;
		// get pointer to struct object
		VARIANT *pVar = NULL;
		SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);
		IDispatch *pIDispatch = pVar->pdispVal;
		Iwmsoapstruct *pIwmsoapstruct;
		HRESULT res = pIDispatch->QueryInterface(IID_Iwmsoapstruct, (void **)&pIwmsoapstruct);
		if (FAILED(res))
		{
			LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
			*Result = VARIANT_FALSE;
			return S_OK;
		}
		_variant_t varTemp;
		VARIANT_BOOL bResult;
        string strReqURI, strWsdlDocURL;
        wstring wstrWsdlSvc, wstrWsdlPort, wstrBodyProc, wstrNextHopURL, wstrNodeURI;
        list<wstring> listHeaderProcs;
        list<wstring> listRoles;
        bool bEnabled = false;
		// now iterate over struct members
		for (int j = 0;	j < 10; j++)
		{
			// get member
			pIwmsoapstruct->GetMember(bstrNames[j], &varTemp, &bResult);

			switch (j)
			{
				case 0:
					// Service Request URI
                    WideStringToUTF8(wstring(varTemp.bstrVal), strReqURI);
					break;
				case 1:
					// WSDL Service name
					wstrWsdlSvc = varTemp.bstrVal;
					break;
				case 2:
					// WSDL Port name
					wstrWsdlPort = varTemp.bstrVal;
					break;
				case 3:
					// WSDL doc URL
                    WideStringToUTF8(wstring(varTemp.bstrVal), strWsdlDocURL);
					break;
				case 4:
					// Body processor ProgId
					wstrBodyProc = varTemp.bstrVal;
					break;
				case 5:
                    // Header processor ProgIds
                    {
	                    SAFEARRAY *pArray = varTemp.parray;
	                    long arrIndex[1];
	                    for (unsigned int i = pArray->rgsabound[0].lLbound;
			                    i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			                    i++)
	                    {
		                    arrIndex[0] = i;
		                    // get pointer to BSTR
		                    VARIANT *pVar = NULL;
		                    SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);
                            listHeaderProcs.push_back(wstring(pVar->bstrVal));
                        }
                    }
					break;
				case 6:
					// Roles
                    {
	                    SAFEARRAY *pArray = varTemp.parray;
	                    long arrIndex[1];
	                    for (unsigned int i = pArray->rgsabound[0].lLbound;
			                    i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			                    i++)
	                    {
		                    arrIndex[0] = i;
		                    // get pointer to BSTR
		                    VARIANT *pVar = NULL;
		                    SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);
                            listRoles.push_back(wstring(pVar->bstrVal));
                        }
                    }
					break;
				case 7:
					// Next hop URL
					wstrNextHopURL = varTemp.bstrVal;
					break;
				case 8:
					// Node URI
					wstrNodeURI = varTemp.bstrVal;
					break;
				case 9:
					// Enabled flag
                    bEnabled = (varTemp.boolVal == VARIANT_TRUE ? true : false);
					break;
			}
			varTemp.Clear();
		}
		// release interface ptr
		pIwmsoapstruct->Release();
        // see if this is URI given in form "/whatever/*" to 
        // indicate that extra path components may be present
        bool bExtraPathEnabled = false;
        int nLen = strReqURI.length();
        if (strReqURI[nLen - 1] == '*' && strReqURI[nLen - 2] == '/')
        {
            strReqURI = strReqURI.substr(0, nLen - 2);
            bExtraPathEnabled = true;
        }
        map<string, SOAPSvcDesc *>::iterator iM;
        iM = _AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.find(strReqURI);
        if (iM != _AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.end())
        {
            // description already exists so update
		    SOAPSvcDesc* pDesc = (*iM).second;
            pDesc->m_bEnabled = bEnabled;
            pDesc->m_bExtraPathEnabled = bExtraPathEnabled;
            pDesc->m_listHeaderProcProgIds = listHeaderProcs;
            pDesc->m_listRoles = listRoles;
            pDesc->m_strReqURI = strReqURI;
            pDesc->m_strWsdlDocURL = strWsdlDocURL;
            pDesc->m_wstrBodyProcProgId = wstrBodyProc;
            pDesc->m_wstrNextHopURL = wstrNextHopURL;
            pDesc->m_wstrNodeURI = wstrNodeURI;
            pDesc->m_wstrWsdlPort = wstrWsdlPort;
            pDesc->m_wstrWsdlSvc = wstrWsdlSvc;
        }
        else
        {
		    // new description, create and insert into Services map
            SOAPSvcDesc *pSvc = new SOAPSvcDesc(strReqURI,
                                                strWsdlDocURL,
                                                wstrWsdlSvc,
                                                wstrWsdlPort,
                                                wstrBodyProc,
                                                wstrNextHopURL,
                                                listRoles,
                                                wstrNodeURI,
                                                bEnabled,
                                                false, // explicitTypingEnabled
                                                false, // nodeTypeEnabled
                                                bExtraPathEnabled,
                                                listHeaderProcs,
                                                false); // loopbackEnabled
		    if (pSvc == NULL)
		    {
			    LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
			    *Result = VARIANT_FALSE;
			    return S_OK;
		    }
		    _AtlModule.m_pSOAPListener->m_mapSOAPSvcDescriptions.insert(map<string, SOAPSvcDesc *>::value_type(strReqURI, pSvc));
        }
	}
	// done with names
	for (int j = 0; j < 10; j++)
	{
		SysFreeString(bstrNames[j]);
	}
	SafeArrayUnlock(pArray);
	// write settings to config file
	_AtlModule.m_pSOAPListener->StoreSettings();
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::GetHTTPSettings(BSTR *DocRootPath, BSTR *DefaultFilePath, VARIANT *MIMETypes, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	// create SAFEARRAY
	const long lNumDims = 2;
	SAFEARRAYBOUND Bounds[lNumDims];
	// rightmost dimension (cols) will go in Bounds[0]
	Bounds[0].lLbound = 0;
	Bounds[0].cElements = 2;
	// leftmost dimension (rows) will go in Bounds[1]
	Bounds[1].lLbound = 0;
	Bounds[1].cElements = (unsigned long)_AtlModule.m_pSOAPListener->m_mapMIMETypes.size();

	SAFEARRAY *pArray = SafeArrayCreate(VT_VARIANT, lNumDims, &Bounds[0]);
	if (pArray == NULL)
	{
		*Result = VARIANT_FALSE;
		LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
		return S_OK;
	}
	if (MIMETypes->vt & VT_BYREF)
	{
		*(MIMETypes->pparray) = pArray;
	}
	else
	{
		MIMETypes->parray = pArray;
	}
	MIMETypes->vt |= (VT_VARIANT | VT_ARRAY);
	// set up index for insertion
	long *arrIndex = new long[lNumDims];
	// read out MIME type map contents
	map<string, string>::iterator iM1;
	long lCounter = 0;
	_variant_t varTemp;
	// array format: [rows][cols]
	for (iM1 = _AtlModule.m_pSOAPListener->m_mapMIMETypes.begin();
			iM1 != _AtlModule.m_pSOAPListener->m_mapMIMETypes.end(); iM1++)
	{
		// leftmost dimension (rows) is arrIndex[1]
		arrIndex[1] = lCounter++;
		// rightmost dimension (cols) is arrIndex[0]
		arrIndex[0] = 0;
		// name
		varTemp = (*iM1).first.c_str();
		SafeArrayPutElement(pArray, arrIndex, &varTemp);
		// extension
		arrIndex[0] = 1;
		varTemp = (*iM1).second.c_str();
		SafeArrayPutElement(pArray, arrIndex, &varTemp);
	}
	_bstr_t bstrTemp;
	// Doc root path
	bstrTemp = _AtlModule.m_pSOAPListener->m_strDocBasePath.c_str();
	*DocRootPath = bstrTemp.copy();
	// Default file path
	bstrTemp = _AtlModule.m_pSOAPListener->m_strDocDefault.c_str();
	*DefaultFilePath = bstrTemp.copy();
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	delete[] arrIndex;
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::SetHTTPSettings(BSTR DocRootPath, BSTR DefaultFilePath, VARIANT MIMETypes, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	// extract info from SAFEARRAY
	const long lNumDims = 2;
	SAFEARRAY *pArray = MIMETypes.parray;
	long *arrIndex = new long[lNumDims];
	// clear maps
	_AtlModule.m_pSOAPListener->m_mapMIMETypes.clear();
	// lock array
	SafeArrayLock(pArray);
	// array format: [rows][cols] i == rows, j == cols
	// leftmost dimension (rows) is in rgsabound[0]
	for (unsigned int i = pArray->rgsabound[0].lLbound;
			i < (pArray->rgsabound[0].lLbound + pArray->rgsabound[0].cElements);
			i++)
	{
		// leftmost dimension (rows) is arrIndex[1]
		arrIndex[1] = i;
		// rightmost dimension (cols) is in rgsabound[1]
		wstring wstrKey, wstrValue;
		string strKey, strValue;
		for (unsigned int j = pArray->rgsabound[1].lLbound;
			j < (pArray->rgsabound[1].lLbound + pArray->rgsabound[1].cElements);
			j++)
		{
			// rightmost dimension (cols) is arrIndex[0]
			arrIndex[0] = j;
			VARIANT *pVar = NULL;
			SafeArrayPtrOfIndex(pArray, arrIndex, (void **)&pVar);

			switch (j - pArray->rgsabound[1].lLbound)
			{
				case 0:
					// Extension
					wstrKey = pVar->bstrVal;
					WideStringToUTF8(wstrKey, strKey);
					break;
				case 1:
					// MIME Type
					wstrValue = pVar->bstrVal;
					// place item in MIME Types map
					WideStringToUTF8(wstrValue, strValue);
					_AtlModule.m_pSOAPListener->m_mapMIMETypes.insert(map<string, string>::value_type(strKey, strValue));
					break;
			}
		}
	}
	SafeArrayUnlock(pArray);
	// Doc root path
	wstring wstrPath = DocRootPath;
	WideStringToUTF8(wstrPath, _AtlModule.m_pSOAPListener->m_strDocBasePath);
	// Default file path
	wstrPath = DefaultFilePath;
	WideStringToUTF8(wstrPath, _AtlModule.m_pSOAPListener->m_strDocDefault);
	// write settings to config file
	_AtlModule.m_pSOAPListener->StoreSettings();
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::GetLogSettings(BSTR *ServerLogPath, BSTR *UserAgentLogPath, BSTR *SOAPTraceLogPath, VARIANT_BOOL *ServerLogEnabled, VARIANT_BOOL *UserAgentLogEnabled, VARIANT_BOOL *SOAPTraceLogEnabled, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	_bstr_t bstrTemp;
	// Server log path
	bstrTemp = _AtlModule.m_pSOAPListener->m_LogMgr.m_strServerLogPath.c_str();
	*ServerLogPath = bstrTemp.copy();
	*ServerLogEnabled = _AtlModule.m_pSOAPListener->m_LogMgr.m_bServerLogEnable == TRUE ? VARIANT_TRUE : VARIANT_FALSE;
	// User Agent log path
	bstrTemp = _AtlModule.m_pSOAPListener->m_LogMgr.m_strUserAgentLogPath.c_str();
	*UserAgentLogPath = bstrTemp.copy();
	*UserAgentLogEnabled = _AtlModule.m_pSOAPListener->m_LogMgr.m_bUserAgentLogEnable == TRUE ? VARIANT_TRUE : VARIANT_FALSE;
	// SOAP trace log path
	bstrTemp = _AtlModule.m_pSOAPListener->m_LogMgr.m_strSOAPTraceLogPath.c_str();
	*SOAPTraceLogPath = bstrTemp.copy();
	*SOAPTraceLogEnabled = _AtlModule.m_pSOAPListener->m_LogMgr.m_bSOAPTraceLogEnable == TRUE ? VARIANT_TRUE : VARIANT_FALSE;
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	*Result = VARIANT_TRUE;
	return S_OK;
}

STDMETHODIMP Cwmsoapsvcmgr2::SetLogSettings(BSTR ServerLogPath, BSTR UserAgentLogPath, BSTR SOAPTraceLogPath, VARIANT_BOOL ServerLogEnabled, VARIANT_BOOL UserAgentLogEnabled, VARIANT_BOOL SOAPTraceLogEnabled, VARIANT_BOOL *Result)
{
	EnterCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	// Server log path
	wstring wstrPath = ServerLogPath;
	WideStringToUTF8(wstrPath, _AtlModule.m_pSOAPListener->m_LogMgr.m_strServerLogPath);
	_AtlModule.m_pSOAPListener->m_LogMgr.m_bServerLogEnable = ServerLogEnabled == VARIANT_TRUE ? TRUE : FALSE;
	// User Agent log path
	wstrPath = UserAgentLogPath;
	WideStringToUTF8(wstrPath, _AtlModule.m_pSOAPListener->m_LogMgr.m_strUserAgentLogPath);
	_AtlModule.m_pSOAPListener->m_LogMgr.m_bUserAgentLogEnable = UserAgentLogEnabled == VARIANT_TRUE ? TRUE : FALSE;
	// SOAP trace log path
	wstrPath = SOAPTraceLogPath;
	WideStringToUTF8(wstrPath, _AtlModule.m_pSOAPListener->m_LogMgr.m_strSOAPTraceLogPath);
	_AtlModule.m_pSOAPListener->m_LogMgr.m_bSOAPTraceLogEnable = SOAPTraceLogEnabled == VARIANT_TRUE ? TRUE : FALSE;
	// write settings to config file
	_AtlModule.m_pSOAPListener->StoreSettings();
	//
	LeaveCriticalSection(&_AtlModule.m_pSOAPListener->m_CSProperties);
	//
	_AtlModule.m_pSOAPListener->m_LogMgr.OpenLogFiles();
	*Result = VARIANT_TRUE;
	return S_OK;
}
