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

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

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

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

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

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

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

#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);\
					  	}

/******************************************************************
SctsDMServerSession Definition
******************************************************************/

/* Initializing the discoveryAccount.*/
const char *SctsDMServerSession::discoveryTempPath="./TempDMAcc";
SctsDMTree *SctsDMServerSession::discoveryAccount=0;
SctsMutex SctsDMServerSession::discoveryAccountLock;
char *SctsDMServerSession::discoveryCompany=0;
char *SctsDMServerSession::discoveryContact=0;
char *SctsDMServerSession::discoveryName=0;
char *SctsDMServerSession::discoveryDMAccPath=0;
char *SctsDMServerSession::discoveryDMAccName=0;
	
SctsDMServerSession::SctsDMServerSession(SctsServerTransport *_transport,SctsEncoding _encoding,void (*_CallBack)(SctsDMSession *),bool _authenticateAllMsgs)
: SctsDMSession(_encoding,_CallBack), authenticateAllMsgs(_authenticateAllMsgs),maxMsgSize(MAX_WORKSPACE_SIZE/2), sourceLocURI(0), targetLocURI(0), authRetry(true)
{
	proto=SYNCML_DM_1_2;
	transport=_transport;
	device=0;
	receivedDevInfo=false;
	clientInitiatedAlert=false;
	serverInitiatedAlert=false;
	receivedSessionAbortAlert=false;
	targetLocURI=sourceLocURI=0;
	/* Write a 1 to the log file info (denotes a server) */
	fputc(1,logFileInf);
	if (componentUIC.addSession) (*componentUIC.addSession)(this);
}

SctsDMServerSession::~SctsDMServerSession()
{	
	if (device && sessionType==DMSESSION_DISCOVER) 
	{
		if (!IsSuccessful()) 
		{
			SctsDMDevice::RemoveDevice(device);			
			device=0;
		}
		else
		{
			SctsDMNode *node,*tempNode;
			/* Delete ghost account node */
			if (device->accountNode)
			{
				delete device->accountNode;
				device->accountNode=0;
                device->accounts.clear();
			}
			/* If it is a discover session, clean up DMAcc nodes 
			which do not have child nodes */
			node=device->FindDMNode((char *)SctsDMServerSession::discoveryTempPath);
			if (node)
			{
				node=node->child;
				while (node)
				{
					if (!node->child)
					{
						tempNode=node->next;
						delete node;
						node=tempNode;
					}
					else
						node=node->next;												
				}
			}
            std::string fullNodePath = device->dmAccPath;
            fullNodePath += "/";
            fullNodePath += discoveryDMAccName;
            device->accountNode = device->FindDMNode((char *)fullNodePath.c_str());
            if (device->accountNode)
            {
                SctsDMAccount dmAccount((SctsDMServerTree *)device, device->accountNode);
                if (dmAccount.IsDMAcc())
                {
                    device->accounts[device->accountNode->name] =
                        SctsDMDevice::MulDynAccItem(device->accountNode->name,
                                                    dmAccount.GetPath(),
                                                    dmAccount.GetSubAppAddr(),
                                                    dmAccount.GetSubPort(),
                                                    dmAccount.GetSubAppAuthClient(),
                                                    dmAccount.GetSubAppAuthServer(),
                                                    dmAccount.GetSubToConRef());
                }
                else
                {
                    device->accountNode = 0;
                }
            }
		}
        if (discoveryDMAccName)
        {
            sctsFree(discoveryDMAccName);
            discoveryDMAccName=0;
        }
	}
	if (device) tempDevice=(SctsDMDevice *)device;
	if (sourceLocURI) sctsFree(sourceLocURI);
	if (targetLocURI) sctsFree(targetLocURI);
}

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

int SctsDMServerSession::Run()
{
	int rc;
	SctsCommand *pCmd;
	SctsPcdata commandID;
	char errorMsg[300];
	int lastCommandID;
	bool builtFinal;
	/* Session thread entry point */
	
	sctsStatusLogOpen();
	sctsStatusLog("Starting session...\r\n");
	/* Create the error log */
	errorLog=new SctsErrorLog();

	while (processError==PROCESS_ERR_NONE)
	{
		currentCmdID=1;
		processError=PROCESS_ERR_OK;
		recvSyncHdrStatus=0;

		/* Receive the message */
		if (!RecvMessage())
		{
			processError=PROCESS_ERR_STOP;
			break;
		}
		
		/* Process the received message */

#ifdef __SCTS_USING_SCTS__		
		/* Execute test group Pre-process */
		if (sessionType==DMSESSION_TEST && testGroup)
		{
			if (targetPkgCount)
				testGroup->StateManagePreProcess();
			else
				testGroup->StateInitiatePreProcess();
		}
				
#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;
			}
		}
#endif
		/* Postponement of status discrepency : Check only if it is the last message in the package */
		if (messageQueue.size() && recvdFinal  && processError==PROCESS_ERR_NONE)
		{
			/* Check whether status has been received for all commands */
			/* Results discrepency */
			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);
				}
				delete messageQueue.front();
				messageQueue.pop_front();
				messageQueueID++;
			}
			SctsErrorLog::CloseNode();
		}
		
		if (recvSyncHdrStatus==401 || recvSyncHdrStatus==407)
		{
			if (outAuth || currentMsgID==1) 
				sourcePkgCount=targetPkgCount=0;
			else
			{
                if (authRetry)
                {
                    authRetry = false;
                }
                else
                {
				    SctsErrorLog::AppendError("Failed to authenticate. Check username and password settings and restart session.");
				    processError=PROCESS_ERR_STOP;
                }
			} 
		}

		/* Check the received package */
		if (recvSyncHdrStatus<=212 && sentSyncHdrStatus<=212 && processError==PROCESS_ERR_NONE && recvdFinal)
		{
			if (targetPkgCount==0)
				ProcessStateInitiateMessage();
			else		
				ProcessStateManageMessage();
		}
		if (processError==PROCESS_ERR_STOP) break;

#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+1)
		{
			SctsErrorLog::AppendError("Invalid package state. Sync protocol (2.9) : The final element must not be included if the other end has not closed the preceding package.");
			processError=PROCESS_ERR_STOP;
		}

		/* UI Callback */
		if (uiCallback) (*uiCallback)(uiCallbackData,outgoingMessage->GetHeader(),0,true);
		lastCommandID=currentCmdID;
		if (!receivedSessionAbortAlert && (sentSyncHdrStatus==200 || sentSyncHdrStatus==212))
		{
			/* Build the message based on the current state */
			if (sourcePkgCount==0)
			{
				BuildStateInitiateMessage();
				#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST && testGroup && processError==PROCESS_ERR_NONE) testGroup->StateInitiatePostBuild();
				#endif
			}
			if (sourcePkgCount>0 || targetPkgCount>0)
			{
				#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.
		*/
		builtFinal=false;
		if (outgoingMessage->IsFinal())
		{
			builtFinal=true;
			/* Dont switch state if the client hasn't finished sending the preceeding package */
			if (sourcePkgCount==targetPkgCount)
			{
				/* Build Next message Alert */
				if (currentCmdID==2)
				{
					SctsAlert *alert=new SctsAlert(currentCmdID,SctsItemList(),1222);
					outgoingMessage->InsertCommand(alert);
					++currentCmdID;
				}
                else
                {
			        processError=PROCESS_ERR_STOP;
                    SctsErrorLog::AppendError("Failed, not support handle multi message for DM commands other then Result.");
			        break;
                }
				outgoingMessage->IsFinal(false);
				builtFinal=false;
			}
			else
				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;
		}
		/* Break session if received syncHdr failed */
		if (sentSyncHdrStatus!=200 && sentSyncHdrStatus!=212 && sentSyncHdrStatus!=401 && sentSyncHdrStatus!=407) 
		{
			processError=PROCESS_ERR_STOP;
			break;
		}
		
		/* If client was not authenticated remain in state initiate */
		if (sentSyncHdrStatus==401 || sentSyncHdrStatus==407)
		{
			if (inAuth || currentMsgID==1) 
				sourcePkgCount=targetPkgCount=0;
			else
			{
				SctsErrorLog::AppendError("Failed to authenticate. Check username and password settings and restart session.");
				processError=PROCESS_ERR_STOP;
			} 
		}
		if (sentSyncHdrStatus==200 || sentSyncHdrStatus==212)
		{
			/* The Server did not build any management commands and just sent status commands
			   and if the server also sent the final, end the session */
			if (lastCommandID==currentCmdID && builtFinal) break;		
		}	

		/* Increment currentMsgID */
		++currentMsgID;

	} /* End of while */
	#ifdef __SCTS_USING_SCTS__
		if (processError==PROCESS_ERR_NONE && sessionType==DMSESSION_TEST && testGroup) testGroup->StateTerminate();
	#endif
	
	/* V1.1.1 */
	/* Clear the RESULTS Commands which had Prop as DMPROP_STRUCT OR DMPROP_STRUCTDATA
	   Check if RESULTS were got for all the Gets.
	 */
	if (device && sessionType!=DMSESSION_TEST)
	{
		for (std::list<SctsDMCommand *>::iterator cmdIt=device->cmdList.begin();cmdIt!=device->cmdList.end();)
		{
			SctsDMCommand *command=*cmdIt;
			if (command->command==SCTS_RESULTS)
			{
				if (command->prop!=DMPROP_STRUCT && command->prop!=DMPROP_STRUCTDATA && command->prop!=DMPROP_TNDS)
				{
					char buffer[500];
					SctsErrorLog::OpenNode("Results",0);
					sprintf(buffer,"Did not receive Results for Get. (CmdID = %s, MsgID = %d)",command->cmdRef,command->msgRef);
					SctsErrorLog::AppendError(buffer);
					SctsErrorLog::CloseNode();
				}
				delete command;
				cmdIt=device->cmdList.erase(cmdIt);
			}
			else
				cmdIt++;
		}
	}
	return 0;
}

