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

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 "SctsDevManDevice.h"
#include "SctsDevManSession.h"
#include "SctsDevManDMAccount.h"

/******************************************************************
SctsDMDevice
******************************************************************/

std::map <std::string,SctsDMServerDevice *> SctsDMDevice::serverDevices;
std::map <std::string,SctsDMClientDevice *> SctsDMDevice::clientDevices;


char *SctsDMDevice::GetUserID()
{
	SctsDMNode *user;
	if (!accountNode) SCTSASSERT(false);
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
    //MDAccType::iterator it = accounts.begin();
	//for (;it != accounts.end(); ++it)
	//{
    //    MulDynAccItem acc = it->second;
	//}

    std::string userPath = accounts[(char *)accountNode->name].subAppAuthClient;
    userPath += "/AAuthName";
    user=((SctsDMTree *)this)->FindDMNode((char *)userPath.c_str(),accountNode);
	SCTSASSERT(user);
	return sctsStrdup((char *)user->data);
}

char *SctsDMDevice::GetPassword(bool in)
{
	SctsDMNode *pwd;
	if (!accountNode) SCTSASSERT(false);
	IsServerDevice()?in=!in:0;
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
	if (in)
    {
        std::string serverPwd = accounts[(char *)accountNode->name].subAppAuthServer;
        serverPwd += "/AAuthSecret";
        pwd=((SctsDMTree *)this)->FindDMNode((char *)serverPwd.c_str(),accountNode);
    }
	else
    {
        std::string clientPwd = accounts[(char *)accountNode->name].subAppAuthClient;
        clientPwd += "/AAuthSecret";
        pwd=((SctsDMTree *)this)->FindDMNode((char *)clientPwd.c_str(),accountNode);
    }
	SCTSASSERT(pwd);
	if (pwd->data && pwd->size)
		return (char *)pwd->data;
	else
		return 0;
}

unsigned char *SctsDMDevice::GetNonce(bool in,unsigned int& size)
{
	SctsDMNode *nonce;
	if (!accountNode) SCTSASSERT(false);
	IsServerDevice()?in=!in:0;
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
	if (in)
    {
        std::string serverNonce = accounts[(char *)accountNode->name].subAppAuthServer;
        serverNonce += "/AAuthData";
        nonce=((SctsDMTree *)this)->FindDMNode((char *)serverNonce.c_str(),accountNode);
    }
	else
    {
        std::string clientNonce = accounts[(char *)accountNode->name].subAppAuthClient;
        clientNonce += "/AAuthData";
        nonce=((SctsDMTree *)this)->FindDMNode((char *)clientNonce.c_str(),accountNode);
    }
	SCTSASSERT(nonce);
	size=nonce->size;
	return (unsigned char *)nonce->data;
}

void SctsDMDevice::SetUserID(char *userID)
{
	SctsDMNode *user;
	SCTSASSERT(userID);
	if (!accountNode) SCTSASSERT(false);
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
    std::string userPath = accounts[(char *)accountNode->name].subAppAuthClient;
    userPath += "/AAuthName";
    user=((SctsDMTree *)this)->FindDMNode((char *)userPath.c_str(),accountNode);
	SCTSASSERT(user);
	if (user->data)
	{
		sctsFree(user->data);
		user->size=0;
	}
	user->data=sctsStrdup(userID);
	user->size=sctsStrlen(userID);
}

void SctsDMDevice::SetPassword(bool in,char *password)
{
	SctsDMNode *pwd;
	if (!accountNode) SCTSASSERT(false);
	IsServerDevice()?in=!in:0;
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
	if (in)
    {
        std::string serverPwd = accounts[(char *)accountNode->name].subAppAuthServer;
        serverPwd += "/AAuthSecret";
        pwd=((SctsDMTree *)this)->FindDMNode((char *)serverPwd.c_str(),accountNode);
    }
	else
    {
        std::string clientPwd = accounts[(char *)accountNode->name].subAppAuthClient;
        clientPwd += "/AAuthSecret";
        pwd=((SctsDMTree *)this)->FindDMNode((char *)clientPwd.c_str(),accountNode);
    }
	SCTSASSERT(pwd);
	if (pwd->data)
	{
		sctsFree(pwd->data);
		pwd->size=0;
	}
	if (!password) return;
	pwd->data=sctsStrdup(password);
	pwd->size=sctsStrlen(password);
}

