/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/

#include "SctsDevManSession.h"
#include "SctsDevManDMAccount.h"

#ifdef __SCTS_USING_SCTS__
#include "SctsDevManTestEngine.h"
#endif

/*****************************************************************
UI callbacks
******************************************************************/
SctsComponentUICallbacks componentUIC={0,0,0,0};

void sctsSetComponentUIC(SctsComponentUICallbacks *uic)
{
	if (uic)
		sctsMemcpy(&componentUIC,uic,sizeof(SctsComponentUICallbacks));
	else
		sctsMemset(&componentUIC,0,sizeof(SctsComponentUICallbacks));
}
/*****************************************************************/

#ifdef __SCTS_USING_RTK__

/******************************************************************
RTK Callback functions : 
These functions create the appropriate command object and then call
the session objects handler.
******************************************************************/
#define VERIFYWBXMLCONV(X)\
	if ((X)!=SML_ERR_OK)\
	{\
		sctsStatusLog("Error encountered during WBXML conversion...");\
		smlTerminateInstance(((SctsDMSession *)pSession)->wbxmlConverterContext);\
		SctsErrorLog::AppendError("Error encountered during WBXML conversion, message will not be logged.");\
		((SctsDMSession *)pSession)->wbxmlConverterContext=0;\
		((SctsDMSession *)pSession)->wbxmlConverting=false;\
	}

