void	CISO8583AuthorizerServerSession::OnNewMsg(CMultiXAppMsg &Msg)
{
	DebugPrint(1,"New Message Received\n");
	switch(CISO8583Msg::VersionIndependentMTI(Msg.MsgCode()))	//	we check the ISO8583 Version independent MTI value
	{
		case	CISO8583Msg::MTIAuthorizationMessageRequest	:
		case	CISO8583Msg::MTIFinancialMessageRequest	:
			{
				//	If  we have an ISO 8583 Msg Code, we try to parse the msg to make sure that
				//	we have a valid ISO 8583

				CISO8583Msg	ISOMsg;
				CISO8583Msg::TValidationError	Error	=	ISOMsg.FromISO((const	byte_t	*)Msg.AppData(),Msg.AppDataSize());
				if(Error	!=	CISO8583Msg::NoError)
				{
					Msg.Reply(Error);
				}	else	if(ISOMsg.Version()	!=	CISO8583Msg::ISO8583_1_1987)	//	we	Support only 1987 version
				{
					Msg.Reply(CISO8583Msg::VersionNotSupported);
				}	else
				{
					OnISO8583Msg(Msg,ISOMsg);
				}
			}
			break;
		default	:
			//	We	do not know this message, reply with error
			Msg.Reply(CISO8583Msg::MTINotSupported);
			break;

	}
}
void	CMultiXWSServerServerSession::OnNewMsg(CMultiXAppMsg &Msg)
{
	DebugPrint(1,"New Message Received\n");
	if(!Msg.IsWebServiceCall())
	{
		DebugPrint(1,"Error Reply TpmErrMsgNotSupported\n");
		Msg.Reply(TpmErrMsgNotSupported);
		return;
	}

	try
	{
		if(m_pStream	==	NULL)
			m_pStream	=	new	CMultiXWSStream(Msg.WSDllFile(),*this);
		bool	bSuccess	=	m_pStream->CallServiceNoWait(Msg);
		if(!bSuccess)
		{
			Owner()->Logger()->ReportError(DebugPrint(0,"Error on CallServiceNoWait\n"));
			Msg.Reply(WSErrgSoapDllNotFound);
		}
	}catch(...)
	{
		DebugPrint(1,"Error Reply WSErrgSoapDllNotFound\n");
		Msg.Reply(WSErrgSoapDllNotFound);
	}
}
/*
	This function is called when we receive a valid ISO 8583 Message. Here we check the specific MTI and call the appropriate
	function to handle the request.

*/
void	CISO8583AuthorizerServerSession::OnISO8583Msg(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	//	First we make sure that we have a connected database

	if(!Owner()->DBConnected())
	{
		Msg.Reply(CISO8583Msg::NoDatabaseConnection);
		return;
	}



	//	Here we check for specific message codes(MTI values) and if we support the specific code, 
	//	we call a handler function, otherwise we reply with error
	switch(ISOMsg.VersionIndependentMTI())
	{
		case	CISO8583Msg::MTIAuthorizationMessageRequest	:
			OnAuthorizationRequest(Msg,ISOMsg);
			break;
		case	CISO8583Msg::MTIFinancialMessageRequest	:
			OnSaleRequest(Msg,ISOMsg);
			break;
		default	:
			//	We	do not know this message, reply with error
			Msg.Reply(CISO8583Msg::MTINotSupported);
			break;
	}
}
void	CISO8583AcquirerGatewayFEServerSession::OnNetworkManagementRequest(CMultiXAppMsg &Msg)
{
	CISO8583Msg	ISOMsg;
	CISO8583Msg::TValidationError	Error	=	ISOMsg.FromISO((const	byte_t	*)Msg.AppData(),Msg.AppDataSize());
	if(Error	!=	CISO8583Msg::NoError)
	{
		Msg.Reply(Error);
		return;
	}

	/*
		Since Network Management messages include the destination gateway ID, we use it to find the link associated with this gateway.
	*/
	int	ReplyError	=	ErrUnableToForwardMsg;
	CISO8583AcquirerGatewayFELink	*Link	=	Owner()->FindReadyLink(ISOMsg.TransactionDestinationInstitutionIdentificationCode());
	if(Link)
	{
		std::string	MsgKey	=	ISOMsg.STAN() + ISOMsg.DateTimeLocal() + ISOMsg.TransactionOriginatorInstitutionIdentificationCode();
		ReplyError	=	Link->Forward(Msg,MsgKey);
	}
	if(ReplyError	==	0)
	{
		Msg.Keep();
	}	else
	{
		Msg.Reply(ReplyError);
	}
}
void	CISO8583BackEndServerSession::OnSendMsgFailed(CMultiXAppMsg &FailedMsg,bool	bTimeout)
{
	/*
		If we forwarded a message to another process, we need to check the failure and decide what to do.
	*/

	switch(CISO8583Msg::VersionIndependentMTI(FailedMsg.MsgCode()))	//	this will give us version independent MTI
	{
	case	CISO8583Msg::MTIAuthorizationMessageRequest	:
	case	CISO8583Msg::MTIReversalMessageAdvice	:
	case	CISO8583Msg::MTIReversalMessageAdviceRepeat	:
		{
			/*
				These are all messages we received from acquirer gateways or acquirers in general,
				and failed to forward them to remote gateways/issuers, so we respond to the acquirer 
				with an error indicating that we were unable to forward the request.
			*/

			//	We extract the acquirer we saved when we forwarded the message.
			CMultiXAppMsg	*AcquirerMsg	=	(CMultiXAppMsg	*)FailedMsg.SavedContext();

			AcquirerMsg->Reply(CISO8583Msg::ForwardToIssuerFailed);
			delete	AcquirerMsg;					//	WE MUST DELETE THE MESSAGE BECAUSE WE CALLED "Keep()" BEFORE WE FORWARDED IT.
		}
		break;
	}
}
void	CMultiXProcess::OnNewMsgFromTpm(CMultiXAppMsg &AppMsg)
{

    if(Owner()->TpmProcID()	==	0)
        Owner()->m_TpmProcID	=	this->ProcessID();
    if(Owner()->TpmProcID()	!=	this->ProcessID())
    {
        Reject();
    }	else
    {
        switch(AppMsg.MsgCode())
        {
        case	CMultiXTpmCtrlMsg::ConfigDataMsgCode	:
        {
            OnTpmConfigData(AppMsg);
            break;
        }
        case	CMultiXTpmCtrlMsg::ProcessShutdownMsgCode	:
            OnPrepareForShutdown(AppMsg);
            break;
        case	CMultiXTpmCtrlMsg::ProcessRestartMsgCode	:
            OnProcessRestart(AppMsg);
            break;
        case	CMultiXTpmCtrlMsg::ProcessSuspendMsgCode	:
            OnProcessSuspend(AppMsg);
            break;
        case	CMultiXTpmCtrlMsg::ProcessResumeMsgCode	:
            OnProcessResume(AppMsg);
            break;
        }
    }
    AppMsg.Reply(MultiXNoError);
}
//!	see CMultiXSession::OnDataReplyReceived
void	CMultiXWSServerServerSession::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg,CMultiXAppMsg &OriginalMsg)
{
	DebugPrint(3,"Data Reply Received\n");
	/*
	We received some response from a process we sent a message to before, or response we sent before to a request, was acknoledged with some data.
	*/
	//	TODO:	Add your code to handle the response

	ReplyMsg.Reply();
}
//!	see CMultiXSession::OnDataReplyReceived
void	CISO8583BackEndServerSession::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg,CMultiXAppMsg &ForwardedMsg)
{
	DebugPrint(3,"Data Reply Received\n");
	/*
		We get here when we receive a response for a message we forwarded before. In this case we will forward the response back to
		the originator, we do not care for the content, we forward it back almost AS IS except for few fields that
		we need to restore because changed them before we forwarded the message, the fields are:
		MTI - Convert it to 1993 version.
		BMP 7 - Set Transmission time
		BMP 11 - restore sender STAN
		BMP 12	-	Restore sender Date and Time Local
		BMP 32 - Restore senders Acquiring Institution Identification Code
	*/
	/*
		In order to restore old values, we need to restore the message we received originaly from the acquirer or from the pos terminal.
		this message is saved in the SaveContext() of the ForwardedMsg.
	*/
	CMultiXAppMsg	*AcquirerMsg	=	(CMultiXAppMsg	*)ForwardedMsg.SavedContext();

	CISO8583Msg	AcquirerISO;
	CISO8583Msg	ReplyISO;
	AcquirerISO.FromISO((const	byte_t	*)AcquirerMsg->AppData(),AcquirerMsg->AppDataSize());
	ReplyISO.FromISO((const	byte_t	*)ReplyMsg.AppData(),ReplyMsg.AppDataSize());

	ReplyISO.SetTimes(time(NULL),true);
	ReplyISO.SetDateTimeLocal(AcquirerISO.DateTimeLocal());
	ReplyISO.SetSTAN(AcquirerISO.STAN());
	ReplyISO.SetAcquiringInstitutionIdentificationCode(AcquirerISO.AcquiringInstitutionIdentificationCode());
	ReplyISO.ToISO();

	AcquirerMsg->Reply(CISO8583Msg::VersionDependentMTI(CISO8583Msg::ISO8583_2_1993,ReplyMsg.MsgCode()),
		ReplyISO.ISOBuffer(),
		ReplyISO.ISOBufferSize(),0,0,0,0,0,ReplyMsg.Error());

	delete	AcquirerMsg;	//	WE MUST DELETE THE MESSAGE BECAUSE WE CALLED "Keep()" BEFORE WE FORWARDED IT.

	
	/*	
		we reply the ReplyMsg for the case that the process that replied to us expects to receive a notification that we
		received the reply, if it does not wait for the reply, no reply is sent.
	*/
	ReplyMsg.Reply();	
}
void	CISO8583AcquirerGatewayFEServerSession::OnTransactionRequest(CMultiXAppMsg &Msg)
{
	CISO8583Msg	ISOMsg;
	CISO8583Msg::TValidationError	Error	=	ISOMsg.FromISO((const	byte_t	*)Msg.AppData(),Msg.AppDataSize());
	if(Error	!=	CISO8583Msg::NoError)
	{
		Msg.Reply(Error);
		return;
	}

	if(Owner()->DebugLevel()	>=	5)
	{
		std::string	S;
		ISOMsg.Dump(S);
		DebugPrint(2,"New ISO 8583 Message\n%s\n",S.c_str());
	}

	/*
		When we receive a transaction for forwarding, we have no indication within the message, to which gateway we should forward the message.
		It is assumed that there is some mechanism to use the PAN and/or Track2 in order to decide to which gateway we should forward the request.
		In this application, we do not use any logic to derive the Gateway ID from these details. We just use a stub routine that gets PAN
		as input and returns the gateway ID of the issuer. Using the gateway ID, we look for a link that its RemoteGatewayID() is equal to
		the value returned. If we find one and it is signed in, we forward the request to it, otherwise we reply with an error.
	*/
	int	ReplyError	=	ErrUnableToForwardMsg;
	std::string	RemoteGatewayID	=	PANToGatewayID(ISOMsg.PAN());
	CISO8583AcquirerGatewayFELink	*Link	=	Owner()->FindReadyLink(RemoteGatewayID);
	if(Link)
	{
		std::string	MsgKey	=	ISOMsg.STAN() + ISOMsg.DateTimeLocal() + ISOMsg.AcquiringInstitutionIdentificationCode();
		ReplyError	=	Link->Forward(Msg,MsgKey);
	}
	if(ReplyError	==	0)
	{
		Msg.Keep();
	}	else
	{
		Msg.Reply(ReplyError);
	}
}
/*!
	see	CMultiXSession::OnDataReplyReceived

	this reply is for a message or an ACK previously received from the POS terminal.
*/
void	CMultiplexerClientFEClientSession::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg,CMultiXAppMsg &OriginalMsg)
{
	DebugPrint(2,"Data Reply Received\n");
	
		
	CMultiplexerClientFELink	*pLink	=	GetLink();
	

	if(!pLink)	//	probably the link was disconnected before the reply was received
	{
		int	Error	=	ErrLinkDisconnected;	
		//	TODO:	Set an application specific error code
		
		ReplyMsg.Reply(Error);
		return;
	}

	if(ReplyMsg.AppDataSize()	==	0)	//	an empty reply from the server application
	{
		if(ReplyMsg.Error()	!=	0)
			pLink->OnSessionSendFailed(OriginalMsg,ReplyMsg.Error());
		else
			pLink->OnSessionSendCompleted(OriginalMsg);
		ReplyMsg.Reply();	//	just reply to the received msg, in case the sender expects a reply
		return;
	}


	// forward the reply to the associated link
	CMultiXBuffer	*Buf	=	Owner()->AllocateBuffer(ReplyMsg.AppData(),ReplyMsg.AppDataSize());

	pLink->OnSessionReply(*Buf,OriginalMsg);
	Buf->ReturnBuffer();
	ReplyMsg.Reply(0);

	}