void SctsDMDevice::SetNonce(bool in,unsigned char *_nonce,unsigned int size)
{
	SctsDMNode *nonce;
	if (!accountNode) SCTSASSERT(false);
	IsServerDevice()?in=!in:0;
    /*
     * Change to support DM 1.2 DMAcc node. 
     */
	if (in)
    {
        std::string serverNonce = accounts[(char *)accountNode->name].subAppAuthServer;
        serverNonce += "/AAuthData";
        nonce=((SctsDMTree *)this)->FindDMNode((char *)serverNonce.c_str(),accountNode);
    }
	else
    {
        std::string clientNonce = accounts[(char *)accountNode->name].subAppAuthClient;
        clientNonce += "/AAuthData";
        nonce=((SctsDMTree *)this)->FindDMNode((char *)clientNonce.c_str(),accountNode);
    }
	SCTSASSERT(nonce);
	if (nonce->data)
	{
		sctsFree(nonce->data);
		nonce->data=0;
		nonce->size=0;
	}
	if (!_nonce || !size) return;
	nonce->data=sctsMalloc(size);
	sctsMemcpy(nonce->data,_nonce,size);
	nonce->size=size;
}


SctsDMServerDevice *SctsDMDevice::GetServerDevice(char *userID)
{
	std::map <std::string,SctsDMServerDevice *>::iterator devicesIt;
	sctsStatusLog("Finding server device (");
	sctsStatusLog(userID);
	sctsStatusLog(")...\r\n");
	if ((devicesIt=serverDevices.find(userID))==serverDevices.end())
	{
		sctsStatusLog("Not found...\r\n");
		return 0;
	}
	return devicesIt->second;
}

SctsDMClientDevice *SctsDMDevice::GetClientDevice(char *devID)
{
	std::map <std::string,SctsDMClientDevice *>::iterator devicesIt;
	sctsStatusLog("Finding client device (");
	sctsStatusLog(devID);
	sctsStatusLog(")...\r\n");
	if ((devicesIt=clientDevices.find(devID))==clientDevices.end())
	{
		sctsStatusLog("Not found...\r\n");
		return 0;
	}
	return devicesIt->second;
}

void SctsDMDevice::RemoveDevice(SctsDMDevice *device)
{
	if (device->IsServerDevice())
		serverDevices.erase(serverDevices.find(((SctsDMServerDevice *)device)->userID));
	else
		clientDevices.erase(clientDevices.find(((SctsDMClientDevice *)device)->devID));
	delete device;
}

SctsDMServerDevice *SctsDMDevice::AddServerDevice(char *serverID,char *dmAccPath,char *userID,char *name,char *contact,char *company)
{
	SctsDMServerDevice *newdevice;
	std::map <std::string,SctsDMServerDevice *>::iterator devicesIt;
	sctsStatusLog("Adding server device (");
	sctsStatusLog(userID);
	sctsStatusLog(")...\r\n");
	if ((devicesIt=serverDevices.find(userID))!=serverDevices.end())
	{
		sctsStatusLog("Already exists...\r\n");
		return 0;
	}
	newdevice=new SctsDMServerDevice(serverID,dmAccPath,userID,name,contact,company);
	serverDevices[userID]=newdevice;
	return newdevice;
}

SctsDMClientDevice *SctsDMDevice::AddClientDevice(char *devID,char *dmACCPath,long maxObjSize,SctsEncoding encoding,char *name,char *contact,char *company)
{
	SctsDMClientDevice *newdevice=new SctsDMClientDevice(devID,dmACCPath,maxObjSize,encoding,name,contact,company);
	clientDevices[devID]=newdevice;
	return newdevice;
}
void SctsDMDevice::RemoveAll()
{
	std::map <std::string,SctsDMServerDevice *>::iterator sit;
	std::map <std::string,SctsDMClientDevice *>::iterator cit;
	while ((sit=serverDevices.begin())!=serverDevices.end())
	{
		sit->second->Lock();
		delete (SctsDMDevice *)sit->second;
		serverDevices.erase(sit);
	}
	while ((cit=clientDevices.begin())!=clientDevices.end())
	{
		cit->second->Lock();
		delete (SctsDMDevice *)cit->second;
		clientDevices.erase(cit);
	}
}

void SctsDMDevice::SaveAll(FILE *fp)
{
	std::map <std::string,SctsDMServerDevice *>::iterator sit;
	std::map <std::string,SctsDMClientDevice *>::iterator cit;
	for (sit=serverDevices.begin();sit!=serverDevices.end();sit++) 
	{
		fputc(1,fp);
		sit->second->Save(fp);
	}
	fputc(0,fp);
	for (cit=clientDevices.begin();cit!=clientDevices.end();cit++) 
	{
		fputc(1,fp);
		cit->second->Save(fp);
	}
	fputc(0,fp);
}

