// wmwsrouter2Obj.cpp : Implementation of Cwmwsrouter2Obj
//
// Copyright (c) 2002 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// Cwmwsrouter2Obj class - implementation of Web Services Routing Protocol.
// 
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "wmwsrouter2Obj.h"

#include "..\soap_source\xmlparser.h"
#include "..\soap_source\SOAPDIMEHTTPClient.h"
#include "..\soap_source\charencode.h"
#include "..\wmsoapmsg\wmsoapmsg_i.c"
#include "..\wmsoapmsg\wmsoapmsg.h"
#include "..\soap_source\soap.h"

// this version of namespace conforms to prose in WS-Routing spec
static wchar_t *g_pwszHeaderNS = L"http://schemas.xmlsoap.org/rp";
//static wchar_t *g_pwszHeaderNS = L"http://schemas.xmlsoap.org/rp/";
static char *g_pszUserAgent = "White Mesa WS-Routing Agent/1.2";

// Cwmwsrouter2Obj

bool Cwmwsrouter2Obj::ReadFault(WMXMLElement *pFaultElement)
{
	// initialize flags
	m_bNeedEndpoint = false;
	m_bNeedFound = false;
	m_bNeedMaxsize = false;
	m_bNeedMaxtime = false;
	m_bNeedRetryAfter = false;

	// get 'faultcode' element
	WMXMLElement *pChild = pFaultElement->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"code"));
//	WMXMLElement *pChild = pFaultElement->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"faultcode"));
	if (pChild != NULL)
	{
		m_wstrFaultcode = pChild->GetContent();
	}
	// get 'faultreason' element
	pChild = pFaultElement->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"reason"));
//	pChild = pFaultElement->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"faultreason"));
	if (pChild != NULL)
	{
		m_wstrFaultreason = pChild->GetContent();
	}
	// get 'endpoint' element
	pChild = pFaultElement->GetChildElement(wstring(L""), wstring(L"endpoint"));
	if (pChild != NULL)
	{
		m_wstrEndpoint = pChild->GetContent();
		m_bNeedEndpoint = true;
	}
	// get 'found' element
	pChild = pFaultElement->GetChildElement(wstring(L""), wstring(L"found"));
	if (pChild != NULL)
	{
		ReadFoundList(pChild, m_listFound);
		m_bNeedFound = true;
	}
	// get 'maxsize' element
	pChild = pFaultElement->GetChildElement(wstring(L""), wstring(L"maxsize"));
	if (pChild != NULL)
	{
		m_wstrMaxsize = pChild->GetContent();
		m_bNeedMaxsize = true;
	}
	// get 'maxtime' element
	pChild = pFaultElement->GetChildElement(wstring(L""), wstring(L"maxtime"));
	if (pChild != NULL)
	{
		m_wstrMaxtime = pChild->GetContent();
		m_bNeedMaxtime = true;
	}
	// get 'retryAfter' element
	pChild = pFaultElement->GetChildElement(wstring(L""), wstring(L"retryAfter"));
	if (pChild != NULL)
	{
		m_wstrRetryAfter = pChild->GetContent();
		m_bNeedRetryAfter = true;
	}
	return true;
}

bool Cwmwsrouter2Obj::PopulateAtList(list<wstring>& listAtList, WMXMLElement *pListElem)
{
	list<wstring>::iterator iter;
	for (iter = listAtList.begin(); iter != listAtList.end(); iter++)
	{
		// "at" member element
		WMXMLElement *pChild = new WMXMLElement(wstring(L"at"));
		if (pChild != NULL)
		{
			pListElem->AddChildElement(pChild);
			pChild->AppendContent(*iter);
		}
		else
		{
			return false;
		}
	}
	return true;
}

