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

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 "SctsTransport.h"
#include "SctsAuth.h"
#include "SctsDevManSession.h"
#include "SctsLog.h"
#ifdef __SCTS_USING_SCTS__
#include "SctsDevManTestEngine.h"
#endif
#include "SctsDevManDevice.h"
#include "SctsDevManT&D.h"

/* Global session timeout */
long sctsSessionTimeout=60000;

/*****************************************************************
Error logging functions
******************************************************************/
extern "C" void sctsTransportLogError(char *error)
{
	sctsStatusLog(error);
	sctsStatusLog("\r\n");
	SctsErrorLog::AppendError(error);
}
typedef int Bool_t;
extern "C" Bool_t httpGetActiveAddress(XptCommunicationID_t id,char **pchIP);

/*****************************************************************
Raw data logging functions
******************************************************************/
extern "C" void sctsTransportLogData(char *data,long size,char sent)
{
	char buffer[300];
	char hex[17]="0123456789ABCDEF";
	char *dataPos=buffer+8;
	char *bytePos=buffer+26;
	unsigned char byte;
	long pos=0;
	sprintf(buffer,"%s data chunk (%ld bytes)...",sent?"Sent":"Received",size);
	sctsStatusLog(buffer);
	sctsMemset(buffer,' ',sizeof(char)*300);
	sctsStrcpy(buffer,"\r\n0000  ");
	while (pos<size)
	{
		byte=*data;
		if (byte>31 && byte<127)
			*dataPos=byte;
		else
			*dataPos='.';
		*bytePos++=hex[byte>>4];
		*bytePos++=hex[byte&0xF];
		*bytePos++=' ';
		++pos;
		++dataPos;
		++data;
		if (!(pos&15))
		{
			*bytePos=0;
			sctsStatusLog(buffer);
			sctsMemset(buffer,' ',sizeof(char)*300);
			sprintf(buffer,"\r\n%04X  ",pos-16);
			dataPos=buffer+8;
			bytePos=buffer+26;
		}
	}
	if (pos&15)
	{
		*bytePos=0;
		sctsStatusLog(buffer);
	}
	sctsStatusLog("\r\n");
}

/*****************************************************************
Http header logging functions
******************************************************************/
static std::map <int,char *> httpHeaders;
static SctsMutex httpHeadersLock;
extern "C" void sctsSetHttpHeader(char *httpHeader,long httpHeaderSize)
{
	int threadID=SctsThread::GetID();
	std::map <int,char *>::iterator it;
	char *_httpHeader=0;
	long _httpHeaderSize=0;
	httpHeadersLock.Lock();
	if ((it=httpHeaders.find(threadID))!=httpHeaders.end())
	{
		_httpHeader=it->second;
		_httpHeaderSize=sctsStrlen(_httpHeader);
	}
	_httpHeader=(char *)sctsRealloc(_httpHeader,_httpHeaderSize+httpHeaderSize+1);
	sctsMemcpy(_httpHeader+_httpHeaderSize,httpHeader,httpHeaderSize);
	_httpHeader[_httpHeaderSize+httpHeaderSize]=0;
	httpHeaders[threadID]=_httpHeader;
	httpHeadersLock.Unlock();
}

static char *sctsGetHttpHeader()
{
	char *httpHeader=0;
	std::map <int,char *>::iterator it;
	httpHeadersLock.Lock();
	if ((it=httpHeaders.find(SctsThread::GetID()))!=httpHeaders.end())
	{
		httpHeader=it->second;
		httpHeaders.erase(it);
	}
	httpHeadersLock.Unlock();
	return httpHeader;
}

/*****************************************************************
SctsTransportServer Definition
******************************************************************/
void *SctsTransportServer::uiCallbackData=0;
void (*SctsTransportServer::uiCallback)(void *,SctsTransportServer *,SctsTransportServerState)=0;

void SctsTransportServer::SetTerminate(bool _terminate)
{
	SetState(SERVER_STOPPING);
	SctsThread::SetTerminate(_terminate);
}

SctsTransportServer::SctsTransportServer() : SctsThread(SERVER_THREAD)
{
}

SctsTransportServer::~SctsTransportServer()
{
	if (state==SERVER_STOPPING) SetState(SERVER_STOPPED);
}

void SctsTransportServer::SetUICallback(void *_uiCallbackData,void (*_uiCallback)(void *,SctsTransportServer *,SctsTransportServerState))
{
	uiCallbackData=_uiCallbackData;
	uiCallback=_uiCallback;
}

void SctsTransportServer::SetState(SctsTransportServerState _state)
{
	state=_state;
	if (uiCallback) (*uiCallback)(uiCallbackData,this,state);
}

/*****************************************************************
Function	: Adds a server transport to a SctsTransportServer's
			  list of transports
In			: SctsServerTransport *
			  The server transport to be added to the list
*****************************************************************/

void SctsTransportServer::AddServerTransport(SctsServerTransport *transport)
{
	sctsStatusLog("Adding server transport...\r\n");
	SCTSASSERT(transport);
	serverTransportsLock.Lock();
	serverTransports.insert(transport);
	serverTransportsLock.Unlock();
}

/*****************************************************************
Function	: Removes a server transport from a SctsTransportServer's
			  list of transports
In			: SctsServerTransport *
			  The server transport to be removed
*****************************************************************/

void SctsTransportServer::RemoveServerTransport(SctsServerTransport *transport)
{
	sctsStatusLog("Removing server transport...\r\n");
	SCTSASSERT(transport);
	serverTransportsLock.Lock();
	serverTransports.erase(transport);
	serverTransportsLock.Unlock();
}



/******************************************************************
RTK Transport classes
******************************************************************/
#ifdef __SCTS_USING_RTK__

static bool sctsRTKError(int error)
{
	if (error!=SML_ERR_OK)
	{
        char * errMsgToken = sctsStrdup(sctsGetRTKError(error));
        char *it1 = errMsgToken;
        char *it2 = 0;

        while ((it2 = sctsStrstr(it1, "\n")) != 0)
        {
            *it2 = '\0';
            SctsErrorLog::AppendError(it1);
		    sctsStatusLog(it1);
		    sctsStatusLog("\r\n");
            it1 = it2 + 1;
        }
        if (*it1 != '\0')
        {
            SctsErrorLog::AppendError(it1);
		    sctsStatusLog(it1);
		    sctsStatusLog("\r\n");
        }
		sctsStatusLog("...\r\n");
        sctsFree(errMsgToken);
        SctsErrorLog::AppendError("Toolkit error : ");
        sctsClearRTKError();
		return false;
	}
	return  true;
}

/******************************************************************
SctsHttpClientTransport Definition
******************************************************************/

/******************************************************************
Function	: Constructor
In			: char *_mimeType
			  The mime type to be used
			  SctsURI *_serverAddr
			  The servers address as an absolute URI
			  char *_proxyAddr
			  The proxy servers address
******************************************************************/