void SctsDMDevice::LoadAll(FILE *fp)
{
	SctsDMServerDevice *sDevice;
	SctsDMClientDevice *cDevice;
	while (fgetc(fp))
	{
		sDevice=new SctsDMServerDevice(fp);
		serverDevices[sDevice->userID]=sDevice;
	}
	while (fgetc(fp))
	{
		cDevice=new SctsDMClientDevice(fp);
		clientDevices[cDevice->devID]=cDevice;		
	}	
}

void SctsDMDevice::Save(FILE *fp)
{
	sctsFWriteString(serverID,fp);
	sctsFWriteString(dmAccPath,fp);
	sctsFWriteString(productName,fp);
	sctsFWriteString(productContact,fp);
	sctsFWriteString(productCompany,fp);

    int size = accounts.size();
    fwrite(&size,sizeof(int),1,fp);
    for (MDAccType::iterator it = accounts.begin(); it != accounts.end(); ++it)
    {
        sctsFWriteString((char *)(it->first.c_str()),fp);
        sctsFWriteString((char *)(it->second.accName.c_str()),fp);
        sctsFWriteString((char *)(it->second.accPath.c_str()),fp);
        sctsFWriteString((char *)(it->second.subAppAddr.c_str()),fp);
        sctsFWriteString((char *)(it->second.subPort.c_str()),fp);
        sctsFWriteString((char *)(it->second.subAppAuthClient.c_str()),fp);
        sctsFWriteString((char *)(it->second.subAppAuthServer.c_str()),fp);
        sctsFWriteString((char *)(it->second.subToConRef.c_str()),fp);
    }

	tester->Save(fp);
}

SctsDMDevice::SctsDMDevice(FILE *fp)
{
	serverID=sctsFReadString(fp);
    dmAccPath=sctsFReadString(fp);
	productName=sctsFReadString(fp);
	productContact=sctsFReadString(fp);
	productCompany=sctsFReadString(fp);

    int size = 0;
    fread(&size,sizeof(int),1,fp);
    char *accName = 0;
    char *tmpStr = 0;
    MulDynAccItem dynAcc;
    for (int i = 0; i < size; ++i)
    {
        accName = sctsFReadString(fp);
        tmpStr = sctsFReadString(fp);
        dynAcc.accName = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.accPath = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.subAppAddr = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.subPort = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.subAppAuthClient = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.subAppAuthServer = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        tmpStr = sctsFReadString(fp);
        dynAcc.subToConRef = tmpStr?tmpStr:"";
        sctsFree(tmpStr);
        accounts[accName] = dynAcc;
        sctsFree(accName);
    }

	sessionType=DMSESSION_NORMAL;
	tester=new SctsDMTester(fp);
	tester->device=this;
	accountNode=0;
	uiData=0;
}

SctsDMDevice::SctsDMDevice(char *name,char *contact,char *company) 
{
	serverID=0;
    dmAccPath=0;
	if (name)
		productName=sctsStrdup(name);
	else
		productName=0;
	if (contact)
		productContact=sctsStrdup(contact);
	else
		productContact=0;
	if (company)
		productCompany=sctsStrdup(company);
	else
		productCompany=0;
	sessionType=DMSESSION_NORMAL;
	accountNode=0;
	uiData=0;
}

SctsDMDevice::~SctsDMDevice()
{
	if (serverID) sctsFree(serverID);
	if (dmAccPath) sctsFree(dmAccPath);
	if (productCompany) sctsFree(productCompany);
	if (productContact) sctsFree(productContact);
	if (productName) sctsFree(productName);
	if (tester) delete tester;
}

/******************************************************************
SctsDMServerDevice
******************************************************************/

void SctsDMServerDevice::SetAuthType(bool in,SctsAuthType authType) 
{
	if (in) 
		inAuthType=authType; 
	else 
		outAuthType=authType;
}

SctsAuthType SctsDMServerDevice::GetAuthType(bool in) 
{
	return in?inAuthType:outAuthType;
}

void SctsDMServerDevice::Save(FILE *fp)
{
	SctsDMDevice::Save(fp);
	sctsFWriteString(userID,fp);
	SctsDMServerTree::Save(fp);
	fwrite(&inAuthType,sizeof(SctsAuthType),1,fp);
	fwrite(&outAuthType,sizeof(SctsAuthType),1,fp);
}