void	CISO8583AuthorizerServerSession::ForwardToIssuer(int	CreditAccountAtIssuer,CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	/*
		we get here if we need someone else to authorize the request. In that case we need to forward the request to our Acquirer Gateway Front End.
		To do that we need to forward it with a different message code, so MultiXTpm will not forward it back to us. The way we do it,
		the message code change is by setting the MTI version field to CISO8583Msg::ISO8583_Private. When the message is received by our
		Gateway process, it will revert back to CISO8583Msg::ISO8583_2_1993 and forward it on.
		
		When we forward a request, we do not block for a response, when a response arrives, we get it thru
		the event "OnDataReplyReceived". in order to be able to associate the response with the original msg,
		we pass a pointer to the original message in the "Context" parameter of the "Send" function, and when
		"OnDataReplyReceived" is called, we retrieve this pointer by using "SavedContext()" in the Original msg we sent.
		Since MultiX automatically destroys messages it forwards to the application, we must call "Keep()" on
		the received message, to prevent it from being destroyed, in that case, when the reply is received, we need
		to destroy the original message ourselves.

		When we play the role of an acquirer gateway, usualy get the request from the POS terminal, do validation required
		and maybe modify some data, and then forward the message to the issuer gateway, in our case, the forward will be to a process
		in our system, that will decide to which issuer to forward to, based on that, will use a specific connection to the spcific
		issuer gateway.
	*/
	/*
		Before we forward the request, we need to set 3 fields to identify the message as a one sent from this process :
		BMP 11 - STAN,
		BMP 12 - Times,
		BMP 32 - Our Acquirer ID
		BMP 42 - our account within the issuer

		When we receive the response from the remote gateway/issuer, we must replace these fields again to the orignal values
		that the sender set before sending the request to us
	*/
	ISOMsg.SetTimes(time(NULL));
	ISOMsg.SetSTAN(Owner()->GetNextSTAN());
	ISOMsg.SetAcquiringInstitutionIdentificationCode(Owner()->MyAcquirerID());
	CISO8583ElementValue	Value(CISO8583Utilities::ToString(CreditAccountAtIssuer),CISO8583ElementValue::ISO8583ElementTypeNumeric);
	ISOMsg.SetCardAcceptorIdentificationCode(Value);
	ISOMsg.ToISO();

	if(Send(CISO8583Msg::VersionDependentMTI(CISO8583Msg::ISO8583_Private,Msg.MsgCode()),ISOMsg.ISOBuffer(),ISOMsg.ISOBufferSize(),CMultiXAppMsg::FlagNotifyAll,0,0,&Msg))
		Msg.Keep();
	else
		Msg.Reply(ErrUnableToForwardMsg);
}
void	CMultiplexerServerFEServerSession::OnNewMsg(CMultiXAppMsg &Msg)
{

	DebugPrint(1,"New Message Received\n");
	
	int	ReplyError	=	ErrUnableToForwardMsg;
	CMultiplexerServerFELink	*Link	=	Owner()->FindReadyLink(Msg.MsgCode());
	if(Link)
	{
		ReplyError	=	Link->Forward(Msg);
	}
	if(ReplyError	==	0)
	{
		Msg.Keep();
	}	else
	{
		Msg.Reply(ReplyError);
	}
}
void	CISO8583AcquirerGatewayFEServerSession::OnNewMsg(CMultiXAppMsg &Msg)
{
	DebugPrint(1,"New Message Received\n");
	switch(CISO8583Msg::VersionIndependentMTI(Msg.MsgCode()))
	{
		case	CISO8583Msg::MTIAuthorizationMessageRequest	:
		case	CISO8583Msg::MTIFinancialMessageRequest	:
		case	CISO8583Msg::MTIReversalMessageAdviceRepeat	:
		case	CISO8583Msg::MTIReversalMessageAdvice	:
			OnTransactionRequest(Msg);
			break;
		case	CISO8583Msg::MTINetworkManagementMessageRequestOther	:
		case	CISO8583Msg::MTINetworkManagementMessageRequestAcquirer	:
		case	CISO8583Msg::MTINetworkManagementMessageRequestAcquirerRepeat	:
			OnNetworkManagementRequest(Msg);
			break;
		default	:
			Msg.Reply(ErrInvalidMsgCode);
			break;
	}
}
void CMultiXProcess::OnPrepareForShutdown(CMultiXAppMsg &AppMsg)
{

    CMultiXMsg	Msg(*Owner());
    Msg.Append(AppMsg.AppData(),AppMsg.AppDataSize());

    int32_t	GracePeriod	=	0;

    while(Msg.Next())
    {
        switch(Msg.GetItemCode())
        {

        case	CMultiXTpmCtrlMsg::GracePeriodItemCode	:
            Msg.GetItemData(GracePeriod);
            break;
        }
    }
    AppMsg.Reply(MultiXNoError);
    Owner()->OnPrepareForShutdown(GracePeriod);
}
CMultiXWSStream::~CMultiXWSStream(void)
{
	if(m_pFunctions)
	{
		m_pFunctions->soap_delete(m_pSoap,NULL);
		m_pFunctions->soap_end(m_pSoap);
		m_pFunctions->soap_done(m_pSoap); 
		m_pFunctions->soap_free(m_pSoap);
		UnloadgSoapDll(*m_pFunctions);
	}
	if(m_pInBuf)
		m_pInBuf->ReturnBuffer();
	if(m_pOutBuf)
		m_pOutBuf->ReturnBuffer();
	m_pInBuf	=	NULL;
	m_pOutBuf	=	NULL;
	CMultiXAppMsg	*pMsg	=	m_RequestMsgID.GetObject();
	if(pMsg)
	{
		pMsg->Reply(TpmErrMsgCanceled);
		delete	pMsg;
	}
}
void	CISO8583BackEndServerSession::OnISO8583Msg(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	//	Here we check for specific message codes(MTI values) and if we support the specific code, 
	//	we call a handler function, otherwise we reply with error
	switch(ISOMsg.VersionIndependentMTI())
	{
		case	CISO8583Msg::MTIAuthorizationMessageRequest	:
			OnAuthorizationRequest(Msg,ISOMsg);
			break;
		case	CISO8583Msg::MTIReversalMessageAdviceRepeat	:
		case	CISO8583Msg::MTIReversalMessageAdvice	:
			OnReversalAdvice(Msg,ISOMsg);
			break;
		case	CISO8583Msg::MTINetworkManagementMessageRequestOther	:
		case	CISO8583Msg::MTINetworkManagementMessageRequestAcquirer	:
		case	CISO8583Msg::MTINetworkManagementMessageRequestAcquirerRepeat	:
			OnNetworkManagementRequest(Msg,ISOMsg);
			break;
		default	:
			//	We	do not know this message, reply with error
			Msg.Reply(CISO8583Msg::MTINotSupported);
			break;
	}
}
void	CISO8583BackEndServerSession::OnReversalAdvice(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	std::string	Temp;
	byte_t	ElementIDs[]	=	{2,3,4,6,7,10,11,24,25,30,32,37,38,43,49,51,53,54,56,58,64};

	//	We make sure that no extra elements are found in the request
	CISO8583Msg::TValidationError	Error	=	ISOMsg.EnsureOnlyElementIDs(ElementIDs,sizeof(ElementIDs));
	if(Error	!=	CISO8583Msg::NoError)
	{
		Msg.Reply(Error);
		return;
	}

	//	Check that we have PAN
	Temp	=	ISOMsg.PAN();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::PANIsMissing);
		return;
	}

	//	Check that Processing Code exists and is valid.
	Temp	=	ISOMsg.ProcessingCode();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::ProcessingCodeIsMissing);
		return;
	}
	if(!(Temp	==	"000000"	||	Temp	==	"010000"	||	Temp	==	"090000"))
	{
		Msg.Reply(CISO8583Msg::InvalidProcessingCode);
		return;
	}

	//	Check the transaction amount for existance and that it does not exceede some Maximum
	Temp	=	ISOMsg.TransactionAmount();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionAmountIsMissing);
		return;
	}

	if(CISO8583Utilities::ToInt64(Temp)	>	99999999)
	{
		Msg.Reply(CISO8583Msg::TransactionAmountAboveMaximum);
		return;
	}

	// check Transaction Currency.
	Temp	=	ISOMsg.TransactionCurrencyCode();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionCurrencyIsMissing);
		return;
	}
	if(Temp	!=	"978")	//	Transaction amount is not in Euro
	{
		if(ISOMsg.CardholderBillingAmount()	==	"")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingAmountIsMissing);
			return;
		}
		if(ISOMsg.CardholderBillingCurrencyCode()	!=	"978")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingCurrencyIsNotEuro);
			return;
		}
		if(ISOMsg.CardholderBillingConversionRate()	==	"")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingConversionRateIsMissing);
			return;
		}
		// Lets validate that the conversion to Euro is done correctly.
		int64_t	TRAmount	=	CISO8583Utilities::ToInt64(ISOMsg.TransactionAmount());
		int64_t	BLAmount	=	CISO8583Utilities::ToInt64(ISOMsg.CardholderBillingAmount());
		int64_t	CRate			=	CISO8583Utilities::ToInt64(ISOMsg.CardholderBillingConversionRate());
		int64_t	Divisor	=	CISO8583Utilities::PowerOf10((unsigned	int)(CRate	/	10000000));
		TRAmount	*=	(CRate	%	10000000);
		TRAmount	/=	Divisor;
		if(TRAmount	!=	BLAmount)
		{
			Msg.Reply(CISO8583Msg::CardholderBillingAmountWrong);
			return;
		}
		TRAmount	*=	CRate;
	}	else //	we must make sure that IDs 6,10,51 are not there
	{
		if(!(ISOMsg.CardholderBillingAmount()	==	""	||
				ISOMsg.CardholderBillingCurrencyCode()	==	""	||
				ISOMsg.CardholderBillingConversionRate()	==	""))
		{
			Msg.Reply(CISO8583Msg::ExtraElementsFound);
			return;
		}
	}

	//	Check that we got STAN
	if(ISOMsg.STAN()	==	"")
	{
		Msg.Reply(CISO8583Msg::STANIsMissing);
		return;
	}


	//	Check that we got Function Code
	if(ISOMsg.FunctionCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::FunctionCodeIsMissing);
		return;
	}

	//	Check that we have Message Reason Code
	if(ISOMsg.MessageReasonCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::MessageReasonCodeIsMissing);
		return;
	}


	//	Check that we Original Amounts on Partail Reversal
	if(ISOMsg.OriginalAmounts()	==	""	&&	ISOMsg.FunctionCode()	==	"401")
	{
		Msg.Reply(CISO8583Msg::OriginalAmountsIsMissing);
		return;
	}	else
	if(ISOMsg.OriginalAmounts()	!=	""	&&	ISOMsg.FunctionCode()	!=	"401")
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}

	//	Check that we got Acquiring Institution Identification Code
	if(ISOMsg.AcquiringInstitutionIdentificationCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::AcquiringInstitutionIdentificationCodeIsMissing);
		return;
	}

	//	Check that we have Retrieval Reference Number
	if(ISOMsg.RRN()	==	"")
	{
		Msg.Reply(CISO8583Msg::RRNIsMissing);
		return;
	}

	//	Check that we have Approval Code
	if(ISOMsg.ApprovalCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::ApprovalCodeIsMissing);
		return;
	}


	//	check that we have Card Acceptor Name/Location
	if(ISOMsg.CardAcceptorNameLocation().Size()	==	0)	
	{
		Msg.Reply(CISO8583Msg::CardAcceptorNameLocationIsMissing);
		return;
	}


	//	check that we have Security Related Control Information, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.SecurityRelatedControlInformation()	==	"")	
	{
		Msg.Reply(CISO8583Msg::SecurityRelatedControlInformationIsMissing);
		return;
	}

	//	check that we have Additional amounts when processing code is "090000"
	if(ISOMsg.ProcessingCode()	==	"090000")	
	{
		if(ISOMsg.AdditionalAmounts().Size()	==	0)
		{
			Msg.Reply(CISO8583Msg::AdditionalAmountsIsMissing);
			return;
		}
	}	else if(ISOMsg.AdditionalAmounts().Size()	!=	0)
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}


	//	check that we have Original Data Elements
	if(ISOMsg.OriginalDataElements().Size()	==	0)
	{
		Msg.Reply(CISO8583Msg::OriginalDataElementsIsMissing);
		return;
	}

	//	check that we have Authorizing Agent Institution Identification Code
	if(ISOMsg.AuthorizingAgentInstitutionIdentificationCode().Size()	==	0)
	{
		Msg.Reply(CISO8583Msg::AuthorizingAgentInstitutionIdentificationCodeIsMissing);
		return;
	}

	//	check that we have MAC, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.MAC1()	==	"")	
	{
		Msg.Reply(CISO8583Msg::MAC1IsMissing);
		return;
	}

	/*
	After we finished validating the request, we need to decide if we authorize locally or we forward it to 
	the issuer for authorization
		*/
	if(AuthorizeLocally(ISOMsg))	//	in this example it is always true
	{
		//	We create a new ISO Message
		//	we will decline this message
		CISO8583Msg	Rsp;
		//	We will Dup field from the original message and add/ change the ones that are relevant for the response
		Rsp.SetMTI(CISO8583Msg::VersionDependentMTI(CISO8583Msg::ISO8583_2_1993,CISO8583Msg::MTIReversalMessageAdviceResponse));	//	this is a response
		Rsp.SetPAN(ISOMsg.PAN());
		Rsp.SetProcessingCode(ISOMsg.ProcessingCode());
		Rsp.SetTransactionAmount(ISOMsg.TransactionAmount());
		Rsp.SetCardholderBillingAmount(ISOMsg.CardholderBillingAmount());
		Rsp.SetTimes(time(NULL),true);	//	This will set transmission time
		Rsp.SetDateTimeLocal(ISOMsg.DateTimeLocal());
		Rsp.SetCardholderBillingConversionRate(ISOMsg.CardholderBillingConversionRate());
		Rsp.SetSTAN(ISOMsg.STAN());
		Rsp.SetAcquiringInstitutionIdentificationCode(ISOMsg.AcquiringInstitutionIdentificationCode());
		Rsp.SetRRN(ISOMsg.RRN());
		Rsp.SetActionCode(std::string("909"));	//	System Mulfunction
		Rsp.SetTransactionCurrencyCode(ISOMsg.TransactionCurrencyCode());
		Rsp.SetCardholderBillingCurrencyCode(ISOMsg.CardholderBillingCurrencyCode());
		Rsp.SetSecurityRelatedControlInformation(std::string("00000007000001FFFF")); // this is a dummy value, real value should be set based on Keys.
		Rsp.SetOriginalDataElements(ISOMsg.OriginalDataElements());
		Rsp.SetMAC1(std::string("0123456789ABCDEF"));	//	dummy value, should be based on keys
		CISO8583Msg::TValidationError	Error	=	Rsp.ToISO();
		if(Error	!=	CISO8583Msg::NoError)
			Throw();
		// we are done preparing the response, we reply with an MTI = CISO8583Msg::MTIAuthorizationMessageResponse
		// and the handling is complete.
		Msg.Reply(Rsp.MTI(),Rsp.ISOBuffer(),Rsp.ISOBufferSize());
	}	else
	{
		/*
			we get here if we need some external processing on behalf of this request, so we forward the request
			with a different message code (so MultiXTpm will not forward it back to us). In this case we just set
			the msg code to the same MTI but with CISO8583Msg::ISO8583_Private version (in MultiXTpm we must configure this message code !!!).
			When we forward a request, we do not block for a response, when a response arrives, we get it thru
			the event "OnDataReplyReceived". in order to be able to associate the response with the original msg,
			we pass a pointer to the original message in the "Context" parameter of the "Send" function, and when
			"OnDataReplyReceived" is called, we retrieve this pointer by using "SavedContext()" in the Original msg.
			Since MultiX automatically destroys messages it forwards to the application, we must call "Keep()" on
			the received message, to prevent it from being destroyed, in that case, when the reply is received, we need
			to destroy the original message ourselves.

			When we play the role of an acquirer gateway, we usualy get the request from the POS terminal, do validation required
			and maybe modify some data, and then forward the message to the issuer gateway, in our case, the forward will be to a process
			in our system, that will decide to which issuer to forward to, based on that, will use a specific connection to the spcific
			issuer gateway.
		*/
		if(Owner()->MyAcquirerID().length()	==	0)
			Msg.Reply(ErrUnableToForwardMsg);

		/*
			Before we forward the request, we need to set 3 fields to identify the message as a one sent from this process :
			BMP 11 - STAN,BMP 12 - Times, BMP 32 - Our Acquirer ID
			When we receive the response from the remote gateway/issuer, we must replace these fields again to the orignal values
			that the sender set before sending the request to us
		*/
		ISOMsg.SetTimes(time(NULL));
		ISOMsg.SetSTAN(Owner()->GetNextSTAN());
		ISOMsg.SetAcquiringInstitutionIdentificationCode(Owner()->MyAcquirerID());
		ISOMsg.ToISO();

		if(Send(CISO8583Msg::VersionDependentMTI(CISO8583Msg::ISO8583_Private,Msg.MsgCode()),ISOMsg.ISOBuffer(),ISOMsg.ISOBufferSize(),CMultiXAppMsg::FlagNotifyAll,0,0,&Msg))
			Msg.Keep();
		else
			Msg.Reply(ErrUnableToForwardMsg);
	}
}
/*!
	This function is called when an authorization request is received from an acquirer gateway or from POS terminal. 
	When we receive such a message, we do all syntax checking, and if everything is OK, we might process the request locally
	or we might forward it to remote Issuer Gateway for authorization.
	In this implementation we assume local processing, so we reply we with a fixed response, but the logic
	to forward the request and handling the response is there.
*/
void	CISO8583BackEndServerSession::OnAuthorizationRequest(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	std::string	Temp;
	byte_t	ElementIDs[]	=	{2,3,4,6,7,10,11,12,14,22,23,24,26,32,35,37,41,42,43,49,51,52,53,54,55,59,64};

	//	We make sure that no extra elements are found in the request
	CISO8583Msg::TValidationError	Error	=	ISOMsg.EnsureOnlyElementIDs(ElementIDs,sizeof(ElementIDs));
	if(Error	!=	CISO8583Msg::NoError)
	{
		Msg.Reply(Error);
		return;
	}

	//	Check that we have PAN
	Temp	=	ISOMsg.PAN();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::PANIsMissing);
		return;
	}

	//	Check that Processing Code exists and is valid.
	Temp	=	ISOMsg.ProcessingCode();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::ProcessingCodeIsMissing);
		return;
	}
	if(!(Temp	==	"000000"	||	Temp	==	"010000"	||	Temp	==	"090000"))
	{
		Msg.Reply(CISO8583Msg::InvalidProcessingCode);
		return;
	}

	//	Check the transaction amount for existance and that it does not exceede some Maximum
	Temp	=	ISOMsg.TransactionAmount();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionAmountIsMissing);
		return;
	}

	if(CISO8583Utilities::ToInt64(Temp)	>	99999999)
	{
		Msg.Reply(CISO8583Msg::TransactionAmountAboveMaximum);
		return;
	}

	// check Transaction Currency.
	Temp	=	ISOMsg.TransactionCurrencyCode();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionCurrencyIsMissing);
		return;
	}
	if(Temp	!=	"978")	//	Transaction amount is not in Euro
	{
		if(ISOMsg.CardholderBillingAmount()	==	"")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingAmountIsMissing);
			return;
		}
		if(ISOMsg.CardholderBillingCurrencyCode()	!=	"978")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingCurrencyIsNotEuro);
			return;
		}
		if(ISOMsg.CardholderBillingConversionRate()	==	"")
		{
			Msg.Reply(CISO8583Msg::CardholderBillingConversionRateIsMissing);
			return;
		}
		// Lets validate that the conversion to Euro is done correctly.
		int64_t	TRAmount	=	CISO8583Utilities::ToInt64(ISOMsg.TransactionAmount());
		int64_t	BLAmount	=	CISO8583Utilities::ToInt64(ISOMsg.CardholderBillingAmount());
		int64_t	CRate			=	CISO8583Utilities::ToInt64(ISOMsg.CardholderBillingConversionRate());
		int64_t	Divisor	=	CISO8583Utilities::PowerOf10((unsigned	int)(CRate	/	10000000));
		TRAmount	*=	(CRate	%	10000000);
		TRAmount	/=	Divisor;
		if(TRAmount	!=	BLAmount)
		{
			Msg.Reply(CISO8583Msg::CardholderBillingAmountWrong);
			return;
		}
		TRAmount	*=	CRate;
	}	else //	we must make sure that IDs 6,10,51 are not there
	{
		if(!(ISOMsg.CardholderBillingAmount()	==	""	||
				ISOMsg.CardholderBillingCurrencyCode()	==	""	||
				ISOMsg.CardholderBillingConversionRate()	==	""))
		{
			Msg.Reply(CISO8583Msg::ExtraElementsFound);
			return;
		}
	}

	//	Check that we got STAN
	if(ISOMsg.STAN()	==	"")
	{
		Msg.Reply(CISO8583Msg::STANIsMissing);
		return;
	}

	//	Check that we got Local Date and Time
	if(ISOMsg.DateTimeLocal()	==	"")
	{
		Msg.Reply(CISO8583Msg::DateTimeLocalIsMissing);
		return;
	}

	//	Check that we got Expiration Date when track 2 is missing
	if(ISOMsg.ExpirationDate()	==	""	&&	ISOMsg.Track2Data()	==	"")
	{
		Msg.Reply(CISO8583Msg::ExpirationDateIsMissing);
		return;
	}

	//	Check that we got POS Data Code
	if(ISOMsg.POSDataCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::POSDataCodeIsMissing);
		return;
	}

	CISO8583ElementValue	ICCData	=	ISOMsg.ICCData();

	if(ISOMsg.CardSequenceNumber()	==	"")
	{
		// lets make sure that it is not an ICC transaction and if it is, lets make sure we do not have tag 0x5f34
		if(ISOMsg.POSDataCode()[6]	==	'5')	//	ICC Transaction
		{
			if(ICCData.Size()	>	0	&&	CISO8583Utilities::TLVDataHasTag((const	byte_t	*)ICCData.RawData(),ICCData.Size(),0x5f34))
			{
				Msg.Reply(CISO8583Msg::CardSequenceNumberIsMissing);
				return;
			}
		}
	}	else
	{
		// lets make sure that IT IS an ICC transaction and we have tag 0x5f34
		if(!(ISOMsg.POSDataCode()[6]	==	'5'	&&	ICCData.Size()	>	0	&&	CISO8583Utilities::TLVDataHasTag((const	byte_t	*)ICCData.RawData(),ICCData.Size(),0x5f34)))
		{
			Msg.Reply(CISO8583Msg::ExtraElementsFound);
			return;
		}
	}

	//	Check that we got Function Code
	if(ISOMsg.FunctionCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::FunctionCodeIsMissing);
		return;
	}

	//	Check that we got Card Acceptor Business Code
	if(ISOMsg.CardAcceptorBusinessCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::CardAcceptorBusinessCodeIsMissing);
		return;
	}

	//	Check that we got Acquiring Institution Identification Code
	if(ISOMsg.AcquiringInstitutionIdentificationCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::AcquiringInstitutionIdentificationCodeIsMissing);
		return;
	}

	//	Check that we have Track2 if not E Commerce
	if(ISOMsg.Track2Data()	==	""	&&	ISOMsg.POSDataCode()[7]	!=	'U')
	{
		Msg.Reply(CISO8583Msg::Track2DataIsMissing);
		return;
	}

	//	Check that we have Retrieval Reference Number
	if(ISOMsg.RRN()	==	"")
	{
		Msg.Reply(CISO8583Msg::RRNIsMissing);
		return;
	}

	//	check that we have Card Acceptor Terminal Identification
	if(ISOMsg.CardAcceptorTerminalIdentification().Size()	==	0)	
	{
		Msg.Reply(CISO8583Msg::TerminalIDIsMissing);
		return;
	}

	//	check that we have Card Acceptor Identification Code
	if(ISOMsg.CardAcceptorIdentificationCode().Size()	==	0)	
	{
		Msg.Reply(CISO8583Msg::CardAcceptorIdentificationCodeIsMissing);
		return;
	}

	//	check that we have Card Acceptor Name/Location
	if(ISOMsg.CardAcceptorNameLocation().Size()	==	0)	
	{
		Msg.Reply(CISO8583Msg::CardAcceptorNameLocationIsMissing);
		return;
	}

	//	check that we have PIN , if required
	if((ISOMsg.POSDataCode()[6]	==	'2'	&&	ISOMsg.POSDataCode()[7]	!=	'5')	||	// magnetic stripe + PIN
		(ISOMsg.POSDataCode()[6]	==	'5'	&&	ISOMsg.POSDataCode()[7]	==	'1'))	// chip + PIN
	{
		if(ISOMsg.PIN()	==	"")
		{
			Msg.Reply(CISO8583Msg::PINIsMissing);
			return;
		}
	}	else if(ISOMsg.PIN()	!=	"")
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}

	//	check that we have Security Related Control Information, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.SecurityRelatedControlInformation()	==	"")	
	{
		Msg.Reply(CISO8583Msg::SecurityRelatedControlInformationIsMissing);
		return;
	}

	//	check that we have Additional amounts when processing code is "090000"
	if(ISOMsg.ProcessingCode()	==	"090000")	
	{
		if(ISOMsg.AdditionalAmounts().Size()	==	0)
		{
			Msg.Reply(CISO8583Msg::AdditionalAmountsIsMissing);
			return;
		}
	}	else if(ISOMsg.AdditionalAmounts().Size()	!=	0)
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}

	//	check that we have ICC Data for chip transactions
	if(ISOMsg.POSDataCode()[6]	==	'5')	
	{
		if(ICCData.Size()	==	0)
		{
			Msg.Reply(CISO8583Msg::ICCDataIsMissing);
			return;
		}
	}	else if(ICCData.Size()	!=	0)
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}

	//	check that we have Additional Private Data when E-Commerce transaction
	if(ISOMsg.POSDataCode()[7]	==	'U')	
	{
		if(ISOMsg.AdditionalPrivateData().Size()	==	0)
		{
			Msg.Reply(CISO8583Msg::AdditionalPrivateDataIsMissing);
			return;
		}
	}	else if(ISOMsg.AdditionalPrivateData().Size()	!=	0)
	{
		Msg.Reply(CISO8583Msg::ExtraElementsFound);
		return;
	}


	//	check that we have MAC, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.MAC1()	==	"")	
	{
		Msg.Reply(CISO8583Msg::MAC1IsMissing);
		return;
	}

	/*
	After we finished validating the request, we need to decide if we authorize locally or we forward it to 
	the issuer for authorization
		*/
	if(AuthorizeLocally(ISOMsg))	//	in this example it is always true
	{
		//	We create a new ISO Message
		//	we will decline this message
		CISO8583Msg	Rsp;
		//	We will Dup field from the original message and add/ change the ones that are relevant for the response
		Rsp.SetMTI(ISOMsg.MTI() +	10);	//	this is a response
		Rsp.SetPAN(ISOMsg.PAN());
		Rsp.SetProcessingCode(ISOMsg.ProcessingCode());
		Rsp.SetTransactionAmount(ISOMsg.TransactionAmount());
		Rsp.SetCardholderBillingAmount(ISOMsg.CardholderBillingAmount());
		Rsp.SetTimes(time(NULL),true);	//	This will set, transmission times
		Rsp.SetDateTimeLocal(ISOMsg.DateTimeLocal());
		Rsp.SetCardholderBillingConversionRate(ISOMsg.CardholderBillingConversionRate());
		Rsp.SetSTAN(ISOMsg.STAN());
		Rsp.SetOriginalAmounts(ISOMsg.TransactionAmount()+"000000000000");	//	this is adecline response, we include the original amounts
		Rsp.SetAcquiringInstitutionIdentificationCode(ISOMsg.AcquiringInstitutionIdentificationCode());
		Rsp.SetRRN(ISOMsg.RRN());
		Rsp.SetActionCode(std::string("909"));	//	System Mulfunction
		Rsp.SetCardAcceptorTerminalIdentification(ISOMsg.CardAcceptorTerminalIdentification());
		Rsp.SetCardAcceptorIdentificationCode(ISOMsg.CardAcceptorIdentificationCode());
		Rsp.SetTransactionCurrencyCode(ISOMsg.TransactionCurrencyCode());
		Rsp.SetCardholderBillingCurrencyCode(ISOMsg.CardholderBillingCurrencyCode());
		Rsp.SetSecurityRelatedControlInformation(std::string("00000007000001FFFF")); // this is a dummy value, real value should be set based on Keys.
		Rsp.SetICCData(ISOMsg.ICCData());	//	not mandatory
		Rsp.SetAuthorizingAgentInstitutionIdentificationCode(CISO8583ElementValue("12345678901",CISO8583ElementValue::ISO8583ElementTypeNumeric));	//	dummy value
		Rsp.SetMAC1(std::string("0123456789ABCDEF"));	//	dummy value, should be based on keys
		CISO8583Msg::TValidationError	Error	=	Rsp.ToISO();
		if(Error	!=	CISO8583Msg::NoError)
			Throw();
		/*
			we are done preparing the response, we reply with an MTI = CISO8583Msg::MTIAuthorizationMessageResponse
			and the handling is complete.
		*/

		Msg.Reply(Rsp.MTI(),Rsp.ISOBuffer(),Rsp.ISOBufferSize());
	}	else
	{
		/*
			we get here if we need someone else to authorize the request. In that case we need to forward the request to our Acquirer Gateway Front End.
			To do that we need to forward it with a different message code, so MultiXTpm will not forward it back to us. The way we do the message code change
			is by setting the MTI version field to CISO8583Msg::ISO8583_Private. When the message is received by our Gateway process, it will revert back
			to CISO8583Msg::ISO8583_2_1993 and forward it on.
			
			When we forward a request, we do not block for a response, when a response arrives, we get it thru
			the event "OnDataReplyReceived". in order to be able to associate the response with the original msg,
			we pass a pointer to the original message in the "Context" parameter of the "Send" function, and when
			"OnDataReplyReceived" is called, we retrieve this pointer by using "SavedContext()" in the Original msg we sent.
			Since MultiX automatically destroys messages it forwards to the application, we must call "Keep()" on
			the received message, to prevent it from being destroyed, in that case, when the reply is received, we need
			to destroy the original message ourselves.

			When we play the role of an acquirer gateway, usualy we get the request from the POS terminal, do validation required
			and maybe modify some data, and then forward the message to the issuer gateway, in our case, the forward will be to a process
			in our system, that will decide to which issuer to forward to, based on that, will use a specific connection to the spcific
			issuer gateway.
		*/
		/*
			Before we forward the request, we need to set 3 fields to identify the message as a one sent from this process :
			BMP 11 - STAN,
			BMP 12 - Times,
			BMP 32 - Our Acquirer ID

			When we receive the response from the remote gateway/issuer, we must replace these fields again to the orignal values
			that the sender set before sending the request to us
		*/
		ISOMsg.SetTimes(time(NULL));
		ISOMsg.SetSTAN(Owner()->GetNextSTAN());
		ISOMsg.SetAcquiringInstitutionIdentificationCode(Owner()->MyAcquirerID());
		ISOMsg.ToISO();

		if(Send(CISO8583Msg::VersionDependentMTI(CISO8583Msg::ISO8583_Private,Msg.MsgCode()),ISOMsg.ISOBuffer(),ISOMsg.ISOBufferSize(),CMultiXAppMsg::FlagNotifyAll,0,0,&Msg))
			Msg.Keep();
		else
			Msg.Reply(ErrUnableToForwardMsg);
	}
}
void	CISO8583BackEndServerSession::OnNetworkManagementRequest(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	std::string	Temp;
	byte_t	ElementIDs[]	=	{1,11,12,24,25,53,93,94,128};

	//	We make sure that no extra elements are found in the request
	CISO8583Msg::TValidationError	Error	=	ISOMsg.EnsureOnlyElementIDs(ElementIDs,sizeof(ElementIDs));
	if(Error	!=	CISO8583Msg::NoError)
	{
		Msg.Reply(Error);
		return;
	}


	//	Check that we got STAN
	if(ISOMsg.STAN()	==	"")
	{
		Msg.Reply(CISO8583Msg::STANIsMissing);
		return;
	}

	//	Check that we got Local Date and Time
	if(ISOMsg.DateTimeLocal()	==	"")
	{
		Msg.Reply(CISO8583Msg::DateTimeLocalIsMissing);
		return;
	}

	//	Check that we got Function Code
	if(ISOMsg.FunctionCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::FunctionCodeIsMissing);
		return;
	}

	//	Check that Function Code has a valid value
	if(!(ISOMsg.FunctionCode()	==	"801"	||	ISOMsg.FunctionCode()	==	"802"	||	ISOMsg.FunctionCode()	==	"831"))
	{
		Msg.Reply(CISO8583Msg::FunctionCodeIsInvalid);
		return;
	}

	//	Check that we have Message Reason Code for sign-off and echo-test
	if(ISOMsg.MessageReasonCode()	==	""	&&	ISOMsg.FunctionCode()	!=	"801")
	{
		Msg.Reply(CISO8583Msg::MessageReasonCodeIsMissing);
		return;
	}


	//	check that we have Security Related Control Information, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.SecurityRelatedControlInformation()	==	"")	
	{
		Msg.Reply(CISO8583Msg::SecurityRelatedControlInformationIsMissing);
		return;
	}

	//	Check that we have Transaction Destination Institution Identification Code
	if(ISOMsg.TransactionDestinationInstitutionIdentificationCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionDestinationInstitutionIdentificationCodeIsMissing);
		return;
	}

	//	Check that we have Transaction Originator Institution Identification Code
	if(ISOMsg.TransactionOriginatorInstitutionIdentificationCode()	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionOriginatorInstitutionIdentificationCodeIsMissing);
		return;
	}

	//	check that we have MAC2, we do not check the values because we do not have the Keys
	// in this implementation.
	if(ISOMsg.MAC2()	==	"")	
	{
		Msg.Reply(CISO8583Msg::MAC2IsMissing);
		return;
	}

	/*
	We get here after we validated that all required fields exist in the request.
	Now we will process the request based on the specific Function Code.
	First We Build the response Message
	*/

	//	We create a new ISO Message
	CISO8583Msg	Rsp;
	//	We will Dup field from the original message and add/ change the ones that are relevant for the response
	Rsp.SetMTI(ISOMsg.MTI() +	10);	//	this is a response
	Rsp.SetTimes(time(NULL),true);	//	This will set transmission times
	Rsp.SetDateTimeLocal(ISOMsg.DateTimeLocal());
	Rsp.SetSTAN(ISOMsg.STAN());
	Rsp.SetActionCode(std::string("800"));	//	Accepted
	Rsp.SetSecurityRelatedControlInformation(std::string("00000007000001FFFF")); // this is a dummy value, real value should be set based on Keys.
	Rsp.SetTransactionDestinationInstitutionIdentificationCode(ISOMsg.TransactionDestinationInstitutionIdentificationCode());
	Rsp.SetTransactionOriginatorInstitutionIdentificationCode(ISOMsg.TransactionOriginatorInstitutionIdentificationCode());
	Rsp.SetMAC2(std::string("0123456789ABCDEF"));	//	dummy value, should be based on keys

	if(ISOMsg.FunctionCode()	==	"801")	//	this is a Sign On request
	{
		/*
		At this point we would go to the DB and verify that the Sender (Transaction Destination Institution Identification Code) is
		a valid one. In our example we assume it is OK so we accept the request.

		Since the request arrived in the context of a specific MultiX Session, we can assume that all future requests from the specific
		Remote gateway will arrive to this session. So we will keep the remote gateway ID in a local member variable and specify
		that it is signed on, when we receive other requests on that session, we can check the remote gateway and it status.
		for example, an Authorization request from a gateway that  not sign-On will allways be rejected.
		*/

		m_bRemoteGateway	=	true;
		m_bSignedON	=	true;
		m_RemoteGatewayID	=	ISOMsg.TransactionDestinationInstitutionIdentificationCode();
	}	else	if(ISOMsg.FunctionCode()	==	"802")	//	this is a Sign Off request
	{
		/*
		we check that the session is with a remote gateway and that it is signed on, if so, we sign it off and clear the ID.
		When the actual connection with the remote gateway is terminated, the Gateway process in our system will destroy the session
		and the session object in this process will be deleted also.
		*/
		
		if(!(m_bRemoteGateway	&&	m_bSignedON	&&	m_RemoteGatewayID	==	ISOMsg.TransactionDestinationInstitutionIdentificationCode()))	//	invalid request
		{
			Msg.Reply(CISO8583Msg::InvalidRequest);
			return;
		}
		m_bRemoteGateway	=	false;
		m_bSignedON	=	false;
		m_RemoteGatewayID	=	"";
	}	else	if(ISOMsg.FunctionCode()	==	"831")	//	this is a Echo-test
	{
		/*
		we check that the session is with a remote gateway and that it is signed on.
		*/
		
		if(!(m_bRemoteGateway	&&	m_bSignedON	&&	m_RemoteGatewayID	==	ISOMsg.TransactionDestinationInstitutionIdentificationCode()))	//	invalid request
		{
			Msg.Reply(CISO8583Msg::InvalidRequest);
			return;
		}
	}	else
	{
		Msg.Reply(CISO8583Msg::InvalidRequest);
		return;
	}
	Error	=	Rsp.ToISO();
	if(Error	!=	CISO8583Msg::NoError)
		Throw();
	Msg.Reply(Rsp.MTI(),Rsp.ISOBuffer(),Rsp.ISOBufferSize());
}
void	CMultiXProcess::OnTpmConfigData(CMultiXAppMsg &AppMsg)
{
    CMultiXMsg	Msg(*Owner());
    std::string	ParamName;
    std::string	ParamValue;
    Msg.Append(AppMsg.AppData(),AppMsg.AppDataSize());

    CMultiXTpmConfiguredLink	Link;
    while(Msg.Next())
    {
        switch(Msg.GetItemCode())
        {

        case	CMultiXTpmCtrlMsg::DebugLevelItemCode	:
            Msg.GetItemData(Owner()->DebugLevel());
            break;
        case	CMultiXTpmCtrlMsg::AdditionalConfigTextItemCode	:
            Msg.GetItemData(Owner()->AdditionalConfigText());
            break;
        case	CMultiXTpmCtrlMsg::DefaultSendTimeoutItemCode	:
            Msg.GetItemData(Owner()->DefaultSendTimeout());
            break;
        case	CMultiXTpmCtrlMsg::StartLinkItemCode	:
            break;
        case	CMultiXTpmCtrlMsg::LinkIDItemCode	:
            Msg.GetItemData(Link.LinkID);
            break;
        case	CMultiXTpmCtrlMsg::LinkDescriptionItemCode	:
            Msg.GetItemData(Link.Description);
            break;
        case	CMultiXTpmCtrlMsg::LinkTypeItemCode	:
            Msg.GetItemData(Link.LinkType);
            break;
        case	CMultiXTpmCtrlMsg::OpenModeItemCode	:
            Msg.GetItemData(Link.OpenMode);
            break;
        case	CMultiXTpmCtrlMsg::IsRawItemCode	:
            Msg.GetItemData(Link.bRaw);
            break;
        case	CMultiXTpmCtrlMsg::LocalAddressItemCode	:
            Msg.GetItemData(Link.LocalAddress);
            break;
        case	CMultiXTpmCtrlMsg::LocalPortItemCode	:
            Msg.GetItemData(Link.LocalPort);
            break;
        case	CMultiXTpmCtrlMsg::RemoteAddressItemCode	:
            Msg.GetItemData(Link.RemoteAddress);
            break;
        case	CMultiXTpmCtrlMsg::RemotePortItemCode	:
            Msg.GetItemData(Link.RemotePort);
            break;
        case	CMultiXTpmCtrlMsg::EndLinkItemCode	:
            if(Link.LinkType	==	MultiXLinkTypeTcp	&&
                    Link.OpenMode	==	MultiXOpenModeServer	&&
                    Link.bRaw			==	false)
            {
                CMultiXTpmLink	*TpmLink	=	new	CMultiXTpmLink(Link.ConfigParams,false,MultiXOpenModeServer);
                Owner()->AddLink(TpmLink);
                TpmLink->Listen(Link.LocalPort,Link.LocalAddress);
            }	else
            {
                Owner()->OnTpmConfiguredLink(Link);
            }
            break;
        case	CMultiXTpmCtrlMsg::StartParamItemCode	:
            ParamName.clear();
            ParamValue.clear();
            break;
        case	CMultiXTpmCtrlMsg::ParamNameItemCode	:
            Msg.GetItemData(ParamName);
            break;
        case	CMultiXTpmCtrlMsg::ParamValueItemCode	:
            Msg.GetItemData(ParamValue);
            break;
        case	CMultiXTpmCtrlMsg::EndProcessParamItemCode	:
            if(ParamName.length()	>	0)
                Owner()->AddConfigParam(ParamName,ParamValue);
            break;
        case	CMultiXTpmCtrlMsg::EndLinkParamItemCode	:
            if(ParamName.length()	>	0)
                Link.ConfigParams[ParamName]	=	ParamValue;
            break;


        }
    }
    AppMsg.Reply(MultiXNoError);
    Owner()->OnTpmConfigCompleted();
}
bool CMultiXProcess::OnAppMsg(CMultiXMsg &Msg)
{
    if(!ReceiverEnabled()	||	!SenderEnabled())
        return	false;
    CMultiXAppMsg	*OrgMsg	=	NULL;
    CMultiXSession	*Session	=	NULL;
    CMultiXAppMsg	*AppMsg	=	CreateNewAppMsg(&Msg);
    //if(m_MsgCount++	==	1)
//		m_LastPrintTime	=	Owner()->GetMilliClock();
    m_LastMsgRecvMilliClock	=	Owner()->GetMilliClock();

    AddToMsgQueue(m_pInQueue,AppMsg);

    if(!AppMsg->ResponseRequired())
    {
        if(AppMsg->NotifyAny())
            AppMsg->Reply(MultiXNoError);
    }

    if(AppMsg->IsResponse())
    {
        OrgMsg	=	AppMsg->ReceiverMsgID().GetObject();
        if(OrgMsg	!=	NULL)
        {
            Session	=	Owner()->FindSession(OrgMsg->SessionID());
            OrgMsg->m_bKeep	=	false;
            OrgMsg->ID().RemoveObject();

            if(AppMsg->AppDataSize()	||	OrgMsg->ResponseRequired())
            {
                if(Session)
                {
                    if(AppMsg->IsCtrlMsgFromTpm())
                        Session->OnDataReplyFromTpmReceived(*AppMsg,*OrgMsg);
                    else
                        Session->OnDataReplyReceivedNV(*AppMsg,*OrgMsg);
                }	else
                {
                    if(AppMsg->IsCtrlMsgFromTpm())
                        OnDataReplyFromTpmReceived(*AppMsg,*OrgMsg);
                    else
                        OnDataReplyReceived(*AppMsg,*OrgMsg);
                }
            }	else if(AppMsg->Error())
            {
                if(OrgMsg->NotifyError())
                {
                    if(Session)
                    {
                        if(AppMsg->IsCtrlMsgFromTpm())
                            Session->OnSendMsgToTpmFailed(*OrgMsg);
                        else
                            Session->OnSendMsgFailedNV(*OrgMsg);
                    }	else
                    {
                        if(AppMsg->IsCtrlMsgFromTpm())
                            OnSendMsgToTpmFailed(*OrgMsg);
                        else
                            OnSendMsgFailed(*OrgMsg);
                    }
                }
            }	else
            {
                if(OrgMsg->NotifySuccess())
                {
                    if(Session)
                    {
                        if(AppMsg->IsCtrlMsgFromTpm())
                            Session->OnSendMsgToTpmCompleted(*OrgMsg);
                        else
                            Session->OnSendMsgCompletedNV(*OrgMsg);
                    }	else
                    {
                        if(AppMsg->IsCtrlMsgFromTpm())
                            OnSendMsgToTpmCompleted(*OrgMsg);
                        else
                            OnSendMsgCompleted(*OrgMsg);
                    }
                }
            }
        }	else	//	it is a response but the original does not exist
        {
            AppMsg->Reply(TpmErrUnableToForwardMsg);
        }
    }	else
    {
        Session	=	Owner()->FindSession(AppMsg->SessionID(),true);
        if(Session)
        {
            if(AppMsg->IsCtrlMsgFromTpm())
                Session->OnNewMsgFromTpm(*AppMsg);
            else
                Session->OnNewMsgNV(*AppMsg);
        }	else
        {
            if(AppMsg->IsCtrlMsgFromTpm())
                OnNewMsgFromTpm(*AppMsg);
            else
                OnNewMsg(*AppMsg);
        }
        if(AppMsg->ResponseRequired()	&&	!(AppMsg->ReplySent()	||	AppMsg->m_bKeep))
            Throw();
    }

    if(!(AppMsg->ReplySent()	||	AppMsg->m_bKeep))
    {
        if(AppMsg->ResponseRequired())
            Throw();
        else if(AppMsg->NotifyAny())
            AppMsg->Reply(MultiXNoError);
    }

    if(OrgMsg	&&	!OrgMsg->m_bKeep)
        delete	OrgMsg;
    if(!AppMsg->m_bKeep)
        delete	AppMsg;
    return	true;
}
void CMultiXProcess::OnProcessSuspend(CMultiXAppMsg &AppMsg)
{
    AppMsg.Reply(MultiXNoError);
    Owner()->OnProcessSuspend();
}
/*!
	This function is called when a Sale request is received from an acquirer gateway or from POS terminal. 
	When we receive such a message, we do all syntax checking, and if everything is OK, we process the request locally.
*/
void	CISO8583AuthorizerServerSession::OnSaleRequest(CMultiXAppMsg &Msg,CISO8583Msg	&ISOMsg)
{
	std::string	Temp;
	double Amount;

	//	Check that we have PAN
	if(ISOMsg.PAN().length()	==	0)
	{
		Msg.Reply(CISO8583Msg::PANIsMissing);
		return;
	}

	//	Check the transaction amount for existance.
	Temp	=	ISOMsg.TransactionAmount();
	if(Temp	==	"")
	{
		Msg.Reply(CISO8583Msg::TransactionAmountIsMissing);
		return;
	}

	//	We save the amount in decimal format for later checking against the database
	Amount	=	(double)CISO8583Utilities::ToInt64(Temp)/100;

	//	Check that we got STAN
	if(ISOMsg.STAN().length()	==	0)
	{
		Msg.Reply(CISO8583Msg::STANIsMissing);
		return;
	}

	int	MerchantAccount	=	(int)CISO8583Utilities::ToInt64(ISOMsg.CardAcceptorIdentificationCode().StringData());
	if(!IsValidMerchant(MerchantAccount))
	{
		Msg.Reply(CISO8583Msg::RequestRejected);
		return;
	}

	if(PANToIssuerCode(ISOMsg.PAN().c_str())	!=	Owner()->OurIssuerIdentificationCode())
	{
		//	This is a foriegn card, we check that we support the issuer
		mysqlpp::Query Query = Owner()->DBConn().query();
		Query << "select * from customer_account where AccountNumber = %0";
		Query.parse();
		std::vector<customer_account>	DataSet;
		Query.storein(DataSet,CISO8583Utilities::ToString(PANToIssuerAccount(ISOMsg.PAN().c_str())).c_str());
		if(DataSet.empty())
		{
			//	we have not found the record in the database. so we try forwarding the request to the issuer
			Msg.Reply(CISO8583Msg::RequestRejected);
		}	else
		{
			ForwardToIssuer(PANToOurAccountAtIssuer(ISOMsg.PAN().c_str()),Msg,ISOMsg);
		}
		return;
	}

	/*
		After we finish all validation, we query the database for the card number and the balance
		We retrieve the record from the database based on the PAN specified in the request
	*/

  mysqlpp::Query Query = Owner()->DBConn().query();
	Query << "select * from customer_account where CardNumber = %0q";
	Query.parse();
	std::vector<customer_account>	DataSet;
	Query.storein(DataSet,ISOMsg.PAN().c_str());
	if(DataSet.empty())
	{
		Msg.Reply(CISO8583Msg::RequestRejected);
		return;
	}

	//	Lets make sure that we have enough money in the account

	if(DataSet[0].CurrentBalance	<	Amount)
	{
		Msg.Reply(CISO8583Msg::RequestRejected);
		return;
	}

	if(!UpdateAuthorizedSale(DataSet[0].AccountNumber,MerchantAccount,DataSet[0].CardNumber,Amount))
	{
		Msg.Reply(CISO8583Msg::RequestRejected);
		return;
	}

	//	we can approve the authorization now.
	/* here we set balance in the response - if required 

	char	BalanceString[200];
	sprintf(BalanceString,"0001000%c%s",DataSet[0].CurrentBalance < 0 ? 'D' : 'C',CISO8583Utilities::ToString((int64_t)(DataSet[0].CurrentBalance * 100),12).c_str());
	CISO8583ElementValue	BalanceValue(BalanceString,CISO8583ElementValue::ISO8583ElementTypeAlphaNumeric);
	ISOMsg.SetAdditionalAmounts(BalanceValue);
	
	*/


	ISOMsg.SetMTI(ISOMsg.MTI() +	10);	//	this is a response
	ISOMsg.SetTimes(time(NULL),true);	//	This will set, transaction and transmission times
	ISOMsg.SetDateTimeLocal(ISOMsg.DateTimeLocal());
	if(ISOMsg.Version()	==	CISO8583Msg::ISO8583_1_1987)
		ISOMsg.SetActionCode(std::string("00"));
	else
		ISOMsg.SetActionCode(std::string("000"));
	CISO8583Msg::TValidationError	Error	=	ISOMsg.ToISO();
	if(Error	!=	CISO8583Msg::NoError)
		Throw();
	/*
		we are done preparing the response, we reply with an MTI = CISO8583Msg::MTIAuthorizationMessageResponse
		and the handling is complete.
	*/

	Msg.Reply(ISOMsg.MTI(),ISOMsg.ISOBuffer(),ISOMsg.ISOBufferSize());
}
void CMultiXProcess::OnProcessResume(CMultiXAppMsg &AppMsg)
{
    AppMsg.Reply(MultiXNoError);
    Owner()->OnProcessResume();
}
/*!
	the only replies we expect here is for messages we explicitly send to Tpm, reguardless of any session or link.
*/
void CISO8583IssuerGatewayWSFEProcess::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg, CMultiXAppMsg &OriginalMsg)
{
	//	by default we reply any message, in order to free resources.
	ReplyMsg.Reply();
}
//!	see CMultiXSession::OnDataReplyReceived
void	CISO8583AuthorizerServerSession::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg,CMultiXAppMsg &ForwardedMsg)
{
	DebugPrint(3,"Data Reply Received\n");

	switch(CISO8583Msg::VersionIndependentMTI(ForwardedMsg.MsgCode()))	//	this will give us version independent MTI
	{
	case	CISO8583Msg::MTIAuthorizationMessageRequest	:
	case	CISO8583Msg::MTIFinancialMessageRequest	:
		{
			CMultiXAppMsg	*AcquirerMsg	=	(CMultiXAppMsg	*)ForwardedMsg.SavedContext();
			if(ReplyMsg.AppDataSize()	==	0)
			{
				AcquirerMsg->Reply(ReplyMsg.Error());
				delete	AcquirerMsg;
				break;
			}

			CISO8583Msg	AcquirerISO;
			CISO8583Msg	ReplyISO;
			AcquirerISO.FromISO((const	byte_t	*)AcquirerMsg->AppData(),AcquirerMsg->AppDataSize());
			ReplyISO.FromISO((const	byte_t	*)ReplyMsg.AppData(),ReplyMsg.AppDataSize());


			/*
				before we send the reply, we need to check if it is MTI 200 and if the response is positive, if so	:
				1. we debit the issuer account for the sales amount + commission. in this sample we derive the issuer account from the PAN.
				2. we credit our own account for these amounts
				3. we write transactions log.
			*/

			if(CISO8583Msg::VersionIndependentMTI(AcquirerMsg->MsgCode())	==	CISO8583Msg::MTIFinancialMessageRequest)
			{
				if(CISO8583Utilities::ToInt64(ReplyISO.ActionCode())	==	0)
				{
					double	Amount	=	(double)CISO8583Utilities::ToInt64(ReplyISO.TransactionAmount())/100;
					int	IssuerAccount	=	PANToIssuerAccount(AcquirerISO.PAN());
					int	MerchantAccount	=	(int)CISO8583Utilities::ToInt64(AcquirerISO.CardAcceptorIdentificationCode().StringData());
					if(!UpdateAuthorizedSale(IssuerAccount,MerchantAccount,AcquirerISO.PAN(),Amount))
					{
						AcquirerMsg->Reply(CISO8583Msg::RequestRejected);
		//				SendReversalToIssuer(ReplyISO); not implemented
						delete	AcquirerMsg;
						return;
					}
				}
			}	else	if(CISO8583Msg::VersionIndependentMTI(AcquirerMsg->MsgCode())	==	CISO8583Msg::MTIAuthorizationMessageRequest)
			{
				int	IssuerAccount	=	PANToIssuerAccount(AcquirerISO.PAN());
				double	Amount	=	(double)CISO8583Utilities::ToInt64(AcquirerISO.TransactionAmount())/100;

				mysqlpp::Transaction	Tran(Owner()->DBConn());
				mysqlpp::Query Query = Owner()->DBConn().query();
				transactions_log	Log;
				Log.Time			=	TomysqlppDateTime(time(NULL));
				Log.AccountNumber	=	IssuerAccount;
				Log.CardNumber		=	AcquirerISO.PAN();
				Log.Action				=	11;	//	Query
				Log.Amount				=	Amount;
				Log.NewBalance		=	0;
				Query.insert(Log);
				Query.execute();
				Tran.commit();
			}

			/*
				We get here when we receive a response for a message we forwarded before. In this case we will forward the response back to
				the originator, we do not care for the content, we forward it back almost AS IS except for few fields that
				we need to restore because changed them before we forwarded the message, the fields are:

				BMP 7 - Set Transmission time
				BMP 11 - restore sender STAN
				BMP 12	-	Restore sender Date and Time Local
				BMP 32 - Restore senders Acquiring Institution Identification Code
			*/
			/*
				In order to restore old values, we need to restore the message we received originaly from the acquirer or from the pos terminal.
				this message is saved in the SaveContext() of the ForwardedMsg.
			*/



			ReplyISO.SetTimes(time(NULL),true);
			ReplyISO.SetSTAN(AcquirerISO.STAN());
			ReplyISO.SetDateTimeLocal(AcquirerISO.DateTimeLocal());
			ReplyISO.SetAcquiringInstitutionIdentificationCode(AcquirerISO.AcquiringInstitutionIdentificationCode());
			ReplyISO.ToISO();


			AcquirerMsg->Reply(AcquirerMsg->MsgCode(),
				ReplyISO.ISOBuffer(),
				ReplyISO.ISOBufferSize(),0,0,0,0,0,ReplyMsg.Error());

			delete	AcquirerMsg;	//	WE MUST DELETE THE MESSAGE BECAUSE WE CALLED "Keep()" BEFORE WE FORWARDED IT.




		}
		break;
	}



	
	/*	
		we reply the ReplyMsg for the case that the process that replied to us expects to receive a notification that we
		received the reply, if it does not wait for the reply, no reply is sent.
	*/
	ReplyMsg.Reply();	
}
/*!
	the only replies we expect here is for messages we explicitly send to Tpm, reguardless of any session or link.
*/
void CMultiXWSServerProcess::OnDataReplyReceived(CMultiXAppMsg &ReplyMsg, CMultiXAppMsg &OriginalMsg)
{
	//	by default we reply any message, in order to free resources.
	ReplyMsg.Reply();
}
CMultiXLayer::EventHandlerReturn	CMultiXWSStream::OnNewRequestMessage(CMultiXEvent	*Event)
{
	CMultiXWSStreamEvent	*Ev	=	(CMultiXWSStreamEvent	*)Event;
	//	if we have a valid message saved, we reply it with error - this will happen only if we have not replied to it before
	//	we will also delete the message, since we do not need it any more.
	CMultiXAppMsg	*pMsg	=	m_RequestMsgID.GetObject();
	if(pMsg	!=	NULL)
	{
		pMsg->Reply(TpmErrMsgCanceled);
		delete	pMsg;
	}

	m_RequestMsgID	=	Ev->m_MsgID;
	pMsg	=	m_RequestMsgID.GetObject();
	if(pMsg	==	NULL)
		return	CMultiXLayer::DeleteEvent;

	bool	bExit	=	false;


	while(!bExit)	//	we do a "while" here just so we can fall thru the end of function and delete the message object
	{
		bExit	=	true;
		if(!pMsg->IsWebServiceCall())
		{
			pMsg->Reply(TpmErrMsgNotSupported);
			break;
		}
		std::string	FuncName;
		std::string	DLLName;
		EXPORTABLE_STL::map<int32_t,std::string>::iterator	It	=	m_MsgCodeToFunctionMap.find(pMsg->MsgCode());
		if(It	!=	m_MsgCodeToFunctionMap.end())
		{
			DLLName	=	It->second.substr(0,It->second.find("|||"));
			FuncName	=	It->second.substr(It->second.find("|||")+3);
		}
		else
		{
			DLLName	=	pMsg->WSDllFile();
			FuncName	=	pMsg->WSDllFunction();
		}


		try
		{
			InitgSoap(DLLName);
		}	catch(...)
		{
			pMsg->Reply(WSErrgSoapDllNotFound);
			break;
		}
		TgSoapServiceFunction	Func	=	(TgSoapServiceFunction)GetProcAddress(m_pFunctions->m_pDLLHandle,FuncName.c_str());

		if(Func	==	NULL)
		{
			pMsg->Reply(WSErrServiceFunctionNotFound);
			break;
		}	else	if(It	==	m_MsgCodeToFunctionMap.end())
		{
			m_MsgCodeToFunctionMap[pMsg->MsgCode()]	=	DLLName	+	"|||"	+ pMsg->WSDllFunction();
		}

		ResetData();
		if(m_pInBuf)
			m_pInBuf->ReturnBuffer();
		m_pInBuf	=	pMsg->Owner()->Owner()->AllocateBuffer(pMsg->AppData(),pMsg->AppDataSize());
		int	Error	=	Func(gSoap());
		if(OutBuf().Length()	>	0)
		{
			pMsg->Reply(pMsg->MsgCode(),OutBuf());
		}	else
		{
			pMsg->Reply(Error);
		}
	}
	if(pMsg)
		delete	pMsg;

	m_RequestMsgID.Init();
	return	CMultiXLayer::DeleteEvent;
}