SctsHttpClientTransport::SctsHttpClientTransport(SctsURI *_serverAddr,char *_proxyAddr) 
		: xptServiceID(0),xptProtocolID(0),xptCommID(0),lastHttpHeader(0)
{
    /*
     * Change to support HTTPS. 
     */
    memset(&xptDocInfo,0,sizeof(XptCommunicationInfo_t));
	const XptProtocolInfo* xptInfo;
	char xptMeta[MAX_URI_SIZE+100]="HOST=";
	sctsStatusLog("Creating HTTP client transport...\r\n");
	SCTSASSERT(_serverAddr);
	SCTSASSERT(_serverAddr->scheme && _serverAddr->authority && _serverAddr->IsAbsPath());
	SCTSASSERT(xptGetProtocol("HTTP",&xptInfo)==SML_ERR_OK);
	xptProtocolID=xptInfo->id;
	sctsStrcat(xptMeta,_serverAddr->authority+2);
	if (_proxyAddr)
	{
		sctsStrcat(xptMeta," PROXYHOST=");
		sctsStrcat(xptMeta,_proxyAddr);
	}
    if (!sctsStrcmp(_serverAddr->scheme, "https:"))
    {
		sctsStrcat(xptMeta," SSL=1");
    }
	SCTSASSERT(xptSelectProtocol(xptProtocolID,xptMeta,XPT_CLIENT,&xptServiceID)==SML_ERR_OK);
	SCTSASSERT((serverAddr=new SctsURI(*_serverAddr)));
	if (_proxyAddr)
		proxyAddr=sctsStrdup(_proxyAddr);
	else
		proxyAddr=0;
}

/*****************************************************************
Function	: Sets the response address of a client transport,
			  this will be the address used the next time a transport
			  sends a message.
In			: SctsURI *
			  The RespURI
Out			: bool
			  true - if the response address was set
			  false - if the response address is invalid
*****************************************************************/

bool SctsHttpClientTransport::SetRespAddr(SctsURI *respAddr)
{
	char xptMeta[MAX_URI_SIZE+50]="HOST=";
	SCTSASSERT(respAddr && xptServiceID && !xptCommID);
	if (!respAddr->scheme || !respAddr->authority || !respAddr->IsAbsPath()) return false;
	delete serverAddr;
	SCTSASSERT((serverAddr=new SctsURI(*respAddr)));
	xptDeselectProtocol(xptServiceID);
	xptServiceID=0;
	sctsStrcat(xptMeta,serverAddr->authority+2);
	if (proxyAddr)
	{
		sctsStrcat(xptMeta," PROXYHOST=");
		sctsStrcat(xptMeta,proxyAddr);
	}
    /*
     * Change to support HTTPS. 
     */
    if (!sctsStrcmp(serverAddr->scheme, "https:"))
    {
		sctsStrcat(xptMeta," SSL=1");
    }
	SCTSASSERT(xptSelectProtocol(xptProtocolID,xptMeta,XPT_CLIENT,&xptServiceID)==SML_ERR_OK);
	return true;
}

char *SctsHttpClientTransport::GetTransportHdr()
{
	return lastHttpHeader;
}

char *SctsHttpClientTransport::GetRespAddr()
{
	SCTSASSERT(serverAddr);
	return serverAddr->Build();
}

/*****************************************************************
Function	: Sends a message over the transport.
In			: char *
			  The source buffer which contains the message data.
In			: int
			  The length of the source buffer
Out			: bool
			  true - if the message was sent successfully
			  false - if the message failed to be sent
*****************************************************************/

bool SctsHttpClientTransport::SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo)
{
	unsigned int sentData=0;
	char *_serverAddr;
	sctsStatusLog("Connecting to ");
	SCTSASSERT(buffer && bufferLen && xptServiceID);
	SCTSASSERT(serverAddr && serverAddr->IsAbsPath());
	_serverAddr=serverAddr->Build();
	sctsStatusLog(_serverAddr);
	sctsStatusLog("...\r\n");
	sctsFree(_serverAddr);
	sentData=sctsStrlen(serverAddr->path);
	if (serverAddr->query) sentData+=sctsStrlen(serverAddr->query);
	SCTSASSERT(sentData<XPT_DOC_NAME_SIZE);
	if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_SENDER,&xptCommID))) return false;
	if (!sctsRTKError(xptBeginExchange(xptCommID))) return false;
	/* Construct XptCommunicationInfo structure */
	xptDocInfo.cbSize=sizeof(XptCommunicationInfo_t);
	xptDocInfo.cbLength=bufferLen;
	xptDocInfo.hmacInfo=macInfo;
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	sctsStrcpy(xptDocInfo.docName,serverAddr->path);
	if (serverAddr->query) sctsStrcat(xptDocInfo.docName,serverAddr->query);
	sctsStatusLog("Sending HTTP header...\r\n");
	if (!sctsRTKError(xptSetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	if (lastHttpHeader) sctsFree(lastHttpHeader);
	lastHttpHeader=sctsGetHttpHeader();
	if (!sctsRTKError(xptSendData(xptCommID,(const void *)buffer,bufferLen,&sentData))) return false;
	if (!sctsRTKError(xptSendComplete(xptCommID))) return false;
	SCTSASSERT(sentData==bufferLen);
	sctsStatusLog("Sent ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

/*****************************************************************
Function	: Receives a message over the transport
In			: char *
			  The target buffer
In/Out		: int&
			  In - the length of the target buffer
			  Out - the received message size (-1) if more data is
			  to be received
Out			: bool
			  true - if the message was received successfully
			  false - if the message failed to be received

Note		: The buffer and bufferLen should be atleast 1 byte larger
			  than the expected message
*****************************************************************/

bool SctsHttpClientTransport::RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo)
{
	unsigned int recvData;
	char *_buffer=buffer;
	sctsStatusLog("Receiving HTTP header...\r\n");
	SCTSASSERT(buffer && bufferLen && xptServiceID);
	if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	SetHmacInfo(xptDocInfo.hmacInfo);
	if (macInfo) *macInfo=&hmacInfo;
	if (lastHttpHeader) sctsFree(lastHttpHeader);
	lastHttpHeader=sctsGetHttpHeader();
	/* SyncFest : MIME type can have charset */
	if(!sctsStrstr(xptDocInfo.mimeType,mimeType))
	{
		char buffer[100];
		sctsStatusLog("Received invalid MIME type : ");
		sctsStatusLog(xptDocInfo.mimeType);
		sctsStatusLog("...\r\n");
		sprintf(buffer,"Received invalid MIME type : %s",xptDocInfo.mimeType);
		SctsErrorLog::AppendError(buffer);
		return false;
	}
	do
	{
		if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,&recvData))) return false;
		bufferLen-=recvData;
		_buffer+=recvData;
	}
	while (bufferLen && recvData);
	if (recvData)
		bufferLen=-1;
	else
		bufferLen=_buffer-buffer;
	sctsStatusLog("Received ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	sctsStatusLog("Closing connection...\r\n");
	if (!sctsRTKError(xptEndExchange(xptCommID))) return false;
	if (!sctsRTKError(xptCloseCommunication(xptCommID))) return false;
	xptCommID=0;
	return true;
}
		
SctsHttpClientTransport::~SctsHttpClientTransport()
{
	if (serverAddr) delete serverAddr;
	if (proxyAddr) sctsFree(proxyAddr);
	if (xptCommID) xptCloseCommunication(xptCommID);
	if (xptServiceID) xptDeselectProtocol(xptServiceID);
	if (lastHttpHeader) sctsFree(lastHttpHeader);
}