SctsDMServerDevice::SctsDMServerDevice(FILE *fp)
: SctsDMDevice(fp)
{
	userID=sctsFReadString(fp);
	if (componentUIC.addServerDevice) (*componentUIC.addServerDevice)(this);
	SctsDMServerTree::Load(fp);
	fread(&inAuthType,sizeof(SctsAuthType),1,fp);
	fread(&outAuthType,sizeof(SctsAuthType),1,fp);
}

SctsDMServerDevice::SctsDMServerDevice(char *_serverID,char *_dmAccPath,char *_userID,char *name,char *contact,char *company)	
: SctsDMDevice(name,contact,company), SctsDMServerTree()
{
	char tempBuf[300];
	/* Initialization */
	serverID=sctsStrdup(_serverID);
    dmAccPath=sctsStrdup(_dmAccPath);
	userID=sctsStrdup(_userID);
	tester=new SctsDMTester(this);
	if (componentUIC.addServerDevice) (*componentUIC.addServerDevice)(this);
	
	/* Create the tree with permanent nodes */
	/* Build ./DevInf */
	sprintf(tempBuf,"./DevInfo");
	this->AddDMNode(tempBuf,SIDX,"node",true,0,0,0,0,0);
	
	sprintf(tempBuf,"./DevInfo/DevId");
	this->AddDMNode(tempBuf,SIDX,"chr",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevInfo/Man");
	this->AddDMNode(tempBuf,SIDX,"chr",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevInfo/Mod");
	this->AddDMNode(tempBuf,SIDX,"chr",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevInfo/DmV");
	this->AddDMNode(tempBuf,SIDX,"chr",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevInfo/Lang");
	this->AddDMNode(tempBuf,SIDX,"chr",true,0,0,0,0,0);

	/* Build ./DevDetail */
	inAuthType=AUTH_NONE;
	outAuthType=AUTH_NONE;
}

SctsDMServerDevice::~SctsDMServerDevice()
{
	if (componentUIC.removeServerDevice) (*componentUIC.removeServerDevice)(this);
}

/******************************************************************
SctsDMClientDevice
******************************************************************/
SctsMutex SctsDMClientDevice::notificationMutex;
SctsDMClientDevice *SctsDMClientDevice::notificationDevice=0;
void (*SctsDMClientDevice::notificationCallback)(SctsDMSession *)=0;

void SctsDMClientDevice::SetAuthType(bool in,SctsAuthType authType)
{
	if (!accountNode) return;
	if (in)
		inAuthTypes[accountNode->name]=authType;
	else
		outAuthTypes[accountNode->name]=authType;
}

SctsAuthType SctsDMClientDevice::GetAuthType(bool in)
{
	std::map<std::string,SctsAuthType>::iterator it;
	if (!accountNode) return AUTH_NONE;
	if (in && (it=inAuthTypes.find(accountNode->name))==inAuthTypes.end()) return AUTH_NONE;
	if (!in && (it=outAuthTypes.find(accountNode->name))==outAuthTypes.end()) return AUTH_NONE;
	return it->second;
}

void SctsDMClientDevice::Save(FILE *fp)
{
	std::map<std::string,SctsAuthType>::iterator it;
	SctsDMNode *node;
	SctsDMDevice::Save(fp);
	sctsFWriteString(devID,fp);
	fwrite(&lastSessionID,sizeof(unsigned int),1,fp);
	fwrite(&encoding,sizeof(SctsEncoding),1,fp);
	fwrite(&proto,sizeof(SctsSyncMLProto),1,fp);
	fwrite(&maxMsgSize,sizeof(long),1,fp);
	fwrite(&maxObjSize,sizeof(long),1,fp);
	SctsDMTree::Save(fp);
	/* Persist only valid authentication information */
	node=FindDMNode(dmAccPath);
	for (it=inAuthTypes.begin();it!=inAuthTypes.end();++it)
	{
		if (!FindDMNode((char *)it->first.c_str(),node)) continue;
		fputc(1,fp);
		sctsFWriteString(it->first.c_str(),fp);
		fwrite(&it->second,sizeof(SctsAuthType),1,fp);
	}
	fputc(0,fp);
	for (it=outAuthTypes.begin();it!=outAuthTypes.end();++it)
	{
		if (!FindDMNode((char *)it->first.c_str(),node)) continue;
		fputc(1,fp);
		sctsFWriteString(it->first.c_str(),fp);
		fwrite(&it->second,sizeof(SctsAuthType),1,fp);
	}
	fputc(0,fp);
}

SctsDMClientDevice::SctsDMClientDevice(FILE *fp)
: SctsDMDevice(fp)
{
	char *name;
	SctsAuthType authType;
	devID=sctsFReadString(fp);
	fread(&lastSessionID,sizeof(unsigned int),1,fp);
	fread(&encoding,sizeof(SctsEncoding),1,fp);
	fread(&proto,sizeof(SctsSyncMLProto),1,fp);
	fread(&maxMsgSize,sizeof(long),1,fp);
	fread(&maxObjSize,sizeof(long),1,fp);
	if (componentUIC.addClientDevice) (*componentUIC.addClientDevice)(this);
	SctsDMTree::Load(fp);
	while (fgetc(fp))
	{
		name=sctsFReadString(fp);
		fread(&authType,sizeof(SctsAuthType),1,fp);
		inAuthTypes[name]=authType;
		sctsFree(name);
	}
	while (fgetc(fp))
	{
		name=sctsFReadString(fp);
		fread(&authType,sizeof(SctsAuthType),1,fp);
		outAuthTypes[name]=authType;
		sctsFree(name);
	}

    //MDAccType::iterator it = accounts.begin();
	//for (;it != accounts.end(); ++it)
	//{
    //    MulDynAccItem acc = it->second;
	//}
}

SctsDMClientDevice::SctsDMClientDevice(char *_devID,char *_dmACCPath,long _maxObjSize,SctsEncoding _encoding,char *name,char *contact,char *company)
: SctsDMDevice(name,contact,company)
{
	char tempBuf[300];
	SCTSASSERT(_devID);
	SctsDMNode *tempNode=0;
	/* Inititialization */
	devID=sctsStrdup(_devID);
    dmAccPath=sctsStrdup(_dmACCPath);
	maxMsgSize=MAX_WORKSPACE_SIZE/2;
	maxObjSize=_maxObjSize;
	lastSessionID=0;
	encoding=_encoding;
	proto=SYNCML_DM_1_2;
	sessionType=DMSESSION_NORMAL;
	tester=new SctsDMTester(this);
	
	if (componentUIC.addClientDevice) (*componentUIC.addClientDevice)(this);

	/* Create the tree with permanent nodes */

    /* Build DMAcc for DM1.2 */
	if (dmAccPath && sctsStrcmp(dmAccPath, "."))
	{
	    this->AddFullDMNode(dmAccPath,SIDX,"node",true,0,0,0,&tempNode,0);
		if (tempNode)
		{
			tempNode->acl=sctsStrdup("Get=*");
			tempNode=0;
		}
	}
	sprintf(tempBuf,"%s/Con",dmAccPath);
	this->AddFullDMNode(tempBuf,SIDX,"node",true,0,0,0,&tempNode,0);
	if (tempNode)
	{
		tempNode->acl=sctsStrdup("Get=*");
		tempNode=0;
	}

	/* Build ./DevInf */
	sprintf(tempBuf,"./DevInfo");
	this->AddDMNode(tempBuf,SIDX,"node",true,0,0,0,&tempNode,0);
	if (tempNode)
	{
		tempNode->acl=sctsStrdup("Get=*");
		tempNode=0;
	}

	sprintf(tempBuf,"./DevInfo/DevId");
	this->AddDMNode(tempBuf,SIDX,"chr",true,devID,0,sctsStrlen(devID),0,0);

	sprintf(tempBuf,"./DevInfo/Man");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"SyncML",0,6,0,0);

	sprintf(tempBuf,"./DevInfo/Mod");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"scts devman",0,11,0,0);

	sprintf(tempBuf,"./DevInfo/DmV");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"4.0",0,3,0,0);

	sprintf(tempBuf,"./DevInfo/Lang");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"en-us",0,5,0,0);

	/* Build ./DevDetail */
	sprintf(tempBuf,"./DevDetail");
	this->AddDMNode(tempBuf,SIDX,"node",true,0,0,0,&tempNode,0);
	if (tempNode)
	{
		tempNode->acl=sctsStrdup("Get=*");
		tempNode=0;
	}

	sprintf(tempBuf,"./DevDetail/Bearer");
	this->AddDMNode(tempBuf,SIDX,"node",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevDetail/URI");
	this->AddDMNode(tempBuf,SIDX,"node",true,0,0,0,0,0);

	sprintf(tempBuf,"./DevDetail/URI/MaxDepth");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"0",0,1,0,0);

	sprintf(tempBuf,"./DevDetail/URI/MaxTotLen");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"0",0,1,0,0);

	sprintf(tempBuf,"./DevDetail/URI/MaxSegLen");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"0",0,1,0,0);

	sprintf(tempBuf,"./DevDetail/DevTyp");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"Windows workstation",0,19,0,0);

	sprintf(tempBuf,"./DevDetail/OEM");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"SyncML Initiative",0,17,0,0);

	sprintf(tempBuf,"./DevDetail/FwV");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"1.0",0,3,0,0);
	
	sprintf(tempBuf,"./DevDetail/SwV");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"4.0",0,3,0,0);

	sprintf(tempBuf,"./DevDetail/HwV");
	this->AddDMNode(tempBuf,SIDX,"chr",true,"intel",0,5,0,0);

	sprintf(tempBuf,"./DevDetail/LrgObj");
	this->AddDMNode(tempBuf,SIDX,"bool",true,"false",0,5,0,0);
}	

