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

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"
/*
 * Change to support DM 1.2 DMAcc node. 
 */
#include "SctsDevManDMAccount.h"
#ifdef __SCTS_USING_SCTS__
#include "SctsDevManTestEngine.h"
#endif
#include "xpt-b64.h"
#include <xptib64.h>

#define CONVERTB64TOBINFIX(CONDVAR,LEN,BUFFERP,FORMATP,SIZE) \
						unsigned long LEN = SIZE; \
						if( (XML == CONDVAR) && (FORMATP) && (0 == sctsStrcmp(FORMATP,"b64")))\
						{\
							int len = LEN*3/4+2;\
							unsigned char* tempBuffer = (unsigned char*)sctsMalloc(len);\
							LEN = base64Decode(tempBuffer,len,(unsigned char*)BUFFERP,&LEN);\
							sctsStrcpy(FORMATP,"bin");\
							sctsMemcpy(BUFFERP,tempBuffer,LEN);\
							sctsFree(tempBuffer);\
					  	}

const static int TNDS_MAX_BUFFER_LEN = 64 * 1024;
/******************************************************************
SctsSyncClientSession Definition
******************************************************************/

SctsStatusRef::SctsStatusRef()
{
	cmdID=0;
	data=0;
	msgID=0;
	prop=DMPROP_NONE;
	status=0;
}

SctsStatusRef::~SctsStatusRef()
{
	sctsFree(cmdID);
	sctsFree(data);
}

/******************************************************************
SctsSyncClientSession Definition
******************************************************************/
bool SctsDMClientSession::useOBEXIR=false;

/*
 * Change to support: TNDS, Correlaotr. 
 */
SctsDMClientSession::SctsDMClientSession(SctsDMClientDevice *_device,SctsEncoding _encoding,void (*_CallBack)(SctsDMSession *),bool _authenticateAllMsgs)
:SctsDMSession(_encoding,_CallBack), authenticateAllMsgs(_authenticateAllMsgs),
 /* What to get for TNDS */
 getTNDSPropSet(-1),
 /* The root node of subtree */
 subTreeRoot(0),getRight(0),
 /* Store gotten SubTree */
 getSubTree(0),
 /* Store gotten SubTree node */
 getSubTreeNode(0),
 /* Store correlator, need to support multiple Exec/Correlator mapping */
 sendGenericAlert(false),
 retryAuth(false)
{
	char buffer[300];
	char transportAddr[300];
	char proxyAddr[300]="";
	SctsDMNode *node;
	/* Initialization */
	sentDevInfo=false;
	sentSessionInitiationAlert=false;
	sentSyncHdrStatus=200;
	lastPendingResults=0;
	/* Assign Device */
	SCTSASSERT(_device);
	device=_device;
	alertCode=1201;
	
#ifdef __SCTS_USING_SCTS__
	testGroup=0;
#endif

	/* Set the session Type */
	sessionType=device->sessionType;
	
	/* Increment the sessionID */
	sessionID=sctsStrdup(sctsInt2Str(++device->lastSessionID,buffer,16));

	/* Setup Outgoing Authentication */
	userID=device->GetUserID();
	password=sctsStrdup(device->GetPassword(false));
	
	outAuth=0;
	if (userID && password)
	{
		switch(device->GetAuthType(false))
		{
		case AUTH_BASIC:
			outAuth=new SctsAuthBasic();
			break;
		case AUTH_MD5:
		case AUTH_HMAC:
			unsigned char *nonce;
			unsigned int size;
			if ((nonce=device->GetNonce(false,size)))
			{
				if (device->GetAuthType(false)==AUTH_HMAC)
					outAuth=new SctsAuthHMAC(nonce,size);
				else
					outAuth=new SctsAuthMD5(nonce,size);
				device->SetNonce(false,0,0);
			}
			break;
		}
	}

	
	/* Setup Incoming Authentication */
	inAuth=0;
	if (device->GetPassword(true))
	{
		switch(device->GetAuthType(true))
		{
		case AUTH_BASIC:
			inAuth=new SctsAuthBasic();
			break;
		case AUTH_MD5:
		case AUTH_HMAC:
			unsigned char *nonce;
			unsigned int size;
			if (!(nonce=device->GetNonce(true,size)))
			{
				nonce=(unsigned char *)&nonce;
				size=sizeof(unsigned char *);
			}
			if (device->GetAuthType(true)==AUTH_HMAC)
				inAuth=new SctsAuthHMAC(nonce,size);
			else
				inAuth=new SctsAuthMD5(nonce,size);
			device->SetNonce(true,0,0);				
			break;
		}
	}

    /*
     * Change to support DM 1.2 DMAcc node. 
     */
    node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subAppAddr + "/AddrType").c_str(),device->accountNode);
	SCTSASSERT(node && node->data && node->size>0);
    char *addrType = (char *)sctsMalloc((node->size + 1) * sizeof(char));
    sctsStrcpy(addrType, (char *)node->data);
	/* HTTP */
	if (!sctsStrcmp("URI", addrType) || !sctsStrcmp("IPv4", addrType))
	{
        /*
         * Change to support DM 1.2 DMAcc node. 
         */
		node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subAppAddr + "/Addr").c_str(),device->accountNode);
		SCTSASSERT(node && node->data && node->size);
		sctsStrcpy(transportAddr,(char *)node->data);
		node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subPort + "/PortNbr").c_str(),device->accountNode);
		if (node && node->data)
		{
            /*
             * Change to support both HTTP and HTTPS schema. 
             */
			char *pos,*pos1;
            const char *schemaStr = "http://";
            int schemaLen = sctsStrlen(schemaStr);
			pos=sctsStrstr(transportAddr,schemaStr);
            if (!pos)
            {
                schemaStr = "https://";
                schemaLen = sctsStrlen(schemaStr);
                pos=sctsStrstr(transportAddr,schemaStr);
            }
			if (pos) 
			{
				pos+=schemaLen;
				pos1=sctsStrchr(pos,'/');
			}
			else
				pos1=sctsStrchr(transportAddr,'/');

			if (pos1)
			{
				pos=sctsStrdup(pos1);
				sprintf(pos1,":%s%s",(char *)node->data,pos);
				sctsFree(pos);
			}
			else
			{
				sctsStrcat(transportAddr,":");
				sctsStrcat(transportAddr,(char *)node->data);
			}
		}
		
		/* Get the ConRef accountNode */
        /*
         * Change to support DM 1.2 DMAcc node. 
         */
		node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subToConRef + "/ConRef").c_str(),device->accountNode);
		SCTSASSERT(node);
		
		if (node->data)
		{
			/* Get proxy address */
			if (node && node->data)
			{
				SctsDMNode *pxNode;
				sprintf(buffer,"%s/Con/%s/PX",device->dmAccPath,(char *)node->data);
				pxNode=device->FindDMNode(buffer);
				if (pxNode)
				{
					node=device->FindDMNode("Addr",pxNode);
					SCTSASSERT(node && node->data && node->size);
					sctsStrcpy(proxyAddr,(char *)node->data);
					proxyAddr[node->size+1]='\0';
					node=device->FindDMNode("PortNbr",pxNode);
					if (node)
					{
						SCTSASSERT(node->data && node->size);
						sctsStrcat(proxyAddr,":");
						sctsStrcat(proxyAddr,(char *)node->data);
					}
				}
			}
		}
		transport=new SctsHttpClientTransport(&SctsURI(transportAddr),proxyAddr[0]?proxyAddr:0);
	}
	/* WSP */
	else if(0)
	{
		transport=0;
	}
	/* OBEX */
	else
	{
        /*
         * Change to support DM 1.2 DMAcc node. 
         */
		node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subAppAddr + "/Addr").c_str(),device->accountNode);
		SCTSASSERT(node && node->data && node->size);
		sctsStrcpy(transportAddr,(char *)node->data);
		if (useOBEXIR)
		{
			transport=new SctsObexIRClientTransport(transportAddr);
		}
		else
		{
			node=device->FindDMNode((char *)(device->accounts[device->accountNode->name].subPort + "/PortNbr").c_str(),device->accountNode);
			transport=new SctsObexTCPClientTransport(transportAddr,(node && node->data)?atoi((char *)node->data):650);
		}
	}
	SCTSASSERT(transport);

	/* Set session proto and MIME type */
	proto=device->proto;
	if (_encoding==XML)
		((SctsClientTransport *)transport)->SetMimeType("application/vnd.syncml.dm+xml");
	else
		((SctsClientTransport *)transport)->SetMimeType("application/vnd.syncml.dm+wbxml");

	/* Set MaxMsgSize */
	maxMsgSize=device->maxMsgSize;
	
	/* Write a 0 to the log file info (denotes a client) */
	fputc(0,logFileInf);

	/* Large Object delivery */
	/* V1.1.1 */
	node=device->FindDMNode("./DevDetail/LrgObj");
	SCTSASSERT(node && node->data);
	if (!sctsStrcmp((char *)node->data,"true"))	
	{
		supportsLrgObj=true;
		largeObjectBufferSize=device->maxObjSize;
	}
	if (componentUIC.addSession) (*componentUIC.addSession)(this);
}


SctsDMClientSession::~SctsDMClientSession()
{
	if (device) tempDevice=device;
	SctsStatusRef *status;
	/* Delete sentStatusRefs */
	while (!sentStatusRefs.empty())
	{
		std::list <SctsStatusRef *> refList=sentStatusRefs.begin()->second;
		while (!refList.empty())
		{
			status=*refList.begin();
			delete status;
			refList.pop_front();
		}
		sentStatusRefs.erase(sentStatusRefs.begin());
	}
}

int SctsDMClientSession::Exit()
{
	/* Display the error log */
	/* Clear the session */
	delete this;
	sctsStatusLog("Session complete.");
	sctsStatusLogClose();
	return 0;
}