/******************************************************************
SctsHttpTransportServer Definition
******************************************************************/
int xptClose;

int SctsHttpTransportServer::Init()
{
	const XptProtocolInfo* xptInfo;
	char xptMeta[30]="SERVERPORT=";
	if (xptGetProtocol("HTTP",&xptInfo)!=SML_ERR_OK) 
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to get HTTP protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	xptProtocolID=xptInfo->id;
	sctsInt2Str(port,xptMeta+11,10);
	if (xptSelectProtocol(xptProtocolID,xptMeta,XPT_SERVER,&xptServiceID)!=SML_ERR_OK)
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to select HTTP protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	return 0;
}


char *parseForHttpHeader(char *header,char *&headerName,char *&headerValue)
{
	headerName=0;
	headerValue=0;
	if (header[0]=='\r' && header[1]=='\n') return header+2;
	headerName=header;
	header=sctsStrchr(header,':');
	*header=0;
	++header;
	headerValue=header;
	do
	{
		header=sctsStrstr(header,"\r\n");
		header+=2;
	} while (*header=='\t' || *header==' ');
	*(header-2)=0;
	return header;
}

int SctsHttpTransportServer::Run()
{
	XptCommunicationInfo_t xptDocInfo;
	XptHmacInfo_t xptHmacInfo;
	SctsHttpServerTransport *transport;
//	HOSTENT *hostent;
	char *query;
	char *host;
	unsigned int querySize;
	int rc;
	SctsEncoding encoding;
	SctsDMSession *session;
	SctsLog transportLog;
	char *httpHeader;
	sctsStatusLogOpen();
	sctsStatusLog("Starting HTTP transport server...\r\n");
	SetState(SERVER_RUNNING);
//	hostent=gethostbyname(0);
//	if (!hostent || !hostent->h_addr_list)
//	{
//		sctsStatusLog("Could not get host IP address.");
//		SetState(SERVER_ERROR);
//		return 1;
//	}
//	host=sctsStrdup(inet_ntoa(*(struct in_addr *)hostent->h_addr_list[0]));
	while (true)
	{
		sctsStatusLog("Waiting for client...\r\n");
		if ((rc=xptOpenCommunication(xptServiceID,XPT_REQUEST_RECEIVER,&xptCommID))!=SML_ERR_OK) 
		{
			if (rc==SML_ERR_A_XPT_TERMINATE) break;
			sctsRTKError(rc);
			SetState(SERVER_ERROR);
			return 1;
		}

		httpGetActiveAddress(xptCommID,&host);
		xptDocInfo.hmacInfo=&xptHmacInfo;
		if (!sctsRTKError(xptBeginExchange(xptCommID)) || !sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo)))
		{
			xptCloseCommunication(xptCommID);
			continue;
		}
		SCTSASSERT(xptDocInfo.mimeType);
		httpHeader=sctsGetHttpHeader();
		/* Check mime type */
		if (sctsStrstr(xptDocInfo.mimeType,"application/vnd.syncml.dm+wbxml"))
			encoding=WBXML;
		else if (sctsStrstr(xptDocInfo.mimeType,"application/vnd.syncml.dm+xml")) 
			encoding=XML;
		/* OTA-HTTP Push */
		else if (sctsStrstr(xptDocInfo.mimeType,"application/http"))
		{
			SctsDMClientDevice *notificationDevice=SctsDMClientDevice::getNotificationDevice();
			void (*notificationCallback)(SctsDMSession *)=(void (*)(SctsDMSession *))SctsDMClientDevice::getNotificationCallback();
			/* Check if there is a client device registered for notification */
			if (!notificationDevice)
			{
				MessageBox(0,"No Client Device registered for handling the Notification message.","Notification Session",MB_ICONEXCLAMATION);
				sctsStatusLog("No Client Device registered for handling the Notification message....\r\n");
				xptCloseCommunication(xptCommID);
				continue;
			}

			/* Check servlet path */
			if (sctsStrcmp(xptDocInfo.docName,"/wappush"))
			{
				sctsStatusLog("Bad servlet path...\r\n");
				sctsStatusLog("Connection rejected...\r\n");
				xptCloseCommunication(xptCommID);
				continue;
			}
			/* Parse contained message */
			if (xptDocInfo.cbLength<=0)
			{
				sctsStatusLog("Cannot parse notification request without content length...\r\n");
				sctsStatusLog("Connection rejected...\r\n");
				xptCloseCommunication(xptCommID);
				continue;
			}
			char *buffer=(char *)sctsMalloc(xptDocInfo.cbLength+1);
			char *_buffer=buffer;
			int bufferLen=xptDocInfo.cbLength+1;
			int recvData;
			do
			{
				if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,(unsigned int *)&recvData))) 
				{
					recvData=-1;
					break;
				}
				bufferLen-=recvData;
				_buffer+=recvData;
			}
			while (bufferLen && recvData);
			if (recvData==-1)
			{
				sctsFree(buffer);
				xptCloseCommunication(xptCommID);
				continue;
			}
			/* Use recvData as a flag */
			recvData=-1;
			while (true)
			{
				char *headerName;
				char *headerValue;
				if (sctsMemcmp(buffer,"HTTP/1.1 ",9)) break;
				/* Check status code */
				_buffer=sctsStrchr(buffer+9,' ');
				*_buffer=0;
				if (atoi(buffer+9)!=200) break;
				/* Ignore status description */
				_buffer=sctsStrstr(_buffer+1,"\r\n")+2;
				/* Parse for headers */
				xptDocInfo.cbLength=-1;
				xptDocInfo.mimeType[0]=0;
				while (true)
				{
					_buffer=parseForHttpHeader(_buffer,headerName,headerValue);
					if (!headerName) break;
					if (!stricmp(headerName,"Content-Type"))
						strcpy(xptDocInfo.mimeType,headerValue);
					if (!stricmp(headerName,"Content-Length"))
						xptDocInfo.cbLength=atoi(headerValue);
				}
				if (!sctsStrstr(xptDocInfo.mimeType,"application/vnd.syncml.notification")) break;
				if (xptDocInfo.cbLength==-1) break;
				/* Handle notification message - starts at _buffer */
				if (xptDocInfo.cbLength<24)
				{
					sctsStatusLog("Notification Message is not complete...\r\n");
					break;
				}
				
				int sessionID;
				char *serverId;
				SctsDMNode *password;
				SctsDMNode *nonce;
				SctsDMNode *node;

				if (_buffer[16]+_buffer[17]&0x3!=11)
				{
					/* Version error */
				}
				sessionID=((unsigned char)_buffer[21]<<8)+(unsigned char)_buffer[22];
				if (xptDocInfo.cbLength!=24+(unsigned char)_buffer[23])
				{
					sctsStatusLog("Notification Message is not complete...\r\n");
					break;
				}
				serverId=(char *)sctsMalloc((unsigned char)_buffer[23]+1);
				sctsMemcpy(serverId,_buffer+24,(unsigned char)_buffer[23]+1);
				serverId[(unsigned char)_buffer[23]]=0;

				/* Get the DMAcc with the server Id and validate the digest */
				node=notificationDevice->FindDMNode(notificationDevice->dmAccPath);
				SCTSASSERT(node);
				node=node->child;
				while (node)
				{
					nonce=notificationDevice->FindDMNode("ServerID",node);
					if (nonce && nonce->data && !sctsStrcmp((char *)nonce->data,serverId)) break;
					node=node->next;
				}
				if (!node)
				{
					sctsStatusLog("There is no DMAcc configured with a ServerID sent in the notification message...\r\n");
					break;
				}
				/* Get Password and Nonce */
				password=notificationDevice->FindDMNode((char *)(notificationDevice->accounts[node->name].subAppAuthServer + "/AAuthSecret").c_str(), node);
				nonce=notificationDevice->FindDMNode((char *)(notificationDevice->accounts[node->name].subAppAuthServer + "/AAuthData").c_str(), node);
						
				if (password && nonce)	
				{			
					/* Compute the Digest */
					char encrypt[300];
					MD5_CTX md5Context;
					char md5Digest[16];
					char *str;
					char *str1;
					unsigned int _size;
					unsigned int _size1;

					/* H(trigger) */
					MD5Init(&md5Context);
					MD5Update(&md5Context,(char *)_buffer+16,xptDocInfo.cbLength-16);
					MD5Final(md5Digest,&md5Context);
					_size=16;
					
					/* B64(H(trigger) */
					str=sctsBase64Encode((unsigned char *)md5Digest,_size);

					/* H(serverId:password) */
					sctsStrcpy(encrypt,serverId);
					sctsStrcat(encrypt,":");
					sctsStrncat(encrypt,(char *)password->data,password->size);
					_size1=sctsStrlen(serverId)+1+password->size;

					MD5Init(&md5Context);
					MD5Update(&md5Context,(char *)encrypt,_size1);
					MD5Final(md5Digest,&md5Context);
					_size1=16;

					/* B64(H(serverId:password)) */
					str1=sctsBase64Encode((unsigned char *)md5Digest,_size1);
					
					/* B64(H(username:password)):nonce:B64(H(trigger)) */
					sctsStrcpy(encrypt,str1);
					sctsStrcat(encrypt,":");
					++_size1;
					sctsMemcpy(encrypt+_size1,nonce->data,nonce->size);
					_size1+=nonce->size;
					encrypt[_size1++]=':';
					sctsMemcpy(encrypt+_size1,str,_size);
					_size1+=_size;

					/* H(B64(H(serverId:password)):nonce:B64(H(trigger))) */
					MD5Init(&md5Context);
					MD5Update(&md5Context,(char *)encrypt,_size1);
					MD5Final(md5Digest,&md5Context);
					
					/* Clean up */
					sctsFree(str);
					sctsFree(str1);
					/* Verify with the received digest */
					if (!sctsMemcmp(buffer,md5Digest,16))
					{
						sctsStatusLog("Not authenticated. Invalid Digest...\r\n");
						break;
					}
				}
				/* Send response */
				xptDocInfo.mimeType[0]=0;
				xptDocInfo.cbLength=0;
				xptSetDocumentInfo(xptCommID,&xptDocInfo);
				xptEndExchange(xptCommID);
				xptCloseCommunication(xptCommID);
				/* Create a Client Session */
				SctsDMClientSession *clientSession;
				notificationDevice->accountNode=node;
				clientSession=new SctsDMClientSession(notificationDevice,notificationDevice->encoding,notificationCallback);
				clientSession->alertCode=1200;
				sctsFree(clientSession->sessionID);
				clientSession->sessionID=sctsStrdup(itoa(sessionID,buffer,10));
				clientSession->Create();
				recvData=0;
				break;
			}/* End of While */
			continue;
		}
		else
		{
			sctsStatusLog("Bad MIME type (");
			sctsStatusLog(xptDocInfo.mimeType);
			sctsStatusLog("...\r\nConnection rejected...\r\n");
			xptCloseCommunication(xptCommID);
			continue;
		}
		/* Look for query string in the doc name */
		if (!sctsStrncmp(xptDocInfo.docName,"/Scts?",6))
		{
			query=xptDocInfo.docName+6;
			sctsStatusLog("Looking for session (");
			sctsStatusLog(query);
			sctsStatusLog(")...\r\n");
			querySize=sctsStrlen(query);
			query=(char *)sctsBase64Decode(query,querySize);
			if (!query || querySize!=sizeof(SctsHttpServerTransport *))
			{
				sctsStatusLog("Not found...\r\n");
				if (query) sctsFree(query);
				xptCloseCommunication(xptCommID);
				continue;
			}
			sctsMemcpy(&transport,query,querySize);
			sctsFree(query);
			serverTransportsLock.Lock();
			if (serverTransports.find(transport)==serverTransports.end() || !transport->xptClose || transport->nextXptCommID)
			{
				serverTransportsLock.Unlock();
				xptCloseCommunication(xptCommID);
				continue;
			}
			/* Write the Http header */
			if (transport->lastHttpHeader) sctsFree(transport->lastHttpHeader);
			transport->lastHttpHeader=httpHeader;

			sctsMemcpy(&transport->nextXptDocInfo,&xptDocInfo,sizeof(XptCommunicationInfo_t));
			serverTransportsLock.Unlock();
			transport->nextXptCommID=xptCommID;
			transport->nextXptCommLock.Unlock();
			continue;
		}
		/* Servlet : /Manage */
		if (!sctsStrcmp(xptDocInfo.docName,"/Manage"))
		{
			/* Create the transport object and the session object */
			transport=new SctsHttpServerTransport(xptDocInfo.mimeType,this,xptCommID,xptClose?true:false,&xptDocInfo);
			/* Write the Http header */
			transport->lastHttpHeader=httpHeader;
			/* If it is a close type connection set the respURI */
			if (xptClose)
			{
				char respURI[50];
				if (port==80)
					sprintf(respURI,"http://%s/Scts?",host);
				else
					sprintf(respURI,"http://%s:%d/Scts?",host,port);
				querySize=sizeof(SctsHttpServerTransport *);
				query=sctsBase64Encode((unsigned char *)&transport,querySize);
				sctsStatusLog("Close type HTTP connection, setting query string (");
				sctsStatusLog(query);
				sctsStatusLog("...\r\n");
				sctsStrcat(respURI,query);
				sctsFree(query);
				transport->SetRespAddr(&SctsURI(respURI));
			}
			session=(SctsDMSession *)new SctsDMServerSession(transport,encoding,0);
			session->Create();
			continue;
		}
		sctsStatusLog("Bad servlet path...\r\n");
		sctsStatusLog("Connection rejected...\r\n");
		xptCloseCommunication(xptCommID);
		
	}
	sctsStatusLogClose();