WMXMLElement *Cwmwsrouter2Obj::CreateSOAPFault(int nCode, Iwmsoapmsg2 *pIwmsoapmsg)
{
    // determine SOAP version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);
	// create new header entry
	WMXMLElement *pBody = new WMXMLElement(wstring(L"SOAP-ENV:Body"));
	if (pBody != NULL)
	{
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
		    pBody->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoapEnvelopeNS));
        }
        else
        {
		    pBody->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoap12EnvelopeNS));
        }
	}
	else
	{
		return NULL;
	}
	// 'SOAP-ENV:Fault' element
	WMXMLElement *pFault = new WMXMLElement(wstring(L"SOAP-ENV:Fault"));
	if (pFault != NULL)
	{
		pBody->AddChildElement(pFault);
	}
	else
	{
		delete pBody;
		return NULL;
	}
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
	    wstring wstrFaultcode, wstrFaultstring;
	    if (nCode < 800)
	    {
		    wstrFaultcode = L"SOAP-ENV:Client";
		    wstrFaultstring = L"WS-Routing Sender fault.";
	    }
	    else
	    {
		    wstrFaultcode = L"SOAP-ENV:Server";
		    wstrFaultstring = L"WS-Routing Receiver fault.";
	    }
	    // 'faultcode' element
	    WMXMLElement *pChild = new WMXMLElement(wstring(L"faultcode"));
	    if (pChild != NULL)
	    {
		    pFault->AddChildElement(pChild);
		    pChild->AppendContent(wstrFaultcode);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
	    // 'faultstring' element
	    pChild = new WMXMLElement(wstring(L"faultstring"));
	    if (pChild != NULL)
	    {
		    pFault->AddChildElement(pChild);
		    pChild->AppendContent(wstrFaultstring);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
	    // 'faultactor' element
	    pChild = new WMXMLElement(wstring(L"faultactor"));
	    if (pChild != NULL)
	    {
		    pFault->AddChildElement(pChild);
		    BSTR bstrNodeURI;
		    pIwmsoapmsg->GetNodeURI(&bstrNodeURI);
		    pChild->AppendContent(wstring(bstrNodeURI));
		    SysFreeString(bstrNodeURI);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
    }
    else
    {
	    wstring wstrCode, wstrReason;
	    if (nCode < 800)
	    {
            wstrCode = L"SOAP-ENV:Sender";
		    wstrReason = L"WS-Routing Sender fault.";
	    }
	    else
	    {
		    wstrCode = L"SOAP-ENV:Receiver";
		    wstrReason = L"WS-Routing Receiver fault.";
	    }
	    // 'Code' element
        WMXMLElement *pChild = new WMXMLElement(wstring(L"SOAP-ENV:Code"));
	    if (pChild != NULL)
	    {
            WMXMLElement *pValue = new WMXMLElement(wstring(L"SOAP-ENV:Value"));
		    pValue->AppendContent(wstrCode);
		    pChild->AddChildElement(pValue);
		    pFault->AddChildElement(pChild);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
	    // 'Reason' element
        pChild = new WMXMLElement(wstring(L"SOAP-ENV:Reason"));
	    if (pChild != NULL)
	    {
		    pFault->AddChildElement(pChild);
		    pChild->AppendContent(wstrReason);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
	    // 'Node' element
        pChild = new WMXMLElement(wstring(L"SOAP-ENV:Node"));
	    if (pChild != NULL)
	    {
		    pFault->AddChildElement(pChild);
		    BSTR bstrNodeURI;
		    pIwmsoapmsg->GetNodeURI(&bstrNodeURI);
		    pChild->AppendContent(wstring(bstrNodeURI));
		    SysFreeString(bstrNodeURI);
	    }
	    else
	    {
		    delete pBody;
		    return NULL;
	    }
    }
	return pBody;
}

WMXMLElement *Cwmwsrouter2Obj::CreateFaultElem()
{
	// create new header entry
	WMXMLElement *pFault = new WMXMLElement(wstring(L"rp:fault"));
	if (pFault != NULL)
	{
		pFault->SetNSPrefix(wstring(L"rp"), wstring(g_pwszHeaderNS));
	}
	else
	{
		return NULL;
	}
	// 'faultcode' element
	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:code"));
//	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:faultcode"));
	if (pChild != NULL)
	{
		pFault->AddChildElement(pChild);
		pChild->AppendContent(m_wstrFaultcode);
	}
	else
	{
		delete pFault;
		return NULL;
	}
	// 'faultreason' element
	pChild = new WMXMLElement(wstring(L"rp:reason"));
//	pChild = new WMXMLElement(wstring(L"rp:faultreason"));
	if (pChild != NULL)
	{
		pFault->AddChildElement(pChild);
		pChild->AppendContent(m_wstrFaultreason);
	}
	else
	{
		delete pFault;
		return NULL;
	}
	// 'endpoint' element
	if (m_bNeedEndpoint == true)
	{
		pChild = new WMXMLElement(wstring(L"endpoint"));
		if (pChild != NULL)
		{
			pFault->AddChildElement(pChild);
			pChild->AppendContent(m_wstrEndpoint);
		}
		else
		{
			delete pFault;
			return NULL;
		}
	}
	// 'found' element
	if (m_bNeedFound == true)
	{
		pChild = new WMXMLElement(wstring(L"found"));
		if (pChild != NULL)
		{
			pFault->AddChildElement(pChild);
			// populate with member elements
			if (PopulateAtList(m_listFound, pChild) == false)
			{
				delete pFault;
				return NULL;
			}
		}
		else
		{
			delete pFault;
			return NULL;
		}
	}
	// 'maxsize' element
	if (m_bNeedMaxsize == true)
	{
		pChild = new WMXMLElement(wstring(L"maxsize"));
		if (pChild != NULL)
		{
			pFault->AddChildElement(pChild);
			pChild->AppendContent(m_wstrMaxsize);
		}
		else
		{
			delete pFault;
			return NULL;
		}
	}
	// 'maxtime' element
	if (m_bNeedMaxtime == true)
	{
		pChild = new WMXMLElement(wstring(L"maxtime"));
		if (pChild != NULL)
		{
			pFault->AddChildElement(pChild);
			pChild->AppendContent(m_wstrMaxtime);
		}
		else
		{
			delete pFault;
			return NULL;
		}
	}
	// 'retryAfter' element
	if (m_bNeedRetryAfter == true)
	{
		pChild = new WMXMLElement(wstring(L"retryAfter"));
		if (pChild != NULL)
		{
			pFault->AddChildElement(pChild);
			pChild->AppendContent(m_wstrRetryAfter);
		}
		else
		{
			delete pFault;
			return NULL;
		}
	}
	return pFault;
}

wstring Cwmwsrouter2Obj::GenerateId()
{
	GUID g;
	CoCreateGuid(&g);
	OLECHAR wszBuffer1[64];
	OLECHAR wszBuffer2[64];
	StringFromGUID2(g, wszBuffer1, 64);
	wszBuffer1[37] = 0;
	swprintf(wszBuffer2, L"uuid:%s", &wszBuffer1[1]);
	return wstring(wszBuffer2);
}

wstring Cwmwsrouter2Obj::GetFromURI()
{
	char szBuffer[128];
	CRegKey key;
	long lRes = key.Create(HKEY_LOCAL_MACHINE,
		_T("SOFTWARE\\White Mesa Software\\White Mesa WS-RP\\1.0"));
	if (lRes == ERROR_SUCCESS)
	{
		unsigned long len = 128;
        lRes = key.QueryStringValue(_T("FromURI"), szBuffer, &len);
		USES_CONVERSION;
		if (lRes == ERROR_SUCCESS)
		{
			return wstring(A2BSTR(szBuffer));
		}
		else
		{
            key.SetStringValue(_T("FromURI"), _T("endpoint@example.org"));
		}
	}
	return wstring(L"endpoint@example.org");
}

bool Cwmwsrouter2Obj::PopulateViaList(list<wstring>& listViaList, WMXMLElement *pListElem)
{
	list<wstring>::iterator iter;
	for (iter = listViaList.begin(); iter != listViaList.end(); iter++)
	{
		// "via" member element
		WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:via"));
		if (pChild != NULL)
		{
			pListElem->AddChildElement(pChild);
			pChild->AppendContent(*iter);
		}
		else
		{
			return false;
		}
	}
	return true;
}

bool Cwmwsrouter2Obj::CheckIdentity(const wstring& wstrURL, Iwmsoapmsg2 *pIwmsoapmsg)
{
	BSTR bstrURI;
    pIwmsoapmsg->GetNodeURI(&bstrURI);
	bool bRtn = (wstrURL == bstrURI ? true : false);
	SysFreeString(bstrURI);
	return bRtn;
}

bool Cwmwsrouter2Obj::CheckURLScheme(const wstring& wstrURL)
{
	if (wstrURL.find(L"http://") != 0)
	{
		return false;
	}
	return true;
}

bool Cwmwsrouter2Obj::ReadViaList(WMXMLElement *pListElem, list<wstring>& listViaList)
{
	// components of qname
	wstring wstrChildElemName(L"via");
	wstring wstrChildElemNS(g_pwszHeaderNS);

	// clear list
	listViaList.clear();
	// iterate over elements in list
	ChildElementsList::iterator iL;
	for (iL = pListElem->GetChildElements().begin();
			iL != pListElem->GetChildElements().end();
			iL++)
	{
		if(*iL != NULL && (*iL)->GetLocalName() == wstrChildElemName && (*iL)->GetURI() == wstrChildElemNS)
		{
			// add to list
			listViaList.push_back((*iL)->GetContent());
		}
	}
	return true;
}

bool Cwmwsrouter2Obj::ReadFoundList(WMXMLElement *pListElem, list<wstring>& listFoundList)
{
	// components of qname
	wstring wstrChildElemName(L"at");
	wstring wstrChildElemNS(L"");

	// iterate over elements in list
	ChildElementsList::iterator iL;
	for (iL = pListElem->GetChildElements().begin();
			iL != pListElem->GetChildElements().end();
			iL++)
	{
		if(*iL != NULL && (*iL)->GetLocalName() == wstrChildElemName && (*iL)->GetURI() == wstrChildElemNS)
		{
			// add to list
			listFoundList.push_back((*iL)->GetContent());
		}
	}
	return true;
}

bool Cwmwsrouter2Obj::ReadHeader(Iwmsoapmsg2 *pIwmsoapmsg)
{
	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"path");
	BSTR bstrXML;
	wstring wstrXML;
	VARIANT_BOOL bResult;
	HRESULT hRes = pIwmsoapmsg->GetHeaderElemLiteral(bstrNamespaceURI, bstrLocalName, &bstrXML, &bResult);
	SysFreeString(bstrLocalName);
	SysFreeString(bstrNamespaceURI);
	if (hRes != S_OK || bResult == VARIANT_FALSE)
	{
		return false;
	}
	wstrXML = bstrXML;
	SysFreeString(bstrXML);
	// set up for parsing
	WMXMLParser Parser;
	bool bRtn = true;
	// parse the XML fragment representing the header entry
	try
	{
		Parser.ParseXML_WideString(wstrXML, NULL);
	}
	catch(int e)
	{
		int x = e;
		return false;
	}
	// get the WMXMLElement pointer representing root node of parse tree
	WMXMLElement *pRoot = Parser.DetachDocRoot();
	if (pRoot == NULL)
	{
		return false;
	}

	// reset flags
	m_bActionElemFound = false;
	m_bToElemFound = false;
	m_bFwdElemFound = false;
	m_bRevElemFound = false;
	m_bFromElemFound = false;
	m_bIdElemFound = false;
	m_bRelatesToElemFound = false;
	m_bFaultElemFound = false;

	// get 'action' element
	WMXMLElement *pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"action"));
	if (pChild != NULL)
	{
		m_wstrAction = pChild->GetContent();
		m_bActionElemFound = true;

	}
	// get 'to' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"to"));
	if (pChild != NULL)
	{
		m_wstrTo = pChild->GetContent();
		m_bToElemFound = true;
	}
	// get 'fwd' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"fwd"));
	if (pChild != NULL)
	{
		ReadViaList(pChild, m_listFwd);
		m_bFwdElemFound = true;
	}
	// get 'rev' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"rev"));
	if (pChild != NULL)
	{
		ReadViaList(pChild, m_listRev);
		m_bRevElemFound = true;
	}
	// get 'from' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"from"));
	if (pChild != NULL)
	{
		m_wstrFrom = pChild->GetContent();
		m_bFromElemFound = true;
	}
	// get 'id' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"id"));
	if (pChild != NULL)
	{
		m_wstrId = pChild->GetContent();
		m_bIdElemFound = true;
	}
	// get 'relatesTo' element
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"relatesTo"));
	if (pChild != NULL)
	{
		m_wstrRelatesTo = pChild->GetContent();
		m_bRelatesToElemFound = true;
	}
	// capture 'fault' element contents
	pChild = pRoot->GetChildElement(wstring(g_pwszHeaderNS), wstring(L"fault"));
	if (pChild != NULL)
	{
		ReadFault(pChild);
		m_bFaultElemFound = true;
	}
	delete pRoot;
	return true;
}