int SctsDMClientSession::Run()
{
	int rc;
	SctsCommand *pCmd;
	SctsPcdata commandID;
	std::map<SctsDMCommand *,char *>::iterator resultsIt;
	char errorMsg[300];
	/* Session thread entry point */
	sctsStatusLogOpen();
	sctsStatusLog("Starting session...\r\n");
	/* Create the error log */
	errorLog=new SctsErrorLog();
	sentSyncHdrStatus=200;
	
	while (processError==PROCESS_ERR_NONE)
	{
		if (sentSyncHdrStatus==200 || sentSyncHdrStatus==212)
		{
			/* Build the message based on the current state */
			if (sourcePkgCount==0)
			{
				#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST && testGroup) testGroup->StateInitiatePreBuild();
				#endif
				BuildStateInitiateMessage();
				#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST && testGroup && processError==PROCESS_ERR_NONE) testGroup->StateInitiatePostBuild();
				#endif
			}
			else
			{
				#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST && testGroup) testGroup->StateManagePreBuild();
				#endif
				BuildStateManageMessage();
				#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST && testGroup && processError==PROCESS_ERR_NONE) testGroup->StateManagePostBuild();
				#endif
			}
			if (processError==PROCESS_ERR_STOP) break;			
		}
		/* 
		Need to build the </SyncBody> tag only if the maximum message size hasn't been
		reached, since exceeding the maximum message size will close the <SyncBody> and
		set the outgoingMessage final flag to false automatically.
		*/

		if (outgoingMessage->IsFinal())
		{
			/* Don't sent final if the sourcePkgCount>targetPkgCount*/
			if (sourcePkgCount>targetPkgCount)
			{
				/* Build Next message Alert */
				/* V1.1.1 */
				if (currentCmdID<3 || (largeObjectSize && largeObjectCmd!=SCTS_RESULTS))
				{
					SctsAlert *alert=new SctsAlert(currentCmdID,SctsItemList(),1222);
					outgoingMessage->InsertCommand(alert);
					++currentCmdID;
				}		
				outgoingMessage->IsFinal(false);
			}
			else
			{
				/* V1.1.1 */
				if (currentCmdID<3) break;
				sourcePkgCount++;
			}				
			outgoingMessage->InsertCommand(0);
		}
		/* Postponement of status discrepency : push message onto message queue */
		messageQueue.push_back(outgoingMessage);
		outgoingMessage=0;

		/* Send the message */
		if (!SendMessage())
		{
			processError=PROCESS_ERR_STOP;
			break;
		}
		
		/* If server was not authenticated send chal and break out of session 
		if (sentSyncHdrStatus==401 || sentSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Server failed to authenticate. A challenge has been sent, restart the session after a short period.");
			processError=PROCESS_ERR_STOP;
			break;
		}*/

		/* Receive the message */
		if (!RecvMessage())
		{
			processError=PROCESS_ERR_STOP;
			break;
		}
		
		/* Process the received message */
		recvSyncHdrStatus=0;
		++currentMsgID;
		currentCmdID=1;
		processError=PROCESS_ERR_OK;
		
#ifdef __SCTS_USING_SCTS__		
		/* Execute test group Pre-process */
		if (targetPkgCount==0)
			if (sessionType==DMSESSION_TEST && testGroup) testGroup->StateInitiatePreProcess();
		else
			if (sessionType==DMSESSION_TEST && testGroup) testGroup->StateManagePreProcess();
			
#endif

#ifdef __SCTS_USING_RTK__
		if (wbxmlConverterContext) 
			wbxmlConverting=true;
		else
			wbxmlConverting=false;
		while (processError==PROCESS_ERR_OK || wbxmlConverting)
		{
			if ((rc=smlProcessData(sessionContext,SML_NEXT_COMMAND))!=SML_ERR_OK)
			{
				sprintf(errorMsg,"Toolkit error : %s",sctsGetRTKError(rc));
				SctsErrorLog::AppendError(errorMsg);
				sctsStatusLog(errorMsg);
				sctsStatusLog("...\r\n");
				processError=PROCESS_ERR_STOP;
				break;
			}
			outgoingMessage->lastCommandNotBuilt;
		}
#endif
		/* Postponement of status discrepency : Check only if it is the last message in the package */
		/* Check whether status has been received for all commands */
		/* Status on results discrepency */
		if (recvdFinal && processError==PROCESS_ERR_NONE)
		{
			SctsErrorLog::OpenNode("Status","Did not receive Status for all commands.");
			while (messageQueue.size())
			{
				for (;(pCmd=messageQueue.front()->GetCurrentCommand()) && (pCmd->GetType()==SCTS_STATUS || pCmd->GetType()==SCTS_RESULTS || pCmd->GetType()==SCTS_HEADER);messageQueue.front()->DeleteCurrentCommand());
				if (pCmd)
				{
					processError=PROCESS_ERR_STOP;
					pCmd->GetCommandID(commandID);
					sprintf(errorMsg,"Command : %s, Command ID : %s",sctsCommandStrings[pCmd->GetType()],(char *)commandID);
					SctsErrorLog::AppendError(errorMsg);
					break;
				}
				delete messageQueue.front();
				messageQueue.pop_front();
				messageQueueID++;
			}
			SctsErrorLog::CloseNode();
		}
	
#ifdef __SCTS_USING_SCTS__		
		/* Execute test group Post-process */
		if (processError==PROCESS_ERR_NONE && sessionType==DMSESSION_TEST && testGroup)
		{
			if (targetPkgCount)
				testGroup->StateManagePostProcess();
			else
				testGroup->StateInitiatePostProcess();
		}
		if (processError==PROCESS_ERR_STOP) break;
#endif
		/* Switch target state */
		if (recvdFinal) targetPkgCount++;	
		
		/* Check state */
		if (targetPkgCount>sourcePkgCount)
		{
			SctsErrorLog::AppendError("Invalid package state.The final element must not be included if the other end has not closed the preceding package.");
			processError=PROCESS_ERR_STOP;
		}

		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			if (outAuth)
				sourcePkgCount=targetPkgCount=0;
			else
			{
				if (!retryAuth)
				{
					retryAuth = true;
					sourcePkgCount=targetPkgCount=0;
				}
				else
				{
					SctsErrorLog::AppendError("Failed to authenticate. Check username and password settings and restart session.");
					break;
				}
			}
		}

		/* UI Callback only if commands remain */
		if (uiCallback && (!sentSessionInitiationAlert || !outgoingMessage->IsFinal() || currentCmdID>2 || largeObjectSize || !pendingResults.empty())) (*uiCallback)(uiCallbackData,outgoingMessage->GetHeader(),0,true);
		
		if (!pendingStatus.empty())
		{
			outgoingMessage->IsFinal(false);
			outgoingMessage->InsertCommand(0);
			continue;
		}
		if (sentSyncHdrStatus==200 || sentSyncHdrStatus==212)
		{
			/* Large Object delivery */
			if (!largeObjectSize || (largeObjectCmd==SCTS_RESULTS && !LargeObjectSendChunk()))
			{
				/* Build pending Results */
				while (processError==PROCESS_ERR_NONE && !pendingResults.empty())
				{
					SctsDMResults *result;
					SctsResults *results;
					SctsMeta meta;
					bool setMeta=false;
					SctsPcdata *pcData=0;
					
					result=pendingResults.front();
					pendingResults.pop_front();
					
					if (result->pcData)
					{
						pcData=new SctsPcdata();
						pcData->rawData=(SmlPcdataPtr_t)sctsMalloc(sizeof(SmlPcdata_t));
						pcData->rawData->content=sctsMalloc(result->pcData->rawData->length);
						sctsMemcpy(pcData->rawData->content,result->pcData->rawData->content,result->pcData->rawData->length);
						pcData->rawData->contentType=result->pcData->rawData->contentType;
						pcData->rawData->length=result->pcData->rawData->length;
					}
									
					if (supportsLrgObj && pcData && pcData->GetLength()>maxMsgSize/2 && pcData->GetLength()>outgoingMessage->GetFreeSize() && (!largeObjectBufferSize || pcData->GetLength()<=largeObjectBufferSize))
					{
						LargeObjectClear();
						if (result->format!=DMFORMAT_CHR) largeObjectFormat=sctsStrdup(SctsDMFormatString[result->format]);
						if (result->type) largeObjectType=result->type;
						result->type=0;
						/* V1.1.1 */
						largeObjectSize=pcData->GetLength();
						largeObjectBuffer=(char *)sctsMalloc(largeObjectSize);
						sctsMemcpy(largeObjectBuffer,pcData->rawData->content,largeObjectSize);
						largeObjectBufferUsedSize=0;
						largeObjectSURI=result->source;
						result->source=0;
						largeObjectTURI=0;
						largeObjectCmd=SCTS_RESULTS;
						largeObjectCmdRef=result->cmdRef;
						result->cmdRef=0;
						largeObjectMsgRef=result->msgRef;
						LargeObjectSendChunk();
						delete result;
						delete pcData;
						break;
					}
					
					if (largeObjectBufferSize && pcData && pcData->GetLength()>largeObjectBufferSize)
					{
						SctsErrorLog::AppendError("Unable to fit 'Results' using current max obj size setting."); 
						break;
					}
					/* Set Meta */
					if (result->type) 
					{
						meta.SetType(&SctsPcdata(result->type));
						setMeta=true;
					}
					if (result->format!=DMFORMAT_CHR)
					{
						meta.SetFormat(&SctsPcdata(SctsDMFormatString[result->format]));
						setMeta=true;
					}
					results=new SctsResults(currentCmdID,result->cmdRef,SctsItemList(SctsItem(result->source,0,0,0,setMeta?&meta:0,pcData)));
					if (result->msgRef!=1) results->SetMsgRef(result->msgRef);
					if (!outgoingMessage->InsertCommand(results)) 
					{
						delete results;
						if (lastPendingResults && lastPendingResults==result)
						{
							delete result;
							SctsErrorLog::AppendError("Unable to fit 'Results' using current message size setting."); 
						}
						else
						{
							lastPendingResults=result;
							pendingResults.push_front(result);
						}
						outgoingMessage->IsFinal(false);
						break;
					}
					else
					{
						++currentCmdID;
						delete result;
					}
				} /* End of pending Results while */
			} /* Large Object Delivery */

			/* Build pending Generic Alerts */
			if (!device->pendingGenericAlerts.empty() && !sendGenericAlert && !largeObjectSize)
			{
				SctsDMGenericAlert *gAlert=0;
				SctsAlert *genericAlert=0;

				gAlert=device->pendingGenericAlerts.front();
				device->pendingGenericAlerts.pop_front();

				SctsMeta metaGenericAlert;
				metaGenericAlert.SetType(&SctsPcdata(gAlert->type));
				metaGenericAlert.SetFormat(&SctsPcdata(gAlert->format));
				SctsItem itemGenericAlert(gAlert->source,0,0,0,&metaGenericAlert,&SctsPcdata(gAlert->data),0);
				SctsItemList itemListGenericAlert(itemGenericAlert);
				genericAlert = new SctsAlert(currentCmdID,itemListGenericAlert,1226);
				genericAlert->SetCorrelator(gAlert->correlator);

				if (!outgoingMessage->InsertCommand(genericAlert)) 
				{
					delete genericAlert;
					device->pendingGenericAlerts.push_front(gAlert);
				}
				else
				{
					++currentCmdID;
					sendGenericAlert = true;
					delete gAlert;
				}
			}
		}		
	} /* End of while */	
	
#ifdef __SCTS_USING_SCTS__
	if (processError==PROCESS_ERR_NONE && sessionType==DMSESSION_TEST && testGroup) testGroup->StateTerminate();
#endif
	return 0;
}	

void SctsDMClientSession::BuildStateInitiateMessage()
{
	SctsItemList itemList;
	SctsAlert *alert;
	SctsDMNode *node,*startNode;
	SctsReplace *replace;
	sctsStatusLog("Building state initiate message...\r\n");
	char *tempStr;
	/* 
	Build the first message's SyncHdr and create the new message object, subsequent
	message objects and SyncHdrs are created on processing the response message.
	*/
	if (currentMsgID==1) 
	{
		SctsSyncHdr *syncHdr;
		syncHdr=BuildSyncHdr();
		if (uiCallback) (*uiCallback)(uiCallbackData,syncHdr,0,true);
		outgoingMessage=new SctsMessage(sessionContext,encoding,syncHdr,maxMsgSize,wbxmlConverterContext,uiCallbackData,uiCallback);
		if (wbxmlConverterContext) syncHdr->Build(wbxmlConverterContext);
	}

	/* Build Alert */
	if (!sentSessionInitiationAlert)
	{
		alert=new SctsAlert(currentCmdID,itemList,alertCode);
		outgoingMessage->InsertCommand(alert);
		++currentCmdID;
	}

	/* Send device information */
	if (!sentDevInfo)
	{
		startNode=device->FindDMNode("./DevInfo");
		node=startNode->child;
		SCTSASSERT(node);
		while (node)
		{
			/* Build item */
			SctsItem item(tempStr=device->GetPath(node),0,0,0,0,0);
			SctsMeta meta;
			SctsDMNodeFormat format;
			SctsPcdata pcData;
			sctsFree(tempStr);
			
			node->GetPcdata(pcData,format,encoding);
			item.SetData(&pcData);
			
			if (format!=DMFORMAT_CHR) 
			{
				meta.SetFormat(&SctsPcdata(SctsDMFormatString[format]));
				item.SetMeta(&meta);
			}
			if (node->mimeType && sctsStrcmp(node->mimeType,"text/plain")) 
			{
				meta.SetType(&SctsPcdata(node->mimeType));
				if (format==DMFORMAT_CHR) item.SetMeta(&meta);
			}
			if (!itemList)
			{
				replace=new SctsReplace(currentCmdID,SctsItemList(item));
				replace->GetItemList(itemList);
			}
			else
				itemList.SetNextData(item);

			if (node->child) 
			{
				node=node->child;
				continue;
			}
			if (node->next)
			{
				node=node->next;
				continue;
			}
			while (!node->next && node!=startNode) node=node->parent;
			if (node==startNode) break;
			node=node->next;
		}
		outgoingMessage->InsertCommand(replace);
		++currentCmdID;
	}

	/* Build pending Generic Alerts */
	if (!device->pendingGenericAlerts.empty())
	{
		SctsDMGenericAlert *gAlert=0;
		SctsAlert *genericAlert=0;

		gAlert=device->pendingGenericAlerts.front();
		device->pendingGenericAlerts.pop_front();

		SctsMeta metaGenericAlert;
		metaGenericAlert.SetType(&SctsPcdata(gAlert->type));
		metaGenericAlert.SetFormat(&SctsPcdata(gAlert->format));
		SctsItem itemGenericAlert(gAlert->source,0,0,0,&metaGenericAlert,&SctsPcdata(gAlert->data),0);
		SctsItemList itemListGenericAlert(itemGenericAlert);
		genericAlert = new SctsAlert(currentCmdID,itemListGenericAlert,1226);
		genericAlert->SetCorrelator(gAlert->correlator);

		if (!outgoingMessage->InsertCommand(genericAlert)) 
		{
			delete genericAlert;
			device->pendingGenericAlerts.push_front(gAlert);
		}
		else
		{
			++currentCmdID;
			sendGenericAlert = true;
			delete gAlert;
		}
	}
}

void SctsDMClientSession::BuildStateManageMessage()
{
}
	
void SctsDMClientSession::BuildResults(SctsDMResults *results,SctsDMNode *node)
{
	SCTSASSERT(results && node);
	SctsPcdata *pcData=0;
	SctsDMNodeFormat format=DMFORMAT_CHR;	
		
	switch(results->prop)
	{
	case DMPROP_STRUCT:
		results->pcData=0;
		format=node->format;
		break;
	case DMPROP_NONE:
		if (node->format==DMFORMAT_NODE)
		{
			char *result=0;
			SctsDMNode *_node=node->child;
			format=DMFORMAT_NODE;
			while(_node)
			{
				if (result)
				{
					result=(char *)sctsRealloc(result,strlen(result)+strlen(_node->name)+2);
					strcat(result,"/");
					strcat(result,_node->name);
				}						
				else
					result=sctsStrdup(_node->name);
				_node=_node->next;
			}
			if (result)
			{
				pcData=new SctsPcdata(result);					
				sctsFree(result);
			}
			else
				pcData=new SctsPcdata("");
			results->type=sctsStrdup("text/plain");
			break;
		}	
	//	Ref May23rd,2003 Added the || case 
	//Other wise the STRUCTDATA won't have node...
	case DMPROP_STRUCTDATA:
		if (node->size || (DMFORMAT_NODE == node->format))
		{
			pcData=new SctsPcdata();
			node->GetPcdata(*pcData,format,encoding);
		}
		break;
    /*
     * Change to support TNDS. 
     */
    case DMPROP_TNDS:
        pcData=results->pcData;
        if (!pcData)
        {
            /* Check which format used, XML or Binary WBXML */
            results->format=encoding==XML?DMFORMAT_XML:DMFORMAT_BIN;
            results->type=sctsStrdup(encoding==XML?"application/vnd.syncml.dmtnds+xml":"application/vnd.syncml.dmtnds+wbxml");
            pcData=new SctsPcdata((SmlPcdataPtr_t)sctsMalloc(sizeof(SmlPcdata_t)));
            pcData->rawData=(SmlPcdataPtr_t)sctsMalloc(sizeof(SmlPcdata_t));
            pcData->rawData->contentType=encoding==XML?SML_PCDATA_CDATA:SML_PCDATA_OPAQUE;
            pcData->rawData->length=0;
            /* Allocate buffer to strore subtree */
            if ((pcData->rawData) && (pcData->rawData->content=sctsMalloc(TNDS_MAX_BUFFER_LEN)))
            {
                results->pcData=pcData;
                getSubTree = (SmlSubTreePtr_t)smlLibMalloc(sizeof(SmlSubTree_t));
                memset(getSubTree, 0, sizeof(SmlSubTree_t));
                getSubTree->version = smlString2Pcdata((char *)"1.2");
                getSubTreeNode = (SmlSubTreeNodePtr_t)smlLibMalloc(sizeof(SmlSubTreeNode_t));
                memset(getSubTreeNode, 0, sizeof(SmlSubTreeNode_t));
                getSubTree->node = getSubTreeNode;
            }
            else
            {
                sctsFree(pcData->rawData);
                delete pcData;
                pcData=0;
                results->pcData=0;
            }
        }
        else
        {
            if ((char *)(*pcData))
            {
                char * pBufPos = (char *)(*pcData);
                /* Build TNDS Message */
                int rc = smlMarshalMgmtTree(encoding==XML?0:1, pBufPos + TNDS_MAX_BUFFER_LEN, &pBufPos, getSubTree);
                if (rc == SML_ERR_OK)
                {
                    /* Log TNDS WBXML. */
                    pcData->rawData->length = pBufPos - (char *)(*pcData);
                    FILE *fp = fopen("tnds.wbxml", "wb");
                    if (fp)
                    {
                        fwrite(pcData->rawData->content, pcData->rawData->length, 1, fp);
                        fclose(fp);
                    }
                }
            }
        }
        return;
        break;
    /*
     * Change to support TNDS. 
     */
    case DMPROP_TNDS_STARTNODE:
        pcData=results->pcData;
        if (pcData && (char *)(*pcData))
        {
            if (node->name)
            {
                getSubTreeNode->nodeName=smlString2Pcdata(node->name);
            }
            if (subTreeRoot==node)
            {
                std::string path;
                for (SctsDMNode *node = subTreeRoot->parent; node; node = node->parent)
                {
                    path.insert(0, "/");
                    path.insert(0, node->name);
                }
                if (path.length())
                {
                    path.erase(path.end() - 1);
                }
                getSubTreeNode->path=path.length()?smlString2Pcdata((char *)path.c_str()):0;
            }
            /*
             * Check if has enough right. 
             */
            if (getRight==200)
            {
                char tempString[64]="";
                if (node->mimeType)
                {
                    getSubTreeNode->mimeType=smlString2Pcdata(node->mimeType);
                }
                /*
                 * Get Format of node? 
                 */
                if (isGetTNDSProperty(GET_TNDS_FORMAT))
                {
                    if (node->format)
                    {
                        getSubTreeNode->format=smlString2Pcdata(SctsDMFormatString[node->format]);
                    }
                    else
                    {
                        getSubTreeNode->format=smlString2Pcdata((char *)"chr");
                    }
                }
                /*
                 * Get ACL of node? 
                 */
                if (isGetTNDSProperty(GET_TNDS_ACL) && node->acl)
                {
                    getSubTreeNode->ACL=smlString2Pcdata(node->acl);
                }
                /*
                 * Get VerNO of node? 
                 */
                if (isGetTNDSProperty(GET_TNDS_VERNO) && itoa(node->version, tempString, 10))
                {
                    getSubTreeNode->verNo=smlString2Pcdata(tempString);
                }
                /*
                 * Get Title of node? 
                 */
                if (isGetTNDSProperty(GET_TNDS_TITLE) && node->title)
                {
                    getSubTreeNode->title=smlString2Pcdata(node->title);
                }

                /*
                 * Get Value of node? 
                 */
                SctsPcdata tempNodeData;
                SctsDMNodeFormat tempFormat = DMFORMAT_CHR;
                node->GetPcdata(tempNodeData,tempFormat,encoding);
                if (isGetTNDSProperty(GET_TNDS_VALUE) && (char *)tempNodeData)
                {
                    getSubTreeNode->data=smlString2Pcdata((char *)tempNodeData);
                }
            }
        }
        return;
        break;
    case DMPROP_TNDS_ENDNODE:
        pcData=results->pcData;
        if (pcData && (char *)(*pcData))
        {
            /* debug TNDS tree */
        }
        return;
        break;
	case DMPROP_ACL:
		if(node->acl) 
		{
			pcData=new SctsPcdata();
			pcData->rawData=(SmlPcdataPtr_t)sctsMalloc(sizeof(SmlPcdata_t));
			pcData->rawData->content=sctsMalloc(pcData->rawData->length=sctsStrlen(node->acl));
			sctsMemcpy(pcData->rawData->content,node->acl,pcData->rawData->length);
			pcData->rawData->contentType=encoding==XML?SML_PCDATA_CDATA:SML_PCDATA_OPAQUE;
		}
		break;
	case DMPROP_FORMAT:
		if(node->format) pcData=new SctsPcdata(SctsDMFormatString[node->format]);
		break;
	case DMPROP_NAME:
		pcData=new SctsPcdata(node->name);
		break;
	case DMPROP_TITLE:
		if(node->title) pcData=new SctsPcdata((char *)node->title);
		break;
	case DMPROP_TIMESTAMP:
		if(node->timeStamp) pcData=new SctsPcdata(node->timeStamp);
		break;
	case DMPROP_MIMETYPE:
		if(node->mimeType) pcData=new SctsPcdata(node->mimeType);
		break;
	case DMPROP_SIZE:
		if(node->size) pcData=new SctsPcdata(node->size);
		break;
	case DMPROP_VERSION:
		if(node->version) pcData=new SctsPcdata(node->version);
		break;
	};

	if (!pcData && results->prop!=DMPROP_STRUCT && (results->prop!=DMPROP_STRUCTDATA || node->format!=DMFORMAT_NODE))
	{
		format=DMFORMAT_NULL;
		pcData=new SctsPcdata("");
	}
	if (format!=DMFORMAT_CHR) results->format=format;
	if (node->mimeType && sctsStrcmp(node->mimeType,"text/plain") && !(results->format==DMFORMAT_NODE && results->prop==DMPROP_NONE)) results->type=sctsStrdup(node->mimeType);
	results->pcData=pcData;
}
	