//	sctsFree(host);
	return 0;
}

/******************************************************************
SctsHttpServerTransport Definition
******************************************************************/

SctsHttpServerTransport::SctsHttpServerTransport(char *_mimeType,
														 SctsHttpTransportServer *transportServer,
														 XptCommunicationID_t _xptCommID,
														 bool _xptClose,
														 XptCommunicationInfoPtr_t pXptDocInfo)
: SctsServerTransport(_mimeType,transportServer),nextXptCommLock(1,1),lastHttpHeader(0)
{
	SCTSASSERT(_xptCommID);
	sctsMemcpy(&xptDocInfo,pXptDocInfo,sizeof(XptCommunicationInfo_t));
	xptCommID=_xptCommID;
	nextXptCommID=0;
	firstRecv=true;
	xptClose=_xptClose;
	if (xptClose)
		nextXptCommLock.Lock();
	respAddr=0;
}

SctsHttpServerTransport::~SctsHttpServerTransport()
{
	if (xptClose) xptCloseCommunication(xptCommID);
	if (lastHttpHeader) sctsFree(lastHttpHeader);
}

/*****************************************************************
Function	: Sends a message over the transport.
In			: char *
			  The source buffer which contains the message data.
In			: int
			  The length of the source buffer
Out			: bool
			  true - if the message was sent successfully
			  false - if the message failed to be sent
*****************************************************************/