void SctsDMServerSession::BuildStateInitiateMessage()
{
	if (targetLocURI && device)
	{
		SctsDMNode *node=device->FindDMNode("./DevInfo/DevId");
		if (!node || !node->data)
		{
			SctsErrorLog::OpenNode("./DevInfo/DevId",0);
			SctsErrorLog::AppendError("DevInfo/DevId node does not exist or does not have a value");
			SctsErrorLog::CloseNode();
			IsSuccessful(false);
		}
		else if (sctsStrcmp((char *)node->data,targetLocURI))
		{
			char buffer[500];
			SctsErrorLog::OpenNode("./DevInfo/DevId",0);
			sprintf(buffer,"The value in the Source LocURI (%s) of the SyncHdr sent by the client and the value of the ./DevInfo/DevId (%s) does not match",targetLocURI,node->data);
			SctsErrorLog::AppendError(buffer);
			SctsErrorLog::CloseNode();
		}
	}
}

void SctsDMServerSession::BuildStateManageMessage()
{
	SctsDelete *pDelete;
	SctsAdd *pAdd;
	SctsReplace *pReplace;
	SctsGet *pGet;		
    /*
     * Change to support Exec/Copy command. 
     */
	SctsExec *pExec;
	SctsCopy *pCopy;
	SctsSequence *pSequence;
	SctsAtomic *pAtomic;
	SctsAlert *pAlert;
	SctsDMCommand *cmdItem;
	SctsDMNode *node;
	char **nestingCmdRef;
	int nestingLevel=0;
	int nestingCmdID;
	char buffer[30];
	std::list<SctsDMCommand *>::iterator commandIt;
	
	/* Build any unbuilt status */
	outgoingMessage->BuildAllUnbuilt();

	/* 	Large Object Delivery : If server is sending/receiving a large object hold 
	all management commands until large object delivery is complete */
	if (supportsLrgObj && largeObjectSize)
	{
		/* Receiving a large object */
		if (largeObjectCmd==SCTS_RESULTS)
		{
			/* Build Next message Alert */
			SctsAlert *alert=new SctsAlert(currentCmdID,SctsItemList(),1222);
			outgoingMessage->InsertCommand(alert);
			++currentCmdID;
			/* Clear the final flag */
			outgoingMessage->IsFinal(false);
			outgoingMessage->InsertCommand(0);
			return;
		}
		/* Sending a large object */
		/* Update the CmdRef and MsgRef of the command */
		if (largeObjectCommand->cmdRef) sctsFree(largeObjectCommand->cmdRef);
		largeObjectCommand->cmdRef=sctsStrdup(sctsInt2Str(currentCmdID,buffer,10));
		largeObjectCommand->msgRef=currentMsgID;
		if (LargeObjectSendChunk()) return;
	}
	if (targetPkgCount==sourcePkgCount) return;
	for (commandIt=device->cmdList.begin();commandIt!=device->cmdList.end() && (*commandIt)->cmdRef;++commandIt);
	for(;commandIt!=device->cmdList.end() && !largeObjectSize;commandIt++)
	{
		SctsMeta meta;
		SctsPcdata *pcData=0;
		SctsDMNodeFormat format=DMFORMAT_CHR;
		char *target=0;
		bool setMeta=false;
		bool built=true;

		cmdItem=*commandIt;		
		if (cmdItem->command!=SCTS_ATOMIC_START && cmdItem->command!=SCTS_ATOMIC_END && cmdItem->command!=SCTS_SEQUENCE_START && cmdItem->command!=SCTS_SEQUENCE_END && cmdItem->command!=SCTS_ALERT)
		{
			node=cmdItem->nodeRef;
			SCTSASSERT(node);
			target=device->GetPath(node,0);
			SCTSASSERT(target);
			if (cmdItem->prop!=DMPROP_NONE)
			{
				if (cmdItem->prop==DMPROP_STRUCT || cmdItem->prop==DMPROP_STRUCTDATA || cmdItem->prop==DMPROP_TNDS)
					sctsStrcpy(buffer,"?list=");
				else
					sctsStrcpy(buffer,"?prop=");
				sctsStrcat(buffer,SctsDMNodePropertyString[cmdItem->prop]);
                if (cmdItem->prop==DMPROP_TNDS && cmdItem->cmdSpecific.tndsFields.length())
                {
                    sctsStrcat(buffer,(char *)cmdItem->cmdSpecific.tndsFields.c_str());
                }
				target=(char *)sctsRealloc(target,sctsStrlen(target)+sctsStrlen(buffer)+1);
				sctsStrcat(target,buffer);
			}  
		}
		switch(cmdItem->command)
		{
		case SCTS_ALERT:
			{
				SctsItemList itemList;
				int i;
				char **_data=(char **)cmdItem->data;
				pAlert=new SctsAlert(currentCmdID,SctsItemList(SctsItem(0,0,0,0,0,&SctsPcdata(_data[1],sctsStrlen(_data[1]),encoding))),(int)_data[0]);
				pAlert->GetItemList(itemList);
				for (i=2;i<cmdItem->size;++i)
					itemList.SetNextData(SctsItem(0,0,0,0,0,&SctsPcdata(_data[i],sctsStrlen(_data[i]),encoding)));
				built=outgoingMessage->InsertCommand(pAlert,nestingLevel==0,false);
				if (!built) delete pAlert;
				break;
			}
		case SCTS_REPLACE:
			{
				switch(cmdItem->prop)
				{
				case DMPROP_NAME:
					{
						pcData=new SctsPcdata(node->name);
						break;
					}
				case DMPROP_TITLE:
					{
						if (node->title) pcData=new SctsPcdata(node->title);
						break;
					}
				case DMPROP_ACL:
					{
						if (node->acl) 
						{
							if (encoding==WBXML)
								pcData=new SctsPcdata(node->acl);
							else
								pcData=new SctsPcdata(node->acl,sctsStrlen(node->acl),XML);
						}
						break;
					}
				case DMPROP_NONE:
					{					
						pcData=new SctsPcdata();
						node->GetPcdata(*pcData,format,encoding);
						break;
					}
				default:
					SCTSASSERT(false);
				}
				/* Large Object Delivery */
				if (supportsLrgObj && !nestingLevel && pcData && (!largeObjectBufferSize || pcData->GetLength()<=largeObjectBufferSize) && pcData->GetLength()>maxMsgSize/2 && pcData->GetLength()>outgoingMessage->GetFreeSize())
				{
					sctsFree(largeObjectType);
					sctsFree(largeObjectFormat);
					largeObjectFormat=0;
					largeObjectType=0;
					if (cmdItem->prop==DMPROP_NONE && node->mimeType)
						largeObjectType=sctsStrdup(node->mimeType);
					if (format!=DMFORMAT_CHR)
						largeObjectFormat=sctsStrdup(SctsDMFormatString[format]);
					largeObjectBuffer=(char *)sctsMalloc(pcData->GetLength());
					sctsMemcpy(largeObjectBuffer,(char *)(*pcData),pcData->GetLength());
					largeObjectSize=pcData->GetLength();
					largeObjectBufferUsedSize=0;
					largeObjectSURI=0;
					largeObjectTURI=target;
					largeObjectCmd=SCTS_REPLACE;
					largeObjectCommand=cmdItem;
					pcData->Clear();
					delete pcData;
					LargeObjectSendChunk();
					break;
				}
				
				/* Build the replace */
				
				if (cmdItem->prop==DMPROP_NONE && node->mimeType)
				{
					meta.SetType(&SctsPcdata(node->mimeType));
					setMeta=true;
				}
				
				if (format!=DMFORMAT_CHR)
				{
					meta.SetFormat(&SctsPcdata(SctsDMFormatString[format]));
					setMeta=true;
				}
				if (!pcData) pcData=new SctsPcdata("");
				pReplace=new SctsReplace(currentCmdID,SctsItemList(SctsItem(0,0,target,0,setMeta?&meta:0,pcData)));
				delete pcData;
				sctsFree(target);
				built=outgoingMessage->InsertCommand(pReplace,nestingLevel==0,false);
				if (!built) delete pReplace;
				break;
			}
		case SCTS_DELETE:
			{
				pDelete=new SctsDelete(currentCmdID,SctsItemList(SctsItem(0,0,target,0,0,0)));
				built=outgoingMessage->InsertCommand(pDelete,nestingLevel==0,false);
				if (!built) delete pDelete;
				break;
			}
		case SCTS_ADD:
			{
				pcData=new SctsPcdata();
				node->GetPcdata(*pcData,format,encoding);
				/* Large Object Delivery */
				if (supportsLrgObj && !nestingLevel && (!largeObjectBufferSize || pcData->GetLength()<=largeObjectBufferSize) && pcData->GetLength()>maxMsgSize/2 && pcData->GetLength()>outgoingMessage->GetFreeSize())
				{
					sctsFree(largeObjectType);
					sctsFree(largeObjectFormat);
					largeObjectFormat=0;
					largeObjectType=0;
					if (node->mimeType)
						largeObjectType=sctsStrdup(node->mimeType);
					if (format!=DMFORMAT_CHR)
						largeObjectFormat=sctsStrdup(SctsDMFormatString[format]);
					largeObjectBuffer=(char *)sctsMalloc(pcData->GetLength());
					sctsMemcpy(largeObjectBuffer,(char *)(*pcData),pcData->GetLength());
					largeObjectSize=pcData->GetLength();
					largeObjectBufferUsedSize=0;
					largeObjectSURI=0;
					largeObjectTURI=target;
					largeObjectCmd=SCTS_ADD;
					largeObjectCommand=cmdItem;
					pcData->Clear();
					delete pcData;
					LargeObjectSendChunk();
					break;
				}
				if (node->mimeType)
				{
					meta.SetType(&SctsPcdata(node->mimeType));
					setMeta=true;
				}
				if (format!=DMFORMAT_CHR)
				{
					meta.SetFormat(&SctsPcdata(SctsDMFormatString[format]));
					setMeta=true;
				}

				pAdd=new SctsAdd(currentCmdID,SctsItemList(SctsItem(0,0,target,0,setMeta?&meta:0,pcData)));
				delete pcData;
				sctsFree(target);
				built=outgoingMessage->InsertCommand(pAdd,nestingLevel==0,false);
				if (!built) delete pAdd;
				break;
			}
		case SCTS_GET:
			{
				pGet=new SctsGet(currentCmdID,SctsItemList(SctsItem(0,0,target,0,0,0)));
				sctsFree(target);
				built=outgoingMessage->InsertCommand(pGet,nestingLevel==0,false);
				if (!built) delete pGet;
				break;
			}
        /*
         * Change to support Exec command. 
         */
		case SCTS_EXEC:
			{
				SctsItem eItem(0,0,target,0,0,0);
                if(cmdItem->cmdSpecific.correlator.length())
                {
				    pExec=new SctsExec(currentCmdID,&eItem,(char *)cmdItem->cmdSpecific.correlator.c_str());
                    SctsDMGenericAlert *gAlert = new SctsDMGenericAlert;
                    gAlert->source = sctsStrdup(target);
                    gAlert->correlator = sctsStrdup((char *)cmdItem->cmdSpecific.correlator.c_str());
                    device->pendingGenericAlerts.push_back(gAlert);
                }
                else
                {
                    pExec=new SctsExec(currentCmdID,&eItem);
                }
				built=outgoingMessage->InsertCommand(pExec,nestingLevel==0,false);
				if (!built) delete pExec;
				break;
			}
        /*
         * Change to support Copy command. 
         */
		case SCTS_COPY:
			{
                SctsItem cItem((char *)cmdItem->cmdSpecific.copyFrom.c_str(),0,target,0,0,0);
                pCopy=new SctsCopy(currentCmdID,SctsItemList(cItem));
				built=outgoingMessage->InsertCommand(pCopy,nestingLevel==0,false);
				if (!built) delete pCopy;
				break;
			}
		case SCTS_SEQUENCE_START:
			{
				pSequence=new SctsSequence(currentCmdID,0);
				if (!nestingLevel) 
				{
					nestingCmdRef=&cmdItem->cmdRef;
					nestingCmdID=currentCmdID;
				}
				++nestingLevel;
				built=outgoingMessage->InsertCommand(pSequence,nestingLevel==0,false);
				if (!built) delete pSequence;
				break;
			}
		case SCTS_SEQUENCE_END:
			{
                SCTSASSERT(nestingLevel>0);
				built=outgoingMessage->InsertCommand(0);
                // reserved for retry
				//commandIt=device->cmdList.erase(commandIt);
				//commandIt--;
				--nestingLevel;
				break;
			}
		case SCTS_ATOMIC_START:
			{
				pAtomic=new SctsAtomic(currentCmdID,0);
				if (!nestingLevel) 
				{
					nestingCmdRef=&cmdItem->cmdRef;
					nestingCmdID=currentCmdID;
				}
				++nestingLevel;
				built=outgoingMessage->InsertCommand(pAtomic,nestingLevel==0,false);
				if (!built) delete pAtomic;
				break;				
			}
		case SCTS_ATOMIC_END:
			{
                SCTSASSERT(nestingLevel>0);
				built=outgoingMessage->InsertCommand(0);
                // reserved for retry
				//commandIt=device->cmdList.erase(commandIt);
				//commandIt--;
				--nestingLevel;
				break;
			}
		} //End of Switch
		if (!built)
		{
			if (nestingLevel) 
			{
				sctsFree(*nestingCmdRef);
				*nestingCmdRef=0;
				outgoingMessage->DeleteAllUnbuilt();
				currentCmdID=nestingCmdID;
			}
			/* If the outgoing message has only status on the SyncHdr the command will never be built so close the package */
			/* V1.1.1 changed <= to < */
			if (currentCmdID<3 || (sourcePkgCount==0 && currentCmdID<=4))
			{
				if (supportsLrgObj)
					SctsErrorLog::AppendError("Could not fit management command(s), ending management session.");
				else
					SctsErrorLog::AppendError("Client does not support Large Object Delivery, ending management session.");
				outgoingMessage->IsFinal(true);
			}
			/* If the server is not into Large object delivery then close the package..V1.1.1 */
			if (!largeObjectSize) outgoingMessage->IsFinal(true);
			/* Close the message if the final flag has not been set */
			if (!outgoingMessage->IsFinal()) outgoingMessage->InsertCommand(0);
			break;
		}
		if (cmdItem->command!=SCTS_ATOMIC_END && cmdItem->command!=SCTS_SEQUENCE_END)
		{
			char tempBuf[20];
			sctsInt2Str(currentCmdID,tempBuf,10);
			if (cmdItem->cmdRef) sctsFree(cmdItem->cmdRef);
			cmdItem->cmdRef=sctsStrdup(tempBuf);
			cmdItem->msgRef=currentMsgID;
			++currentCmdID;
		}
        else
        {
			cmdItem->cmdRef=sctsStrdup("-1");
			cmdItem->msgRef=currentMsgID;
        }
	}// End of For
}