SctsSyncHdr *SctsDMClientSession::BuildSyncHdr()
{
	SctsCred *cred=0;
	SctsTargetSource *target=0;
	SctsTargetSource *source=0;
	SctsAuthType authType=AUTH_NONE;
	SctsSyncHdr *syncHdr;
	SctsMeta meta;
	char *tempStr;
	
	/* Construct the credentials */
	if (outAuth) authType=outAuth->GetType();
	if (authType==AUTH_MD5 || authType==AUTH_BASIC)
		cred=outAuth->BuildCred(userID,password,encoding);
    /*
     * Change to support DM 1.2. 
     */
    char devid[64];
    memset(devid, 0, sizeof(devid));
    SctsDMNode *devidNode;
    devidNode=device->FindDMNode("./DevInfo/DevId");
    if ( devidNode == NULL)
    {
        /* Construct the source */
        if (authType==AUTH_MD5)
            source=new SctsTargetSource(device->devID,userID);
        else
            source=new SctsTargetSource(device->devID);
    }
    else
    {
        strncpy(devid, (char*)(devidNode->data), sizeof(devid));
        if (authType==AUTH_MD5)
            source=new SctsTargetSource(devid,userID);
        else
            source=new SctsTargetSource(devid);
    }

	/* Construct the target */
	target=new SctsTargetSource(tempStr=((SctsClientTransport *)transport)->GetRespAddr());
	sctsFree(tempStr);
	/* Create the syncHdr */
    syncHdr=new SctsSyncHdr(cred,0,source,target,"1.2","DM/1.2",sessionID,currentMsgID);
	/* Create meta */
	meta.SetMaxMsgSize(maxMsgSize);
	if (supportsLrgObj && largeObjectBufferSize) meta.SetMaxObjSize(largeObjectBufferSize);
	syncHdr->SetMeta(&meta);
	/* Clean up */
	if (cred) delete cred;
	delete source;
	delete target;
	/* Complete */
	return syncHdr;
}

void SctsDMClientSession::HandleStartMessage(SctsSyncHdr &cmd)
{
	SctsErrorLog::OpenNode("Sync Header",0);
	int messageID;
	SctsPcdata tempPcdata;
	SctsTargetSource tempTS;
	SctsMeta meta;
	int statusCode=0;
	SctsChal *chal=0;
	int newMaxObjSize=0;
	int newMaxMsgSize=0;
	ProcessStackCmd *processCmd;
	while(true)
	{
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;
		
		/* Check if message id is valid */
		if (!(messageID=cmd.GetMsgID()))
		{
			SctsErrorLog::AppendError("Invalid message identifier.SyncML Representation protocol V1.1.2 (6.1.12) : The value is a monotonically increasing numeric value starting at one (1) for the first message in the SyncML session.");
			break;
		}

		/* Check if message id is monotonic */
		if (messageID<=processMsgID)
		{
			SctsErrorLog::AppendError("Message identifier not monotonically increasing. SyncML Representation protocol V1.1.2 (6.1.12) : The value is a monotonically increasing numeric value starting at one (1) for the first message in the SyncML session.");
			break;
		}
		
		/* Check verDTD and verProto */
		cmd.GetVersion(tempPcdata);
        /*
         * Change to support DM 1.2. 
         */
		if (!(tempPcdata=="1.2"))
		{
			char errorMsg[200];
			sprintf(errorMsg,"Invalid VerDTD element. SyncML DM protocol V1.1.2 (8.4) : The value of the VerDTD element MUST be '1.1.");
			SctsErrorLog::AppendError(errorMsg);
			break;
		}
		if (!(cmd.GetProto(tempPcdata)=="DM/1.2"))
		{
			char errorMsg[200];
			sprintf(errorMsg,"Invalid VerProto element. SyncML DM protocol V1.1.2 (8.4) : The value MUST be 'DM/1.1' when complying with this specification.");
			SctsErrorLog::AppendError(errorMsg);
			break;
		}
		
		/* Check session ID */
		if (!(cmd.GetSessionID(tempPcdata)==sessionID))
		{
			SctsErrorLog::AppendError("SessionID has changed. SyncML DM Protocol V1.1.2(8.4) : Same SessionID MUST be used throughout the whole session.");
			break;
		}
		
		/* Process the respURI */
		if (cmd.GetRespURI(tempPcdata))
		{
			SctsURI respURI((char *)tempPcdata);
			if (!((SctsClientTransport *)transport)->SetRespAddr(&respURI))
			{
				SctsErrorLog::AppendError("Invalid RespURI.SyncML Representation protocol (6.1.16) : The value of this element is the address, in the form of an absolute URI...");
				break;
			}
		}
		
		/* Adapt to MaxObjSize */
		newMaxObjSize=cmd.GetMeta(meta).GetMaxObjSize();
		if (newMaxObjSize!=-1)
		{
			if (largeObjectSize>newMaxObjSize)
			{
				SctsErrorLog::AppendError("New MaxObjSize less than size of object already in large object buffer.");
				break;
			} 
			if (!largeObjectBufferSize || newMaxObjSize<=largeObjectBufferSize || newMaxObjSize<=device->maxObjSize) largeObjectBufferSize=newMaxObjSize;						
		}
		/* Adapt to MaxMsgSize */
		newMaxMsgSize=cmd.GetMeta(meta).GetMaxMsgSize();
		if (newMaxMsgSize!=-1 && (!maxMsgSize || newMaxMsgSize<=maxMsgSize)) maxMsgSize=newMaxMsgSize;						
		
		/* Check authentication */
		if (inAuth)
		{
			SctsCred cred;
			char *serverPW=device->GetPassword(true);
			if (!serverPW)
			{
				SctsErrorLog::AppendError("Server password is not configured for incoming authentication.");
				break;
			}
			statusCode=inAuth->VerifyCred(cmd.GetCred(cred),device->serverID,serverPW,encoding);
			if (!statusCode) break;
			/* Store the new nonce and set the authentication type of the device */
			if (inAuth->GetType()==AUTH_MD5 || inAuth->GetType()==AUTH_HMAC)
			{
				if (inAuth->GetType()==AUTH_MD5)
					device->SetNonce(true,((SctsAuthMD5 *)inAuth)->nonce,((SctsAuthMD5 *)inAuth)->size);
				else
					device->SetNonce(true,((SctsAuthHMAC *)inAuth)->nonce,((SctsAuthHMAC *)inAuth)->size);
				chal=inAuth->BuildChal(encoding);
			}
			else if (statusCode!=200) chal=inAuth->BuildChal(encoding);

			if (statusCode==200 && !authenticateAllMsgs && inAuth->GetType()!=AUTH_HMAC) 
			{
				delete inAuth;
				inAuth=0;
				statusCode=212;
			}
		}
		else
			statusCode=212;
		break;
	}

	if (statusCode)
	{
		/* Push command onto process stack */
		processCmd=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
		processCmd->type=SCTS_HEADER;
		processCmd->status=statusCode;
		processStack.push(processCmd);
		processMsgID=messageID;

		/* UI callback */
		if (uiCallback)
		{
			cmd.status=statusCode;
			(*uiCallback)(uiCallbackData,&cmd,0,false);
		}
		sentSyncHdrStatus=statusCode;
		
		/* Store status */
		if (cmd.IsNoResp())
		{
			nextSyncHdrStatus=0;
			messageNoResp=true;
		}
		else
		{
			nextSyncHdrStatus=new SctsStatus(currentCmdID,processMsgID,"0","SyncHdr",statusCode);
			/* TargetRef/SourceRef discrepancy */
			cmd.GetTarget(tempTS).GetLocURI(tempPcdata);
			if (tempPcdata) nextSyncHdrStatus->SetTargetRefList(&SctsTargetRefList(SctsPcdata((char *)tempPcdata)));
			cmd.GetSource(tempTS).GetLocURI(tempPcdata);
			if (tempPcdata) nextSyncHdrStatus->SetSourceRefList(&SctsSourceRefList(SctsPcdata((char *)tempPcdata)));
			if (chal) 
			{
				nextSyncHdrStatus->SetChal(chal);
				delete chal;
			}
			++currentCmdID;
			messageNoResp=false;
		}
	}
	else
		processError=PROCESS_ERR_STOP;

	/* Close error log node and clean up*/
	SctsErrorLog::CloseNode();
}


void SctsDMClientSession::HandleEndMessage(bool final)
{
	ProcessStackCmd *parent=processStack.top();
	if (parent->type!=SCTS_HEADER)
	{
		char errorMsg[100];
		SctsErrorLog::OpenNode("End SyncBody",0);
		sprintf(errorMsg,"Nesting error. Expecting : %s",sctsCommandStrings[parent->type+1]);
		SctsErrorLog::AppendError(errorMsg);
		SctsErrorLog::CloseNode();
		processError=PROCESS_ERR_STOP;
	}
	else
	{
		/* UI callback */
		if (uiCallback)	(*uiCallback)(uiCallbackData,0,SCTS_BODY_END,false);
		processStack.pop();
		sctsFree(parent);
		recvdFinal=final;
		processError=PROCESS_ERR_NONE;
	}
}