bool SctsHttpServerTransport::SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo)
{
	unsigned int sentData;
	SCTSASSERT(buffer && bufferLen);
	
	/* Construct XptCommunicationInfo structure */
	xptDocInfo.cbSize=sizeof(XptCommunicationInfo_t);
	xptDocInfo.cbLength=bufferLen;
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	xptDocInfo.docName[0]=0;
	xptDocInfo.hmacInfo=macInfo;

	sctsStatusLog("Sending HTTP header...\r\n");
	if (!sctsRTKError(xptSetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	if (lastHttpHeader) sctsFree(lastHttpHeader);
	lastHttpHeader=sctsGetHttpHeader();
	if (!sctsRTKError(xptSendData(xptCommID,(const void *)buffer,bufferLen,&sentData))) return false;
	if (!sctsRTKError(xptSendComplete(xptCommID))) return false;
	SCTSASSERT(sentData==bufferLen);
	sctsStatusLog("Sent ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	if (!sctsRTKError(xptEndExchange(xptCommID))) return false;
	if (xptClose) 
	{
		sctsStatusLog("Closing connection...\r\n");
		xptCloseCommunication(xptCommID);
		xptCommID=0;
	}
	return true;
}

/*****************************************************************
Function	: Receives a message over the transport
In			: char *
			  The target buffer
In/Out		: int&
			  In - the length of the target buffer
			  Out - the received message size (-1) if more data is
			  to be received
Out			: bool
			  true - if the message was received successfully
			  false - if the message failed to be received

Note		: The buffer and bufferLen should be atleast 1 byte larger
			  than the expected message
*****************************************************************/

bool SctsHttpServerTransport::RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo)
{
	unsigned int recvData;
	char *_buffer=buffer;

	SCTSASSERT(buffer && bufferLen);
	sctsStatusLog("Receiving HTTP header...\r\n");
	if (!firstRecv)
	{
		if (xptClose)
		{
			if (!nextXptCommLock.Lock(sctsSessionTimeout))
			{
				bufferLen=0;
				return true;
			}
			xptCommID=nextXptCommID;
			nextXptCommID=0;
			sctsMemcpy(&xptDocInfo,&nextXptDocInfo,sizeof(XptCommunicationInfo_t));
			if (macInfo) *macInfo=xptDocInfo.hmacInfo;
		}
		else
		{
			if (!sctsRTKError(xptBeginExchange(xptCommID))) return false;
			if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo))) return false;
			if (macInfo) *macInfo=xptDocInfo.hmacInfo;
			if (lastHttpHeader) sctsFree(lastHttpHeader);
			lastHttpHeader=sctsGetHttpHeader();
			SCTSASSERT(!sctsStrcmp(xptDocInfo.mimeType,mimeType));
		}
	}
	else
	{
		if (macInfo) *macInfo=xptDocInfo.hmacInfo;
		firstRecv=false;
	}
	do
	{
		if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,&recvData))) return false;
		bufferLen-=recvData;
		_buffer+=recvData;
	}
	while (bufferLen && recvData);
	if (recvData)
		bufferLen=-1;
	else
		bufferLen=_buffer-buffer;
	sctsStatusLog("Received ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

char *SctsHttpServerTransport::GetRespAddr()
{
	if (!respAddr) return 0;
	return respAddr->Build();
}

char *SctsHttpServerTransport::GetTransportHdr()
{
	return lastHttpHeader;
}

bool SctsHttpServerTransport::SetRespAddr(SctsURI *_respAddr)
{
	if (respAddr) delete respAddr;
	if (_respAddr)
		respAddr=new SctsURI(*_respAddr);
	else
		respAddr=0;
	return true;
}

/******************************************************************
SctsTransportProfile Definition
******************************************************************/

void SctsTransportProfile::Save(FILE *fp)
{
	fwrite(&transport,sizeof(SctsSupportedTransport),1,fp);
}


SctsTransportProfile *SctsTransportProfile::Load(FILE *fp)
{
	SctsSupportedTransport transport;
	fread(&transport,sizeof(SctsSupportedTransport),1,fp);
	switch(transport)
	{
	case HTTP:
		return new SctsHttpTransportProfile(fp);
	case OBEXTCP:
		return new SctsObexTCPTransportProfile(fp);
	case OBEXIR:
		return new SctsObexIRTransportProfile(fp);
	}
	return 0;
}

SctsHttpTransportProfile::SctsHttpTransportProfile(FILE *fp) : serverAddress(fp)
{
	transport=HTTP;
	proxyAddress=sctsFReadString(fp);
}

void SctsHttpTransportProfile::Save(FILE *fp)
{
	SctsTransportProfile::Save(fp);
	serverAddress.Save(fp);
	sctsFWriteString(proxyAddress,fp);
}
	
SctsObexTCPTransportProfile::SctsObexTCPTransportProfile(FILE *fp)
{
	transport=OBEXTCP;
	hostAddr=sctsFReadString(fp);
	fread(&port,sizeof(int),1,fp);
}

void SctsObexTCPTransportProfile::Save(FILE *fp)
{
	SctsTransportProfile::Save(fp);
	sctsFWriteString(hostAddr,fp);
	fwrite(&port,sizeof(int),1,fp);
}

SctsObexIRTransportProfile::SctsObexIRTransportProfile(FILE *fp)
{
	transport=OBEXIR;
	serviceName=sctsFReadString(fp);
}

void SctsObexIRTransportProfile::Save(FILE *fp)
{
	SctsTransportProfile::Save(fp);
	sctsFWriteString(serviceName,fp);
}

/******************************************************************
SctsObexTCPTransportServer Definition
******************************************************************/
int obexTCPState=0;

int SctsObexTCPTransportServer::Init()
{
	const XptProtocolInfo* xptInfo;
	char xptMeta[50];
	SCTSASSERT(obexTCPState!=2);
	obexTCPState=1;
	if (xptGetProtocol("OBEX/TCP",&xptInfo)!=SML_ERR_OK) 
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to get OBEX/TCP protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	xptProtocolID=xptInfo->id;
	sprintf(xptMeta,"HOST=localhost PORT=%d",port);
	if (xptSelectProtocol(xptProtocolID,xptMeta,XPT_SERVER,&xptServiceID)!=SML_ERR_OK)
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to select OBEX/TCP protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	return 0;
}

int SctsObexTCPTransportServer::Run()
{
	XptCommunicationInfo_t recvXptDocInfo;
	SctsObexServerTransport *transport;
	HOSTENT *hostent;
	char *host;
	bool errorFlag=false;
	SctsEncoding encoding;
	SctsDMSession *session;
	SctsLog transportLog;
	sctsStatusLogOpen();
	sctsStatusLog("Starting OBEX/TCP transport server...\r\n");
	SetState(SERVER_RUNNING);
	hostent=gethostbyname(0);
	if (!hostent || !hostent->h_addr_list)
	{
		sctsStatusLog("Could not get host IP address.");
		SetState(SERVER_ERROR);
		return 1;
	}
	host=sctsStrdup(inet_ntoa(*(struct in_addr *)hostent->h_addr_list[0]));
	if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_RECEIVER,&xptCommID))) return 1;
	while (!GetTerminate())
	{
		if (errorFlag)
		{
			/* Try to restart server */
			sctsStatusLog("Rejecting connection...\r\nTrying to restart OBEX/TCP server...\r\n");
			xptCloseCommunication(xptCommID);
			if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_RECEIVER,&xptCommID))) 
			{
				SetState(SERVER_ERROR);
				return 1;
			}
		}
		errorFlag=true;
		sctsStatusLog("Waiting for client...\r\n");
		if (!sctsRTKError(xptBeginExchange(xptCommID)) || !sctsRTKError(xptGetDocumentInfo(xptCommID,&recvXptDocInfo))) continue;
		if (!recvXptDocInfo.mimeType)
		{
			sctsStatusLog("Missing MIME type...");
			continue;
		}
		/* Check mime type */
		if (!sctsStrcmp(recvXptDocInfo.mimeType,"application/vnd.syncml.dm+wbxml"))
			encoding=WBXML;
		else
		{
			if (sctsStrcmp(recvXptDocInfo.mimeType,"application/vnd.syncml.dm+xml")) 
			{
				sctsStatusLog("Bad MIME type (");
				sctsStatusLog(recvXptDocInfo.mimeType);
				sctsStatusLog(")...\r\n");
				continue;
			}
			encoding=XML;
		}

		/* Create the transport object and the session object */
		transport=new SctsObexServerTransport(recvXptDocInfo.mimeType,this,xptCommID,recvXptDocInfo.hmacInfo);
		transport->obexServerLock=&obexServerLock;
		session=(SctsDMSession *)new SctsDMServerSession(transport,encoding,0);			
		session->Create();
		/* Wait for session to complete */
		obexServerLock.Lock();
		if (!sctsRTKError(xptEndExchange(xptCommID))) continue;
		errorFlag=false;
	}
	sctsStatusLogClose();
	sctsFree(host);
	if (xptCommID) xptCloseCommunication(xptCommID);
	return 0;
}