SctsSyncHdr *SctsDMServerSession::BuildSyncHdr()
{
	SctsCred *cred=0;
	SctsTargetSource *target;
	SctsTargetSource *source=0;
	SctsAuthType authType=AUTH_NONE;
	SctsSyncHdr *syncHdr;
	SctsMeta meta;
	char *tempStr;
	/* Construct the credentials */
	if (outAuth && outAuth->GetType()!=AUTH_HMAC)
	{
		authType=outAuth->GetType();
		cred=outAuth->BuildCred(device->serverID,device->GetPassword(false),encoding);
		/* Construct the source */
		if (authType==AUTH_MD5)
			source=new SctsTargetSource(sourceLocURI,device->serverID);	
	}
	if (!source)
		source=new SctsTargetSource(sourceLocURI);

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


void SctsDMServerSession::HandleStartMessage(SctsSyncHdr &cmd)
{
	SctsErrorLog::OpenNode("Sync Header",0);
	int messageID;
	int newMaxMsgSize;
	int newMaxObjSize;
	int statusCode=412;
	char *deviceUserID;
	char tempBuffer[500];
	SctsCred cred;
	SctsPcdata tempPcdata;
	SctsTargetSource tempTS;
	SctsChal *chal=0;
	SctsMeta meta;
	SctsDMNode *node;
	SctsStatus *status;
	ProcessStackCmd *processCmd;
	
	while(true)
	{
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto))
		{
			processError=PROCESS_ERR_STOP;
			return;
		}
		
		/* Check if message id is valid */
   		if (!(messageID=cmd.GetMsgID()))
		{
			SctsErrorLog::AppendError("Invalid message identifier. SyncML Representation protocol (5.1.12) : The value is a monotonically increasing numeric value starting at one (1) for the first message in the SyncML session.");
			processError=PROCESS_ERR_STOP;
			return;
		}

		/* Check if message id is monotonic */
		if (messageID<=processMsgID)
		{
			SctsErrorLog::AppendError("Message identifier not monotonically increasing. SyncML Representation protocol (5.1.12) : The value is a monotonically increasing numeric value starting at one (1) for the first message in the SyncML session.");
			processError=PROCESS_ERR_STOP;
			return;
		}

		/* Assign protocol version based on first syncHdr received */
		cmd.GetVersion(tempPcdata);
		
		/* Check verDTD and verProto */
        /*
         * Change to support DM 1.2. 
         */
		if (!(tempPcdata=="1.2"))
		{
			SctsErrorLog::AppendError("Invalid VerDTD element. SyncML DM protocol (8.3) : The value of the VerDTD element MUST be '1.1'.");
			processError=PROCESS_ERR_STOP;
			return;
		}
		if (!(cmd.GetProto(tempPcdata)=="DM/1.2"))
		{
			SctsErrorLog::AppendError("Invalid VerProto element. SyncML DM protocol (8.3) : The value MUST be 'DM/1.1' when complying with this specification.");
			processError=PROCESS_ERR_STOP;
			return;
		}

		/* Adapt to MaxMsgSize */
		if ((newMaxMsgSize=cmd.GetMeta(meta).GetMaxMsgSize())!=-1)
		{
			if (newMaxMsgSize<maxMsgSize)
				maxMsgSize=newMaxMsgSize;
		}
		else
			maxMsgSize=20000;
		
		/* 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) largeObjectBufferSize=newMaxObjSize;						
		}
				
		/* Get the session ID if it is the first message */
		if (currentMsgID==1)
		{
			/* Initialize session ID */
			sessionID=cmd.GetSessionID(tempPcdata).GetString();

			/* Copy targetLocURI and sourceLocURI to be used for outgoing SyncHdr */
			sourceLocURI=cmd.GetTarget(tempTS).GetLocURI(tempPcdata).GetString();
			if (!sourceLocURI || !*sourceLocURI || !sctsStrcmp(sourceLocURI,""))
			{
				SctsErrorLog::AppendError("Source LocURI MUST be present. SyncML Representation Protocol Section 5.1.10: MUST be either an absolute or a relative URI or a well-known URN.");
				processError=PROCESS_ERR_STOP;
				return;
			}
			targetLocURI=cmd.GetSource(tempTS).GetLocURI(tempPcdata).GetString();
			if (!sourceLocURI || !*sourceLocURI || !sctsStrcmp(sourceLocURI,""))
			{
				SctsErrorLog::AppendError("Target LocURI MUST be present. SyncML Representation Protocol Section 5.1.10: MUST be either an absolute or a relative URI or a well-known URN.");
				processError=PROCESS_ERR_STOP;
				return;
			}
		}
		else
		{
			/* Check session ID */
			if (!(cmd.GetSessionID(tempPcdata)==sessionID))
			{
				SctsErrorLog::AppendError("Session ID has changed. SyncML DM protocol (8.2) : Same SessionID MUST be used throughout the whole session.");
				break;
			}
		}

		/* Get the device */
		if (!userID)
		{
			if (!device)
			{
                if (inAuth)
                {
                    SctsErrorLog::AppendError("Unable to find available server device.");
                    statusCode = 500;
                    delete inAuth;
                    inAuth = 0;
                    break;
                }
				/* Get user name from credentials if any */
				cmd.GetCred(cred);
				if (!cred)
				{
					statusCode=407;
					chal=SctsAuthBasic().BuildChal(encoding);
					break;
				}

				/* Check if cred is valid */
				if (!SctsAuthBasic().VerifyCred(cred,0,0,encoding))
				{
					statusCode=412;
					break;
				}

				/* Get type */
				if (cred.GetMeta(meta).GetType(tempPcdata)=="syncml:auth-md5")
				{
					if (!cmd.GetSource(tempTS).GetLocName(tempPcdata))
					{
						SctsErrorLog::AppendError("SyncHdr->Source->LocName missing for MD5 authentication. Representation protocol (4.13) : To specify the userID for the credentials, when the credentials do not include it in the resolvable form, the userID must be transferred in the LocName element of Source in SyncHdr.");
						statusCode=412;
						break;
					}
					deviceUserID=sctsStrdup((char *)tempPcdata);
				}
				else
				{
					unsigned char *credData=0;
					unsigned int size=cred.GetData(tempPcdata).GetLength();		
					if (size) credData=sctsBase64Decode((char *)tempPcdata,size);
					if (credData)
					{
						deviceUserID=sctsStrchr((char *)credData,':');
						if (deviceUserID)
						{
							*deviceUserID=0;
							deviceUserID=sctsStrdup((char *)credData);
						}
						sctsFree(credData);
					}
					if (!deviceUserID)
					{
						SctsErrorLog::AppendError("Unable to extract user name from base-64 encoded credential string.");
						statusCode=500;
						break;
					}
				}

				/* Create a new device if it is a discover session */
				discoveryAccountLock.Lock();
				if (discoveryAccount)
				{
                    std::string fullPath = SctsDMServerSession::discoveryTempPath;
                    fullPath += "/AppAuth/SctsClient/AAuthName";
					node=discoveryAccount->FindDMNode((char *)fullPath.c_str());
					if (!sctsStrcmp(deviceUserID,(char *)node->data))
					{
						SctsDMCommand *newCommand;
						/* Create a new server device */
						device=SctsDMDevice::AddServerDevice(SctsDMDevice::GetSctsServerID(),discoveryDMAccPath,deviceUserID,discoveryName,discoveryContact,discoveryCompany);
						/* 'Nodenap' the discovery accounts root node */
						device->accountNode=discoveryAccount->root;

                        SctsDMAccount dmAccount(discoveryAccount, device->accountNode, SctsDMServerSession::discoveryTempPath);
                        if (dmAccount.IsDMAcc())
                        {
                            device->accounts[device->accountNode->name] =
                                SctsDMDevice::MulDynAccItem(device->accountNode->name,
                                                            dmAccount.GetPath(),
                                                            dmAccount.GetSubAppAddr(),
                                                            dmAccount.GetSubPort(),
                                                            dmAccount.GetSubAppAuthClient(),
                                                            dmAccount.GetSubAppAuthServer(),
                                                            dmAccount.GetSubToConRef());
                        }

						discoveryAccount->root=0;
						delete discoveryAccount;
						discoveryAccount=0;
						/* Set the new device flag to false so that we can send management commands */
						device->newDevice=false;
						if (discoveryName)
						{
							sctsFree(discoveryName);
							discoveryName=0;
						}
						if (discoveryContact)
						{
							sctsFree(discoveryContact);
							discoveryContact=0;
						}
						if (discoveryCompany)
						{
							sctsFree(discoveryCompany);
							discoveryCompany=0;
						}
                        if (discoveryDMAccPath)
                        {
                            sctsFree(discoveryDMAccPath);
                            discoveryDMAccPath=0;
                        }
						sessionType=DMSESSION_DISCOVER;
						newCommand=new SctsDMCommand(SCTS_GET,device->root);
						newCommand->nodeRef=device->root;
						device->InsertCommand(newCommand);
						newCommand=new SctsDMCommand(SCTS_GET,device->root,DMPROP_ACL);
						newCommand->nodeRef=device->root;
						device->InsertCommand(newCommand);
						supportsLrgObj=true;
					}
				}	
				discoveryAccountLock.Unlock();
			}

			if (!device)
			{
				/* Find device */
				device=SctsDMServerDevice::GetServerDevice(deviceUserID);
				//if (deviceUserID) sctsFree(deviceUserID);	
				if (!device)
				{
					sprintf(tempBuffer,"Could not find device : %s",deviceUserID);
					SctsErrorLog::AppendError(tempBuffer);
					statusCode=404;
					break;
				}
				/* Set the SessionType */
				sessionType=device->sessionType;
			}

			if (!userID)
			{
				/* Check if device is busy */
				if (!device->Lock(0))
				{
					SctsErrorLog::AppendError("Device is busy.");
					device=0;
					statusCode=417;
					break;
				}
				if (!device->IsServerDevice())
				{
					if (componentUIC.addSession) (*componentUIC.addSession)(this);
					SctsErrorLog::AppendError("This device is used for testing servers and cannot accept client connections");
					statusCode=500;
					break;
				}
			}

			/* Check if the device supports Large Object Delivery */
			if (sessionType!=DMSESSION_DISCOVER && device)
			{
				node=device->FindDMNode("./DevDetail/LrgObj");
				if (!node || !node->data)
				{
					SctsErrorLog::AppendError("./DevDetail/LrgObj node is missing.");
					statusCode=500;
					break;
				}
				else
				{
					if (!sctsStrcmp((char *)node->data,"true"))	supportsLrgObj=true;
				}
			}

			if (!device->accountNode)
			{
				/* Find account node */
                if (!(node=device->FindDMNode(device->dmAccPath)))
				{
					SctsErrorLog::AppendError("DMAccount node is missing.");
					statusCode=500;
					break;
				}
				device->accountNode=0;
				for (device->accountNode=node->child;device->accountNode;device->accountNode=device->accountNode->next)
				{
					node=device->FindDMNode("ServerID",device->accountNode);
					if (node && node->data && !sctsStrcmp((char *)node->data,device->serverID)) break;
				}
				if (!device->accountNode)
				{
					if (componentUIC.addSession) (*componentUIC.addSession)(this);
					SctsErrorLog::AppendError("Could not find a DMAccount for SCTS' server ID.");
					statusCode=500;
					break;
				}
                if (!device->accountNode->child)
                {
                    device->accountNode = 0;
				    SctsErrorLog::AppendError("DMAccount subnode is missing.");
				    statusCode=500;
				    break;
                }
                SctsDMAccount dmAccount((SctsDMTree *)device, device->accountNode);
                if (dmAccount.IsDMAcc())
                {
                    device->accounts[device->accountNode->name] =
                        SctsDMDevice::MulDynAccItem(device->accountNode->name,
                                                    dmAccount.GetPath(),
                                                    dmAccount.GetSubAppAddr(),
                                                    dmAccount.GetSubPort(),
                                                    dmAccount.GetSubAppAuthClient(),
                                                    dmAccount.GetSubAppAuthServer(),
                                                    dmAccount.GetSubToConRef());
                }
                else
                {
					if (componentUIC.addSession) (*componentUIC.addSession)(this);
					SctsErrorLog::AppendError("Could not find a DMAccount for SCTS' server ID.");
					statusCode=500;
					break;
                }
			}
            else if (!device->accountNode->child)
            {
                device->accountNode = 0;
				SctsErrorLog::AppendError("DMAccount subnode is missing.");
				statusCode=500;
				break;
            }
			
			/* Get userID and password */
			userID=device->GetUserID();			
			password=sctsStrdup(device->GetPassword(true));

#ifdef __SCTS_USING_SCTS__
 			if (sessionType==DMSESSION_TEST)
			{
				SCTSASSERT(device->tester);
				if (device->tester->GetState()==TE_IDLE) 
				{
					if (componentUIC.addSession) (*componentUIC.addSession)(this);
					SctsErrorLog::AppendError("Device not expecting connection.");
					statusCode=500;
					break;
				}
				device->tester->nextTestGroup->session=this;
				switch(device->tester->GetState())
				{
				case TE_STAGE_CHECK:
					CallBack=sctsTestDeviceExecuteStageTest;
					break;
				case TE_STAGE_TEST:
					CallBack=sctsTestDeviceExecuteStageTerminate;
					testGroup=device->tester->nextTestGroup;
					testGroup->StateInitiatePreProcess();
					break;
				}
			}
#endif
			/* Setup Incoming Authentication only if it isn't HMAC, this is setup when receiving the first message */
			if (!inAuth)
			{
				if (userID && password)
				{
					switch(device->GetAuthType(true))
					{
					case AUTH_BASIC:
						inAuth=new SctsAuthBasic();
						break;
					case AUTH_HMAC:
					case AUTH_MD5:
						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_MD5)
							inAuth=new SctsAuthMD5(nonce,size);
						else
							inAuth=new SctsAuthHMAC(nonce,size);
						device->SetNonce(true,0,0);
						break;
					}				
				}
			}
			
			/* Setup Outgoing Authentication */
			outAuth=0;
			if (device->GetPassword(false))
			{
				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_MD5)
							outAuth=new SctsAuthMD5(nonce,size);
						else
							outAuth=new SctsAuthHMAC(nonce,size);
						device->SetNonce(false,0,0);
					}
					break;
				}
			}
			
			if (componentUIC.addSession) (*componentUIC.addSession)(this);
		}
		/* Check authentication */
		if (inAuth)
		{
			statusCode=inAuth->VerifyCred(cmd.GetCred(cred),userID,password,encoding);
			/* 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;
	}
	sentSyncHdrStatus=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);
	}
	
	#ifdef __SCTS_USING_SCTS__
		if (sourcePkgCount==0 && sessionType==DMSESSION_TEST && testGroup) testGroup->StateInitiatePreBuild();
	#endif

	outgoingMessage=new SctsMessage(sessionContext,encoding,BuildSyncHdr(),maxMsgSize,wbxmlConverterContext,uiCallbackData,uiCallback);
	
	if (outgoingMessage->GetFreeSize()<0)
	{
		processError=PROCESS_ERR_STOP;
		SctsErrorLog::AppendError("Cannot build message with current MaxMsgSize, an insufficient MaxMsgSize was either received from the server or set in the UI.");
		return;
	}
	
	if (cmd.IsNoResp())
	{
		messageNoResp=true;
	}
	else
	{
		/* Build status */
		status=new SctsStatus(currentCmdID,processMsgID,"0","SyncHdr",statusCode);
		/* TargetRef/SourceRef discrepancy */
		cmd.GetTarget(tempTS).GetLocURI(tempPcdata);
		if (tempPcdata) status->SetTargetRefList(&SctsTargetRefList(SctsPcdata((char *)tempPcdata)));
		cmd.GetSource(tempTS).GetLocURI(tempPcdata);
		if (tempPcdata) status->SetSourceRefList(&SctsSourceRefList(SctsPcdata((char *)tempPcdata)));
		if (chal) 
		{
			status->SetChal(chal);
			delete chal;
		}
		outgoingMessage->InsertCommand(status,false);
		++currentCmdID;
		messageNoResp=false;
	}
	/* Close error log node and clean up*/
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleEndMessage(bool final)
{
	ProcessStackCmd *parent=processStack.top();
	/* Check if parent is <SyncBody> */
	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;
		if (processError==PROCESS_ERR_OK) 
			processError=PROCESS_ERR_NONE;
		else
			processError=PROCESS_ERR_STOP;
	}
}