void SctsDMClientSession::HandleStatus(SctsStatus &cmd)
{
	SctsCommand *pCmd;
	SctsCommandType cmdType;
	SctsPcdata tempPcdata1;
	SctsPcdata tempPcdata2;
	SctsItemList itemList=0;
	char errorMsg[300]="";
	int status;
	int msgRef;
	bool multipleStatus=false;
	bool error=true;
	SctsAuth *auth=0;
	SctsChal chal;

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		status=cmd.GetData();
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		/* Get MsgRef */
		msgRef=cmd.GetMsgRef();
		cmd.GetCmdRef(tempPcdata1);
		if (tempPcdata1=="0")
		{
			pCmd=messageQueue.back()->GetCurrentCommand();
			if (msgRef!=currentMsgID-1)
				sprintf(errorMsg,"Invalid MsgRef element, expecting Status for MsgID : %d.",currentMsgID-1);
		}
		else
		{
			while (!errorMsg[0])
			{
				/* Check if there is a command for which status is required */
				if (messageQueue.size())
				{
					pCmd=messageQueue.front()->GetCurrentCommand();
					if (!pCmd)
					{
						delete messageQueue.front();
						messageQueue.pop_front();
						messageQueueID++;
						continue;
					}
				}
				else
				{
					sprintf(errorMsg,"Not expecting status, received status for all sent commands.");
					break;
				}
				/*Check cmdRef and msgRef*/
				if (tempPcdata1==pCmd->GetCommandID(tempPcdata2) && msgRef==messageQueueID) break;
				if (!tempPcdata2 && tempPcdata1=="0") break;

				/* Status on Results discrepency */
				if (pCmd->GetType()!=SCTS_STATUS && pCmd->GetType()!=SCTS_RESULTS)
				{
					sprintf(errorMsg,"Expecting CmdRef : %s, received CmdRef : %s.SyncML Representation protocol V1.1.2 (6.4.1) : Ordering of Status commands in a SyncML response MUST match the order of the commands in the corresponding SyncML request.",(char *)tempPcdata2,(char *)tempPcdata1);
					break;
				}
				messageQueue.front()->DeleteCurrentCommand();
			}
		}
		if (errorMsg[0]) break;

		/* Check cmdName */
		cmdType=pCmd->GetType();
		if (!(cmd.GetCmd(tempPcdata1)==sctsCommandStrings[cmdType]))
		{
			sprintf(errorMsg,"Expecting Cmd : %s, received Cmd : %s.",sctsCommandStrings[cmdType],tempPcdata1);
			break;
		}

		/* Create a new node */
		SctsErrorLog::CloseNode();
		sprintf(errorMsg,"Command ID : %s, Message Ref.ID : %d, Command Ref.ID : %s, Command : %s",(char *)cmd.GetCommandID(tempPcdata1),msgRef,(char *)cmd.GetCmdRef(tempPcdata2),sctsCommandStrings[cmdType]);
		SctsErrorLog::OpenNode("Status",errorMsg);
		errorMsg[0]=0;

		cmd.GetChal(chal);

		if (chal)
		{
			if (encoding==XML && (!chal.GetFormat(tempPcdata1) || !(tempPcdata1=="b64")))
			{
				sprintf(errorMsg,"Missing or invalid Status->Chal->Meta->Format. Representation protocol (5.1.2) : The format value MUST be b64, when using the clear-text, XML representation.");
				break;
			}
			if (!chal.GetType(tempPcdata1))
				auth=new SctsAuthBasic();
			if (!auth && tempPcdata1=="syncml:auth-basic")
				auth=new SctsAuthBasic();
			if (!auth && tempPcdata1=="syncml:auth-md5")
			{
				if (chal.GetNextNonce(tempPcdata1))
					auth=new SctsAuthMD5((char *)tempPcdata1);
				else
				{
					sprintf(errorMsg,"Chal for 'syncml:auth-md5' missing NextNonce, unable to proceed.");
					break;
				}
			}
			if (!auth && tempPcdata1=="syncml:auth-MAC")
			{
				if (chal.GetNextNonce(tempPcdata1))
					auth=new SctsAuthHMAC((char *)tempPcdata1);
				else
				{
					sprintf(errorMsg,"Chal for 'syncml:auth-MAC' missing NextNonce, unable to proceed.");
					break;
				}
			}
			if (!auth)
			{
				sprintf(errorMsg,"Unsupported Chal->Meta->Type.");
				break;
			}
		}

		/* Don't process the status if the status of the synchdr was 401 or 407
		   Exception : Process the status on the SyncHdr to process the chal
		*/
		if (cmdType!=SCTS_HEADER && (recvSyncHdrStatus==401 || recvSyncHdrStatus==407))
		{
			error=false;
			break;
		}

		/* Handle status for different commands */
		switch(cmdType)
		{
		case SCTS_ADD:
		case SCTS_DELETE:
		case SCTS_SYNC_START:
		case SCTS_PUT:
		case SCTS_GET:
		case SCTS_COPY:
			{
				sprintf(errorMsg,"Not Expecting Status for %s.",sctsCommandStrings[cmdType]);
				break;
			}

		case SCTS_ALERT:
			{
				if (status==200) 
					sentSessionInitiationAlert=true;
				else
				{
					sprintf(errorMsg,"Unable to handle Status for %s.",sctsCommandStrings[cmdType]);
					break;
				}
				error=false;
				break;
			}
		case SCTS_REPLACE:
			{
				if (status==200) 
					sentDevInfo=true;
				else
				{
					sprintf(errorMsg,"Unable to handle Status for %s.",sctsCommandStrings[cmdType]);
					break;
				}
				error=false;
				break;
			}
		case SCTS_RESULTS:
			{
				if (status!=200 && status!=213) 
				{
					sprintf(errorMsg,"Unable to handle Status for %s.",sctsCommandStrings[cmdType]);
					if (largeObjectSize && largeObjectCmd==SCTS_RESULTS) LargeObjectClear();
					break;
				}
				error=false;
				break;
			}
		case SCTS_HEADER:
			{
				if (status!=200 && status!=212 && status!=101 && status!=401 && status!=407)
				{
					sprintf(errorMsg,"Unable to handle status for SyncHdr.");
					break;
				}
				/* Store the new nonce and set the authentication type of the device */
				if (auth && (auth->GetType()==AUTH_MD5 || auth->GetType()==AUTH_HMAC))
				{
					if (auth->GetType()==AUTH_MD5)
						device->SetNonce(false,((SctsAuthMD5 *)auth)->nonce,((SctsAuthMD5 *)auth)->size);
					else
						device->SetNonce(false,((SctsAuthHMAC *)auth)->nonce,((SctsAuthHMAC *)auth)->size);
				}
				if (status==200 && auth)
				{
					if (outAuth && auth->GetType()!=outAuth->GetType())
					{
						sprintf(errorMsg,"Authentication type change at server layer not allowed. Sync protocol (3.1) : Once authentication has occurred, the authentication type for a security layer MUST be kept same for the whole session.");
						break;
					}
					if (outAuth) delete outAuth;
					outAuth=auth;
					auth=0;
				}
				if (status==212 && outAuth)
				{
					delete outAuth;
					outAuth=0;
				}

				/* Chal discrepency : Look for chal if status is 401/407 */
				if (status==401 || status==407)
				{
					/* Check if chal for the same scheme was received */
					if (auth && outAuth && outAuth->GetType()==auth->GetType() && currentMsgID>2)
					{
						delete auth;	
						auth=0;
						delete outAuth;
						outAuth=0;
					}
					else
					{
						if (outAuth) delete outAuth;
						outAuth=auth;
						auth=0;
						device->SetAuthType(false,outAuth?outAuth->GetType():AUTH_NONE);
					}										
				}

				recvSyncHdrStatus=status;

				/* Create next outgoing message */
				outgoingMessage=new SctsMessage(sessionContext,encoding,BuildSyncHdr(),maxMsgSize,wbxmlConverterContext,uiCallbackData,uiCallback);
				if (outgoingMessage->GetFreeSize()<0)
				{
					sprintf(errorMsg,"Cannot build message with MaxMsgSize, an insufficient MaxMsgSize was either received from the server or set in the UI.");
					break;
				}
					
				if (nextSyncHdrStatus)
				{
					outgoingMessage->InsertCommand(nextSyncHdrStatus);
					nextSyncHdrStatus=0;
				}
				/* V1.1.1 Build pending status if any */
				while (!pendingStatus.empty())
				{
					SctsCommand *command=pendingStatus.front();
					((SctsStatus *)command)->SetCommandID(currentCmdID);
					if (!outgoingMessage->InsertCommand(command)) break;
					currentCmdID++;
					pendingStatus.pop_front();
				} 
				error=false;
				break;
			}
		}
		break;
	}
	if (error) 
		processError=PROCESS_ERR_STOP;
	else
	{
		/* UI callback */
		if (!itemList && uiCallback) (*uiCallback)(uiCallbackData,&cmd,0,false);
		if (itemList && !HandleStatusRefs(cmd,itemList,multipleStatus)) processError=PROCESS_ERR_STOP;
		if (cmdType==SCTS_HEADER)
			messageQueue.back()->DeleteCurrentCommand();
		else
			if (!multipleStatus) messageQueue.front()->DeleteCurrentCommand();
	}
	if (errorMsg[0]) SctsErrorLog::AppendError(errorMsg);
	SctsErrorLog::CloseNode();
	return;
}


void SctsDMClientSession::HandleAlert(SctsAlert& cmd)
{
	int statusCode=0;
	int alertCode=cmd.GetData();
	char errorMsg[300]="";
	char *statusItem=0;
	SctsTargetSource tempTS;
	SctsStatus *status=0;
	SctsPcdata tempPcdata1;
	SctsPcdata tempPcdata2;
	SctsItem item,_item;
	SctsItemList itemList;
	SctsMeta meta;
	SctsCred cred;
	SctsChal *chal=0;
    /*
     * Change to support multi choices. 
     */
	std::list<char *> items;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}
		/* Get the item list and the first item */
		cmd.GetItemList(itemList).GetData(item);
		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_ATOMIC_START && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Alert MUST be Syncbody, Atomic or Sequence .Representation protocol(5.5.2) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;
		/* Check immediate parents status */
		if (parent->status>=300 || parent->status==215)
		{
			statusCode=500;			
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) statusCode=215;
			if (parent->type==SCTS_ATOMIC_START && parent->status==507) statusCode=215;
			if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401) statusCode=sentSyncHdrStatus;
			break;
		}
		switch (alertCode)
		{
		case 1200:
		case 1201:
			{
				SctsErrorLog::AppendError("SyncML DM ConReqs V1.1.2 : The client does not expect Alert codes 1200/1201 from the server.");
				statusCode=406;
				break;
			}
		case 1221:
			{
				statusCode=200;
				break;
			}
		case 1222:
			{
				statusCode=200;
				break;
			}
		case 1223:
			{
				processError=PROCESS_ERR_STOP;
				SctsErrorLog::AppendError("The server sent a 'Session Abort' alert.");
				break;
			}
		case 1225:
			{
				processError=PROCESS_ERR_STOP;
				SctsErrorLog::AppendError("The server sent a 'NO End of Data' alert while the client was sending a Large Object.Ending Session.");
				break;
			}
				
		case 1100:
		case 1101:
		case 1102:
		case 1103:
        /*
         * Change to support multi choices. 
         */
        case 1104:
			{
				char *data=0,*temp=0,*dr=0;
				char et=0,it=0;
				int maxDT=-1,minDT=-1,maxLen=-1;
				if (!componentUIC.interactionAlert)
				{
					statusCode=406;
					break;
				}
				statusCode=500;
				itemList.GetData(item);
				if (item)
				{
					
					data=(char *)tempPcdata1;
					if (data)
					{
						while (true)
						{
							temp=(char *)-1;
							if (!sctsStrncmp(data,"MAXDT=",6))
							{
								if (maxDT!=-1)
								{
									SctsErrorLog::AppendError("User interaction Alert : MAXDT already specified.");
									break;
								}
								maxDT=atoi(data+6);
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
								if (maxDT<0)
								{
									temp=(char *)-1;
									SctsErrorLog::AppendError("User interaction Alert : Invalid MAXDT.");
									break;
								}
							}
							if (!sctsStrncmp(data,"MINDT=",6))
							{
								if (minDT!=-1)
								{
									SctsErrorLog::AppendError("User interaction Alert : MINDT already specified.");
									break;
								}
								minDT=atoi(data+6);
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
								if (minDT<0)
								{
									temp=(char *)-1;
									SctsErrorLog::AppendError("User interaction Alert : Invalid MINDT.");
									break;
								}
							}
							if (!sctsStrncmp(data,"MAXLEN=",7))
							{
								if (maxLen!=-1)
								{
									SctsErrorLog::AppendError("User interaction Alert : MAXLEN already specified.");
									break;
								}
								maxLen=atoi(data+6);
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
								if (maxLen<0)
								{
									temp=(char *)-1;
									SctsErrorLog::AppendError("User interaction Alert : Invalid MAXLEN.");
									break;
								}
							}
							if (!sctsStrncmp(data,"DR=",3))
							{
								if (dr)
								{
									SctsErrorLog::AppendError("User interaction Alert : DR already specified.");
									break;
								}
								dr=data+3;
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
							}
							if (!sctsStrncmp(data,"IT=",3))
							{
								if (it)
								{
									SctsErrorLog::AppendError("User interaction Alert : IT already specified.");
									break;
								}
								it=data[4];
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
								if ((it!='A' && it!='N' || it!='D' && it!='T' || it!='P' && it!='I') || data[5])
								{
									temp=(char *)-1;
									SctsErrorLog::AppendError("User interaction Alert : Invalid IT.");
									break;
								}
							}
							if (!sctsStrncmp(data,"ET=",3))
							{
								if (et)
								{
									SctsErrorLog::AppendError("User interaction Alert : ET already specified.");
									break;
								}
								et=data[4];
								if ((temp=sctsStrchr(data,'&'))) *temp=0;
								if ((et!='T' && et!='P') || data[5])
								{
									temp=(char *)-1;
									SctsErrorLog::AppendError("User interaction Alert : Invalid ET.");
									break;
								}
							}
							if (!temp || temp==(char *)-1) break;
							data=temp+1;
						}
					}
				}
				else
				{
					SctsErrorLog::AppendError("User interaction Alert : Missing options Item.");
					break;
				}

				while (temp!=(char *)-1 && itemList.GetNextData(item))
				{
					if (!item.GetData(tempPcdata1))
					{
						temp=(char *)-1;
						SctsErrorLog::AppendError("User interaction Alert : Item missing data.");
						break;
					}
					items.push_back((char *)tempPcdata1);
				}
				if (temp==(char *)-1)
				{
					SctsErrorLog::AppendError("Invalid user interaction Alert.");
					break;
				}
				if (!items.size())
				{
					SctsErrorLog::AppendError("User interaction Alert has insufficient number of items.");
					break;
				}
				statusCode=(*componentUIC.interactionAlert)(device->devID,alertCode,items,maxDT,minDT,maxLen,dr,et,it);
				if (alertCode>=1102 && items.size()) statusItem=items.back();
				break;
			}
		default:
			{
				SctsErrorLog::AppendError("Invalid Alert code.");
				break;
			}
		}
		break;
	} /* End of while */
	if (statusCode) 
	{
		/* Atomic Handling */
		if (parent->type==SCTS_ATOMIC_START && statusCode!=200)
			parent->status=507;

		/* Sequence Handling */
		if (parent->type==SCTS_SEQUENCE_START && statusCode!=200)
			parent->status=215;
				
		/* UI callback */
		if (uiCallback)
		{
			cmd.status=statusCode;
			(*uiCallback)(uiCallbackData,&cmd,0,false);
		}
		SctsStatusRef *statusRef=new SctsStatusRef();
		SctsPcdata tempPcdata;
		statusRef->status=statusCode;
		statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
		statusRef->msgID=processMsgID;
		statusRef->data=sctsMalloc(sizeof(int));
		sctsMemcpy(statusRef->data,&alertCode,sizeof(int));
		sentStatusRefs[SCTS_ALERT].push_back(statusRef);
		if (!messageNoResp && !cmd.IsNoResp())
		{
			status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata1),"Alert",statusCode);
			if (statusItem)
			{
                /*
                 * Change to support multi choices. 
                 */
                if (alertCode==1104)
                {
                    statusItem=*items.rbegin();
                    SctsItemList tmpItems(SctsItem(0,0,0,0,0,(statusItem&&sctsStrcmp(statusItem,""))?&SctsPcdata(statusItem):&SctsPcdata("")));
                    SmlItemList_t *pItemList=tmpItems.rawData;
                    std::list<char *>::reverse_iterator it=items.rbegin();
                    for (++it;it!=items.rend();++it)
                    {
                        statusItem=*it;
                        tmpItems.SetNextData(SctsItem(0,0,0,0,0,(statusItem&&sctsStrcmp(statusItem,""))?&SctsPcdata(statusItem):&SctsPcdata("")));
                        sctsFree(statusItem);
                    }
                    status->SetItemList(&SctsItemList(pItemList));
                    statusItem=0;
                }
                else
                {
				    status->SetItemList(&SctsItemList(SctsItem(0,0,0,0,0,(statusItem&&sctsStrcmp(statusItem,""))?&SctsPcdata(statusItem):&SctsPcdata(""))));
				    sctsFree(statusItem);
				    statusItem=0;
                }
			}
			if (status) 
			{
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
			}
			++currentCmdID;
		}
	}
	else
		processError=PROCESS_ERR_STOP;
	if (statusItem) sctsFree(statusItem);
	if (errorMsg[0]) SctsErrorLog::AppendError(errorMsg);
	SctsErrorLog::CloseNode();
	return;
}