/******************************************************************
SctsObexTCPClientTransport Definition
******************************************************************/

/******************************************************************
Function	: Constructor
In			: char *_mimeType
			  The mime type to be used
******************************************************************/

SctsObexTCPClientTransport::SctsObexTCPClientTransport(char *_hostAddr,int _port) 
		: xptServiceID(0),xptProtocolID(0),xptCommID(0)
{
	const XptProtocolInfo* xptInfo;
	char xptMeta[100];
	SCTSASSERT(obexTCPState!=1);
	obexTCPState=2;
	sctsStatusLog("Creating OBEX/TCP client transport...\r\n");
	SCTSASSERT(_hostAddr);
	SCTSASSERT(xptGetProtocol("OBEX/TCP",&xptInfo)==SML_ERR_OK);
	xptProtocolID=xptInfo->id;
	sprintf(xptMeta,"HOST=%s PORT=%d",_hostAddr,_port);
	SCTSASSERT(xptSelectProtocol(xptProtocolID,xptMeta,XPT_CLIENT,&xptServiceID)==SML_ERR_OK);
	hostAddr=sctsStrdup(_hostAddr);
	port=_port;
	respAddr=new SctsURI(_hostAddr);
}

/*****************************************************************
Function	: Sets the response address of a client transport,
			  not used for OBEX since the connections must stay open
			  for the entire session.
In			: SctsURI *
			  The RespURI
Out			: bool
			  true - if the response address was set
			  false - if the response address is invalid
*****************************************************************/

bool SctsObexTCPClientTransport::SetRespAddr(SctsURI *_respAddr)
{
	if (respAddr) delete respAddr;
	respAddr=new SctsURI(*_respAddr);
	return true;
}

char *SctsObexTCPClientTransport::GetTransportHdr()
{
	return 0;
}

char *SctsObexTCPClientTransport::GetRespAddr()
{
	if (!respAddr) return 0;
	return respAddr->Build();
}

/*****************************************************************
Function	: Sends a message over the transport.
In			: char *
			  The source buffer which contains the message data.
In			: int
			  The length of the source buffer
Out			: bool
			  true - if the message was sent successfully
			  false - if the message failed to be sent
*****************************************************************/