void SctsDMServerSession::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;
	char *cmdRef;
	SctsDMCommand *command;

	std::list<SctsDMCommand *>::iterator commandIt;
	/* Create error log node */
	CreateErrorNode(cmd);
	
	cmd.GetCmd(tempPcdata1);
	while(true)
	{
		status=cmd.GetData();
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) break;
		
		/* Find last command that hasn't received status */
		cmd.GetCmdRef(tempPcdata1);
		/* Get the MsgRef */
		msgRef=cmd.GetMsgRef();
		if (tempPcdata1=="0")
		{
			if (messageQueue.size())
			{
				pCmd=messageQueue.back()->GetCurrentCommand();
				/* Ref#0021 : Check MsgRef */
				if (msgRef!=currentMsgID-1)
					sprintf(errorMsg,"Invalid MsgRef element, expecting Status for MsgID : %d.",currentMsgID-1);
			}
			else
				sprintf(errorMsg,"Not expecting status for SyncHdr, client's message may not have been directed to an already running session due to the client's incorrect handling of the RespURI.");
		}
		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) && messageQueueID==msgRef) 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. Representation protocol (5.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),currentMsgID-1,(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;
			}
		}

		cmd.GetCmdRef(tempPcdata1);
		cmdRef=(char *)tempPcdata1;
		
		command=0;
		if (device)
		{
			for(commandIt=device->cmdList.begin();commandIt!=device->cmdList.end();commandIt++)
			{
				command=*commandIt;
				if (command->command==SCTS_SEQUENCE_END || command->command==SCTS_ATOMIC_END || command->status || !command->cmdRef || !command->msgRef) continue;
				if (!sctsStrcmp(command->cmdRef,cmdRef) && command->msgRef==msgRef) break;
			}
			if (commandIt==device->cmdList.end()) command=0;				
		}

		/* 
		Don't process the status if the status of the synchdr was 401 or 407 
		Exception : Process the status on the SyncHdr to get the chal. If there
		is a command erase its cmdRef so that it gets resent.
		*/
		if ( cmdType!=SCTS_HEADER && (recvSyncHdrStatus==401 || recvSyncHdrStatus==407))
		{
			if (command)
			{
				sctsFree(command->cmdRef);
				command->cmdRef=0;
			}
			error=false;
			break;
		}
		
		/* Handle status for different commands */
		switch(cmdType)
		{
		case SCTS_ADD:
			{	
				error=false;
				SCTSASSERT(command);
				if (status==213) break;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					if (status!=200 && largeObjectSize && largeObjectCommand==command) 
					{
						sprintf(errorMsg,"Large Object Delivery Failed. Received a status code of %d for Add.",status);
						LargeObjectClear();
					}
					command->status=status;
					break;
				}
#endif
				if (status!=200 && status!=418)
				{
					if (device->uiCallback) (*device->uiCallback)((SctsDMTree *)device,command->nodeRef,SCTS_DELETE);
					command->RollBack(device->cmdList,commandIt);
				}
				if (largeObjectSize && largeObjectCommand==command) 
				{
					sprintf(errorMsg,"Large Object Delivery Failed. Received a status code of %d for Add.",status);
					LargeObjectClear();
				}
				delete command;
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_COPY:
			{	
				error=false;
				SCTSASSERT(command);
				if (status==213) break;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					break;
				}
#endif
				if (status!=200 && status!=418)
				{
					if (device->uiCallback) (*device->uiCallback)((SctsDMTree *)device,command->nodeRef,SCTS_DELETE);
					command->RollBack(device->cmdList,commandIt);
				}
				delete command;
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_DELETE:
			{
				SCTSASSERT(command);								
				error=false;				
				if (status==200) 
				{
					device->DeleteDMNode(command->nodeRef,SIDX,0);
					command->nodeRef=0;
				}
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					break;
				}
#endif
				if (status!=200 && status!=404 && status!=211)
				{
					command->RollBack();
					if (device->uiCallback) (*device->uiCallback)((SctsDMTree *)device,command->nodeRef,SCTS_ADD);
				}
				else
					device->DeleteDMNode(command->nodeRef,SIDX,0);
				delete command;
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_EXEC:
			{
				SCTSASSERT(command);
				error=false;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					break;
				}
#endif
				delete command;
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_REPLACE:
			{
				error=false;	
				SCTSASSERT(command);
				if (status==213) break;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					if (status!=200 && largeObjectSize && largeObjectCommand==command) 
					{
						sprintf(errorMsg,"Large Object Delivery Failed. Received a status code of %d for Replace.",status);
						LargeObjectClear();
					}
					break;
				}
#endif
				if (status!=200) command->RollBack();
				delete command;
				if (largeObjectSize && largeObjectCommand==command) 
				{
					sprintf(errorMsg,"Large Object Delivery Failed. Received a status code of %d for Replace.",status);
					LargeObjectClear();
				}
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_HEADER:
			{
      			if (status!=200 && status!=212 && status!=101 && status!=401 && status!=407)
				{
					sprintf(errorMsg,"Unable to handle status for SyncHdr.");
					break;
				}
                if (!device)
                {
                    sprintf(errorMsg,"Unable to find available server device.");
				    error=true;
				    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;
                    SctsSyncHdr *syncHdr=(SctsSyncHdr *)outgoingMessage->GetHeader();
					syncHdr->SetCred(0);
					outgoingMessage->Rebuild();
				}
				if (status==401 || status==407)
				{
					/* Check if chal for the same scheme was received */
					if (auth && outAuth && outAuth->GetType()==auth->GetType())
					{
						delete auth;
						auth=0;
					}
					if (outAuth) delete outAuth;
					outAuth=auth;
					auth=0;
				    device->SetAuthType(false,outAuth?outAuth->GetType():AUTH_NONE);
				}

				if (outAuth)
				{
					SctsCred *cred;
					SctsSyncHdr *syncHdr=(SctsSyncHdr *)outgoingMessage->GetHeader();
					/* Get the ServerPW from the tree */
					char *serverPW=device->GetPassword(false);
					if (!serverPW)
					{
						sprintf(errorMsg,"ServerPW is not configured.");
						break;
					}
					cred=outAuth->BuildCred(device->serverID,(char *)serverPW,encoding);
					/* Construct the source */
					if (outAuth->GetType()==AUTH_MD5) syncHdr->SetSource(sourceLocURI,device->serverID);
					syncHdr->SetCred(cred);
					outgoingMessage->Rebuild();
					delete cred;
				}

				recvSyncHdrStatus=status;
				
				error=false;
				break;
			}
		case SCTS_ALERT:
			{
				error=false;
				if (!command) break;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					break;
				}
#endif
				delete command;
				device->cmdList.erase(commandIt);
				break;
			}
		case SCTS_GET:
			{
				SCTSASSERT(command);
				error=false;
				command->command=SCTS_RESULTS;
				command->status=status;				
				if (sessionType!=DMSESSION_TEST && status!=200)
				{
					delete command;
					device->cmdList.erase(commandIt);
					break;
				}
				if (command->prop==DMPROP_STRUCT || command->prop==DMPROP_STRUCTDATA)
				{
					std::list<SctsDMNode *> *refList=new std::list<SctsDMNode *>;
					std::list<SctsDMNode *> childList; 
					if (command->nodeRef) 
					{
						SctsDMNode *current=command->nodeRef;
						refList->push_back(current);
						if (current->child) childList.push_back(current);
						while (!childList.empty())
						{
							current=childList.front();
							childList.pop_front();
							current=current->child;
							while (current)
							{
								refList->push_back(current);
								if (current->child) childList.push_back(current);
								current=current->next;		
							}												
						}
					}
					command->data=(void *)refList;
				}
				break;
			}
		case SCTS_SEQUENCE_START:
		case SCTS_ATOMIC_START:
			{
				SCTSASSERT(command);
				error=false;
#ifdef __SCTS_USING_SCTS__
				if (sessionType==DMSESSION_TEST)
				{
					command->status=status;
					break;
				}
#endif
				delete command;
                std::list<SctsDMCommand *>::iterator commandEndIt = commandIt;
                SctsCommandType cmdEndType = cmdType == SCTS_SEQUENCE_START? SCTS_SEQUENCE_END:SCTS_ATOMIC_END;
                for(++commandEndIt; commandEndIt!= device->cmdList.end(); ++commandEndIt)
                {
                    if((*commandEndIt)->command == cmdEndType)
                    {
                        device->cmdList.erase(commandEndIt);
                        break;
                    }
                }
				device->cmdList.erase(commandIt);
				break;
			}
		} /* End of switch */
	break;
	} /* End of while */
	
	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 (auth) delete auth;
	if (errorMsg[0]) SctsErrorLog::AppendError(errorMsg);
	SctsErrorLog::CloseNode();
	return;
}	