void SctsDMClientSession::HandleAdd(SctsAdd& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
	int statusCode=500;
	int itemCnt=0;
	char *cmdMime=0;
	char *cmdFormat=0;
	char *mime=0;
	char *format=0;
	char *target;
	SctsMeta meta;
	SctsItem item;
	SctsStatus *status=0;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsTargetSource tempTS;
	SctsDMCommand *command;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if parents are valid */
		if (parent->type!=SCTS_ATOMIC_START && parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Add MUST be Syncbody,Atomic or Sequence. Representation protocol (5.5.1) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_ATOMIC_START && parent->status==507) cmd.status=215;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (sentSyncHdrStatus==401 || sentSyncHdrStatus==407) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);

			/* Create the StatusRef and push it into the StatusRef List*/

			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_ADD].push_back(statusRef);
			
			if (!messageNoResp && !cmd.IsNoResp())
			{
				SctsStatus *status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Add",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}

		/* Get the mimeType */
		if (cmd.GetMeta(meta))
		{
			cmdMime=(char *)meta.GetType(tempPcdata);
			cmdFormat=(char *)meta.GetFormat(tempPcdata);
		}
		/* Process the commands Item list */
		cmd.GetItemList(itemList);
		itemList.GetData(item);
		for (;item && statusCode;itemList.GetNextData(item))
		{
			statusCode=0;
			while(true)
			{
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START && parent->status!=200)
				{
					statusCode=215;
					break;
				}
				
				/* Check if source is present */
				if (item.GetSource(tempTS))
				{
					SctsErrorLog::AppendError("Item->Source element is not allowed. DM Representation protocol (5.5.1) The Target MUST be used to add a item.");
					break;
				}

				/* Check if target is present */
				if (!item.GetTarget(tempTS).GetLocURI(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.1) : Target specified in the Item MUST be full device URI.");
					break;
				}
				target=(char *)tempPcdata;
				
				/* Large object delivery */
				if (largeObjectSize && largeObjectCmd!=SCTS_RESULTS)
				{
								
					int size=largeObjectSize;
					if (!LargeObjectRecvChunk(false,statusCode,SCTS_ADD,item,cmd.GetMeta(meta))) break;

					if (!statusCode)
					{
                        /*
                         * Change to support TNDS. 
                         */
                        if (largeObjectFormat && largeObjectType && !sctsStrcmp("xml", largeObjectFormat) && !sctsStrcmp("application/vnd.syncml.dmtnds+xml", largeObjectType))
                        {
                            CONVERTB64TOBINFIX(device->encoding,nsize,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            SmlSubTreePtr_t pMgmtTree=0;
                            if(smlProcessMgmtTree(0, largeObjectBuffer + nsize - 1, largeObjectBuffer, &pMgmtTree))
                            {
                                statusCode=500;
						        SctsErrorLog::AppendError("Process management tree failed.");
                            }
                            else
                            {
                                statusCode=addDMTree(device, target, pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                            }
                        }
                        else if (largeObjectFormat && largeObjectType && !sctsStrcmp("bin", largeObjectFormat) && !sctsStrcmp("application/vnd.syncml.dmtnds+wbxml", largeObjectType))
                        {
                            CONVERTB64TOBINFIX(device->encoding,nsize,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            SmlSubTreePtr_t pMgmtTree=0;
                            if(smlProcessMgmtTree(1, largeObjectBuffer + nsize, largeObjectBuffer, &pMgmtTree))
                            {
                                statusCode=500;
						        SctsErrorLog::AppendError("Process management tree failed.");
                            }
                            else
                            {
                                statusCode=addDMTree(device, target, pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                            }
                        }
                        else
                        {
                            /* VERSION 1.1.2*/
                            //0003 the b64 data that comes in shoule be reconverted back to bin if the encoing type is XML
                            CONVERTB64TOBINFIX(device->encoding,nret,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            statusCode=device->AddFullDMNode(target,device->serverID,largeObjectFormat,false,largeObjectBuffer,largeObjectType,nret);
                        }
					}
					LargeObjectClear();					
					break;
				}
				/* Get the mimeType */
				mime=cmdMime;
				format=cmdFormat;
				if (item.GetMeta(meta).GetType(tempPcdata)) mime=(char *)tempPcdata;
				if (item.GetMeta(meta).GetFormat(tempPcdata)) format=(char *)tempPcdata;

				/* Large object delivery */
				if (item.IsChunked())
				{
					if (supportsLrgObj)
					{
						SCTSASSERT(!largeObjectSize);
						sctsFree(largeObjectType);
						sctsFree(largeObjectFormat);
						largeObjectType=sctsStrdup(mime);
						largeObjectFormat=sctsStrdup(format);
						LargeObjectRecvChunk(true,statusCode,SCTS_ADD,item,cmd.GetMeta(meta));
					}
					else
						statusCode=406;
					break;
				}
				
				/* Check if data is present if the item being added is not node */
				if (!item.GetData(tempPcdata) && format && sctsStrcmp(format,"node"))
				{
					SctsErrorLog::AppendError("Item->Data element is missing. SyncML DM protocol (8.3) : The Data element inside Item is used to include the data itself if the operation is not a deletion.");
					break;
				}

                /*
                 * Change to support TNDS. 
                 */
                if (format && mime && !sctsStrcmp("xml", format) && !sctsStrcmp("application/vnd.syncml.dmtnds+xml", mime))
                {
                    CONVERTB64TOBINFIX(device->encoding,nsize,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                    SmlSubTreePtr_t pMgmtTree=0;
                    if(smlProcessMgmtTree(0, (char*)tempPcdata + nsize - 1, (char*)tempPcdata, &pMgmtTree))
                    {
                        statusCode=500;
						SctsErrorLog::AppendError("Process management tree failed.");
                    }
                    else
                    {
                        statusCode=addDMTree(device, target, pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                    }
                }
                else if (format && mime && !sctsStrcmp("bin", format) && !sctsStrcmp("application/vnd.syncml.dmtnds+wbxml", mime))
                {
                    CONVERTB64TOBINFIX(device->encoding,nsize,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                    SmlSubTreePtr_t pMgmtTree=0;
                    if(smlProcessMgmtTree(1, (char*)tempPcdata + nsize, (char*)tempPcdata, &pMgmtTree))
                    {
                        statusCode=500;
						SctsErrorLog::AppendError("Process management tree failed.");
                    }
                    else
                    {
                        statusCode=addDMTree(device, target, pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                    }
                }
                else
                {
                    //* Add the item */
                    /* VERSION 1.1.2*/
                    //0003 the b64 data that comes in shoule be reconverted back to bin if the encoing type is XML
                    CONVERTB64TOBINFIX(device->encoding,nret,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                    statusCode=device->AddFullDMNode(target,device->serverID,format,false,(char *)tempPcdata,mime,nret,0,parent->type==SCTS_ATOMIC_START?&command:0);
                }
				
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START)
				{
					if (statusCode==200)
						atomicStack.push(command);
					else
						parent->status=507;
				}
				/* DMFINAL Sequence Handling 
				if (parent->type==SCTS_SEQUENCE_START && statusCode!=200)
					parent->status=215;
				*/
				break;
			}
			
			if (statusCode)
			{
				/* UI callback */
				if (uiCallback)
				{
					cmd.status=statusCode;
					(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
				}
				if (!messageNoResp && !cmd.IsNoResp())
				{
					/* Multiple status */
					it=targetRefs.find(statusCode);
					if (it==targetRefs.end())
					{
						SctsTargetRefList *targetRefList;
						if (status) 
						{
							if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
								pendingStatus.push_back(status);
						}
						status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Add",statusCode);
						++currentCmdID;
						targetRefList=new SctsTargetRefList(SctsPcdata(target));
						targetRefs[statusCode]=targetRefList;
						status->SetTargetRefList(targetRefList);
						/* Create the StatusRef and push it into the StatusRef List*/
						SctsStatusRef *statusRef=new SctsStatusRef();
						statusRef->status=statusCode;
						statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
						statusRef->msgID=processMsgID;
						sentStatusRefs[SCTS_ADD].push_back(statusRef);
						}
					else
					{
						it->second->SetNextData(SctsPcdata(target));
					} 
				}
			}
		}
		break;
	}
	if (targetRefs.size()==1) 
		/* TargetRef/SourceRef discrepancy */
	if (itemCnt>1) status->SetTargetRefList(0); 
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}
	
	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP; 
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleReplace(SctsReplace& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
	int statusCode=0;
	int itemCnt=0;
	char *cmdMime=0;
	char *cmdFormat=0;
	char *mime=0;
	char *format=0;
	char *target;
	char *tempStr=0;
	SctsMeta meta;
	SctsItem item;
	SctsStatus *status=0;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsTargetSource tempTS;
	SctsDMNodeProp prop;
	SctsDMCommand *command;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if parents are valid */
		if (parent->type!=SCTS_ATOMIC_START && parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Replace MUST be SyncBody/Atomic/Sequence. Representation protocol (5.5.11) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_ATOMIC_START && parent->status==507) cmd.status=215;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);

			/* Create the StatusRef and push it into the StatusRef List*/
			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_REPLACE].push_back(statusRef);

			if (!messageNoResp && !cmd.IsNoResp())
			{
				SctsStatus * status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Replace",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}

		/* Get the mimeType */
		if (cmd.GetMeta(meta))
		{
			cmdMime=(char *)meta.GetType(tempPcdata);
			cmdFormat=(char *)meta.GetFormat(tempPcdata);
		}

		/* Process the commands Item list */
		statusCode=200;
		cmd.GetItemList(itemList);
		itemList.GetData(item);
		for (;item && statusCode;itemList.GetNextData(item))
		{
			++itemCnt;
			statusCode=0;
			while(true)
			{
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START && parent->status!=200)
				{
					statusCode=215;
					break;
				}
				/* Check if data is present */
				if (!item.GetData(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Data element is missing. SyncML DM protocol (8.3) : The Data element inside Item is used to include the data itself if the operation is not a deletion.");
					break;
				}

				/* Check if source is present */
				if (item.GetSource(tempTS))
				{
					SctsErrorLog::AppendError("Item->Source element is not allowed. DM Representation protocol (5.5.11)");
					break;
				}

				/* Check if target is present */
				if (!item.GetTarget(tempTS).GetLocURI(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.11)");
					break;
				}
				target=(char *)tempPcdata;

				/* Large object delivery */
				if (largeObjectSize && largeObjectCmd!=SCTS_RESULTS)
				{
					int size=largeObjectSize;
					if (!LargeObjectRecvChunk(false,statusCode,SCTS_REPLACE,item,cmd.GetMeta(meta))) break;
					if (!statusCode)
					{
                        /*
                         * Change to support TNDS. 
                         */
                        if (largeObjectFormat && largeObjectType && !sctsStrcmp("xml", largeObjectFormat) && !sctsStrcmp("application/vnd.syncml.dmtnds+xml", largeObjectType))
                        {
                            CONVERTB64TOBINFIX(device->encoding,nsize,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            SmlSubTreePtr_t pMgmtTree=0;
                            if(smlProcessMgmtTree(0, largeObjectBuffer + nsize - 1, largeObjectBuffer, &pMgmtTree))
                            {
                                statusCode=500;
						        SctsErrorLog::AppendError("Process management tree failed.");
                            }
                            else
                            {
                                statusCode=replaceDMTree(device,target,pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                            }
                        }
                        else if (largeObjectFormat && largeObjectType && !sctsStrcmp("bin", largeObjectFormat) && !sctsStrcmp("application/vnd.syncml.dmtnds+wbxml", largeObjectType))
                        {
                            CONVERTB64TOBINFIX(device->encoding,nsize,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            SmlSubTreePtr_t pMgmtTree=0;
                            if(smlProcessMgmtTree(1, largeObjectBuffer + nsize, largeObjectBuffer, &pMgmtTree))
                            {
                                statusCode=500;
						        SctsErrorLog::AppendError("Process management tree failed.");
                            }
                            else
                            {
                                statusCode=replaceDMTree(device,target,pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                            }
                        }
                        else
                        {
                            /* VERSION 1.1.2*/
                            //0003 the b64 data that comes in shoule be reconverted back to bin if the encoing type is XML
                            CONVERTB64TOBINFIX(device->encoding,nret,largeObjectBuffer,largeObjectFormat,largeObjectSize)
                            statusCode=device->ReplaceDMNodeData(target,device->serverID,largeObjectBuffer,nret,largeObjectFormat,largeObjectType);	
                        }
					}
					LargeObjectClear();
					break;
				}

				/* Get the mimeType */
				mime=cmdMime;
				format=cmdFormat;
				if (item.GetMeta(meta).GetType(tempPcdata)) mime=(char *)tempPcdata;
				if (item.GetMeta(meta).GetFormat(tempPcdata)) format=(char *)tempPcdata;
				
				/* Large object delivery */
				if (item.IsChunked())
				{
					if (supportsLrgObj)
					{
						SCTSASSERT(!largeObjectSize);
						sctsFree(largeObjectType);
						sctsFree(largeObjectFormat);
						largeObjectType=sctsStrdup(mime);
						largeObjectFormat=sctsStrdup(format);
						LargeObjectRecvChunk(true,statusCode,SCTS_REPLACE,item,cmd.GetMeta(meta));
					}
					else
						statusCode=406;
					break;
				}
					
				/* Get the data */
				item.GetData(tempPcdata);

				/* Check whether to replace data or property */
				if ((tempStr=sctsStrstr(target,"?prop=")))
				{
					prop=DMPROP_NONE;
					if (!sctsStrcmp(tempStr+6,"ACL"))
						prop=DMPROP_ACL;
					if (!sctsStrcmp(tempStr+6,"Name"))
						prop=DMPROP_NAME;
					if (!sctsStrcmp(tempStr+6,"Title"))
						prop=DMPROP_TITLE;
					if (prop==DMPROP_NONE)
					{
						statusCode=500;
						break;
					}
					*tempStr=0;
					statusCode=device->ReplaceDMNodeProp(target,device->serverID,prop,(char *)tempPcdata,parent->type==SCTS_ATOMIC_START?&command:0);
					*tempStr='?';
				}
				else
				{
                    /*
                     * Change to support TNDS. 
                     */
                    if (format && mime && !sctsStrcmp("xml", format) && !sctsStrcmp("application/vnd.syncml.dmtnds+xml", mime))
                    {
                        CONVERTB64TOBINFIX(device->encoding,nsize,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                        SmlSubTreePtr_t pMgmtTree=0;
                        if(smlProcessMgmtTree(0, (char *)tempPcdata + nsize - 1, (char *)tempPcdata, &pMgmtTree))
                        {
                            statusCode=500;
                            SctsErrorLog::AppendError("Process Management Tree failed.");
                        }
                        else
                        {
                            statusCode=replaceDMTree(device,target,pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                        }
                    }
                    else if (format && mime && !sctsStrcmp("bin", format) && !sctsStrcmp("application/vnd.syncml.dmtnds+wbxml", mime))
                    {
                        CONVERTB64TOBINFIX(device->encoding,nsize,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                        SmlSubTreePtr_t pMgmtTree=0;
                        if(smlProcessMgmtTree(1, (char *)tempPcdata + nsize, (char *)tempPcdata, &pMgmtTree))
                        {
                            statusCode=500;
                            SctsErrorLog::AppendError("Process Management Tree failed.");
                        }
                        else
                        {
                            statusCode=replaceDMTree(device,target,pMgmtTree,parent->type==SCTS_ATOMIC_START?&command:0);
                        }
                    }
                    else
                    {
                        /* VERSION 1.1.2*/
                        //0003 the b64 data that comes in shoule be reconverted back to bin if the encoing type is XML
                        CONVERTB64TOBINFIX(device->encoding,nret,(unsigned char*)(char*)tempPcdata,format,tempPcdata.GetLength())
                        statusCode=device->ReplaceDMNodeData(target,device->serverID,(char *)tempPcdata,nret,format,mime,parent->type==SCTS_ATOMIC_START?&command:0);
                    }
				}
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START)
				{
					if (statusCode==200)
						atomicStack.push(command);
					else
						parent->status=507;
				}
				/* Sequence Handling DMFINAL
				if (parent->type==SCTS_SEQUENCE_START && statusCode!=200)
					parent->status=215;
				*/
				break;
			}
			
			if (statusCode)
			{
				/* UI callback */
				if (uiCallback)
				{
					cmd.status=statusCode;
					(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
				}
				if (!messageNoResp && !cmd.IsNoResp())
				{
					/* Multiple status */
					it=targetRefs.find(statusCode);
					if (it==targetRefs.end())
					{
						SctsTargetRefList *targetRefList;
						if (status) 
						{
							if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
								pendingStatus.push_back(status);
						}
						status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Replace",statusCode);
						++currentCmdID;
						targetRefList=new SctsTargetRefList(SctsPcdata(target));
						targetRefs[statusCode]=targetRefList;
						status->SetTargetRefList(targetRefList);

						/* Create the StatusRef and push it into the StatusRef List*/
						SctsStatusRef *statusRef=new SctsStatusRef();
						statusRef->status=statusCode;
						statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
						statusRef->msgID=processMsgID;
						sentStatusRefs[SCTS_REPLACE].push_back(statusRef);
					}
					else
					{
						it->second->SetNextData(SctsPcdata(target));
					}
				}
			}
		}
		break;
	}
	if (targetRefs.size()==1) 
		/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetTargetRefList(0);
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}
	
	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP; 
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleDelete(SctsDelete& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
	int statusCode=0;
	int itemCnt=0;
	char *target;
	SctsMeta meta;
	SctsItem item;
	SctsStatus *status=0;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsTargetSource tempTS;
	SctsDMCommand *command;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if parents are valid */
		if (parent->type!=SCTS_ATOMIC_START && parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Delete MUST be Sync/Atomic/Sequence. Representation protocol (5.5.5) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_ATOMIC_START && parent->status==507) cmd.status=215;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);

			/* Create the StatusRef and push it into the StatusRef List*/
			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_DELETE].push_back(statusRef);

			if (!messageNoResp && !cmd.IsNoResp())
			{
				SctsStatus *status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Delete",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}
		
		/* Large object delivery 
		if (largeObjectSize)
		{
			/* UI callback 
			if (uiCallback)
			{
				cmd.status=405;
				(*uiCallback)(uiCallbackData,&cmd,0,false);
			}
			if (!messageNoResp && !cmd.IsNoResp())
			{
				outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Delete",405),false);
				++currentCmdID;
			}
			SctsErrorLog::AppendError("Large object delivery : unexpected command.");
			SctsErrorLog::CloseNode();
			return;
		}
		*/

		/* Process the commands Item list */
		statusCode=200;
		cmd.GetItemList(itemList);
		itemList.GetData(item);
		for (;item && statusCode;itemList.GetNextData(item))
		{
			++itemCnt;
			statusCode=0;
			while(true)
			{
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START && parent->status!=200)
				{
					statusCode=215;
					break;
				}
				/* Check if data is present */
				if (item.GetData(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Data element is not allowed. SyncML DM protocol (8.3) : The Data element inside Item is used to include the data itself if the operation is not a deletion.");
					break;
				}

				/* Check if source is present */
				if (item.GetSource(tempTS))
				{
					SctsErrorLog::AppendError("Item->Source element is not allowed.");
					break;
				}

				/* Check if target is present */
				if (!item.GetTarget(tempTS).GetLocURI(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.5) : The Target specified within the Item element type MUST be a full device URI.");
					break;
				}
				target=(char *)tempPcdata;
				
				/* Delete the item */
				statusCode=device->DeleteDMNode(target,device->serverID,parent->type==SCTS_ATOMIC_START?&command:0);
				/* Atomic Handling */
				if (parent->type==SCTS_ATOMIC_START)
				{
					if (statusCode==200)
						atomicStack.push(command);
					else
						parent->status=507;
				}
				/* Sequence Handling DMFINAL
				if (parent->type==SCTS_SEQUENCE_START && statusCode!=200)
					parent->status=215;
				*/
				break;
			}
			if (statusCode)
			{
				/* UI callback */
				if (uiCallback)
				{
					cmd.status=statusCode;
					(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
				}
				if (!messageNoResp && !cmd.IsNoResp())
				{
					/* Multiple status */
					it=targetRefs.find(statusCode);
					if (it==targetRefs.end())
					{
						SctsTargetRefList *targetRefList;
						if (status) 
						{
							if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
								pendingStatus.push_back(status);
						}
						status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Delete",statusCode);
						++currentCmdID;
						targetRefList=new SctsTargetRefList(SctsPcdata(target));
						targetRefs[statusCode]=targetRefList;
						status->SetTargetRefList(targetRefList);

						/* Create the StatusRef and push it into the StatusRef List*/
						SctsStatusRef *statusRef=new SctsStatusRef();
						statusRef->status=statusCode;
						statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
						statusRef->msgID=processMsgID;
						sentStatusRefs[SCTS_DELETE].push_back(statusRef);
					}
					else
					{
						it->second->SetNextData(SctsPcdata(target));
					}
				}
			}
		}
		break;
	}
	if (targetRefs.size()==1) 
		/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetTargetRefList(0);
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}
	
	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP; 
	SctsErrorLog::CloseNode();
}


void SctsDMClientSession::HandleGet(SctsGet& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
	int statusCode=0,itemCnt=0;
	unsigned int size=0;
	SctsTargetSource tempTS;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsItem item;
	SctsMeta meta;
	SctsStatus *status=0;
	SctsDMResults *result=0;
	SctsDMNodeProp prop;
	char *tempStr,*target,*targetRefStr;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Get MUST be SyncBody or Sequence.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback) (*uiCallback)(uiCallbackData,&cmd,0,false);
			
			/* Create the StatusRef and push it into the StatusRef List*/
			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_GET].push_back(statusRef);

			if (!messageNoResp && !cmd.IsNoResp())
			{
				status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Get",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}
		
		/* Process the commands Item list */
		statusCode=200;
		cmd.GetItemList(itemList);
		itemList.GetData(item);
		for (;item && statusCode;itemList.GetNextData(item))
		{
			++itemCnt;
			statusCode=0;
			while(true)
			{
				/* Check if data is present */
				if (item.GetData(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Data element is not allowed. SyncML DM protocol (8.3) : The Data element inside Item is used to include the data itself if the operation is not a deletion.");
					break;
				}

				/* Check if source is present */
				if (item.GetSource(tempTS))
				{
					SctsErrorLog::AppendError("Item->Source element is not allowed.");
					break;
				}

				/* Check if target is present */
				if (!item.GetTarget(tempTS).GetLocURI(tempPcdata))
				{
					SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.7) : The Target specified within the Item element type MUST be a full device URI.");
					break;
				}
				target=(char *)tempPcdata;				
				if (target) targetRefStr=sctsStrdup(target);
				/* Get the data */
				item.GetData(tempPcdata);
				
				/* Check whether it is a Get on a property or data */
				prop=DMPROP_NONE;
				if ((tempStr=sctsStrstr(target,"?prop=")))
				{
					*tempStr=0;
					for (prop=DMPROP_ACL;prop!=DMPROP_STRUCT && sctsStrcmp(tempStr+6,SctsDMNodePropertyString[prop]);prop=(SctsDMNodeProp)((int)prop+1));
					if (prop==DMPROP_STRUCT)
					{
						char buffer[500];
						sprintf(buffer,"%s is not a valid property of the node",tempStr+6);
						SctsErrorLog::AppendError(buffer);
						statusCode=500;
						break;
					}					
				}
				/* Check if the Get is for a Tree Discovery */
				if ((tempStr=sctsStrstr(target,"?list=")))
				{
					*tempStr=0;
                    /*
                     * Change to support TNDS. 
                     */
                    for (prop=DMPROP_STRUCT;prop!=DMPROP_NONE && !isProperty(tempStr+6,SctsDMNodePropertyString[prop]);prop=(SctsDMNodeProp)((int)prop+1));
					if (prop==DMPROP_NONE)
					{
						char buffer[500];
						sprintf(buffer,"%s is not a valid property of the node",tempStr+6);
						SctsErrorLog::AppendError(buffer);
						statusCode=500;
						break;
                    }
				}
				
				if ((statusCode=device->GetDMNode(target,device->serverID,prop))==200)
				{
					SctsDMNode *current=device->FindDMNode(target);
					if ((prop==DMPROP_NONE || prop==DMPROP_STRUCTDATA) && current && largeObjectBufferSize && current->size>largeObjectBufferSize) 
					{
						char buffer[500];
						sprintf(buffer,"Unable to fit results with the current MaxObjSize.Object Size %d, MaxObjSize %d",current->size,largeObjectBufferSize);
						SctsErrorLog::AppendError(buffer);
						statusCode=413;
						break;
					}
					SctsDMResults *results;
					results=new SctsDMResults();
					results->cmdRef=cmd.GetCommandID(tempPcdata).GetString();
					results->msgRef=processMsgID;
					results->prop=prop;
					BuildResults(results,current);
					
					if (results->prop==DMPROP_STRUCT || results->prop==DMPROP_STRUCTDATA)
					{
						int rc;
						std::deque<SctsDMNode *> refList; 
						
						results->source=sctsStrdup(target);
						*tempStr='?';
						pendingResults.push_back(results);

						current=current->child;					
						while (current)
						{
							refList.push_back(current);
							current=current->next;							
						}
						while (!refList.empty())
						{
							current=(SctsDMNode *)refList.front();
							refList.pop_front();
							if (rc=device->GetDMNode(current,device->serverID,prop)==200)
							{
								if (prop==DMPROP_STRUCTDATA && largeObjectBufferSize && current->size>largeObjectBufferSize) 
								{
									char buffer[500];
									sprintf(buffer,"Unable to fit results with the current MaxObjSize. Object Size %d, MaxObjSize %d",current->size,largeObjectBufferSize);
									SctsErrorLog::AppendError(buffer);
									statusCode=413;
									break;
								}
								results=new SctsDMResults();
								results->prop=prop;
								results->cmdRef=cmd.GetCommandID(tempPcdata).GetString();
								results->msgRef=processMsgID;
								results->source=device->GetPath(current);
								BuildResults(results,current);
								pendingResults.push_back(results);
								current=current->child;
								while (current)
								{
									refList.push_back(current);
									current=current->next;
								}
							}
						}						
					}
                    /*
                     * Change to support TNDS. 
                     */
                    else if (results->prop==DMPROP_TNDS)
                    {
                        const char *propertys=tempStr+10;
                        for (int i = 0; i < 7 /* array size of SctsGetTNDSPropertyString */; ++i)
                        {
                            setGetTNDSProperty((SctsGetTNDSProperty)i,
                                               isPropertySet(propertys, SctsGetTNDSPropertyString[i])
                                              );
                        }
                        subTreeRoot=current;
                        int totalSize = subTreeRoot->size;
                        getRight=device->GetDMNode(current,device->serverID,prop);
                        results->prop=DMPROP_TNDS_STARTNODE;
                        BuildResults(results,subTreeRoot);
                        if (current->child)
                        {
                            getSubTreeNode->child = (SmlSubTreeNodePtr_t)smlLibMalloc(sizeof(SmlSubTreeNode_t));
                            memset(getSubTreeNode->child, 0, sizeof(SmlSubTreeNode_t));
                            getSubTreeNode->child->parent=getSubTreeNode;
                            getSubTreeNode = getSubTreeNode->child;
                            totalSize+=current->size;
                            current=current->child;
                        }
                        while (current && current!=subTreeRoot)
                        {
                            getRight=device->GetDMNode(current,device->serverID,prop);
                            if (current && largeObjectBufferSize && current->size+totalSize>largeObjectBufferSize)
                            {
                                char buffer[500];
                                sprintf(buffer,"Unable to fit results with the current MaxObjSize.Object Size %d, MaxObjSize %d",current->size,largeObjectBufferSize);
                                SctsErrorLog::AppendError(buffer);
                                statusCode=413;
                                break;
                            }
                            results->prop=DMPROP_TNDS_STARTNODE;
                            BuildResults(results,current);
                            if (current->child)
                            {
                                getSubTreeNode->child = (SmlSubTreeNodePtr_t)smlLibMalloc(sizeof(SmlSubTreeNode_t));
                                memset(getSubTreeNode->child, 0, sizeof(SmlSubTreeNode_t));
                                getSubTreeNode->child->parent=getSubTreeNode;
                                getSubTreeNode = getSubTreeNode->child;
                                current=current->child;
                                totalSize+=current->size;
                            }
                            else if(current->next)
                            {
                                results->prop=DMPROP_TNDS_ENDNODE;
                                BuildResults(results,current);
                                getSubTreeNode->nextSibling = (SmlSubTreeNodePtr_t)smlLibMalloc(sizeof(SmlSubTreeNode_t));
                                memset(getSubTreeNode->nextSibling, 0, sizeof(SmlSubTreeNode_t));
                                getSubTreeNode->nextSibling->prevSibling=getSubTreeNode;
                                getSubTreeNode->nextSibling->parent=getSubTreeNode->parent;
                                getSubTreeNode = getSubTreeNode->nextSibling;
                                current=current->next;
                                totalSize+=current->size;
                            }
                            else
                            {
                                do
                                {
                                    results->prop=DMPROP_TNDS_ENDNODE;
                                    BuildResults(results,current);
                                    current=current->parent;
                                    getSubTreeNode=getSubTreeNode->parent;
                                }
                                while(!current->next && current!=subTreeRoot);
                                if (current != subTreeRoot)
                                {
                                    results->prop=DMPROP_TNDS_ENDNODE;
                                    BuildResults(results,current);
                                    current=current->next;
                                    if (current)
                                    {
                                        getSubTreeNode->nextSibling = (SmlSubTreeNodePtr_t)smlLibMalloc(sizeof(SmlSubTreeNode_t));
                                        memset(getSubTreeNode->nextSibling, 0, sizeof(SmlSubTreeNode_t));
                                        getSubTreeNode->nextSibling->prevSibling=getSubTreeNode;
                                        getSubTreeNode->nextSibling->parent=getSubTreeNode->parent;
                                        totalSize+=current->size;
                                    }
                                    getSubTreeNode = getSubTreeNode->nextSibling;
                                }
                            }
                        }
                        results->prop=DMPROP_TNDS_ENDNODE;
                        BuildResults(results,subTreeRoot);
                        results->prop=DMPROP_TNDS;
                        BuildResults(results,subTreeRoot);
                        subTreeRoot=0;
						results->source=sctsStrdup(target);
                        *tempStr='?';
						pendingResults.push_back(results);
					}
					else
					{
						if (tempStr) *tempStr='?';
						results->source=sctsStrdup(targetRefStr);
						pendingResults.push_back(results);
					}
				}

				/* Sequence Handling DMFINAL
				if (parent->type==SCTS_SEQUENCE_START && statusCode>300)
					parent->status=215;				
				*/
				break;
			}

			if (statusCode)
			{
				/* UI callback */
				if (uiCallback)
				{
					cmd.status=statusCode;
					(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
				}
				if (!messageNoResp && !cmd.IsNoResp())
				{
					/* Multiple status */
					it=targetRefs.find(statusCode);
					if (it==targetRefs.end())
					{
						SctsTargetRefList *targetRefList;
						if (status) 
						{
							if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
								pendingStatus.push_back(status);
						}
						status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Get",statusCode);
						++currentCmdID;
						targetRefList=new SctsTargetRefList(SctsPcdata(targetRefStr));
						targetRefs[statusCode]=targetRefList;
						status->SetTargetRefList(targetRefList);
						/* Create the StatusRef and push it into the StatusRef List*/
						SctsStatusRef *statusRef=new SctsStatusRef();
						statusRef->status=statusCode;
						statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
						statusRef->msgID=processMsgID;
						statusRef->prop=prop;
						if (targetRefStr) statusRef->data=sctsStrdup(targetRefStr);
						sentStatusRefs[SCTS_GET].push_back(statusRef);
					}
					else
					{
						it->second->SetNextData(SctsPcdata(targetRefStr));
					}
				}
			}
		}
		break;
	}
	if (targetRefs.size()==1) 
		/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetTargetRefList(0);
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}
	
	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP; 
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleStartAtomic(SctsAtomic& cmd)
{
	int statusCode=0;
	SctsPcdata tempPcdata;
	SctsStatusRef *statusRef=0;
	ProcessStackCmd *parent=processStack.top();
	
	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		
		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			statusCode=500;
			SctsErrorLog::AppendError("Parent of Atomic MUST be SyncBody/Sequence. Representation protocol (5.5.5) : Parent Elements.");
			break;
		}
		if (parent->status>=300)
		{
			statusCode=500;
			break;
		}
		
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		/* Large object delivery */
		if (largeObjectSize)
		{
			statusCode=405;
			SctsErrorLog::AppendError("Large object delivery : unexpected command.");
			break;
		}
		statusCode=200;
		break;
	}
	if (statusCode)
	{
		/* Push command onto process stack */
		parent=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
		parent->type=SCTS_ATOMIC_START;
		parent->status=statusCode;
		processStack.push(parent);

		/* Create the StatusRef and push it into the StatusRef List*/
		SctsStatusRef *statusRef=new SctsStatusRef();
		statusRef->status=statusCode;
		statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
		statusRef->msgID=processMsgID;
		sentStatusRefs[SCTS_ATOMIC_START].push_back(statusRef);

		/* UI callback */
		if (uiCallback)
		{
			cmd.status=statusCode;
			(*uiCallback)(uiCallbackData,&cmd,0,false);
		}
		/* V1.1.1 */
		lastAtomicStatus=0;
		if (!messageNoResp && !cmd.IsNoResp())
		{
			SctsStatus *status=new SctsStatus(currentCmdID,processMsgID,cmd.GetCommandID(tempPcdata),"Atomic",statusCode);
			if (status) 
			{
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
				else
					lastAtomicStatus=outgoingMessage->syncBody.GetLastChildItem(outgoingMessage->syncBody.GetRootItem());
				++currentCmdID;
			}
		}
	}
	else
		processError=PROCESS_ERR_STOP;
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleEndAtomic()
{
	ProcessStackCmd *parent=processStack.top();
	SctsDMCommand *command;
	/* Check if parent is <Atomic> */
	if (parent->type!=SCTS_ATOMIC_START)
	{
		char errorMsg[100];
		SctsErrorLog::OpenNode("End Atomic",0);
		sprintf(errorMsg,"Nesting error. Expecting : %s",sctsCommandStrings[parent->type+1]);
		SctsErrorLog::AppendError(errorMsg);
		SctsErrorLog::CloseNode();
		processError=PROCESS_ERR_STOP;
	}
	else
	{
		/* Atomic Handling */
		while (!atomicStack.empty())
		{
			command=atomicStack.top();
			atomicStack.pop();
			if (parent->status==507)
			{
				if (command->command==SCTS_ADD && device->uiCallback) (*device->uiCallback)((SctsDMTree *)device,command->nodeRef,SCTS_DELETE);
				if (command->command==SCTS_DELETE && device->uiCallback) (*device->uiCallback)((SctsDMTree *)device,command->nodeRef,SCTS_ADD);
				command->RollBack();
			}
			if (command->command==SCTS_DELETE && parent->status==200)
				device->DeleteDMNode(command->nodeRef,device->serverID);
			delete command;
		}
		if (parent->status==507)
		{
			SctsStatusRef *statusRef=sentStatusRefs[SCTS_ATOMIC_START].back();
			sentStatusRefs[SCTS_ATOMIC_START].pop_back();
			statusRef->status=507;
			sentStatusRefs[SCTS_ATOMIC_START].push_back(statusRef);
		}

		/* Alter status codes */
		if (lastAtomicStatus)
		{
			((SctsStatus *)lastAtomicStatus->data)->SetData(parent->status);
			/* Update the UI */
			if (uiCallback) (*uiCallback)(uiCallbackData,(SctsStatus *)lastAtomicStatus->data,0,true);
		}
		if (parent->status==507)
		{
			int status;
			std::list<SctsCommand *>::iterator commandIt=0;
			if (!pendingStatus.empty())
			{				
				commandIt=pendingStatus.end();
				while(commandIt!=pendingStatus.begin())
				{
					SCTSASSERT(((SctsCommand *)*commandIt)->GetType()==SCTS_STATUS);
					status=((SctsCommand *)*commandIt)->status;
					if (status==215 || status>=300)
					{
						commandIt--;
						continue;
					}
					((SctsCommand *)*commandIt)->status=216;
					if (((SctsCommand *)*commandIt)->GetType()==SCTS_ATOMIC_START)
					{
						((SctsCommand *)*commandIt)->status=parent->status;
						break;
					}
					commandIt--;
				}
			}
			if (lastAtomicStatus)
			{
				SctsTree<SctsCommand *>::Item *commandIt=outgoingMessage->syncBody.GetLastChildItem(outgoingMessage->syncBody.GetRootItem());
				int status;
				for (;commandIt!=lastAtomicStatus;commandIt=outgoingMessage->syncBody.GetPrevSiblingItem(commandIt))
				{
					SCTSASSERT(commandIt->data->GetType()==SCTS_STATUS);
					status=((SctsStatus *)commandIt->data)->GetData();
					if (status==215 || status>=300) continue;
					((SctsStatus *)commandIt->data)->SetData(216);
					/* Update the UI */
					if (uiCallback) (*uiCallback)(uiCallbackData,(SctsStatus *)commandIt->data,0,true);
				}
			}
		}
	
		//Ref 0002 30th-May-2003 
		//[
		//Patch for updating the status of the  Atomic..
		//Depends on the CSessionPane member lastRecvItemStatus to indicates the status
		//the rest is done in the call back handler..See,,,
		//]
		/* UI callback */
		
		PARAMPKT pkt;
		pkt.pParam1 = uiCallbackData;
		pkt.pParam2  = &parent->status;
		

		if (uiCallback)	(*uiCallback)(&pkt,0,SCTS_ATOMIC_END,false);
		
		processStack.pop();
		sctsFree(parent);
	}
}


void SctsDMClientSession::HandleStartSequence(SctsSequence& cmd)
{
	int statusCode=0;
	SctsPcdata tempPcdata;
	ProcessStackCmd *parent=processStack.top();

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check immediate parents status */
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		
		if (parent->status>=300)
		{
			statusCode=500;
			break;
		}

		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Sequenece MUST be SyncBody or Sequence.");
			break;
		}
		
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status==215)
		{
			statusCode=215;
			break;
		}

		/* Large object delivery */
		if (largeObjectSize)
		{
			statusCode=405;
			SctsErrorLog::AppendError("Large object delivery : unexpected command.");
			break;
		}
		statusCode=200;
		break;
	}
	if (statusCode)
	{
		/* Push command onto process stack */
		parent=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
		parent->type=SCTS_SEQUENCE_START;
		parent->status=statusCode;
		processStack.push(parent);

		/* Create the StatusRef and push it into the StatusRef List*/
		SctsStatusRef *statusRef=new SctsStatusRef();
		statusRef->status=statusCode;
		statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
		statusRef->msgID=processMsgID;
		sentStatusRefs[SCTS_SEQUENCE_START].push_back(statusRef);

		/* UI callback */
		if (uiCallback)
		{
			cmd.status=statusCode;
			(*uiCallback)(uiCallbackData,&cmd,0,false);
		}
		if (!messageNoResp && !cmd.IsNoResp())
		{
			SctsStatus *status=new SctsStatus(currentCmdID,processMsgID,cmd.GetCommandID(tempPcdata),"Sequence",statusCode);
			if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
					pendingStatus.push_back(status);
			++currentCmdID;
		}
	}
	else
		processError=PROCESS_ERR_STOP;
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleEndSequence()
{
	ProcessStackCmd *parent=processStack.top();
	/* Check if parent is <Sequence> */
	if (parent->type!=SCTS_SEQUENCE_START)
	{
		char errorMsg[100];
		SctsErrorLog::OpenNode("End Sequence",0);
		sprintf(errorMsg,"Nesting error. Expecting : %s",sctsCommandStrings[parent->type+1]);
		SctsErrorLog::AppendError(errorMsg);
		SctsErrorLog::CloseNode();
		processError=PROCESS_ERR_STOP;
	}
	else
	{
		/* UI callback */
		if (uiCallback)	(*uiCallback)(uiCallbackData,0,SCTS_SEQUENCE_END,false);
		processStack.pop();
		sctsFree(parent);
	}
}


/************************************************************************************
  Currently the optional commands are not supported.
************************************************************************************/

void SctsDMClientSession::HandleCopy(SctsCopy& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
	SctsStatus *status=0;
	int statusCode=0;
	ProcessStackCmd *parent=processStack.top();
	SctsItemList itemList;
	SctsItem item;
	SctsTargetSource tempTarget, tempSource;
    SctsPcdata tempTargetPcdata, tempSourcePcdata;
    char *source=0;
    char *target=0;

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START && parent->type!=SCTS_ATOMIC_START)
		{
			SctsErrorLog::AppendError("Parent of Exec MUST be SyncBody or Sequence or Atomic. Representation protocol (6.5.6) : Parent Elements.");
			break;
		}

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (parent->type==SCTS_ATOMIC_START && parent->status==507) statusCode=215;
			if (sentSyncHdrStatus==401 || sentSyncHdrStatus==407) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);

			/* Create the StatusRef and push it into the StatusRef List*/

			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempTargetPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_COPY].push_back(statusRef);
			
			if (!messageNoResp && !cmd.IsNoResp())
			{
				status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempTargetPcdata),"Copy",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}
        cmd.GetItemList(itemList).GetData(item);
		if (!item.GetTarget(tempTarget).GetLocURI(tempTargetPcdata))
		{
			SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.7) : The Target specified within the Item element type MUST be a full device URI.");
			break;
		}
        target = (char *)tempTargetPcdata;
        if (!item.GetSource(tempSource).GetLocURI(tempSourcePcdata))
		{
			SctsErrorLog::AppendError("Item->Source->LocURI element is missing. DM Representation protocol (5.5.7) : The Source specified within the Item element type MUST be a full device URI.");
			break;
		}
        source = (char *)tempSourcePcdata;
        statusCode=device->CopyDMNode(source,target,device->serverID);
		if (statusCode)
		{
			/* UI callback */
			if (uiCallback)
			{
				cmd.status=statusCode;
				(*uiCallback)(uiCallbackData,&cmd,0,false);
			}
			if (!messageNoResp && !cmd.IsNoResp())
			{
				/* Multiple status */
				it=targetRefs.find(statusCode);
				if (it==targetRefs.end())
				{
					SctsTargetRefList *targetRefList;
					if (status) 
					{
						if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
							pendingStatus.push_back(status);
					}
					status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempTargetPcdata),"Copy",statusCode);
					++currentCmdID;
					targetRefList=new SctsTargetRefList(SctsPcdata(target));
					targetRefs[statusCode]=targetRefList;
					status->SetTargetRefList(targetRefList);
					/* Create the StatusRef and push it into the StatusRef List*/
					SctsStatusRef *statusRef=new SctsStatusRef();
					statusRef->status=statusCode;
					statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempTargetPcdata));
					statusRef->msgID=processMsgID;
					sentStatusRefs[SCTS_COPY].push_back(statusRef);
				}
				else
				{
					it->second->SetNextData(SctsPcdata(target));
				} 
			}
		}
		break;
	}

	//if (targetRefs.size()==1) 
	//	/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetTargetRefList(0);
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}

	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP;
	SctsErrorLog::CloseNode();
}