bool SctsObexTCPClientTransport::SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo)
{
	unsigned int sentData=0;
	/* Connect to server if connection hasn't been established */
	if (!xptCommID)
	{
		sctsStatusLog("Connecting to ");
		SCTSASSERT(buffer && bufferLen && xptServiceID);
		sctsStatusLog(hostAddr);
		sctsStatusLog("...\r\n");
		if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_SENDER,&xptCommID))) return false;
		if (!sctsRTKError(xptBeginExchange(xptCommID))) return false;
	}
	else
		if (!sctsRTKError(xptSkipState(xptCommID))) return false;
	/* Construct XptCommunicationInfo structure */
	xptDocInfo.cbSize=sizeof(XptCommunicationInfo_t);
	xptDocInfo.cbLength=bufferLen;
	xptDocInfo.hmacInfo=macInfo;
	xptDocInfo.docName[0]=0;
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	sctsStatusLog("Sending OBEX message...\r\n");
	if (!sctsRTKError(xptSetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	if (!sctsRTKError(xptSendData(xptCommID,(const void *)buffer,bufferLen,&sentData))) return false;
	if (!sctsRTKError(xptSendComplete(xptCommID))) return false;
	SCTSASSERT(sentData==bufferLen);
	sctsStatusLog("Sent ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

/*****************************************************************
Function	: Receives a message over the transport
In			: char *
			  The target buffer
In/Out		: int&
			  In - the length of the target buffer
			  Out - the received message size (-1) if more data is
			  to be received
Out			: bool
			  true - if the message was received successfully
			  false - if the message failed to be received

Note		: The buffer and bufferLen should be atleast 1 byte larger
			  than the expected message
*****************************************************************/

bool SctsObexTCPClientTransport::RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo)
{
	unsigned int recvData;
	char *_buffer=buffer;
	sctsStatusLog("Receiving OBEX message...\r\n");
	SCTSASSERT(buffer && bufferLen && xptServiceID);
	/* Set the MIME type to be used in the OBEX Type header */
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	SetHmacInfo(xptDocInfo.hmacInfo);
	if (macInfo) *macInfo=xptDocInfo.hmacInfo;
	if(!sctsStrstr(xptDocInfo.mimeType,mimeType))
	{
		char buffer[100];
		sctsStatusLog("Received invalid MIME type : ");
		sctsStatusLog(xptDocInfo.mimeType);
		sctsStatusLog("...\r\n");
		sprintf(buffer,"Received invalid MIME type : %s",xptDocInfo.mimeType);
		SctsErrorLog::AppendError(buffer);
		return false;
	}
	do
	{
		if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,&recvData))) return false;
		bufferLen-=recvData;
		_buffer+=recvData;
	}
	while (bufferLen && recvData);
	if (recvData)
		bufferLen=-1;
	else
		bufferLen=_buffer-buffer;
	sctsStatusLog("Received ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}
		
SctsObexTCPClientTransport::~SctsObexTCPClientTransport()
{
	/* End the exchange and close the connection */
	if (xptCommID)
	{
		sctsStatusLog("Closing connection...\r\n");
		sctsRTKError(xptEndExchange(xptCommID));
		sctsRTKError(xptCloseCommunication(xptCommID));
	}
	sctsFree(hostAddr);
	if (respAddr) delete respAddr;
	if (xptServiceID) xptDeselectProtocol(xptServiceID);
	obexTCPState=0;
}

/******************************************************************
SctsObexIRTransportServer Definition
******************************************************************/
int obexIRState=0;

int SctsObexIRTransportServer::Init()
{
	const XptProtocolInfo* xptInfo;
	char meta[100];
	SCTSASSERT(obexIRState!=2);
	obexIRState=1;
	if (xptGetProtocol("OBEX/IR",&xptInfo)!=SML_ERR_OK) 
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to get OBEX/IR protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	xptProtocolID=xptInfo->id;
	sprintf(meta,"SERVICE=%s",serviceName);
	if (xptSelectProtocol(xptProtocolID,meta,XPT_SERVER,&xptServiceID)!=SML_ERR_OK)
	{
		sctsStatusLog("Could not start transport server (Toolkit : Unable to select OBEX/IR protocol)...\r\n");
		SetState(SERVER_ERROR);
		return 1;
	}
	return 0;
}

int SctsObexIRTransportServer::Run()
{
	XptCommunicationInfo_t recvXptDocInfo;
	SctsObexServerTransport *transport;
	int rc;
	bool errorFlag=false;
	SctsEncoding encoding;
	SctsDMSession *session;
	SctsLog transportLog;
	sctsStatusLogOpen();
	sctsStatusLog("Starting OBEX/IR transport server...\r\n");
	SetState(SERVER_RUNNING);
	while (true)
	{
		if (errorFlag)
		{
			/* Try to restart server */
			sctsStatusLog("Rejecting connection...\r\nTrying to restart OBEX/IR server...\r\n");
			xptCloseCommunication(xptCommID);
		}
		if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_RECEIVER,&xptCommID))) 
		{
			SetState(SERVER_ERROR);
			return 1;
		}
		errorFlag=true;
		sctsStatusLog("Waiting for client...\r\n");
		if ((rc=xptBeginExchange(xptCommID)))
		{
			xptCloseCommunication(xptCommID);
			if (rc==SML_ERR_A_XPT_TERMINATE) break;
			sctsRTKError(rc);
			SetState(SERVER_ERROR);
			return 1;
		}
		if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&recvXptDocInfo))) continue;
		if (!recvXptDocInfo.mimeType)
		{
			sctsStatusLog("Missing MIME type...");
			continue;
		}
		/* Check mime type */
		if (!sctsStrcmp(recvXptDocInfo.mimeType,"application/vnd.syncml.dm+wbxml"))
			encoding=WBXML;
		else
		{
			if (sctsStrcmp(recvXptDocInfo.mimeType,"application/vnd.syncml.dm+xml")) 
			{
				sctsStatusLog("Bad MIME type (");
				sctsStatusLog(recvXptDocInfo.mimeType);
				sctsStatusLog(")...\r\n");
				continue;
			}
			encoding=XML;
		}

		/* Create the transport object and the session object */
		transport=new SctsObexServerTransport(recvXptDocInfo.mimeType,this,xptCommID,recvXptDocInfo.hmacInfo);
		transport->obexServerLock=&obexServerLock;
		session=(SctsDMSession *)new SctsDMServerSession(transport,encoding,0);
		session->Create();
		/* Wait for session to complete */
		obexServerLock.Lock();
		if (!sctsRTKError(xptEndExchange(xptCommID))) continue;
		errorFlag=false;
	}
	sctsStatusLogClose();
	obexIRState=0;
	if (xptCommID) xptCloseCommunication(xptCommID);
	return 0;
}

/******************************************************************
SctsObexServerTransport Definition
******************************************************************/

SctsObexServerTransport::SctsObexServerTransport(char *_mimeType,
														 SctsTransportServer *transportServer,
														 XptCommunicationID_t _xptCommID,
														 XptHmacInfoPtr_t _xptHmacInfo)
: SctsServerTransport(_mimeType,transportServer),xptCommID(_xptCommID),xptHmacInfo(_xptHmacInfo)
{
	obexServerLock=0;
	respAddr=0;
	firstRecv=true;
}

SctsObexServerTransport::~SctsObexServerTransport()
{
	if (obexServerLock) obexServerLock->Unlock();
	if (respAddr) delete respAddr;
}

/*****************************************************************
Function	: Sends a message over the transport.
In			: char *
			  The source buffer which contains the message data.
In			: int
			  The length of the source buffer
Out			: bool
			  true - if the message was sent successfully
			  false - if the message failed to be sent
*****************************************************************/