void SctsDMServerSession::HandleAlert(SctsAlert& cmd)
{
	int statusCode=500;
	int alertCode=cmd.GetData();
	char errorMsg[300]="";
	SctsTargetSource tempTS;
	SctsStatus *status=0;
	SctsPcdata tempPcdata1;
	SctsPcdata tempPcdata2;
	SctsItem item,_item;
	SctsItemList itemList;
	SctsMeta meta;
	SctsCred cred;
	SctsChal *chal=0;
	ProcessStackCmd *parent=processStack.top();

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

	while(true)
	{
		/* Check returned syncHdr status */
		if (
            (recvSyncHdrStatus==401 || recvSyncHdrStatus==407) &&
            (cmd.GetData() != 1226 && cmd.GetData() != 1200 && cmd.GetData() != 1201)
           )
		{
			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. Representation protocol (5.5.2) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) 
		{
			statusCode=412;
			break;
		}
		/* Check immediate parents status and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		if (parent->status>=300) break;
		
		if (alertCode==1200 || alertCode==1201)
		{
			/* Check state */
			if (targetPkgCount>0)
			{
				SctsErrorLog::AppendError("Alerts 1200/1201 must be sent in Package #1. SyncML DM protocol (8.2) : Initialization from Client to Server.");
				break;
			}
			if (itemList.GetNextData(_item))
			{
				SctsErrorLog::AppendError("Not expecting more than one Item.");
				break;
			}
			if (alertCode==1200)
				serverInitiatedAlert=true;
			else
				clientInitiatedAlert=true;
			statusCode=200;
			break;
		}
		if (alertCode==1222) /* Next Message Alert */
		{
			statusCode=200;
			break;
		}
		if (alertCode==1223) /* Session Abort */
		{
			receivedSessionAbortAlert=true;
			statusCode=200;
			break;
		}
		if (alertCode==1226) /* Generic Alert */
		{
			if (cmd.GetCorrelator())
			{
				std::deque<SctsDMGenericAlert *>::iterator it = device->pendingGenericAlerts.begin();
				while (it != device->pendingGenericAlerts.end())
				{
					SctsPcdata tempPcdata;
					SctsTargetSource tempTS;
					item.GetSource(tempTS).GetLocURI(tempPcdata);
					if ((*it)->source && (*it)->correlator && 
						!sctsStrcmp((*it)->source,(char *)tempPcdata) && !sctsStrcmp((*it)->correlator,cmd.GetCorrelator()))
					{
						break;
					}
					++it;
				}
				if (it == device->pendingGenericAlerts.end())
				{
					SctsErrorLog::AppendError("Alerts 1226 with invalid correlator.");
					break;
				}
				delete *it;
				device->pendingGenericAlerts.erase(it);
			}
			statusCode=200;
			break;
		}
		statusCode=412;
		break;
	} /* End of while */
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata1),"Alert",statusCode);
		outgoingMessage->InsertCommand(status,false);
		++currentCmdID;
	}
	if (errorMsg[0]) SctsErrorLog::AppendError(errorMsg);
	
	SctsErrorLog::CloseNode();
	return;
}