/*
 * Change to support TNDS. 
 */
int SctsDMClientDevice::ReplaceDMNodePropTNDS(SctsDMNode *node,char *serverID,SctsDMNodeProp prop,char *propVal,SctsDMCommand **command)
{
    char errorMsg[500]="";
    if (command) *command=0;
    if (!node) return 404;
    if (prop==DMPROP_ACL)
    {
        char *_propVal=0;
        if (propVal && *propVal)
        {
            char *t,*t1;
            _propVal=sctsStrdup(propVal);
            t1=_propVal;
            while (t=sctsStrstr(t1,"&amp;"))
            {
                *(t+1)=0;
                t+=5;
                sctsStrcpy(_propVal,t1);
                sctsStrcat(_propVal,t);
                t1=_propVal;
            }
        }
        if (!node->VerifyACLSyntax(_propVal))
        {
            sprintf(errorMsg,"%s is invalid ACL. The ACL should follow the syntax as specified in SyncML DM T&D V1.1.1 (6.7.1.5).",propVal);
            SctsErrorLog::AppendError(errorMsg);
            return 500;
        }
        if ((node->format!=DMFORMAT_NODE || !node->VerifyACL(serverID,SCTS_REPLACE)) && node->parent && !node->parent->VerifyACL(serverID,SCTS_REPLACE)) return 425;
        if (command) *command=new SctsDMCommand(SCTS_REPLACE,node,prop,true);
        if (node->acl) sctsFree(node->acl);
        node->acl=0;
        if (_propVal && sctsStrlen(_propVal)>1) node->acl=sctsStrdup(_propVal);
        if (_propVal) sctsFree(_propVal);
        if (node->timeStamp) sctsFree(node->timeStamp);
        node->timeStamp=sctsGetTimeStamp(true);
        if (++node->version==0) ++node->version;
    }
    if (prop==DMPROP_TITLE)
    {
        if (!node->VerifyACL(serverID,SCTS_REPLACE)) return 425;
        if (command) *command=new SctsDMCommand(SCTS_REPLACE,node,prop,true);
        if (node->title) sctsFree(node->title);
        node->title=0;
        if (propVal && sctsStrlen(propVal)>1) node->title=sctsStrdup(propVal);
    }
    if (prop==DMPROP_VERSION)
    {
        if (!node->VerifyACL(serverID,SCTS_REPLACE)) return 425;
        if (command) *command=new SctsDMCommand(SCTS_REPLACE,node,prop,true);
        node->version=0;
        if (propVal && sctsStrlen(propVal)>1) node->version=atoi(propVal);
    }
    if (prop==DMPROP_TIMESTAMP)
    {
        if (!node->VerifyACL(serverID,SCTS_REPLACE)) return 425;
        if (command) *command=new SctsDMCommand(SCTS_REPLACE,node,prop,true);
        if (node->timeStamp) sctsFree(node->timeStamp);
        node->timeStamp=0;
        if (propVal && sctsStrlen(propVal)>1) node->timeStamp=sctsStrdup(propVal);
    }
    if (uiCallback) (*uiCallback)(this,node,SCTS_REPLACE);
    return 200;
}

SctsDMClientDevice::~SctsDMClientDevice()
{
	if (componentUIC.removeClientDevice) (*componentUIC.removeClientDevice)(this);
	sctsFree(devID);
}