Ret_t sctsRTKHandleAddCmd(InstanceID_t id,VoidPtr_t pSession,SmlAddPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlAddCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Add...\r\n");
	SctsAdd cmd(pCmd);
	((SctsDMSession *)pSession)->HandleAdd(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleAlertCmd(InstanceID_t id,VoidPtr_t pSession,SmlAlertPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlAlertCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Alert...\r\n");
	SctsAlert cmd(pCmd);
	((SctsDMSession *)pSession)->HandleAlert(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleCopyCmd(InstanceID_t id,VoidPtr_t pSession,SmlCopyPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlCopyCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Copy...\r\n");
	SctsCopy cmd(pCmd);
	((SctsDMSession *)pSession)->HandleCopy(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleDeleteCmd(InstanceID_t id,VoidPtr_t pSession,SmlDeletePtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlDeleteCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Delete...\r\n");
	SctsDelete cmd(pCmd);
	((SctsDMSession *)pSession)->HandleDelete(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleExecCmd(InstanceID_t id,VoidPtr_t pSession,SmlExecPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlExecCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Exec...\r\n");
	SctsExec cmd(pCmd);
	((SctsDMSession *)pSession)->HandleExec(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleGetCmd(InstanceID_t id,VoidPtr_t pSession,SmlGetPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlGetCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Get...\r\n");
	SctsGet cmd(pCmd);
	((SctsDMSession *)pSession)->HandleGet(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandlePutCmd(InstanceID_t id,VoidPtr_t pSession,SmlPutPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlPutCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Put...\r\n");
	SctsPut cmd(pCmd);
	((SctsDMSession *)pSession)->HandlePut(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleMapCmd(InstanceID_t id,VoidPtr_t pSession,SmlMapPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlMapCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Map...\r\n");
	SctsMap cmd(pCmd);
	((SctsDMSession *)pSession)->HandleMap(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleResultsCmd(InstanceID_t id,VoidPtr_t pSession,SmlResultsPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlResultsCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Results...\r\n");
	SctsResults cmd(pCmd);
	((SctsDMSession *)pSession)->HandleResults(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleSearchCmd(InstanceID_t id,VoidPtr_t pSession,SmlSearchPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlSearchCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Search...\r\n");
	SctsSearch cmd(pCmd);
	((SctsDMSession *)pSession)->HandleSearch(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleStatusCmd(InstanceID_t id,VoidPtr_t pSession,SmlStatusPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlStatusCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Status...\r\n");
	SctsStatus cmd(pCmd);
	((SctsDMSession *)pSession)->HandleStatus(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleReplaceCmd(InstanceID_t id,VoidPtr_t pSession,SmlReplacePtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlReplaceCmd(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Replace...\r\n");
	SctsReplace cmd(pCmd);
	((SctsDMSession *)pSession)->HandleReplace(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleStartMessage(InstanceID_t id,VoidPtr_t pSession,SmlSyncHdrPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		VERIFYWBXMLCONV(smlStartMessage(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd));
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing SyncHdr...\r\n");
	SctsSyncHdr cmd(pCmd);
	((SctsDMSession *)pSession)->HandleStartMessage(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleEndMessage(InstanceID_t id,VoidPtr_t pSession,Boolean_t final)
{
	SctsDMSession *session=(SctsDMSession *)pSession;
	if (session->wbxmlConverterContext) 
	{
		long filePos;
		long bufferLen;
		char *buffer;
		char ch;
		SctsTree<SctsCommand *>::Item *command;
		session->wbxmlConverting=false;
		smlEndMessage(session->wbxmlConverterContext,final);
		/* Lock RTK's workspace buffer */
		SCTSASSERT(smlLockReadBuffer(session->wbxmlConverterContext,(MemPtr_t *)&buffer,&bufferLen)==SML_ERR_OK);
		/* Write to log file */
		ch=buffer[bufferLen-1];
		buffer[bufferLen-1]=0;
		fputc(1,session->logFileInf);
		filePos=ftell(session->logFile);
		fwrite(&filePos,sizeof(long),1,session->logFileInf);
		fprintf(session->logFile,"<Message><TransportHdr><![CDATA[%s]]></TransportHdr>%s%c</Message>",session->transport->GetTransportHdr(),sctsStrstr(buffer,"<SyncML"),ch);
		filePos=ftell(session->logFile)-filePos;
		fwrite(&filePos,sizeof(long),1,session->logFileInf);
		buffer[bufferLen-1]=ch;
		/* Unlock buffer */
		SCTSASSERT(smlUnlockReadBuffer(session->wbxmlConverterContext,bufferLen)==SML_ERR_OK);
		/* Build pending status */
		if (session->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
		command=session->outgoingMessage->syncBody.GetRootItem();
		command->data->Build(session->wbxmlConverterContext);
		command=session->outgoingMessage->syncBody.GetFirstChildItem(command);
		while (command)
		{
			if (command->data) command->data->Build(session->wbxmlConverterContext);
			command=session->outgoingMessage->syncBody.GetNextSiblingItem(command);
		}
	}
	sctsStatusLog("Processing End Message...\r\n");
	((SctsDMSession *)pSession)->HandleEndMessage(final?true:false);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleStartSync(InstanceID_t id,VoidPtr_t pSession,SmlSyncPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlStartSync(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Start Sync...\r\n");
	SctsSync cmd(pCmd);
	((SctsDMSession *)pSession)->HandleStartSync(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleEndSync(InstanceID_t id,VoidPtr_t pSession)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlEndSync(((SctsDMSession *)pSession)->wbxmlConverterContext);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing End Sync...\r\n");
	((SctsDMSession *)pSession)->HandleEndSync();
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleStartAtomic(InstanceID_t id,VoidPtr_t pSession,SmlAtomicPtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlStartAtomic(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Atomic...\r\n");
	SctsAtomic cmd(pCmd);
	((SctsDMSession *)pSession)->HandleStartAtomic(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleEndAtomic (InstanceID_t id,VoidPtr_t pSession)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlEndAtomic(((SctsDMSession *)pSession)->wbxmlConverterContext);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing End Atomic...\r\n");
	((SctsDMSession *)pSession)->HandleEndAtomic();
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleStartSequence(InstanceID_t id,VoidPtr_t pSession,SmlSequencePtr_t pCmd)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlStartSequence(((SctsDMSession *)pSession)->wbxmlConverterContext,pCmd);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing Start Sequence...\r\n");
	SctsSequence cmd(pCmd);
	((SctsDMSession *)pSession)->HandleStartSequence(cmd);
	return SML_ERR_OK;
}

Ret_t sctsRTKHandleEndSequence (InstanceID_t id,VoidPtr_t pSession)
{
	if (((SctsDMSession *)pSession)->wbxmlConverterContext) 
	{
		smlEndSequence(((SctsDMSession *)pSession)->wbxmlConverterContext);
		if (((SctsDMSession *)pSession)->processError!=PROCESS_ERR_OK) return SML_ERR_OK;
	}
	sctsStatusLog("Processing End Sequence...\r\n");
	((SctsDMSession *)pSession)->HandleEndSequence();
	return SML_ERR_OK;
}

/* Callaback definitions */
SmlCallbacks_t sctsRTKCallbackFunctions  =
{
	sctsRTKHandleStartMessage,
	sctsRTKHandleEndMessage,
	sctsRTKHandleStartSync,
	sctsRTKHandleEndSync,
	sctsRTKHandleStartAtomic,
	sctsRTKHandleEndAtomic,
	sctsRTKHandleStartSequence,
	sctsRTKHandleEndSequence,
	sctsRTKHandleAddCmd,
	sctsRTKHandleAlertCmd,
	sctsRTKHandleDeleteCmd,
	sctsRTKHandleGetCmd,
	sctsRTKHandlePutCmd,
	sctsRTKHandleMapCmd,
	sctsRTKHandleResultsCmd,
	sctsRTKHandleStatusCmd,
	sctsRTKHandleReplaceCmd,
	sctsRTKHandleCopyCmd,
	sctsRTKHandleExecCmd,
	sctsRTKHandleSearchCmd,
	0,
	0
};

#endif

/*************************************************************
SctsDMResults Class 
**************************************************************/

SctsDMResults::SctsDMResults()
{
	cmdRef=source=type=0;
	msgRef=0;
	pcData=0;
	format=DMFORMAT_CHR;
	prop=DMPROP_NONE;
}

SctsDMResults::~SctsDMResults()
{
	sctsFree(cmdRef);
	sctsFree(source);
	sctsFree(type);
	if (pcData)
	{
		pcData->Clear();
		delete pcData;
	}
}

/*************************************************************
SctsDMGenericAlert Class 
**************************************************************/

SctsDMGenericAlert::SctsDMGenericAlert()
{
	source=0;
    type=0;
	format=0;
    correlator=0;
	data=0;
    mark=0;
}

SctsDMGenericAlert::~SctsDMGenericAlert()
{
	if (source) sctsFree(source);
	if (type) sctsFree(type);
    if (format) sctsFree(format);
	if (correlator) sctsFree(correlator);
	if (data) sctsFree(data);
    if (mark) sctsFree(mark);
}

/******************************************************************
SctsDMSession Definition
******************************************************************/

SctsDMSession::SctsDMSession(SctsEncoding _encoding,void (*_CallBack)(SctsDMSession *)) : SctsThread(SESSION_THREAD)
{
    sessionType = DMSESSION_NORMAL;
	userID=0;
	password=0;
	transport=0;
	nextSyncHdrStatus=0;
    largeObjectCmd=SCTS_NONECMD;
	largeObjectBufferSize=0;
	largeObjectBufferUsedSize=0;
	largeObjectSize=0;
	largeObjectBuffer=0;
	largeObjectTURI=0;
	largeObjectSURI=0;
	largeObjectType=0;
	largeObjectFormat=0;
	largeObjectCmdRef=0;
	largeObjectMsgRef=0;
	outAuth=inAuth=0; 
	tempDevice=0;
	encoding=_encoding;
	processError=PROCESS_ERR_NONE;
	outgoingMessage=0;
	sessionID=0;
	processMsgID=0;
	recvSyncHdrStatus=sentSyncHdrStatus=0;
	sessionContext=0;
	wbxmlConverterContext=0;
	itemsPerCommand=1;
	chalForHMAC=false;
	/* V1.1.1 */
	supportsLrgObj=false;
#ifdef __SCTS_USING_SCTS__
	testGroup=0;
#endif
	
/* RTK specific : create session context */
#ifdef __SCTS_USING_RTK__
	SmlInstanceOptions_t options;
	char buffer[20];
	/* Set Instance options */
	if (encoding==XML)
		options.encoding=SML_XML;
	else
		options.encoding=SML_WBXML;
	options.workspaceName=sctsInt2Str((int)this,buffer,16);
	options.workspaceSize=MAX_WORKSPACE_SIZE;
	/* Initialize the RTK instance */
	SCTSASSERT(smlInitInstance(&sctsRTKCallbackFunctions,&options,this,&sessionContext)==SML_ERR_OK);
	/* WBXML Converter */
	if (encoding==WBXML)
	{
		SmlCallbacks_t callbacks;
		sctsMemset(&callbacks,0,sizeof(SmlCallbacks_t));
		options.encoding=SML_XML;
		sctsStrcat(options.workspaceName,"x2w");
		SCTSASSERT(smlInitInstance(&callbacks,&options,this,&wbxmlConverterContext)==SML_ERR_OK);
	}
#endif
	sourcePkgCount=0;
	targetPkgCount=0;
	currentCmdID=1;
	currentMsgID=1;
	/* Postponement of status discrepency : message ID expected in received Status->MsgRef */
	messageQueueID=1;

	/* Create the log file */
	char *timeStamp=sctsGetTimeStamp(true);
	sprintf(logFileName,"_%ld_%x.log",sctsGetTime(),this);
	logFileInf=fopen(logFileName,"wb");
	SCTSASSERT(logFileInf);
	logFileName[sctsStrlen(logFileName)-4]=0;
	sctsStrcat(logFileName,".xml");
	logFile=fopen(logFileName,"wb");
	SCTSASSERT(logFile);
	fprintf(logFile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?><SCTSLog>");
	fprintf(logFile,"<!-- Created on %c%c/%c%c/%c%c%c%c at %c%c:%c%c:%c%c -->",
																		timeStamp[4],
																		timeStamp[5],
																		timeStamp[6],
																		timeStamp[7],
																		timeStamp[0],
																		timeStamp[1],
																		timeStamp[2],
																		timeStamp[3],
																		timeStamp[9],
																		timeStamp[10],
																		timeStamp[11],
																		timeStamp[12],
																		timeStamp[13],
																		timeStamp[14]);
	/* Note : the componentUIC callback must be called before setting the callback since
	   the callback sent in the constructor has a higher priority */
	/* UI Callback */
	CallBack=0;
	uiCallbackData=0;
	uiCallback=0;
	uiData=0;
	if (_CallBack) CallBack=_CallBack;
}

SctsDMSession::~SctsDMSession()
{
	fputc(0,logFileInf);
	fprintf(logFile,"</SCTSLog>");
	fclose(logFileInf);
	fclose(logFile);
	if (tempDevice)
	{
		char buffer[200];
		int pos;
		if (tempDevice->IsServerDevice())
			sprintf(buffer,"%s",((SctsDMServerDevice *)tempDevice)->userID);
		else
			sprintf(buffer,"%s",((SctsDMClientDevice *)tempDevice)->devID);
		while (buffer[(pos=sctsStrcspn(buffer,"/\\:*?\"<>|\0"))]) buffer[pos]='_';
		sctsStrcat(buffer,logFileName);
		rename(logFileName,buffer);
		logFileName[sctsStrlen(logFileName)-4]=0;
		sctsStrcat(logFileName,".log");
		buffer[sctsStrlen(buffer)-4]=0;
		sctsStrcat(buffer,".log");
		rename(logFileName,buffer);
		sctsStrcpy(logFileName,buffer);
		tempDevice->Unlock();
	}
	else
	{
		logFileName[sctsStrlen(logFileName)-4]=0;
		sctsStrcat(logFileName,".log");
	}
	while (messageQueue.size())
	{
		delete messageQueue.front();
		messageQueue.pop_front();
	}
	if (nextSyncHdrStatus) delete nextSyncHdrStatus;
	if (largeObjectType) sctsFree(largeObjectType);
	if (largeObjectFormat) sctsFree(largeObjectFormat);
	if (largeObjectBuffer) sctsFree(largeObjectBuffer);
	if (outgoingMessage) delete outgoingMessage;
	if (sessionID) sctsFree(sessionID);
#ifdef __SCTS_USING_RTK__	
	if (sessionContext) smlTerminateInstance(sessionContext);
	if (wbxmlConverterContext) smlTerminateInstance(wbxmlConverterContext);
#endif
	if (CallBack) (*CallBack)(this);
	if (componentUIC.removeSession) (*componentUIC.removeSession)(this);
	if (errorLog) delete errorLog;
	if (transport) delete transport;
}

bool SctsDMSession::RecvMessage()
{
	long filePos;
	long bufferLen;
	char *buffer;
	char ch;
	XptHmacInfoPtr_t macInfo=0;
	sctsStatusLog("Receiving Message...\r\n");
#ifdef __SCTS_USING_RTK__
	/* Lock RTK's workspace buffer */
	SCTSASSERT(smlLockWriteBuffer(sessionContext,(MemPtr_t *)&buffer,&bufferLen)==SML_ERR_OK);
	/* Get data from transport layer */
	if (!transport->RecvMessage(buffer,(int &)bufferLen,&macInfo) || bufferLen==-1) return false;
	/* Check if session timedout */
	if (bufferLen)
	{
		/* Unlock buffer */
		SCTSASSERT(smlUnlockWriteBuffer(sessionContext,bufferLen)==SML_ERR_OK);
		/* Write to log file */
		if (encoding==XML)
		{
			ch=buffer[bufferLen-1];
			buffer[bufferLen-1]=0;
			fputc(1,logFileInf);
			filePos=ftell(logFile);
			fwrite(&filePos,sizeof(long),1,logFileInf);
			fprintf(logFile,"<Message><TransportHdr><![CDATA[%s]]></TransportHdr>%s%c</Message>",transport->GetTransportHdr(),sctsStrstr(buffer,"<SyncML"),ch);
			filePos=ftell(logFile)-filePos;
			fwrite(&filePos,sizeof(long),1,logFileInf);
			buffer[bufferLen-1]=ch;
		}
		if (macInfo && macInfo->username && IsServerSession() && !GetDevice())
		{
			SctsDMServerDevice *device=SctsDMDevice::GetServerDevice((char *)macInfo->username);
			/* Setup up the incoming auth if it is HMAC */
			if (device)
			{
				char *userID=0;
				SctsDMNode *node=device->FindDMNode(device->dmAccPath);
				SctsDMNode *tempNode;
				/* Set the session type */
				sessionType=device->sessionType;
				/* Find the account node */
				((SctsDMServerSession *)this)->device=device;
				device->accountNode=0;
				if (!node || !node->child) return true;
				for (node=node->child;node;node=node->next)
				{
					if (!(tempNode=device->FindDMNode("./ServerID",node))) continue;
					if (sctsStrcmp((char *)tempNode->data,SctsDMDevice::GetSctsServerID())) continue;
                    /*
                     * Change to support DM 1.2 DMAcc node. 
                     */
                    SctsDMDevice::MulDynAccItem dynAccItem = device->accounts[node->name];
                    std::string uIDPath = dynAccItem.subAppAuthClient + "/AAuthName";
					tempNode = device->FindDMNode((char *)uIDPath.c_str(), node);
					if (!tempNode) return true;
					userID=(char *)tempNode->data;
					break;
				}
				if (!userID) return true;	
				device->accountNode=node;
				if (device->GetAuthType(true)==AUTH_HMAC)
				{
					unsigned char *nonce;
					unsigned int size;
					if (!(nonce=device->GetNonce(true,size)))
					{
						nonce=(unsigned char *)&nonce;
						size=sizeof(unsigned char *);
					}
					inAuth=new SctsAuthHMAC(nonce,size);
					device->SetNonce(true,0,0);
					((SctsAuthHMAC *)inAuth)->VerifyHMACDigest(userID,device->GetPassword(true),buffer,(char *)macInfo->mac,bufferLen);
				}
				return true;
			}
            else
            {
                inAuth=new SctsAuthHMAC;
            }
		}
		if (GetDevice() && inAuth && inAuth->GetType()==AUTH_HMAC)
			((SctsAuthHMAC *)inAuth)->VerifyHMACDigest(IsServerSession()?userID:GetDevice()->serverID,GetDevice()->GetPassword(true),buffer,macInfo?(char *)macInfo->mac:0,bufferLen);
		return true;
	}
	processError=PROCESS_ERR_STOP;
	SctsErrorLog::AppendError("Session timed out/Connection lost/No data received.");
	return false;
#endif
}

bool SctsDMSession::SendMessage()
{
	long filePos;
	long bufferLen;
	char *buffer;
	char *tempBuffer;
	char ch;
	XptHmacInfo_t macInfo={0,0,0};
	sctsStatusLog("Sending Message...\r\n");
#ifdef __SCTS_USING_RTK__
	/* Lock RTK's workspace buffer */
	SCTSASSERT(smlLockReadBuffer(sessionContext,(MemPtr_t *)&buffer,&bufferLen)==SML_ERR_OK);
	/* Send data to transport layer */
	tempBuffer=(char *)sctsMalloc(bufferLen);
	sctsMemcpy(tempBuffer,buffer,bufferLen);
	if (outAuth && outAuth->GetType()==AUTH_HMAC)
	{
		macInfo.username=IsServerSession()?GetDevice()->serverID:userID;
		macInfo.mac=((SctsAuthHMAC *)outAuth)->BuildHMACDigest((char *)macInfo.username,GetDevice()->GetPassword(false),buffer,bufferLen);
	}
	/* Raj */
	if (!transport->SendMessage(tempBuffer,bufferLen,macInfo.username?&macInfo:0)) 
	{
		if (macInfo.mac) sctsFree((char *)macInfo.mac);
		sctsFree(tempBuffer);
		return false;
	}
	if (macInfo.mac) sctsFree((char *)macInfo.mac);
	sctsFree(tempBuffer);
	/* Write to log file */
	if (encoding==XML)
	{
		ch=buffer[bufferLen-1];
		buffer[bufferLen-1]=0;
		fputc(1,logFileInf);
		filePos=ftell(logFile);
		fwrite(&filePos,sizeof(long),1,logFileInf);
		fprintf(logFile,"<Message><TransportHdr><![CDATA[%s]]></TransportHdr>%s%c</Message>",transport->GetTransportHdr(),sctsStrstr(buffer,"<SyncML"),ch);
		filePos=ftell(logFile)-filePos;
		fwrite(&filePos,sizeof(long),1,logFileInf);
		buffer[bufferLen-1]=ch;
	}
	/* Unlock buffer */
	SCTSASSERT(smlUnlockReadBuffer(sessionContext,bufferLen)==SML_ERR_OK);
	if (wbxmlConverterContext)
	{
		/* Lock RTK's workspace buffer */
		SCTSASSERT(smlLockReadBuffer(wbxmlConverterContext,(MemPtr_t *)&buffer,&bufferLen)==SML_ERR_OK);
		/* Write to log file */
		ch=buffer[bufferLen-1];
		buffer[bufferLen-1]=0;
		fputc(1,logFileInf);
		filePos=ftell(logFile);
		fwrite(&filePos,sizeof(long),1,logFileInf);
		fprintf(logFile,"<Message><TransportHdr><![CDATA[%s]]></TransportHdr>%s%c</Message>",transport->GetTransportHdr(),sctsStrstr(buffer,"<SyncML"),ch);
		filePos=ftell(logFile)-filePos;
		fwrite(&filePos,sizeof(long),1,logFileInf);
		buffer[bufferLen-1]=ch;
		/* Unlock buffer */
		SCTSASSERT(smlUnlockReadBuffer(wbxmlConverterContext,bufferLen)==SML_ERR_OK);
	}
	return true;
#endif

}

/* Creates an error node using the command cmdID and command name */
void SctsDMSession::CreateErrorNode(SctsCommand& cmd)
{
	SctsPcdata tempPcdata;
	char nodeDesc[100]="";
	if (processMsgID)
		sprintf(nodeDesc,"Msg ID : %d, ",processMsgID);
	if (cmd.GetCommandID(tempPcdata))
	{
		sctsStrcat(nodeDesc,"Command ID : ");
		sctsStrcat(nodeDesc,(char *)tempPcdata);
	}
	SctsErrorLog::OpenNode(sctsCommandStrings[cmd.GetType()],nodeDesc);
}

/* Processes the TargetRefs and StatusRefs of a status command */
bool SctsDMSession::HandleStatusRefs(SctsStatus& cmd,SctsItemList& itemList,bool& multipleStatus)
{
	SctsSourceRefList sourceRefs;
	SctsTargetRefList targetRefs;
	SctsSourceRefList sourceRefsIt;
	SctsTargetRefList targetRefsIt;
	SctsItem item;
	SctsTargetSource tempTS;
	SctsPcdata tempPcdata;
	char errorMsg[300]="";
	bool recvdAll=true;
	int itemCnt=0;
	int itemID=0;
	cmd.GetTargetRefList(targetRefs);
	cmd.GetSourceRefList(sourceRefs);
	if (!targetRefs && !sourceRefs) 
	{
		/* UI callback */
		if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);
		multipleStatus=false;
		return true;
	}
	if (!itemList)
	{
		SctsErrorLog::AppendError("Received Status with SourceRefs/TargetRefs for a command that has no items. Representation protocol (5.4.1) : The SourceRef and TargetRef elements are used to identify the Item, which the status code applies to.");
		return false;
	}
	itemList.GetData(item);
	for (;item;itemList.GetNextData(item))
	{
		SctsPcdata sourceRef;
		SctsPcdata targetRef;
		SctsPcdata source;
		SctsPcdata target;
		if (item.GetSource(tempTS)) tempTS.GetLocURI(source);
		if (item.GetTarget(tempTS)) tempTS.GetLocURI(target);
		++itemID;
		/* If both are null implies that status for this item has already been received */
		if (!source && !target) 
		{
			recvdAll=false;
			continue;
		}
		++itemCnt;
		/* Find sourceRef */
		if ((bool)source && sourceRefs)
		{
			cmd.GetSourceRefList(sourceRefsIt);
			sourceRefsIt.GetData(sourceRef);
			for (;(bool)sourceRef && !(sourceRef==source);sourceRefsIt.GetNextData(sourceRef));
		}
		/* Find targetRef */
		if ((bool)target && targetRefs)
		{
			cmd.GetTargetRefList(targetRefsIt);
			targetRefsIt.GetData(targetRef);
			for (;(bool)targetRef && !(targetRef==target);targetRefsIt.GetNextData(targetRef));
		}
		if (!targetRef && !sourceRef)
		{
			recvdAll=false;
			continue;
		}
		if ((bool)source && (bool)target && (bool)targetRef && !sourceRef)
		{
			sprintf(errorMsg,"Received only TargetRef for Item (Source : %s, Target : %s). Representation protocol (5.4.1) : If the Item elements of the command associated with the Status command has a Source element, the value MUST be copied into the SourceRef of the Status command.",(char *)source,(char *)target);
			break;
		}
		if ((bool)source && (bool)target && (bool)sourceRef && !targetRef)
		{
			sprintf(errorMsg,"Received only SourceRef for Item (Source : %s, Target : %s). Representation protocol (5.4.1) : If the Item elements of the command associated with the Status command has a Target element, the value MUST be copied into the TargetRef of the Status command.",(char *)source,(char *)target);
			break;
		}
		/* UI Callback */
		if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,itemID,false);

		/* Cleanup */
		if (sourceRef) 
		{
			item.SetSource(0,0);
			sourceRef.Clear();
		}
		if (targetRef) 
		{
			item.SetTarget(0,0);
			targetRef.Clear();
		}
	}
	/* Check if there are any remaining sourceRefs/targetRefs */
	if (!errorMsg[0])
	{
		for (sourceRefs.GetData(tempPcdata);(bool)tempPcdata;sourceRefs.GetNextData(tempPcdata))
		{
			if (!tempPcdata.IsUndef())
			{
				sprintf(errorMsg,"Item with SourceRef : %s, already received Status or doesn't exist.",(char *)tempPcdata);
				break;
			}
		}
		for (targetRefs.GetData(tempPcdata);(bool)tempPcdata;targetRefs.GetNextData(tempPcdata))
		{
			if (!tempPcdata.IsUndef())
			{
				sprintf(errorMsg,"Item with TargetRef : %s, already received Status or doesn't exist.",(char *)tempPcdata);
				break;
			}
		}
	}
	if (errorMsg[0])
	{
		SctsErrorLog::AppendError(errorMsg);
		return false;
	}
	if (itemCnt==1) return true;
	if (recvdAll)
	{
		SctsErrorLog::AppendError("TargetRefs/SourceRefs unnecessary. Representation protocol (5.4.1) : If the request status code is applicable to the entire list of items specified in the associated request command, then the SourceRef/TargetRef element type MUST NOT be specified.");
		return false;
	}
	multipleStatus=true;
	return true;
}

bool SctsDMSession::LargeObjectRecvChunk(bool firstChunk,int &statusCode,SctsCommandType cmdType,SctsItem &item,SctsMeta &meta)
{
	char error[200];
	SctsPcdata tempPcdata;
	SctsTargetSource tempTS;
	int size;
	/* Check if it is the correct item */
	if (largeObjectSize && (largeObjectCmd!=cmdType || 
		!(item.GetSource(tempTS).GetLocURI(tempPcdata)==largeObjectSURI) ||
		!(item.GetTarget(tempTS).GetLocURI(tempPcdata)==largeObjectTURI)))
	{
		LargeObjectSendAlert();
		SctsErrorLog::AppendError("Large object delivery : Wrong object.");
		return false;
	}
	statusCode=0;
	item.GetData(tempPcdata);
	if (firstChunk)
	{
		size=meta.GetSize();
		if (size==-1) size=item.GetMeta(meta).GetSize();
		if (size==-1)
		{
			statusCode=412;
			sprintf(error,"Large object delivery : Meta->Size/Item->Meta->Size element missing.");
		}
		if (!statusCode && (largeObjectBufferSize && size>largeObjectBufferSize))
		{
			statusCode=413;
			sprintf(error,"Large object delivery : size of object greater than the maxobjsize (object size : %d, maxobjsize : %d).",size,largeObjectBufferSize);
		}
		if (!statusCode && tempPcdata.GetLength()>=size)
		{
			statusCode=424;
			sprintf(error,"Large object delivery : size of data chunk greater than/equal to specified object size (object size : %d, chunk size : %d).",size,tempPcdata.GetLength());
		}
		if (statusCode)
		{
			SctsErrorLog::AppendError(error);
			LargeObjectClear();
			return false;
		}
		
		/* Allocate the Large Object Buffer based on the size*/
		largeObjectBuffer=(char *)sctsMalloc(size+1);
		/* Set large object variables */
		sctsMemcpy(largeObjectBuffer,(char *)tempPcdata,tempPcdata.GetLength());
		largeObjectBufferUsedSize=tempPcdata.GetLength();
		largeObjectSize=size;
		largeObjectCmd=cmdType;
		largeObjectSURI=item.GetSource(tempTS).GetLocURI(tempPcdata).GetString();
		largeObjectTURI=item.GetTarget(tempTS).GetLocURI(tempPcdata).GetString();
		//V1.1.1 largeObjectType=meta.GetType(tempPcdata).GetString();
		//largeObjectFormat=meta.GetFormat(tempPcdata).GetString();
		statusCode=213;
		return false;
	}
	/* Check if size has been specified again */
	if (meta.GetSize()!=-1 || item.GetMeta(meta).GetSize()!=-1)
	{
		statusCode=400;
		sprintf(error,"Large object delivery : Meta->Size/Item->Meta->Size already specified.");
	}
	/* Append to the buffer */
	if (!statusCode && tempPcdata.GetLength()>largeObjectSize-largeObjectBufferUsedSize)
	{
		statusCode=424;
		sprintf(error,"Large object delivery : Object size mismatch : %d bytes specified , %d bytes received.",largeObjectSize,largeObjectBufferUsedSize+tempPcdata.GetLength());
	}
	if (statusCode)
	{
		SctsErrorLog::AppendError(error);
		LargeObjectClear();
		return false;
	}
	sctsMemcpy(largeObjectBuffer+largeObjectBufferUsedSize,(char *)tempPcdata,tempPcdata.GetLength());
	largeObjectBufferUsedSize+=tempPcdata.GetLength();
	/* Check if it is the last chunk */
	if (item.IsChunked())
	{
		statusCode=213;
		return false;
	}
	if (largeObjectBufferUsedSize!=largeObjectSize)
	{
		statusCode=424;
		sprintf(error,"Large object delivery : Object size mismatch : %d bytes specified, %d bytes received.",largeObjectSize,largeObjectBufferUsedSize);
		SctsErrorLog::AppendError(error);
	}
	if (statusCode) LargeObjectClear();
	return !statusCode;
}

bool SctsDMSession::LargeObjectSendChunk()
{
	SctsCommand *pCmd;
	SctsMeta meta;
	/* Set size of item data to free size of message, preventing a workspace
	buffer overrun if the MaxObjSize > Max workspace size */
	SctsItem item(largeObjectSURI,0,largeObjectTURI,0,0,&SctsPcdata(largeObjectBuffer,outgoingMessage->GetFreeSize(),encoding));
	int dataSize;
	switch (largeObjectCmd)
	{
	case SCTS_ADD:
		pCmd=new SctsAdd(currentCmdID,SctsItemList(item));
		break;
	case SCTS_REPLACE:
		pCmd=new SctsReplace(currentCmdID,SctsItemList(item));
		break;
	case SCTS_RESULTS:
		pCmd=new SctsResults(currentCmdID,largeObjectCmdRef,SctsItemList(item));
		((SctsResults *)pCmd)->SetMsgRef(largeObjectMsgRef);
		if (largeObjectSURI) ((SctsResults *)pCmd)->SetTargetRef(&SctsPcdata(largeObjectSURI));
		if (largeObjectTURI) ((SctsResults *)pCmd)->SetSourceRef(&SctsPcdata(largeObjectTURI));
		break;
	default:
		return false;
	}
	if (largeObjectType) meta.SetType(&SctsPcdata(largeObjectType));
	if (largeObjectFormat) meta.SetFormat(&SctsPcdata(largeObjectFormat));
		
	/* If it is the first chunk check whether the entire object fits */
	if (!largeObjectBufferUsedSize)
	{
		meta.SetSize(largeObjectSize);
		item.SetMeta(&meta);
		/* Inserting the command WILL cause a the message to exceed the maximum size */
		SCTSASSERT(!outgoingMessage->InsertCommand(pCmd,true,false));
		largeObjectCmdSize=pCmd->size-outgoingMessage->GetFreeSize();
	}
	else if (largeObjectType || largeObjectFormat)
		item.SetMeta(&meta);
	/* Calculate the size available for the item data */
	dataSize=outgoingMessage->GetFreeSize()-largeObjectCmdSize;
	/* Account for more data tag */
	if (encoding==XML)
		dataSize-=11; 
	else
		dataSize--;
	dataSize-=40;
	/* No space for item data, send it in the next message */
	/* Efficiency ? : use the size of the return status as a threshold ?? */
	if (dataSize<=0) 
	{
		outgoingMessage->IsFinal(false);
		outgoingMessage->InsertCommand(0);
		delete pCmd;
		return true;
	}
	/* Reduce size of data */
	if (dataSize<largeObjectSize-largeObjectBufferUsedSize)
		item.IsChunked(true);
	else
		dataSize=largeObjectSize-largeObjectBufferUsedSize;
	item.SetData(&SctsPcdata(largeObjectBuffer+largeObjectBufferUsedSize,dataSize,encoding));
	largeObjectBufferUsedSize+=dataSize;
	SCTSASSERT(outgoingMessage->InsertCommand(pCmd));
	if (largeObjectBufferUsedSize==largeObjectSize)
	{					
		LargeObjectClear();
		++currentCmdID;
		return false;
	}
	outgoingMessage->IsFinal(false);
	outgoingMessage->InsertCommand(0);
	return true;
}

/* Method to send Alert 1225 */
void SctsDMSession::LargeObjectSendAlert()
{
	SctsItemList itemList(SctsItem(largeObjectTURI,0,largeObjectSURI,0,0,0));
	SctsAlert *alert=new SctsAlert(currentCmdID,itemList,1225);
	SCTSASSERT(outgoingMessage->InsertCommand(alert,false));
	LargeObjectClear();
	++currentCmdID;
}

/* Method to clear a large object */
void SctsDMSession::LargeObjectClear()
{
	largeObjectSize=0;
	largeObjectBufferUsedSize=0;
	sctsFree(largeObjectTURI);
	sctsFree(largeObjectSURI);
	sctsFree(largeObjectCmdRef);
	largeObjectSURI=0;
	largeObjectTURI=0;
	largeObjectCmdRef=0;
	largeObjectMsgRef=0;
	if (largeObjectBuffer) sctsFree(largeObjectBuffer);
	largeObjectBuffer=0;	
}