void SctsDMServerSession::HandleResults(SctsResults& cmd)
{
	std::map <int,SctsSourceRefList *> sourceRefs;
	std::map <int,SctsSourceRefList *>::iterator it;
	int statusCode=500;
	int itemCnt=0;
	int msgRef=0;
	int size;
	char *cmdRef=0;
	char *cmdMime=0;
	char *cmdFormat=0;
	char *mime=0;
	char *format=0;
	char *data;
	char *source;
	SctsMeta meta;
	SctsItem item;
	SctsStatus *status=0;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsTargetSource tempTS;
	SctsDMCommand *command;
	char errorMsg[500]="";
	std::list<SctsDMCommand *>::iterator commandIt;

	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)
		{
			SctsErrorLog::AppendError("Parent of Results MUST be SyncBody. Representation protocol (5.5.12) : Parent Elements.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) 
		{
			statusCode=412;
			break;
		}

		/* Check immediate parents status and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		
		/* Get the CmdRef */
		cmdRef=(char *)cmd.GetCmdRef(tempPcdata);

		/* Get the MsgRef */
		msgRef=cmd.GetMsgRef();
		if (!msgRef) msgRef=1;
	
		/* 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;itemList.GetNextData(item))
		{
			++itemCnt;
			statusCode=0;
			while(true)
			{
				SctsDMNodeFormat _format=DMFORMAT_CHR;
				/* Check if source is present */
				if (item.GetSource(tempTS).GetLocURI(tempPcdata))
					source=(char *)tempPcdata;
				else
					source=0;
							
				/* Check if data is present  Discrepancy
				if (!item.GetData(tempPcdata))
				{
					statusCode=412;
					SctsErrorLog::AppendError("Item->Data element is missing. SyncML DM protocol (8.3) : Data element MUST be used to carry data itself if the operation is not a deletion.");
					break;
				}
				*/
								
				/* Large object delivery */
				if (largeObjectSize && largeObjectCmd==SCTS_RESULTS)
				{
					/* Check CmdRef,MsgRef,TargetRef and SourceRef */
					/*  || !(cmd.GetTargetRef(tempPcdata)==largeObjectSURI) */
					if (cmd.GetMsgRef()!=largeObjectMsgRef || !(cmd.GetCmdRef(tempPcdata)==largeObjectCmdRef))
					{
						SctsErrorLog::AppendError("Expecting Large Object.");
						LargeObjectSendAlert();
					}
					else
					{
						/* Receive the chunk */
						size=largeObjectSize;
						if (!LargeObjectRecvChunk(false,statusCode,SCTS_RESULTS,item,cmd.GetMeta(meta)))	break;
						
						if (!statusCode)
						{
							mime=largeObjectType;
							format=largeObjectFormat;
							data=largeObjectBuffer;
							largeObjectBuffer=0;
							data[size]=0;
							statusCode=200;
						}
						else
						{
							LargeObjectClear();
							break;
						}
						LargeObjectClear();
					}
				}
				/* Check if we are expecting RESULTS, (In the handle status for GET,
				   the command type is changed from GET -> RESULTS, if the status for GET 
				   is 200. At the end of session, run thru the RESULTS list to check if we 
				   received RESULTS for all the GETS.
				*/
				for(commandIt=device->cmdList.begin();commandIt!=device->cmdList.end();commandIt++)
				{
					command=*commandIt;
					if (command->command!=SCTS_RESULTS || (command->status!=200)) continue;
					if (!sctsStrcmp(command->cmdRef,cmdRef) && command->msgRef==msgRef) break;				
				}
				if (commandIt==device->cmdList.end()) 
				{
					statusCode=500;
					sprintf(errorMsg,"Not expecting results with cmdRef %s and msgRef %d",cmdRef,msgRef);
					SctsErrorLog::AppendError(errorMsg);
					break;
				}
				
				if (!statusCode)
				{
					/* Get the mimeType & format */
					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)
						{
							sctsFree(largeObjectType);
							sctsFree(largeObjectFormat);
							largeObjectType=sctsStrdup(mime);
							largeObjectFormat=sctsStrdup(format);
							largeObjectCmdRef=cmd.GetCmdRef(tempPcdata).GetString();
							largeObjectMsgRef=cmd.GetMsgRef();
							LargeObjectRecvChunk(true,statusCode,SCTS_RESULTS,item,cmd.GetMeta(meta));
						}
						else
							statusCode=406;
						break;
					}
				
					/* Get Data */
					item.GetData(tempPcdata);
					data=(char *)tempPcdata;
					size=tempPcdata.GetLength();
					statusCode=200;
				}
				
				if (statusCode!=200) break;

				/* VERSION 1.1.2*/
				//Ref 0001
				CONVERTB64TOBINFIX(encoding,nret,data,format,size)
				size = nret;
				if (format)	for (;_format!=DMFORMAT_NONE && sctsStrcmp(SctsDMFormatString[_format],format);_format=(SctsDMNodeFormat)(_format+1));
				if (_format==DMFORMAT_NONE)
				{
					sprintf(errorMsg,"Invalid Format in Results.");
					SctsErrorLog::AppendError(errorMsg);
					break;
				}
				if (command->prop==DMPROP_STRUCT || command->prop==DMPROP_STRUCTDATA || command->prop==DMPROP_TNDS)
				{
					if (command->prop==DMPROP_STRUCT) break;
                    /*
                     * Change to support TNDS. 
                     */
                    if (command->prop==DMPROP_TNDS)
                    {
                        command->data = new SctsDMTNDSTree(format, mime, data, size);
                        break;
                    }
					std::list<SctsDMNode *> *refList=(std::list<SctsDMNode *>*)command->data;
					std::list<SctsDMNode *>::iterator it;
					SctsDMNode *temp=((SctsDMServerTree *)device)->FindDMNode(source);
					if (temp)
					{
						for (it=refList->begin();it!=refList->end();it++)
						{
							SctsDMNode *node=*it;
							if (node==temp)
							{
								if (node->format!=DMFORMAT_NODE && command->prop!=DMPROP_STRUCTDATA) ((SctsDMServerTree *)device)->ReplaceDMNodeData(node,SIDX,data,size,format,mime);
								break;
							}							
						}
						if (it!=refList->end())
							refList->erase(it);
					}
					else
						((SctsDMServerTree *)device)->AddDMNode(source,device->serverID,format,false,data,mime,nret);
					break;
				}
				if (sessionType==DMSESSION_NORMAL)
				{
					if (command->prop==DMPROP_NONE)
					{
						if (_format!=DMFORMAT_NODE)
						{
							SctsDMNode *temp=command->nodeRef;
							temp->format=_format;
							if (mime) 
							{
								if (temp->mimeType) sctsFree(temp->mimeType);
								temp->mimeType=sctsStrdup(mime);
							}
							if (temp->data) sctsFree(temp->data);
							temp->data=sctsMalloc(size+1);
							sctsMemcpy(temp->data,data,size);
							((char *)temp->data)[size]=0;
							temp->size=size;
						}
					}
					else
					{
						switch (command->prop)
						{
						case DMPROP_ACL:
							{
								if (!command->nodeRef->VerifyACLSyntax(data))
								{
									statusCode=500;
									sprintf(errorMsg,"ACL returned in the Results is invalid. cmdRef %s and msgRef %d",cmdRef,msgRef);
									SctsErrorLog::AppendError(errorMsg);
									break;
								}
								if (command->nodeRef->acl) sctsFree(command->nodeRef->acl);
								command->nodeRef->acl=sctsStrdup(data);
								break;
							}
						case DMPROP_NAME:
							{
								if (sctsStrcmp(data,command->nodeRef->name))
								{
									statusCode=500;
									sprintf(errorMsg,"Results on the name property is incorrect. cmdRef %s and msgRef %d",cmdRef,msgRef);
									SctsErrorLog::AppendError(errorMsg);
								}
								break;
							}
						case DMPROP_FORMAT:
								break;
						case DMPROP_TIMESTAMP:
							{
								if (command->nodeRef->timeStamp) sctsFree(command->nodeRef->timeStamp);
								command->nodeRef->timeStamp=sctsStrdup(data);
								break;
							}
						case DMPROP_MIMETYPE:
							{
								if (command->nodeRef->mimeType) sctsFree(command->nodeRef->mimeType);
								command->nodeRef->mimeType=sctsStrdup(data);
								break;
							}
						case DMPROP_VERSION:
							{
								command->nodeRef->version=atoi(data);
								break;
							}
						case DMPROP_SIZE:
							{
								if (command->nodeRef->size!=atoi(data))
								{
									statusCode=500;
									sprintf(errorMsg,"Results on the size property is incorrect. cmdRef %s and msgRef %d",cmdRef,msgRef);
									SctsErrorLog::AppendError(errorMsg);
								}
								break;
							}
						default:
							SCTSASSERT(false);
						};
					}
				}	
				if (sessionType==DMSESSION_TEST)
				{
					if (command->prop==DMPROP_NONE)
						command->data=new SctsDMNode(source,_format,false,0,data,mime,size);
					else
						command->data=sctsStrdup(data);
					break;
				}
				if (sessionType==DMSESSION_DISCOVER)
				{
					if (command->prop==DMPROP_NONE)
					{
						SctsDMNode *tempNode;
						command->nodeRef->format=_format;
						if (_format==DMFORMAT_NODE)
						{
							command->nodeRef->format=DMFORMAT_NODE;
							if (size)
							{
								char tempBuffer[500];
								char *temp,*temp1,*temp2;
								sprintf(tempBuffer,"%s/",source);
								temp=tempBuffer+sctsStrlen(tempBuffer);
								temp1=data;
								do
								{
									if ((temp2=sctsStrchr(temp1,'/'))) *temp2=0;
									sctsStrcpy(temp,temp1);
									tempNode=0;
									if (sctsStrcmp(tempBuffer,"./DevInfo") && device->AddDMNode(tempBuffer,SIDX,"null",false,0,0,0,&tempNode)==200)
									{
										SctsDMCommand *newCommand=new SctsDMCommand(SCTS_GET,tempNode);
										newCommand->nodeRef=tempNode;
										device->InsertCommand(newCommand);
										newCommand=new SctsDMCommand(SCTS_GET,tempNode,DMPROP_ACL);
										newCommand->nodeRef=tempNode;
										device->InsertCommand(newCommand);
									}
									temp1=temp2+1;
								}
								while (temp2);
							}
						}
						else
							device->ReplaceDMNodeData(command->nodeRef,SIDX,data,size,format,mime);
					}
					else
						device->ReplaceDMNodeProp(command->nodeRef,SIDX,command->prop,data);
				}
				if (command && commandIt!=device->cmdList.end())
				{
					delete command;
					device->cmdList.erase(commandIt);
				}
				break;
			}
			/* V1.1.2 
			if (!messageNoResp) */
			if (statusCode!=200)
			{
				/* Multiple status */
				it=sourceRefs.find(statusCode);
				if (it==sourceRefs.end())
				{
					SctsSourceRefList *sourceRefList;
					if (status) outgoingMessage->InsertCommand(status,false);
					status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Results",statusCode);
					++currentCmdID;
					sourceRefList=new SctsSourceRefList(SctsPcdata(source));
					sourceRefs[statusCode]=sourceRefList;
					status->SetSourceRefList(sourceRefList);
				}
				else
				{
					it->second->SetNextData(SctsPcdata(source));
				}
			}
			/* UI callback */
			if (uiCallback)
			{
				cmd.status=statusCode;
				(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
			}
		}
		break;
	}
	/* V1.1.2 
	if (!messageNoResp) */
	if (statusCode!=200)
	{
		if (!sourceRefs.size())
		{
			status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Results",statusCode);
			outgoingMessage->InsertCommand(status,false);
			++currentCmdID;
		}
		else
		{
			if (sourceRefs.size()==1) 
				/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetSourceRefList(0);
			if (status) outgoingMessage->InsertCommand(status,false);
		}
	}
	
	/* Close error log node and clean up*/
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleReplace(SctsReplace& cmd)
{
	std::map <int,SctsSourceRefList *> sourceRefs;
	std::map <int,SctsSourceRefList *>::iterator it;
	int statusCode=500;
	int itemCnt=0;
	char *cmdMime=0;
	char *cmdFormat=0;
	char *mime=0;
	char *format=0;
	char *data;
	char *source;
	SctsMeta meta;
	SctsItem item;
	SctsStatus *status=0;
	SctsPcdata tempPcdata;
	SctsItemList itemList;
	SctsTargetSource tempTS;
	ProcessStackCmd *parent=processStack.top();

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

	while(true)
	{
		/* Check if parents are valid */
		if (parent->type!=SCTS_HEADER)
		{
			SctsErrorLog::AppendError("Parent of Replace MUST be SyncBody.");
			break;
		}
		/* Check if command conforms to DTD */
		if (!cmd.VerifyDTD(proto)) 
		{
			statusCode=412;
			break;
		}

		/* Check immediate parents status and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		if (parent->status>=300) break;
	
		if(targetPkgCount>1)
		{
			statusCode=500;
			SctsErrorLog::AppendError("Server can handle Replace of only in the initialization package of the client.");
			break;
		}

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

		/* Get the format */
		if (cmd.GetMeta(meta)) cmdFormat=(char *)meta.GetFormat(tempPcdata);

		/* Process the commands Item list */
		cmd.GetItemList(itemList);
		itemList.GetData(item);
		receivedDevInfo=true;
		for (;item;itemList.GetNextData(item))
		{
			statusCode=0;
			++itemCnt;
			while(true)
			{
				/* Check if target is present */
				if (item.GetTarget(tempTS))
				{
					statusCode=500;
					SctsErrorLog::AppendError("Item->Target element is not allowed.");
					break;
				}

				/* Check if source is present */
				if (!item.GetSource(tempTS).GetLocURI(tempPcdata))
				{
					statusCode=500;
					SctsErrorLog::AppendError("Item->Source->LocURI element is missing. Sync protocol (5.1) : The Source element MUST be included to indicate the LUID of the data item within the Item element.");
					break;
				}
				source=(char *)tempPcdata;
				if (sctsStrncmp("./DevInfo/",source,10) && sctsStrncmp("DevInfo/",source,8))
				{
					statusCode=500;
					SctsErrorLog::AppendError("Server can handle replaces only on the DevInfo node.");
					break;
				}
				statusCode=412;

				/* Get the mimeType and Format*/
				mime=cmdMime;
				format=cmdFormat;
				if (item.GetMeta(meta).GetType(tempPcdata)) mime=(char *)tempPcdata;
				if (item.GetMeta(meta).GetFormat(tempPcdata)) format=(char *)tempPcdata;
				
				/* Check if data is present */
				if (!item.GetData(tempPcdata))
				{
					statusCode=500;
					SctsErrorLog::AppendError("Item->Data element is missing. Sync protocol (5.1) : Data element MUST be used to carry data itself if the operation is not a deletion.");
					break;
				}
				data=(char *)tempPcdata;
		
				/* Replace the item */
				statusCode=device->ReplaceDMNodeData(source,SIDX,data,tempPcdata.GetLength(),format,mime);
				/* To handle replaces with Ext nodes. SCTS just discards them */
				if (sctsStrstr(source,"/Ext/") && statusCode==404) statusCode=200;
				break;
			}
			if (statusCode!=200) receivedDevInfo=false;
			if (!messageNoResp && !cmd.IsNoResp())
			{
				/* Multiple status */
				it=sourceRefs.find(statusCode);
				if (it==sourceRefs.end())
				{
					SctsSourceRefList *sourceRefList;
					if (status) outgoingMessage->InsertCommand(status,false);
					status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Replace",statusCode);
					++currentCmdID;
					sourceRefList=new SctsSourceRefList(SctsPcdata(source));
					sourceRefs[statusCode]=sourceRefList;
					status->SetSourceRefList(sourceRefList);
				}
				else
				{
					it->second->SetNextData(SctsPcdata(source));
				}
			}
			
			/* UI callback */
			if (uiCallback)
			{
				cmd.status=statusCode;
				(*uiCallback)(uiCallbackData,&cmd,itemCnt,false);
			}
		}
		break;
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		if (!sourceRefs.size())
		{
			status=new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Replace",statusCode);
			outgoingMessage->InsertCommand(status,false);
			++currentCmdID;
		}
		else
		{
			if (sourceRefs.size()==1) 
				/* TargetRef/SourceRef discrepancy */if (itemCnt>1) status->SetSourceRefList(0);
			if (status) outgoingMessage->InsertCommand(status,false);
		}
	}
	
	/* Close error log node and clean up*/
	SctsErrorLog::CloseNode();

}