bool SctsObexServerTransport::SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo)
{
	unsigned int sentData;
	XptCommunicationInfo_t xptDocInfo;
	SCTSASSERT(buffer && bufferLen);
	
	/* Construct XptCommunicationInfo structure */
	xptDocInfo.cbSize=sizeof(XptCommunicationInfo_t);
	xptDocInfo.cbLength=bufferLen;
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	xptDocInfo.docName[0]=0;
	xptDocInfo.hmacInfo=macInfo;

	sctsStatusLog("Sending OBEX message...\r\n");
	if (!sctsRTKError(xptSetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	if (!sctsRTKError(xptSendData(xptCommID,(const void *)buffer,bufferLen,&sentData))) return false;
	if (!sctsRTKError(xptSendComplete(xptCommID))) return false;
	SCTSASSERT(sentData==bufferLen);
	sctsStatusLog("Sent ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

/*****************************************************************
Function	: Receives a message over the transport
In			: char *
			  The target buffer
In/Out		: int&
			  In - the length of the target buffer
			  Out - the received message size (-1) if more data is
			  to be received
Out			: bool
			  true - if the message was received successfully
			  false - if the message failed to be received

Note		: The buffer and bufferLen should be atleast 1 byte larger
			  than the expected message
*****************************************************************/

bool SctsObexServerTransport::RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo)
{
	XptCommunicationInfo_t xptDocInfo;
	unsigned int recvData;
	char *_buffer=buffer;

	SCTSASSERT(buffer && bufferLen);
	sctsStatusLog("Receiving OBEX Message...\r\n");
	if (!firstRecv)
	{
		if (!sctsRTKError(xptSkipState(xptCommID))) return false;
		if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo))) return false;
		if (macInfo) *macInfo=xptDocInfo.hmacInfo;
		SCTSASSERT(!sctsStrcmp(xptDocInfo.mimeType,mimeType));
	}
	else
	{
		if (macInfo) *macInfo=xptHmacInfo;
		firstRecv=false;
	}
	do
	{
		if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,&recvData))) return false;
		bufferLen-=recvData;
		_buffer+=recvData;
	}
	while (bufferLen && recvData);
	if (recvData)
		bufferLen=-1;
	else
		bufferLen=_buffer-buffer;
	sctsStatusLog("Received ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

char *SctsObexServerTransport::GetRespAddr()
{
	if (!respAddr) return 0;
	return respAddr->Build();
}

char *SctsObexServerTransport::GetTransportHdr()
{
	return 0;
}

bool SctsObexServerTransport::SetRespAddr(SctsURI *_respAddr)
{
	if (respAddr) delete respAddr;
	if (_respAddr)
		respAddr=new SctsURI(*_respAddr);
	else
		respAddr=0;
	return true;
}

/******************************************************************
SctsObexIRClientTransport Definition
******************************************************************/

/******************************************************************
Function	: Constructor
In			: char *_mimeType
			  The mime type to be used
******************************************************************/

SctsObexIRClientTransport::SctsObexIRClientTransport(char *_serviceName) 
		: xptServiceID(0),xptProtocolID(0),xptCommID(0)
{
	const XptProtocolInfo* xptInfo;
	char xptMeta[100];
	SCTSASSERT(obexIRState!=1);
	obexIRState=2;
	sctsStatusLog("Creating OBEX/IR client transport...\r\n");
	SCTSASSERT(_serviceName);
	SCTSASSERT(xptGetProtocol("OBEX/IR",&xptInfo)==SML_ERR_OK);
	xptProtocolID=xptInfo->id;
	sprintf(xptMeta,"SERVICE=%s",_serviceName);
	SCTSASSERT(xptSelectProtocol(xptProtocolID,xptMeta,XPT_CLIENT,&xptServiceID)==SML_ERR_OK);
	serviceName=sctsStrdup(_serviceName);
	respAddr=new SctsURI(_serviceName);
}

/*****************************************************************
Function	: Sets the response address of a client transport,
			  not used for OBEX since the connections must stay open
			  for the entire session.
In			: SctsURI *
			  The RespURI
Out			: bool
			  true - if the response address was set
			  false - if the response address is invalid
*****************************************************************/

bool SctsObexIRClientTransport::SetRespAddr(SctsURI *_respAddr)
{
	if (respAddr) delete respAddr;
	respAddr=new SctsURI(*_respAddr);
	return true;
}

char *SctsObexIRClientTransport::GetTransportHdr()
{
	return 0;
}

char *SctsObexIRClientTransport::GetRespAddr()
{
	if (!respAddr) return 0;
	return respAddr->Build();
}

/*****************************************************************
Function	: Sends a message over the transport.
In			: char *
			  The source buffer which contains the message data.
In			: int
			  The length of the source buffer
Out			: bool
			  true - if the message was sent successfully
			  false - if the message failed to be sent
*****************************************************************/

bool SctsObexIRClientTransport::SendMessage(char *buffer,int bufferLen,XptHmacInfoPtr_t macInfo)
{
	unsigned int sentData=0;
	/* Connect to server if connection hasn't been established */
	if (!xptCommID)
	{
		sctsStatusLog("Connecting to ");
		SCTSASSERT(buffer && bufferLen && xptServiceID);
		sctsStatusLog(serviceName);
		sctsStatusLog("...\r\n");
		if (!sctsRTKError(xptOpenCommunication(xptServiceID,XPT_REQUEST_SENDER,&xptCommID))) return false;
		if (!sctsRTKError(xptBeginExchange(xptCommID))) return false;
	}
	else
		if (!sctsRTKError(xptSkipState(xptCommID))) return false;
	/* Construct XptCommunicationInfo structure */
	xptDocInfo.cbSize=sizeof(XptCommunicationInfo_t);
	xptDocInfo.cbLength=bufferLen;
	xptDocInfo.hmacInfo=macInfo;
	xptDocInfo.docName[0]=0;
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	sctsStatusLog("Sending OBEX message...\r\n");
	if (!sctsRTKError(xptSetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	if (!sctsRTKError(xptSendData(xptCommID,(const void *)buffer,bufferLen,&sentData))) return false;
	if (!sctsRTKError(xptSendComplete(xptCommID))) return false;
	SCTSASSERT(sentData==bufferLen);
	sctsStatusLog("Sent ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}

/*****************************************************************
Function	: Receives a message over the transport
In			: char *
			  The target buffer
In/Out		: int&
			  In - the length of the target buffer
			  Out - the received message size (-1) if more data is
			  to be received
Out			: bool
			  true - if the message was received successfully
			  false - if the message failed to be received

Note		: The buffer and bufferLen should be atleast 1 byte larger
			  than the expected message
*****************************************************************/

bool SctsObexIRClientTransport::RecvMessage(char *buffer,int& bufferLen,XptHmacInfoPtr_t *macInfo)
{
	unsigned int recvData;
	char *_buffer=buffer;
	sctsStatusLog("Receiving OBEX message...\r\n");
	SCTSASSERT(buffer && bufferLen && xptServiceID);
	/* Set the MIME type to be used in the OBEX Type header */
	sctsStrcpy(xptDocInfo.mimeType,mimeType);
	if (!sctsRTKError(xptGetDocumentInfo(xptCommID,&xptDocInfo))) return false;
	SetHmacInfo(xptDocInfo.hmacInfo);
	if (macInfo) *macInfo=xptDocInfo.hmacInfo;
	if(!sctsStrstr(xptDocInfo.mimeType,mimeType))
	{
		char buffer[100];
		sctsStatusLog("Received invalid MIME type : ");
		sctsStatusLog(xptDocInfo.mimeType);
		sctsStatusLog("...\r\n");
		sprintf(buffer,"Received invalid MIME type : %s",xptDocInfo.mimeType);
		SctsErrorLog::AppendError(buffer);
		return false;
	}
	do
	{
		if (!sctsRTKError(xptReceiveData(xptCommID,_buffer,bufferLen,&recvData))) return false;
		bufferLen-=recvData;
		_buffer+=recvData;
	}
	while (bufferLen && recvData);
	if (recvData)
		bufferLen=-1;
	else
		bufferLen=_buffer-buffer;
	sctsStatusLog("Received ");
	sctsStatusLog(bufferLen);
	sctsStatusLog(" bytes of data...\r\n");
	return true;
}
		
SctsObexIRClientTransport::~SctsObexIRClientTransport()
{
	/* End the exchange and close the connection */
	if (xptCommID)
	{
		sctsStatusLog("Closing connection...\r\n");
		sctsRTKError(xptEndExchange(xptCommID));
		sctsRTKError(xptCloseCommunication(xptCommID));
	}
	sctsFree(serviceName);
	if (respAddr) delete respAddr;
	if (xptServiceID) xptDeselectProtocol(xptServiceID);
	obexIRState=0;
}

#endif