bool Cwmwsrouter2Obj::ProcessFault(int nCode, Iwmsoapmsg2 *pIwmsoapmsg)
{
	// initialize flags
	m_bNeedEndpoint = false;
	m_bNeedFound = false;
	m_bNeedMaxsize = false;
	m_bNeedMaxtime = false;
	m_bNeedRetryAfter = false;

    // determine SOAP version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);

	switch(nCode)
	{
	case 700:
		{
			// INVALID SOAP-RP HEADER
			m_wstrFaultcode = L"700";
			m_wstrFaultreason = L"Invalid WS-Routing Header";
		}
		break;
	case 701:
		{
			// SOAP-RP HEADER REQUIRED
			m_wstrFaultcode = L"701";
			m_wstrFaultreason = L"WS-Routing Header Required";
		}
		break;
	case 710:
		{
			// ENDPOINT NOT FOUND
			m_wstrFaultcode = L"710";
			m_wstrFaultreason = L"Endpoint Not Found";
			m_wstrEndpoint = m_wstrURI;
			m_bNeedEndpoint = true;
		}
		break;
	case 712:
		{
			// ENDPOINT NOT SUPPORTED
			m_wstrFaultcode = L"712";
			m_wstrFaultreason = L"Endpoint Not Supported";
			m_wstrEndpoint = m_wstrURI;
			m_bNeedEndpoint = true;
		}
		break;
	case 800:
		{
			// UNKNOWN SOAP-RP FAULT
			m_wstrFaultcode = L"800";
			m_wstrFaultreason = L"Unknown WS-Routing Fault";
		}
		break;
	case 810:
		{
			// ELEMENT NOT IMPLEMENTED
			m_wstrFaultcode = L"810";
			m_wstrFaultreason = L"Element Not Implemented";
		}
		break;
	case 811:
		{
			// SERVICE UNAVAILABLE
			m_wstrFaultcode = L"811";
			m_wstrFaultreason = L"Service Unavailable";
		}
		break;
	case 812:
		{
			// SERVICE TOO BUSY
			m_wstrFaultcode = L"812";
			m_wstrFaultreason = L"Service Too Busy";
		}
		break;
	case 820:
		{
			// ENDPOINT NOT REACHABLE
			m_wstrFaultcode = L"820";
			m_wstrFaultreason = L"Endpoint Not Reachable";
			m_wstrEndpoint = m_wstrURI;
			m_bNeedEndpoint = true;
		}
		break;
	default:
		{
			// SHOULD NEVER HAPPEN
			m_wstrFaultcode = L"000";
			m_wstrFaultreason = L"Invalid Fault Code";
			m_wstrEndpoint = m_wstrURI;
			m_bNeedEndpoint = true;
		}
	}
	// create new header entry
	WMXMLElement *pPath = new WMXMLElement(wstring(L"rp:path"));
	if (pPath != NULL)
	{
		pPath->SetNSPrefix(wstring(L"rp"), wstring(g_pwszHeaderNS));
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoapEnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:actor"), wstring(g_pwszSoapActorNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"1"));
        }
        else
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoap12EnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:role"), wstring(g_pwszSoap12RoleNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"true"));
        }
	}
	else
	{
		return false;
	}
	// 'action' element
	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:action"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(wstring(L"http://schemas.xmlsoap.org/soap/fault"));
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'fwd' element (derived from 'rev' path received)
	pChild = new WMXMLElement(wstring(L"rp:fwd"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		if (m_bRevElemFound == true)
		{
			// use contents of "rev" element received
			PopulateViaList(m_listRev, pChild);
		}
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'from' element (only from endpoint)
	if (m_bIntermediary == false)
	{
		pChild = new WMXMLElement(wstring(L"rp:from"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(GetFromURI());
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'id' element
	pChild = new WMXMLElement(wstring(L"rp:id"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(GenerateId());
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'relatesTo' element (value is id of request message)
	pChild = new WMXMLElement(wstring(L"rp:relatesTo"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(m_wstrId);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'fault' element
	pChild = CreateFaultElem();
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
	}
	else
	{
		delete pPath;
		return false;
	}

	// now serialize
	wstring wstrBuffer;
	pPath->Serialize(NULL, wstrBuffer);
	delete pPath;

	BSTR bstrBuffer = SysAllocString(wstrBuffer.c_str());
	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"path");
	VARIANT_BOOL bMustUnderstand = VARIANT_TRUE;
    // determine actor URI
    BSTR bstrActorURI = NULL;
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
		bstrActorURI = SysAllocString(g_pwszSoapActorNext);
    }
    else
    {
		bstrActorURI = SysAllocString(g_pwszSoap12RoleNext);
    }
	BSTR bstrEncodingStyle = SysAllocString(L"");
	VARIANT_BOOL bResult;
	pIwmsoapmsg->AddFaultHeaderElemLiteral( bstrNamespaceURI,
											bstrLocalName,
											bstrBuffer,
											bMustUnderstand,
											bstrActorURI,
											bstrEncodingStyle,
											&bResult);
	SysFreeString(bstrNamespaceURI);
	SysFreeString(bstrLocalName);
	SysFreeString(bstrActorURI);
	SysFreeString(bstrEncodingStyle);
	SysFreeString(bstrBuffer);

	// generate SOAP fault
	BSTR bstrFaultcode, bstrFaultcodeNS, bstrFaultstring;
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
	    if (nCode < 800)
	    {
		    bstrFaultcode = SysAllocString(L"Client");
		    bstrFaultstring = SysAllocString(L"WS-Routing Sender fault.");
	    }
	    else
	    {
		    bstrFaultcode = SysAllocString(L"Server");
		    bstrFaultstring = SysAllocString(L"WS-Routing Receiver fault.");
	    }
        bstrFaultcodeNS = SysAllocString(g_pwszSoapEnvelopeNS);
		pIwmsoapmsg->SetSOAPFault(bstrFaultcode, bstrFaultcodeNS, bstrFaultstring, VARIANT_FALSE, &bResult);
    }
    else
    {
	    if (nCode < 800)
	    {
            bstrFaultcode = SysAllocString(L"Sender");
		    bstrFaultstring = SysAllocString(L"WS-Routing Sender fault.");
	    }
	    else
	    {
		    bstrFaultcode = SysAllocString(L"Receiver");
		    bstrFaultstring = SysAllocString(L"WS-Routing Receiver fault.");
	    }
        bstrFaultcodeNS = SysAllocString(g_pwszSoap12EnvelopeNS);
        BSTR bstrSubcode = SysAllocString(L"");
        BSTR bstrSubcodeNS = SysAllocString(L"");
        BSTR bstrLangId = SysAllocString(L"en");
		pIwmsoapmsg->SetSOAP12Fault(bstrFaultcode, bstrFaultcodeNS, bstrSubcode, bstrSubcodeNS, bstrFaultstring, bstrLangId, &bResult);
        SysFreeString(bstrSubcode);
        SysFreeString(bstrSubcodeNS);
        SysFreeString(bstrLangId);
    }
	SysFreeString(bstrFaultcode);
	SysFreeString(bstrFaultcodeNS);
	SysFreeString(bstrFaultstring);

	// set flag to disable response processing
	m_bRequestFault = true;
	return (bResult == VARIANT_TRUE);
}

bool Cwmwsrouter2Obj::ProcessReqAsIntermediary(Iwmsoapmsg2 *pIwmsoapmsg)
{
	// determine next hop
	if (m_listFwd.empty() == true)
	{
		// we were the last intermediary
		m_wstrURI = m_wstrTo;
	}
	else
	{
		m_wstrURI = m_listFwd.front();
	}
	// is this URL scheme supported?
	if (CheckURLScheme(m_wstrURI) == false)
	{
		ProcessFault(712, pIwmsoapmsg);
		return true;
	}
	// set next hop
	BSTR bstrTemp = SysAllocString(m_wstrURI.c_str());
	pIwmsoapmsg->SetNextHopURL(bstrTemp);
	SysFreeString(bstrTemp);

    // determine SOAP version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);
	// create new header entry
	WMXMLElement *pPath = new WMXMLElement(wstring(L"rp:path"));
	if (pPath != NULL)
	{
		pPath->SetNSPrefix(wstring(L"rp"), wstring(g_pwszHeaderNS));
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoapEnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:actor"), wstring(g_pwszSoapActorNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"1"));
        }
        else
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoap12EnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:role"), wstring(g_pwszSoap12RoleNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"true"));
        }
	}
	else
	{
		return false;
	}
	// 'action' element
	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:action"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(m_wstrAction);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'to' element
	if (m_bToElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:to"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrTo);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'fwd' element
	if (m_bFwdElemFound == true)
	{
		// we have already removed the top "via" element
		pChild = new WMXMLElement(wstring(L"rp:fwd"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			PopulateViaList(m_listFwd, pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'rev' element
	if (m_bRevElemFound == true)
	{
		// add empty "via" element to top of list
		m_listRev.push_front(wstring(L""));
		pChild = new WMXMLElement(wstring(L"rp:rev"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			PopulateViaList(m_listRev, pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'from' element
	if (m_bFromElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:from"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrFrom);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'id' element
	if (m_bIdElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:id"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrId);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'relatesTo' element
	if (m_bRelatesToElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:relatesTo"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrRelatesTo);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'fault' element
	if (m_bFaultElemFound == true)
	{
		pChild = CreateFaultElem();
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}

	// now serialize
	wstring wstrBuffer;
	pPath->Serialize(NULL, wstrBuffer);
	delete pPath;

	BSTR bstrBuffer = SysAllocString(wstrBuffer.c_str());
	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"path");
	VARIANT_BOOL bMustUnderstand = VARIANT_TRUE;
    // determine actor URI
    BSTR bstrActorURI = NULL;
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
		bstrActorURI = SysAllocString(g_pwszSoapActorNext);
    }
    else
    {
		bstrActorURI = SysAllocString(g_pwszSoap12RoleNext);
    }
	BSTR bstrEncodingStyle = SysAllocString(L"");
	VARIANT_BOOL bResult;
	pIwmsoapmsg->AddHeaderElemLiteral(  bstrNamespaceURI,
										bstrLocalName,
										bstrBuffer,
										bMustUnderstand,
										bstrActorURI,
										bstrEncodingStyle,
										&bResult);
	SysFreeString(bstrNamespaceURI);
	SysFreeString(bstrLocalName);
	SysFreeString(bstrActorURI);
	SysFreeString(bstrEncodingStyle);
	SysFreeString(bstrBuffer);

	return (bResult == VARIANT_TRUE);
}

bool Cwmwsrouter2Obj::ProcessReqAsEndpoint(Iwmsoapmsg2 *pIwmsoapmsg)
{
	return true;
}

bool Cwmwsrouter2Obj::ProcessRespAsIntermediary(Iwmsoapmsg2 *pIwmsoapmsg)
{
    // determine SOAP version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);
	// create new header entry
	WMXMLElement *pPath = new WMXMLElement(wstring(L"rp:path"));
	if (pPath != NULL)
	{
		pPath->SetNSPrefix(wstring(L"rp"), wstring(g_pwszHeaderNS));
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoapEnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:actor"), wstring(g_pwszSoapActorNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"1"));
        }
        else
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoap12EnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:role"), wstring(g_pwszSoap12RoleNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"true"));
        }
	}
	else
	{
		return false;
	}
	// 'action' element
	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:action"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(m_wstrAction);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'fwd' element
	if (m_bFwdElemFound == true)
	{
		// we have already removed the top "via" element
		pChild = new WMXMLElement(wstring(L"rp:fwd"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			PopulateViaList(m_listFwd, pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'rev' element
	if (m_bRevElemFound == true)
	{
		// add cached URI indentifying us to top of list
		m_listRev.push_front(m_wstrIntermediaryURI);
		pChild = new WMXMLElement(wstring(L"rp:rev"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			PopulateViaList(m_listRev, pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'from' element
	if (m_bFromElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:from"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrFrom);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'id' element
	if (m_bIdElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:id"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrId);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'relatesTo' element
	if (m_bRelatesToElemFound == true)
	{
		pChild = new WMXMLElement(wstring(L"rp:relatesTo"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			pChild->AppendContent(m_wstrRelatesTo);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'fault' element
	if (m_bFaultElemFound == true)
	{
		pChild = CreateFaultElem();
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// now serialize
	wstring wstrBuffer;
	pPath->Serialize(NULL, wstrBuffer);
	delete pPath;

	BSTR bstrBuffer = SysAllocString(wstrBuffer.c_str());
	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"path");
	VARIANT_BOOL bMustUnderstand = VARIANT_TRUE;
    // determine actor URI
    BSTR bstrActorURI = NULL;
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
		bstrActorURI = SysAllocString(g_pwszSoapActorNext);
    }
    else
    {
		bstrActorURI = SysAllocString(g_pwszSoap12RoleNext);
    }
	BSTR bstrEncodingStyle = SysAllocString(L"");
	VARIANT_BOOL bResult;
	// was this a fault response?
	pIwmsoapmsg->IsSOAPFault(&bResult);
	if (bResult == VARIANT_TRUE)
	{
		pIwmsoapmsg->AddFaultHeaderElemLiteral( bstrNamespaceURI,
												bstrLocalName,
												bstrBuffer,
												bMustUnderstand,
												bstrActorURI,
												bstrEncodingStyle,
												&bResult);
	}
	else
	{
		pIwmsoapmsg->AddHeaderElemLiteral(  bstrNamespaceURI,
											bstrLocalName,
											bstrBuffer,
											bMustUnderstand,
											bstrActorURI,
											bstrEncodingStyle,
											&bResult);
	}
	SysFreeString(bstrNamespaceURI);
	SysFreeString(bstrLocalName);
	SysFreeString(bstrActorURI);
	SysFreeString(bstrEncodingStyle);
	SysFreeString(bstrBuffer);

	return (bResult == VARIANT_TRUE);
}

bool Cwmwsrouter2Obj::ProcessRespAsEndpoint(Iwmsoapmsg2 *pIwmsoapmsg)
{
    // determine SOAP version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);
	// create new header entry
	WMXMLElement *pPath = new WMXMLElement(wstring(L"rp:path"));
	if (pPath != NULL)
	{
		pPath->SetNSPrefix(wstring(L"rp"), wstring(g_pwszHeaderNS));
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoapEnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:actor"), wstring(g_pwszSoapActorNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"1"));
        }
        else
        {
    		pPath->SetNSPrefix(wstring(L"SOAP-ENV"), wstring(g_pwszSoap12EnvelopeNS));
		    pPath->SetAttribute(wstring(L"SOAP-ENV:role"), wstring(g_pwszSoap12RoleNext));
    		pPath->SetAttribute(wstring(L"SOAP-ENV:mustUnderstand"), wstring(L"true"));
        }
	}
	else
	{
		return false;
	}
	// 'action' element
	WMXMLElement *pChild = new WMXMLElement(wstring(L"rp:action"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(m_wstrAction);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'fwd' element
	if (m_bRevElemFound == true)
	{
		// use contents of "rev" element received
		pChild = new WMXMLElement(wstring(L"rp:fwd"));
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
			PopulateViaList(m_listRev, pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// 'rev' element
	// we need to insert "via" element with our URI
	if (m_bToElemFound == true)
	{
		// use the "to" value received
		m_listFwd.push_front(m_wstrTo);
	}
	else
	{
		// use the value of the "via" element found in "fwd"
		m_listFwd.push_front(m_wstrURI);
	}
	pChild = new WMXMLElement(wstring(L"rp:rev"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		PopulateViaList(m_listFwd, pChild);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'from' element
	pChild = new WMXMLElement(wstring(L"rp:from"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(GetFromURI());
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'id' element
	pChild = new WMXMLElement(wstring(L"rp:id"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(GenerateId());
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'relatesTo' element (value is id of request message)
	pChild = new WMXMLElement(wstring(L"rp:relatesTo"));
	if (pChild != NULL)
	{
		pPath->AddChildElement(pChild);
		pChild->AppendContent(m_wstrId);
	}
	else
	{
		delete pPath;
		return false;
	}
	// 'fault' element
	if (m_bFaultElemFound == true)
	{
		pChild = CreateFaultElem();
		if (pChild != NULL)
		{
			pPath->AddChildElement(pChild);
		}
		else
		{
			delete pPath;
			return false;
		}
	}
	// now serialize
	wstring wstrBuffer;
	pPath->Serialize(NULL, wstrBuffer);
	delete pPath;

	BSTR bstrBuffer = SysAllocString(wstrBuffer.c_str());
	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"path");
	VARIANT_BOOL bMustUnderstand = VARIANT_TRUE;
    // determine actor URI
    BSTR bstrActorURI = NULL;
    if (lSOAPVersion == SOAP_VERSION_1_1)
    {
		bstrActorURI = SysAllocString(g_pwszSoapActorNext);
    }
    else
    {
		bstrActorURI = SysAllocString(g_pwszSoap12RoleNext);
    }
	BSTR bstrEncodingStyle = SysAllocString(L"");
	VARIANT_BOOL bResult;
	// was this a fault response?
	pIwmsoapmsg->IsSOAPFault(&bResult);
	if (bResult == VARIANT_TRUE)
	{
		pIwmsoapmsg->AddFaultHeaderElemLiteral( bstrNamespaceURI,
												bstrLocalName,
												bstrBuffer,
												bMustUnderstand,
												bstrActorURI,
												bstrEncodingStyle,
												&bResult);
	}
	else
	{
		pIwmsoapmsg->AddHeaderElemLiteral(  bstrNamespaceURI,
											bstrLocalName,
											bstrBuffer,
											bMustUnderstand,
											bstrActorURI,
											bstrEncodingStyle,
											&bResult);
	}
	SysFreeString(bstrNamespaceURI);
	SysFreeString(bstrLocalName);
	SysFreeString(bstrActorURI);
	SysFreeString(bstrEncodingStyle);
	SysFreeString(bstrBuffer);

	return (bResult == VARIANT_TRUE);
}

bool Cwmwsrouter2Obj::ProcessRequest(Iwmsoapmsg2 *pIwmsoapmsg)
{
	m_bRequestFault = false;
	m_bIntermediary = true;
	m_bNoReversePath = false;
	if (ReadHeader(pIwmsoapmsg) == false)
	{
		// missing soap-rp header
		ProcessFault(701, pIwmsoapmsg);
		return true;
	}
	// is this a fault message?
	if (m_bFaultElemFound == true || m_wstrAction == L"http://schemas.xmlsoap.org/soap/fault")
	{
		// send "no content" response
		pIwmsoapmsg->SetNoContentResponse(VARIANT_TRUE);
		// set flag to abort processing
		m_bAbortProcessing = true;
		return true;
	}
	// was a reverse path specified?
	if (m_bRevElemFound == false)
	{
		// no, set flag, normal processing will proceed
		m_bNoReversePath = true;;
	}
	// were "id" and "action" elements found?
	if (m_bIdElemFound == false || m_bActionElemFound == false)
	{
		{
			// ill formed header... should have "id" and "action" elements
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
	}
	// was a "fwd" element with entries(s) found?
	if (m_bFwdElemFound == false || m_listFwd.empty() == true)
	{
		// no, so check for "to" element
		if (m_bToElemFound == false)
		{
			// ill formed header... should have "to" element
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
		// "to" element found... we are the endpoint
		m_bIntermediary = false;
		// check the URI to make sure it's us
		if (CheckIdentity(m_wstrTo, pIwmsoapmsg) == false)
		{
			// not us... "invalid ws-routing header" fault
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
		// it's us, so process as endpoint
		m_wstrURI = m_wstrTo;
		if (ProcessReqAsEndpoint(pIwmsoapmsg) == false)
		{
			ProcessFault(800, pIwmsoapmsg);
		}
		return true;
	}
	else
	{
		// non-empty "fwd" element... get top element
		m_wstrURI = m_listFwd.front();
		m_listFwd.pop_front();
		// is it us?
		if (CheckIdentity(m_wstrURI, pIwmsoapmsg) == false)
		{
			// not us... send invalid ws-routing header fault
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
		// was this the last one AND no "to" element is present?
		if (m_listFwd.empty() == true && m_bToElemFound == false)
		{
			// we are the endpoint, so process as such
			m_bIntermediary = false;
			if (ProcessReqAsEndpoint(pIwmsoapmsg) == false)
			{
				ProcessFault(800, pIwmsoapmsg);
			}
			return true;
		}
		// we are an intermediary... process as such
		m_wstrIntermediaryURI = m_wstrURI;
		return ProcessReqAsIntermediary(pIwmsoapmsg);
	}
	return true;
}

bool Cwmwsrouter2Obj::ProcessResponse(Iwmsoapmsg2 *pIwmsoapmsg)
{
	// was a reverse path found in request?
	if (m_bNoReversePath == true)
	{
		// send "no content" response and quit
		pIwmsoapmsg->SetNoContentResponse(VARIANT_TRUE);
		return true;
	}
	// was a fault generated in request phase?
	if (m_bRequestFault == true)
	{
		// do nothing
		return true;
	}
	VARIANT_BOOL bResult;
	pIwmsoapmsg->IsIntermediary(&bResult);
	if (bResult == VARIANT_FALSE)
	{
		// we are endpoint, process as such
		if (ProcessRespAsEndpoint(pIwmsoapmsg) == false)
		{
			ProcessFault(800, pIwmsoapmsg);
		}
		// will we be using implicit reverse path?
		wstring wstrFirstRevURL = m_listRev.front();
		if (wstrFirstRevURL.empty() == true || CheckURLScheme(wstrFirstRevURL) == false)
		{
			// use implicit path
			return true;
		}
		// no, an explicit reverse path
		return ForwardMsgHTTP(wstrFirstRevURL, pIwmsoapmsg);
	}
	// we are intermediary... look for WS-Routing header in response
	if (ReadHeader(pIwmsoapmsg) == false)
	{
		// did attempt to forward message fail?
		pIwmsoapmsg->IsSOAPFault(&bResult);
		if (bResult == VARIANT_TRUE)
		{
			BSTR bstrFaultString;
			pIwmsoapmsg->GetSOAPFaultString(&bstrFaultString);
			if (wcscmp(L"Attempt to forward SOAP message by intermediary failed.", bstrFaultString) == 0)
			{
				SysFreeString(bstrFaultString);
				// was a "rev" element with entries(s) found?
				if (m_bRevElemFound == true && m_listRev.empty() == false)
				{
					// non-empty "rev" element... remove top element added in request phase
					m_listRev.pop_front();
				}
				ProcessFault(820, pIwmsoapmsg);
				return true;
			}
			SysFreeString(bstrFaultString);
		}
		// no forwarding failure, no soap-rp header found... do nothing.
		return true;
	}
	// were "id" and "action" elements found?
	if (m_bIdElemFound == false || m_bActionElemFound == false)
	{
		{
			// ill formed header... should have "id" and "action" elements
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
	}
	// was a "fwd" element with entries(s) found?
	if (m_bFwdElemFound == true && m_listFwd.empty() == false)
	{
		// non-empty "fwd" element... get top element
		m_wstrURI = m_listFwd.front();
		m_listFwd.pop_front();
		// is it us (an empty "via" element means it's for us)?
		if (m_wstrURI.empty() == false)
		{
			// not us... send invalid header fault
			ProcessFault(700, pIwmsoapmsg);
			return true;
		}
	}
	// now process as intermediary
	return ProcessRespAsIntermediary(pIwmsoapmsg);
}

STDMETHODIMP Cwmwsrouter2Obj::OnProcessHeader(VARIANT SOAPMsgInterface, VARIANT_BOOL *pResult)
{
	// set up, assume success
	m_bAbortProcessing = false;
	*pResult = VARIANT_TRUE;
	// get interface ptr
	IDispatch *pIDispatch = SOAPMsgInterface.pdispVal;
	Iwmsoapmsg2 *pIwmsoapmsg;
	HRESULT hRes = pIDispatch->QueryInterface(IID_Iwmsoapmsg2, (void **)&pIwmsoapmsg);
	if (hRes != S_OK)
	{
		return E_FAIL;
	}
	VARIANT_BOOL bResult;
	pIwmsoapmsg->IsRequestPhase(&bResult);
	if (bResult == VARIANT_TRUE)
	{
		// this is request phase
		if (ProcessRequest(pIwmsoapmsg) == false)
		{
			ProcessFault(800, pIwmsoapmsg);
		}
		pIwmsoapmsg->Release();
		// abort processing?
		if (m_bAbortProcessing == true)
		{
			// set out parameter to signal abort
			*pResult = VARIANT_FALSE;
		}
		return S_OK;
	}
	// response phase
	if (ProcessResponse(pIwmsoapmsg) == false)
	{
		ProcessFault(800, pIwmsoapmsg);
	}
	pIwmsoapmsg->Release();
	if (m_bAbortProcessing == true)
	{
		// set out parameter to signal abort
		*pResult = VARIANT_FALSE;
	}
	return S_OK;
}

bool Cwmwsrouter2Obj::ForwardMsgHTTP(const wstring& wstrURL, Iwmsoapmsg2 *pIwmsoapmsg)
{
	// toggle to 'response' phase
	pIwmsoapmsg->SetRequestPhase(VARIANT_FALSE);
	VARIANT_BOOL bResult;
	// must forward request, so re-serialize request message
	pIwmsoapmsg->Serialize(&bResult);
	if (bResult == VARIANT_FALSE)
	{
		// failed
		return false;
	}
	// set up HTTP client
	string strNextHopURL, strHost, strSvcURI, strTemp;
	USES_CONVERSION;
	strNextHopURL = OLE2A(wstrURL.c_str());
	int nPortNbr = 80;
	string::size_type pos;
	if ((pos = strNextHopURL.find("http://")) != string::npos)
	{
		strTemp = strNextHopURL.substr(pos + 7);
		pos = strTemp.find('/');
		if (pos == string::npos)
		{
			strSvcURI = "/";
		}
		else
		{
			strSvcURI = strTemp.substr(pos);
		}
		strTemp = strTemp.substr(0, pos);
		if ((pos = strTemp.find(':')) != string::npos)
		{
			// port specified explicitly
			nPortNbr = atoi(strTemp.substr(pos + 1).c_str());
			strHost = strTemp.substr(0, pos);
		}
		else
		{
			strHost = strTemp;
		}
	}
	// get serialized message
	_variant_t varBuffer;
	pIwmsoapmsg->GetBuffer(&varBuffer, &bResult);
	SAFEARRAY *pArray = varBuffer.parray;
	void *pData;
	if (	bResult == VARIANT_FALSE ||
			!(varBuffer.vt & (VT_ARRAY | VT_UI1)) ||
			pArray == NULL ||
			SafeArrayGetDim(pArray) != 1 ||
			FAILED(SafeArrayAccessData(pArray, &pData)))
	{
		return false;
	}
    // get soap version
    long lSOAPVersion;
    pIwmsoapmsg->GetSOAPVersion(&lSOAPVersion);

	DIMEParser dimeParser;
	string strBody;
	long lNumAttachments = 0;
	pIwmsoapmsg->GetNumRespAttachments(&lNumAttachments);
	unsigned long ulMsgLength;
	if (lNumAttachments > 0)
	{
		// try to initialize parser for serialization
		// accept default record size of 4096 octets
		try
		{
			dimeParser.SerializeInit();
		}
		catch (DIMEParserException *e)
		{
			delete e;
			SafeArrayUnaccessData(pArray);
			return false;
		}
        string strTypeURI;
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
            strTypeURI = g_pszSoapEnvelopeNS;
        }
        else
        {
            strTypeURI = g_pszSoap12EnvelopeNS;
        }
		// add primary DIME payload
		if (dimeParser.AddPayload( (const char *)pData,
									pArray->rgsabound[0].cElements,
									string(""),
									strTypeURI,
									DIME_TYPENAME_FORMAT_URI) == false)
		{
			SafeArrayUnaccessData(pArray);
			return false;
		}
		SafeArrayUnaccessData(pArray);
		// now get secondary payloads
		long lPosition;
		BSTR bstrId, bstrType;
		long lTNF;
		IUnknown *pIUnknown;
		_variant_t varOptions;
		for (pIwmsoapmsg->GetFirstDIMEAttachmentResp(&bstrId,
													&bstrType,
													&lTNF,
													&pIUnknown,
													&varOptions,
													&lPosition,
													&bResult);
			 bResult == VARIANT_TRUE;
			 pIwmsoapmsg->GetNextDIMEAttachmentResp( &bstrId,
													&bstrType,
													&lTNF,
													&pIUnknown,
													&varOptions,
													&lPosition,
													&bResult)
		)
		{
			string strId, strType;
			WideStringToUTF8(wstring(bstrId), strId);
			WideStringToUTF8(wstring(bstrType), strType);
			SysFreeString(bstrId);
			SysFreeString(bstrType);
			IStorage *pIStorage;
			HRESULT res = pIUnknown->QueryInterface(IID_IStorage, (void **)&pIStorage);
			if (FAILED(res))
			{
				return false;
			}
			SAFEARRAY *pArray = NULL;
			if ((varOptions.vt & VT_TYPEMASK) & (VT_ARRAY | VT_UI1))
			{
				pArray = varOptions.parray;
			}
			if (dimeParser.AddPayload(  pIStorage,
										strId,
										strType,
										lTNF,
										pArray) == false)
			{
				// this will result in 500 "Internal Server Error"
				pIStorage->Release();
				return false;
			}
			varOptions.Clear();
			pIStorage->Release();
		}
		ulMsgLength = dimeParser.CalcSerialLength();
	}
	else
	{
		// no attachments, send without DIME packaging
		strBody.append((char *)pData, pArray->rgsabound[0].cElements);
		ulMsgLength = pArray->rgsabound[0].cElements;
		SafeArrayUnaccessData(pArray);
	}
	// build HTTP Header
	char szBuffer[128];
	string strHeaders = "Host: ";
	strHeaders += strHost;
	sprintf(szBuffer, ":%d\r\n", nPortNbr);
	strHeaders += szBuffer;
	strHeaders += "User-Agent: ";
	strHeaders += string(g_pszUserAgent);
	if (lNumAttachments > 0)
	{
		strHeaders += "\r\nContent-Type: application/dime\r\n";
	}
	else
	{
        if (lSOAPVersion == SOAP_VERSION_1_1)
        {
	        strHeaders += "\r\nContent-Type: text/xml; charset=\"utf-8\"\r\n";
        }
        else
        {
	        strHeaders += "\r\nContent-Type: application/soap+xml; charset=\"utf-8\"\r\n";
        }
	}
	sprintf(szBuffer, "Content-Length: %d\r\n", ulMsgLength);
	strHeaders += szBuffer;
	// now send message
	WMDIMERequestSock HTTPClient;
	bool bSuccess;
	if (lNumAttachments > 0)
	{
		bSuccess = HTTPClient.SendHTTPRequest(nPortNbr,
											string("POST"),
											strHost,
											strSvcURI,
											string(""),
											strHeaders,
											&dimeParser);
	}
	else
	{
		bSuccess = HTTPClient.SendHTTPRequest(nPortNbr,
											string("POST"),
											strHost,
											strSvcURI,
											string(""),
											strHeaders,
											strBody,
											&dimeParser);
	}
	if (bSuccess == false || HTTPClient.GetStatus() >= 300)
	{
		// something went wrong
		return false;
	}
	// set "no content" response
	pIwmsoapmsg->SetNoContentResponse(VARIANT_TRUE);
	return true;
}

STDMETHODIMP Cwmwsrouter2Obj::OnTestMUHeaderBlock(BSTR bstrNamespace, BSTR bstrLocalName, VARIANT_BOOL *pResult)
{
    *pResult = VARIANT_FALSE;
    if (wcscmp(bstrNamespace, g_pwszHeaderNS) == 0)
    {
        if (wcscmp(bstrLocalName, L"path") == 0)
        {
            *pResult = VARIANT_TRUE;
            return S_OK;
        }
    }
    return S_OK;
}