/************************************************************************************
	The following handlers just return an error as these commands MUST NOT be sent by
	the DM Client.
************************************************************************************/

void SctsDMServerSession::HandleStartSync(SctsSync& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;
	ProcessStackCmd *parent;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.15) : Sync Element is not used in SyncML Device Management protocol.");
		break;
	}
	/* Push command onto process stack */
	parent=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
	parent->type=SCTS_SYNC_START;
	parent->status=statusCode;
	processStack.push(parent);
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();	
}
void SctsDMServerSession::HandleEndSync()
{
	ProcessStackCmd *parent=processStack.top();
	/* Check if parent is <Sync> */
	if (parent->type!=SCTS_SYNC_START)
	{
		char errorMsg[100];
		SctsErrorLog::OpenNode("End Sync",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_SYNC_END,false);
		processStack.pop();
		sctsFree(parent);
	} 
}

void SctsDMServerSession::HandleAdd(SctsAdd& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'ADD' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleDelete(SctsDelete& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'Delete' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleGet(SctsGet& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'GET' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleCopy(SctsCopy& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'COPY' from the client. SyncML DM ConReqs V1.1.2(5.4) : Protocol command elements");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}
			
void SctsDMServerSession::HandleExec(SctsExec& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'Exec' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
	
}

void SctsDMServerSession::HandleSearch(SctsSearch& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.13) : Search Element is not used in SyncML Device Management protocol.");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleMap(SctsMap& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.13) : Search Element is not used in SyncML Device Management protocol.");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp)
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandlePut(SctsPut& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
			SctsErrorLog::AppendError("SyncML DM Representation protocol V1.1.2 (6.5.10) : Put Element is not used in SyncML Device Management protocol.");
		break;
	}
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}
		
void SctsDMServerSession::HandleStartAtomic(SctsAtomic& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;
	ProcessStackCmd *parent;	

	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'Atomic' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* Push command onto process stack */
	parent=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
	parent->type=SCTS_ATOMIC_START;
	parent->status=statusCode;
	processStack.push(parent);
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::HandleEndAtomic()
{
	ProcessStackCmd *parent=processStack.top();
	/* 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
	{
		/* UI callback */
		if (uiCallback)	(*uiCallback)(uiCallbackData,0,SCTS_ATOMIC_END,false);
		processStack.pop();
		sctsFree(parent);
	}
}

void SctsDMServerSession::HandleStartSequence(SctsSequence& cmd)
{
	int statusCode=500;
	SctsPcdata tempPcdata;
	ProcessStackCmd *parent;
	/* 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 and whether there is a currentDB*/
		if (sentSyncHdrStatus==407 || sentSyncHdrStatus==401)
		{
			statusCode=sentSyncHdrStatus;
			break;
		}
		statusCode=501;
		SctsErrorLog::AppendError("Server does not expect a 'Sequence' from the client. SyncML DM ConReqs V1.1.2 (5.4) : Protocol command elements");
		break;
	}
	/* Push command onto process stack */
	parent=(ProcessStackCmd *)sctsMalloc(sizeof(ProcessStackCmd));
	parent->type=SCTS_SEQUENCE_START;
	parent->status=statusCode;
	processStack.push(parent);
	/* UI callback */
	if (uiCallback)
	{
		cmd.status=statusCode;
		(*uiCallback)(uiCallbackData,&cmd,0,false);
	}
	if (!messageNoResp && !cmd.IsNoResp())
	{
		outgoingMessage->InsertCommand(new SctsStatus(currentCmdID,processMsgID,(char *)cmd.GetCommandID(tempPcdata),"Search",statusCode),false);
		++currentCmdID;
	}
	SctsErrorLog::CloseNode();
}

void SctsDMServerSession::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);
	} 
}