void SctsDMClientSession::HandleExec(SctsExec& cmd)
{
	std::map <int,SctsTargetRefList *> targetRefs;
	std::map <int,SctsTargetRefList *>::iterator it;
    SctsStatus *status=0;
    SctsAlert *genericAlert=0;
	int statusCode=0;
	SctsPcdata tempPcdata;
	ProcessStackCmd *parent=processStack.top();
	SctsItem item;
	SctsTargetSource tempTS;
    char *target=0;

	/* Create error log node */
	CreateErrorNode(cmd);

	while(true)
	{
		/* Check returned syncHdr status */
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			SctsErrorLog::AppendError("Command not allowed. Sync protocol (3.1) : The response message indicating the authentication failure on server layer must contain only Status commands.");
			break;
		}

		/* Check if parents are valid */
        /*
         * Change: Exec parent maybe Sequence
         */
		if (parent->type!=SCTS_HEADER && parent->type!=SCTS_SEQUENCE_START)
		{
			SctsErrorLog::AppendError("Parent of Exec MUST be SyncBody or Sequence. Representation protocol (5.5.6) : Parent Elements.");
			break;
		}

		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;

		if (parent->status>=300 || parent->status==215)
		{
			cmd.status=500;
			if (parent->type==SCTS_SEQUENCE_START && parent->status==215) cmd.status=215;
			if (sentSyncHdrStatus==401 || sentSyncHdrStatus==407) cmd.status=sentSyncHdrStatus;
			/* UI callback */
			if (uiCallback)	(*uiCallback)(uiCallbackData,&cmd,0,false);

			/* Create the StatusRef and push it into the StatusRef List*/

			SctsStatusRef *statusRef=new SctsStatusRef();
			statusRef->status=cmd.status;
			statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
			statusRef->msgID=processMsgID;
			sentStatusRefs[SCTS_EXEC].push_back(statusRef);
			
			if (!messageNoResp && !cmd.IsNoResp())
			{
				status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Exec",cmd.status);
				if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status))
					pendingStatus.push_back(status);
				++currentCmdID;
			}
			SctsErrorLog::CloseNode();
			return;
		}

		cmd.GetItem(item);
		if (!item.GetTarget(tempTS).GetLocURI(tempPcdata))
		{
			SctsErrorLog::AppendError("Item->Target->LocURI element is missing. DM Representation protocol (5.5.7) : The Target specified within the Item element type MUST be a full device URI.");
			break;
		}
        target=(char *)tempPcdata;
        statusCode=device->ExecDMNode(target,device->serverID);
		if (statusCode)
		{
			/* UI callback */
			if (uiCallback)
			{
				cmd.status=statusCode;
				(*uiCallback)(uiCallbackData,&cmd,0,false);
			}
			if (!messageNoResp && !cmd.IsNoResp())
			{
				/* Multiple status */
				it=targetRefs.find(statusCode);
				if (it==targetRefs.end())
				{
					SctsTargetRefList *targetRefList;
					if (status) 
					{
						if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
							pendingStatus.push_back(status);
					}
					status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Exec",statusCode);
					++currentCmdID;
					targetRefList=new SctsTargetRefList(SctsPcdata(target));
					targetRefs[statusCode]=targetRefList;
					status->SetTargetRefList(targetRefList);
					/* Create the StatusRef and push it into the StatusRef List*/
					SctsStatusRef *statusRef=new SctsStatusRef();
					statusRef->status=statusCode;
					statusRef->cmdID=sctsStrdup((char *)cmd.GetCommandID(tempPcdata));
					statusRef->msgID=processMsgID;
                    if (cmd.GetCorrelator())
                    {
                        statusRef->data = sctsStrdup(cmd.GetCorrelator());
                    }
					sentStatusRefs[SCTS_EXEC].push_back(statusRef);
				}
				else
				{
					it->second->SetNextData(SctsPcdata(target));
				} 
			}
            if (statusCode >= 200 && statusCode < 300)
            {
                SctsDMGenericAlert *gAlert = new SctsDMGenericAlert;
                gAlert->source = sctsStrdup(target);
                gAlert->correlator = sctsStrdup(cmd.GetCorrelator());
                gAlert->data = sctsStrdup("200");
                gAlert->format = sctsStrdup("int");
                gAlert->type = sctsStrdup("x-oma-application:syncml.dm");
                device->pendingGenericAlerts.push_back(gAlert);
            }
		}
		break;
	}

	//if (targetRefs.size()==1) 
	//	/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetTargetRefList(0);
	if (status) 
	{
		if (!pendingStatus.empty() || !outgoingMessage->InsertCommand(status,false,false))
			pendingStatus.push_back(status);
	}

	/* Close error log node and clean up*/
	if (!statusCode) processError=PROCESS_ERR_STOP;
	SctsErrorLog::CloseNode();
}


/*********************************************************************************
The following commands should not be sent in a DM Session, receiving them will generate
a error and the processing will stop 
***********************************************************************************/

void SctsDMClientSession::HandleStartSync(SctsSync& cmd)
{
	/* Create error log node */
	CreateErrorNode(cmd);

	SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.15) : Sync Element is not used in SyncML Device Management protocol.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=501;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
}

void SctsDMClientSession::HandleEndSync()
{
	/* Create error log node */
	SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.15) : Sync Element is not used in SyncML Device Management protocol.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	
	/* UI callback */
	if (uiCallback)	(*uiCallback)(uiCallbackData,0,SCTS_SYNC_END,false);
}

void SctsDMClientSession::HandleSearch(SctsSearch& cmd)
{
	/* Create error log node */
	CreateErrorNode(cmd);

	SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.13) : Search Element is not used in SyncML Device Management protocol.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=501;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
}

void SctsDMClientSession::HandleMap(SctsMap& cmd)
{
	/* Create error log node */
	CreateErrorNode(cmd);

	SctsErrorLog::AppendError("DM Representataion protocol (5.5.8) : Map Element is not used in SyncML Device Management protocol.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=501;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
}

void SctsDMClientSession::HandleResults(SctsResults& cmd)
{
	/* Create error log node */
	CreateErrorNode(cmd);

	SctsErrorLog::AppendError("Server MUST NOT send Results command in a Device Management Session.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	cmd.status=501;
	/* UI callback */
	if (uiCallback)
		(*uiCallback)(uiCallbackData,&cmd,0,false);	
}

void SctsDMClientSession::HandlePut(SctsPut& cmd)
{
	/* Create error log node */
	CreateErrorNode(cmd);

	SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.10) : Put Element is not used in SyncML Device Management protocol.");
	processError=PROCESS_ERR_STOP;

	SctsErrorLog::CloseNode();	
	
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=501;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
}

/*
 * Change to support TNDS. 
 */
int SctsDMClientSession::addDMTree(SctsDMClientDevice *devicem, char *target, SmlSubTreePtr_t pMgmtTree, SctsDMCommand **command)
{
    int statusCode = 200;
    if (command) *command=0;
    char _nodePath[512]="";
    SmlSubTreeNodePtr_t pRootNode = 0;
    SmlSubTreeNodePtr_t pNode = 0;
    SctsDMNode *pRootDmNode = 0;
    if (!pMgmtTree) return 500;
    pRootNode = pMgmtTree->node;
    if (!pRootNode)
    {
        SctsErrorLog::AppendError("Add Failed : Empty management tree.");
        return 500;
    }
    sctsStrcpy(_nodePath, target);
    char *lastName=_nodePath+sctsStrlen(_nodePath);
    while (lastName!=_nodePath && *lastName!='/') --lastName;
    *lastName=(lastName==_nodePath?(*lastName):'\0');
    pRootDmNode = device->FindDMNode(_nodePath);
    if (!pRootDmNode)
    {
        char tempBuffer[500];
        sprintf(tempBuffer,"Add Failed : Node with path %s not found.",_nodePath);
        SctsErrorLog::AppendError(tempBuffer);
        return 404;
    }
    *lastName='/';
    for (pNode=pRootNode;pNode;)
    {
        if (!pNode->format && pNode->child)
            pNode->format=smlString2Pcdata("node");
        SctsPcdata tempPath(pNode->path);
        SctsPcdata tempNodeName(pNode->nodeName);
        SctsPcdata tempTitle(pNode->title);
        SctsPcdata tempACL(pNode->ACL);
        SctsPcdata tempFormat(pNode->format);
        SctsPcdata tempTStamp(pNode->timeStamp);
        SctsPcdata tempVersion(pNode->verNo);
        SctsPcdata tempMime(pNode->mimeType);
        SctsPcdata tempData(pNode->data);
        SctsPcdata tempSize(pNode->size);
        SctsDMNode *pNNode=0;

        if (!pNode->nodeName)
        {
            SctsErrorLog::AppendError("Add Failed : Node name must not be empty.");
            statusCode = 500;
            break;
        }
        if (pNode->path)
        {
            lastName=sctsStrstr(_nodePath, (char *)tempPath);
            if (!lastName)
            {
                SctsErrorLog::AppendError("Add Failed : Node path error.");
                statusCode=500;
                break;
            }
            lastName+=tempPath.GetLength();
            *lastName='/';
            sctsStrcpy(lastName+1, (char *)tempNodeName);
        }
        else
        {
            lastName=_nodePath+sctsStrlen(_nodePath);
            while (lastName!=_nodePath && *lastName!='/') --lastName;
            lastName=(lastName==_nodePath?_nodePath:lastName+1);
            sctsStrcpy(lastName, (char *)tempNodeName);
        }
        CONVERTB64TOBINFIX(device->encoding,nret,(unsigned char*)(char*)tempData,(char *)tempFormat,tempData.GetLength())
        statusCode=device->AddDMNode(_nodePath,device->serverID,(char *)tempFormat,false,(char *)tempData,(char *)tempMime,nret,&pNNode);
        if (statusCode==200 && pNNode && (char *)tempTitle)
        {
            statusCode=device->ReplaceDMNodePropTNDS(pNNode,device->serverID,DMPROP_TITLE,(char *)tempTitle);
        }
        if (statusCode==200 && pNNode && (char *)tempTStamp)
        {
            statusCode=device->ReplaceDMNodePropTNDS(pNNode,device->serverID,DMPROP_TIMESTAMP,(char *)tempTStamp);
        }
        if (statusCode==200 && pNNode && (char *)tempVersion)
        {
            statusCode=device->ReplaceDMNodePropTNDS(pNNode,device->serverID,DMPROP_VERSION,(char *)tempVersion);
        }
        if (statusCode==200 && pNNode && (char *)tempACL)
        {
            statusCode=device->ReplaceDMNodePropTNDS(pNNode,device->serverID,DMPROP_ACL,(char *)tempACL);
        }
        if (statusCode != 200)
            break;

        if (pNode->child)
        {
            pNode=pNode->child;
            sctsStrcat(_nodePath, "/");
        }
        else if (pNode->nextSibling)
        {
            pNode=pNode->nextSibling;
        }
        else
        {
            char *lastName=_nodePath+sctsStrlen(_nodePath);
            do
            {
                while (lastName!=_nodePath && *lastName!='/') --lastName;
                *lastName='\0';
                pNode=pNode->parent;
            }
            while (pNode && !pNode->nextSibling);
            pNode=pNode?pNode->nextSibling:0;
        }
    }
    if (statusCode==200)
    {
        if (command) *command=new SctsDMCommand(SCTS_ADD,device->FindDMNode(target),DMPROP_NONE,true);
    }
    else if (statusCode!=418)
    {
        if (device->FindDMNode(target))
        {
            device->DeleteDMNode(target, device->serverID);
        }
    }
    return statusCode;
}

/*
 * Change to support TNDS, need to support rollback. 
 */
int SctsDMClientSession::replaceDMTree(SctsDMClientDevice *device, char *target, SmlSubTreePtr_t pMgmtTree, SctsDMCommand **command)
{
    int statusCode = 200;
    if (command) *command=0;
    SmlSubTreeNodePtr_t pRootNode = 0;
    SctsDMNode *pRootDmNode = 0;
    SctsDMNode *pDmNode = 0;
    if (!pMgmtTree) return 500;
    pRootNode = pMgmtTree->node;
    if (!pRootNode)
    {
        SctsErrorLog::AppendError("Replace Failed : Empty management tree.");
        return 500;
    }
    pRootDmNode = device->FindDMNode(target);
    if (!pRootDmNode)
    {
        char tempBuffer[500];
        sprintf(tempBuffer,"Repalce Failed : Node with path %s not found.",target);
        SctsErrorLog::AppendError(tempBuffer);
        return 404;
    }
    pDmNode=new SctsDMNode(pRootDmNode);
    pDmNode->parent=pRootDmNode->parent;
    pDmNode->prev=pRootDmNode->prev;
    pDmNode->next=pRootDmNode->next;
    pDmNode->child=pRootDmNode->child;
    if (pRootDmNode->parent->child==pRootDmNode)
    {
        pRootDmNode->parent->child=0;
    }
    else
    {
        pRootDmNode->prev->next=pRootDmNode->next;
    }
    statusCode=device->DeleteDMNode(pRootDmNode, device->serverID);
    if (statusCode == 200)
    {
        statusCode = addDMTree(device, target, pMgmtTree);
    }
    if (statusCode==200)
    {
        if (command) *command=new SctsDMCommand(SCTS_REPLACE,device->FindDMNode(target),DMPROP_NONE,true);
    }
    if (statusCode != 200)
    {
        if (pDmNode->prev)
        {
            pDmNode->prev->next=pDmNode;
        }
        else
        {
            pDmNode->parent->child=pDmNode;
        }
        if (pDmNode->next)
        {
            pDmNode->next->prev=pDmNode;
        }
    }
    else
    {
        delete pDmNode;
    }
    return statusCode;
}

/*
 * Change to support TNDS. 
 */
int SctsDMClientSession::isProperty(const char *propString, const char *property)
{
    int propLen = sctsStrlen(property);
    if (!sctsStrncmp(propString, property, propLen))
    {
        if (!isalpha(*(propString+propLen)))
        {
            return 1;
        }
    }
    return 0;
}

/*
 * Change to support TNDS. 
 */
int SctsDMClientSession::isPropertySet(const char *propString, const char *property)
{
    const char *pStr = 0;
    int retCode = 0;
    if (pStr = sctsStrstr(propString, property))
    {
        if (pStr != propString && isProperty(pStr, property))
        {
            switch (*(pStr-1))
            {
            case '+':
                retCode = 1;
                break;
            case '-':
                retCode = -1;
                break;
            }
        }
    }
    return retCode;
}

/*
 * Change to support TNDS. 
 */
void SctsDMClientSession::setGetTNDSProperty(SctsGetTNDSProperty property, int value)
{
    if (value==1)
    {
        getTNDSPropSet |= (1u << property);
    }
    else if (value==-1)
    {
        getTNDSPropSet &= ~(1u << property);
    }
}

/*
 * Change to support TNDS. 
 */
int SctsDMClientSession::isGetTNDSProperty(SctsGetTNDSProperty property)
{
    unsigned int val = 0;
    val = 1u << property;
    val &= getTNDSPropSet;
    return val;
}
