#include "p_apps.h"
#include "p_sip.h"
#include "v_task.h"
#include "my_sip.h"

#define MAX_RECV_LEN	255

#define SIP_STATE_INIT				0
#define SIP_STATE_HEADER_BEGIN		1
#define SIP_STATE_HEADER_END		2
#define SIP_STATE_END				5		

 XSHORT Sip_iRegisterPort;
 XSHORT Sip_iRtpPort;

DCHAR Sip_iBodyLines;
DCHAR Sip_iRecvViaNum;
DCHAR Sip_iRecvMethod;

static XCHAR _pRecvPacket[MAX_RECV_LEN+1];
static XCHAR _iState;
static XCHAR _iRecvLen;
static XSHORT _iRecvMsgCode;
static XSHORT _iContentLen;
static BOOLEAN _bRecvRequest;

// Header names
CCHAR _cCallId[] = "Call-ID: "; 
CCHAR _cContact[] = "Contact: ";
CCHAR _cCSeq[] = "CSeq: ";
CCHAR _cFrom[] = "From: ";
CCHAR _cTo[] = "To: ";
CCHAR _cVia[] = "Via: ";
CCHAR _cAllow[] = "Allow: "; 
CCHAR _cExpires[] = "Expires: ";
CCHAR _cReferTo[] = "Refer-To: ";
CCHAR _cReferredBy[] = "Referred-By: ";
CCHAR _cRecordRoute[] = "Record-Route: ";
CCHAR _cRoute[] = "Route: ";
CCHAR _cReplaces[] = "Replaces: ";
CCHAR _cMinExpires[] = "Min-Expires: ";
CCHAR _cRequire[] = "Require: ";
CCHAR _cRAck[] = "RAck: ";
CCHAR _cRSeq[] = "RSeq: ";
CCHAR _cSupported[] = "Supported: ";
CCHAR _cEvent[] = "Event: ";

CCHAR _cTag[] = "tag=";
CCHAR _cSipVer[] = "SIP/2.0";

#define SIP_COLON_LABEL_LEN		4
CCHAR _cSipColon[] = "sip:";

#define SIP_100REL_LABEL_LEN	6
CCHAR _c100rel[] = "100rel";

#define BRANCH_TOKEN_LABEL_LEN	7
CCHAR _cBranchToken[] = "branch=";
/****************************************************************************
********* Accesary functions ************************************************
*****************************************************************************/
UCHAR _GetParam(PCCHAR pToken, UCHAR iOrigTokenLen, UCHAR iSrcIndex)
{
	DCHAR iLen, iTokenLen;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;

	iLen = 0;
	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))	return iLen;

	pCur = p_strchr_x((PXCHAR)Sdram_pDataCache, ';');
	iTokenLen = iOrigTokenLen - 1;
	while (pCur)
	{
		pCur ++;
		pCur += p_count_space(pCur);
		if (p_memcmp_nocase_c2x(pCur, pToken, iTokenLen))
		{
			pCur += iTokenLen;
			pCur += p_count_char(pCur, '=');
			pTemp = SipStrChr(pCur, ';');
			if (pTemp)	pTemp[0] = 0;
			p_strcpy_c2x((PXCHAR)Sdram_pDataCache, pToken);
			p_strcat_x2x((PXCHAR)Sdram_pDataCache, pCur);
			iLen = p_strlen_x((PXCHAR)Sdram_pDataCache);
			break;
		}
		pCur = p_strchr_x(pCur, ';');
	}

	return iLen;
}

void SipGetViaBranch(BOOLEAN bRequest)
{
	DCHAR iLen;

	iLen = _GetParam(_cBranchToken, BRANCH_TOKEN_LABEL_LEN, SIP_RECV_VIA);
	if (iLen)
	{
		SdramWriteData(SIP_TRANS_SDRAM_POS+SIP_TRANS_BRANCH, iLen);
		return;
	}

	if (!bRequest || Sip_iRecvMethod == SIP_REQ_ACK)
	{
		SdramWriteData(SIP_TRANS_SDRAM_POS+SIP_TRANS_BRANCH, 0);
		return;
	}

	// for backward compatible with RFC2543
	p_line_start(Sip_pDataOut);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_TO_TAG);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_FROM_TAG);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_CALL_ID);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_CSEQ);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_REQUEST_URI);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_VIA);
	if (p_line_get_len() > 255)		
	{
		iLen = 255;
	}
	else
	{
		iLen = (UCHAR)p_line_get_len();
	}
	p_memcpy_x2x((PXCHAR)Sdram_pDataCache, Sip_pDataOut, iLen);
	SdramWriteData(SIP_TRANS_SDRAM_POS+SIP_TRANS_BRANCH, iLen);
}

void SipGetTag(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	DCHAR iLen;
	
	iLen = _GetParam(_cTag, TAG_LABEL_LEN, iSrcIndex);
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), iLen);
}

void SipRemoveTag(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	DCHAR iTokenLen;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return;

	pCur = p_strchr_x((PXCHAR)Sdram_pDataCache, ';');
	iTokenLen = TAG_LABEL_LEN - 1;
	while (pCur)
	{
		pTemp = pCur;
		pCur ++;
		pCur += p_count_space(pCur);
		if (p_memcmp_nocase_c2x(pCur, _cTag, iTokenLen))
		{
			pTemp[0] = 0;
			break;
		}
		pCur = p_strchr_x(pCur, ';');
	}
	SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));	
}


BOOLEAN SipGetUri(PXCHAR pDst, UCHAR iSrcIndex)
{
	PXCHAR_D pTemp;
	PXCHAR_D pCur;

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return	FALSE;

	pCur = (PXCHAR)Sdram_pDataCache;
	pTemp = 0;
	while (*pCur)
	{
		if (!pTemp)
		{
			if (!p_memcmp_c2x(pCur, _cSipColon, SIP_COLON_LABEL_LEN))
			{
				pTemp = pCur;
				pCur += SIP_COLON_LABEL_LEN;
				continue;
			}
		}
		else
		{
			if (*pCur == ';' || *pCur == '>' || *pCur == '?')
			{
				*pCur = 0;
				break;
			}
		}
		pCur ++;
	}
	if (pTemp)
	{
		p_strcpy_x2x((PXCHAR)pDst, pTemp);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void _GetName(PXCHAR pSrcStr)
{
	DCHAR iTemp;
	PXCHAR_D pDst;
	PXCHAR_D pSrc;
	BOOLEAN bQuoted;

	pSrc = pSrcStr;
	pDst = Sys_pRemoteNumber;
	bQuoted = FALSE;

	while (*pSrc)
	{
		iTemp = *pSrc;
		if (iTemp == '"')
		{
			if (bQuoted)	break;
			else			bQuoted = TRUE;
		}
		else 
		{	if ((iTemp == ' ' || iTemp == '<') && !bQuoted)
			{
				break;
			}
			else
			{
				*pDst= iTemp;
				pDst ++;
				iTemp = pDst - Sys_pRemoteNumber;
				if (iTemp > DIALED_MAX_LEN)
				{
					break;
				}
			}
		}
		pSrc ++;
	}
	*pDst = 0;
}

void SipGetRemoteId(UCHAR iSrcIndex)
{
	DCHAR iLen;
	PXCHAR_D pTemp;
	PXCHAR_D pCur;

	p_memset_x(Sys_pRemoteNumber, 0, DIALED_MAX_LEN+1);
	p_memset_x(Sys_pPeerDisplay, 0, PHONE_NUMBER_LEN+1);

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return;

	pCur = (PXCHAR)Sdram_pDataCache;
	while (*pCur)
	{
		if (!p_memcmp_c2x(pCur, _cSipColon, SIP_COLON_LABEL_LEN))
		{
			*pCur = 0;
			break;
		}
		pCur ++;
	}
	_GetName((PXCHAR)Sdram_pDataCache);

	if (SipGetUri((PXCHAR)Sdram_pDataCache2, iSrcIndex))
	{
		pCur = (PXCHAR)(Sdram_pDataCache2 + SIP_COLON_LABEL_LEN);
		pTemp = p_strchr_x(pCur, '@');
		if (pTemp) pTemp[0] = 0;
		iLen = p_strlen_x(pCur);
		if (iLen)
		{
			 if (iLen <= PHONE_NUMBER_LEN)
			 {
				p_strcpy_x2x(Sys_pPeerDisplay, pCur);
			 }
			 else
			 {
				 p_memcpy_x2x(Sys_pPeerDisplay, pCur, PHONE_NUMBER_LEN);
			 }
		}
	}
}

USHORT SipGetIPPort(PXCHAR pDstIP, UCHAR iSrcIndex)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DSHORT iDstPort;

	p_memset_ip_0(pDstIP);
	iDstPort = Sys_iServicePort;

	if (SipGetUri((PXCHAR)Sdram_pDataCache2, iSrcIndex))
	{
		pCur = (PXCHAR)(Sdram_pDataCache2 + SIP_COLON_LABEL_LEN);
		pTemp = p_strchr_x(pCur, '@');
		if (pTemp)	
		{
			pCur = pTemp;
			pCur ++;
		}
		p_String2IP(pCur, pDstIP);
		pTemp = p_strchr_x(pCur, ':');
		if (pTemp)	
		{
			pCur = pTemp;
			pCur ++;
			iDstPort = p_atoi(pCur, 10);
		}
	}
	return iDstPort;
}

/*
void SipGetRemoteId(PXCHAR pRemoteId, UCHAR iSrcIndex)
{
	PXCHAR_D pTemp;
	PXCHAR_D pCur;

	pRemoteId[0] = 0;
	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return;

	pCur = (PXCHAR)Sdram_pDataCache;
	while (*pCur)
	{
		if (!p_memcmp_c2x(pCur, _cSipColon, SIP_COLON_LABEL_LEN))
		{
			pCur += SIP_COLON_LABEL_LEN;
			break;
		}
		pCur ++;
	}

	pTemp = pCur;
	while (*pTemp)
	{
		if (*pTemp == '@' || *pTemp == ':' || *pTemp == ';' || *pTemp == '>')
		{
			pTemp[0] = 0;
			p_strcpy_x2x(pRemoteId, pCur);
			break;
		}
		pTemp ++;
	}
}

USHORT SipGetIPPort(PXCHAR pDstIP, UCHAR iSrcIndex)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DSHORT iDstPort;

	p_memset_ip_0(pDstIP);
	iDstPort = Sys_iServicePort;

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))		
		return iDstPort;

	pCur = (PXCHAR)Sdram_pDataCache;
	pTemp = p_strchr_x(pCur, ';');
	if (pTemp)	pTemp[0] = 0;
	pTemp = p_strchr_x(pCur, '>');
	if (pTemp)	pTemp[0] = 0;

	while (*pCur)
	{
		if (!p_memcmp_c2x(pCur, _cSipColon, SIP_COLON_LABEL_LEN))
		{
			pCur += SIP_COLON_LABEL_LEN;
			pTemp = p_strchr_x(pCur, '@');
			if (pTemp)	
			{
				pCur = pTemp;
				pCur ++;
			}
			p_String2IP(pCur, pDstIP);
			pTemp = p_strchr_x(pCur, ':');
			if (pTemp)	
			{
				pCur = pTemp;
				pCur ++;
				iDstPort = p_atoi(pCur, 10);
			}
			break;
		}
		pCur ++;
	}
	return iDstPort;
}
*/
USHORT SipGetSentby(UCHAR iSrcIndex)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DSHORT iDstPort;

	iDstPort = Sys_iServicePort;
	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return iDstPort;

	pCur = (PXCHAR)Sdram_pDataCache;
	pTemp = p_strchr_x(pCur, ';');
	if (pTemp)	pTemp[0] = 0;
	pTemp = p_strchr_x(pCur, ':');
	if (pTemp)	
	{
		pCur = pTemp;
		pCur ++;
		iDstPort = p_atoi(pCur, 10);
	}
	return iDstPort;
}

void SipGetRouteSet(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	PXCHAR_D pCur;
	DCHAR iLen;
	BOOLEAN bFirst;

	iLen = SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex));
	if (!iLen)	return;

	p_line_backup();
	p_line_start((PXCHAR)Sdram_pDataCache2);
	pCur = (PXCHAR)(Sdram_pDataCache + iLen);
	bFirst = TRUE;
	while (pCur != (PXCHAR)Sdram_pDataCache)
	{
		if (*pCur == ',')
		{
			if (bFirst)
			{
				p_line_add_x((PXCHAR)(pCur + 1));
				bFirst = FALSE;
			}
			else
			{
				p_line_add_comma();
				p_line_add_x((PXCHAR)(pCur + 1));
			}
			*pCur = 0;
		}
		pCur --;
	}
	if (p_strlen_x(pCur))
	{
		if (bFirst)
		{
			p_line_add_x(pCur);
		}
		else
		{
			p_line_add_comma();
			p_line_add_x(pCur);
		}
	}
	p_line_restore();
	SdramSaveString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), (PXCHAR)Sdram_pDataCache2);
}

BOOLEAN SipGetReplaces(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	DCHAR iChar;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	XCHAR pBuf[3];

	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), 0);
	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))		return FALSE;

	pCur = (PXCHAR)Sdram_pDataCache2;
	p_strcpy_x2x(pCur, (PXCHAR)Sdram_pDataCache);
	pTemp = p_strchr_x(pCur, '>');
	if (pTemp)	pTemp[0] = 0;
	
	pTemp = p_strchr_x(pCur, '?');
	while (pTemp)
	{
		pCur = pTemp + 1;
		if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"Replaces=", 9))
		{
			pCur += 9;
			pTemp = (PXCHAR)Sdram_pDataCache;
			while (*pCur)
			{
				iChar = *pCur;
				pCur ++;
				if (iChar == '%')
				{
					p_memcpy_x2x_0(pBuf, pCur, 2);
					iChar = (UCHAR)p_atoi(pBuf, 16);
					pCur += 2;
				}
				*pTemp ++ = iChar;
			}
			*pTemp = 0;
			SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));
			return TRUE;
		}
		pTemp = p_strchr_x(pCur, '&');
	}
	return FALSE;
}

void SipAddBracket(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return;
	p_line_backup();
	p_line_start((PXCHAR)Sdram_pDataCache2);
	p_line_add_char('<');
	p_line_add_x((PXCHAR)Sdram_pDataCache);
	p_line_add_char('>');
	p_line_restore();
	SdramSaveString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), (PXCHAR)Sdram_pDataCache2);
}

void SipRemoveBracket(UCHAR iDstIndex, UCHAR iSrcIndex)
{
	PXCHAR_D pTemp;
	PXCHAR_D pCur;

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
		return;

	pCur = (PXCHAR)Sdram_pDataCache;
	pTemp = p_strchr_x(pCur, '<');
	if (pTemp)
	{
		pCur = pTemp;
		pCur ++;
		pTemp = p_strchr_x(pCur, '>');
		if (pTemp)	pTemp[0] = 0;
	}
	SdramSaveString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex), pCur);
}

BOOLEAN SipParse100rel(UCHAR iIndex)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;

	if (!SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iIndex)))
		return FALSE;

	pCur = (PXCHAR)Sdram_pDataCache;
	do
	{
		pTemp = p_strchr_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		if (p_memcmp_nocase_c2x(pCur, _c100rel, SIP_100REL_LABEL_LEN))
		{
			return TRUE;
		}
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++;
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	return FALSE;
}
/******************************************************************
 **** functions to handle received messages ***********************
 ******************************************************************/
void SipInitRecv()
{
	DCHAR i;

	_iRecvMsgCode = SIP_REQ_UNKNOWN;
	Sip_iRecvMethod = SIP_REQ_UNKNOWN;
	_iState = SIP_STATE_INIT;
	Sip_iRecvViaNum = 0;
	Sip_iBodyLines = 0;
	_iContentLen = 0;
	_iRecvLen = 0;

	for (i = SIP_RECV_CONTACT; i <= SIP_RECV_REFERRED_BY; i ++)
	{
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+i), 0);
	}
}

BOOLEAN _ParseFirstLine()
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;

	if (!_iRecvLen)		return TRUE;

	pCur = _pRecvPacket;
	if (!p_memcmp_c2x(pCur, _cSipVer, SIP_VER_LABEL_LEN-1))
	{
		pCur += SIP_VER_LABEL_LEN;
		_iRecvMsgCode = p_atoi(pCur, 10);
		if (_iRecvMsgCode < 100 || _iRecvMsgCode >= 700)
		{
			OutputString(IDS_SIP_INVALID_RESP);
			return FALSE;
		}
		_bRecvRequest = FALSE;
	}
	else
	{
		_iRecvMsgCode = SipGetMethod(pCur);
		if (_iRecvMsgCode == SIP_REQ_UNKNOWN)
		{
			OutputString(IDS_SIP_UNKNOWN_REQ);
			return FALSE;
		}
		_bRecvRequest = TRUE;
		pCur += _cMethodLen[_iRecvMsgCode];
		pCur ++;
		pTemp = p_strchr_x(pCur, ' ');
		if (!pTemp)	pTemp[0] = 0;
		SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REQUEST_URI, pCur);
	}

	_iState = SIP_STATE_HEADER_BEGIN;
	return TRUE;
}

void _ParseHeader()
{
	PXCHAR_D pCur;
	PXCHAR_D pDst;
	PXCHAR_D pTemp;
	DCHAR iLen, iChar;

	pCur = _pRecvPacket;
	pDst = (PXCHAR)Sdram_pDataCache;

	iLen = 0;
	while (*pCur && *pCur != ' ' && *pCur != ':')
	{
		pDst[iLen] = *pCur;
		iLen ++;
		pCur ++;
	}
	pDst[iLen] = 0;
	if (!iLen)	return;

	p_strcat_c2x(pDst, (PCCHAR)": ");
	pCur += p_count_char(pCur, ':');
	if (iLen == 1)
	{
		iChar = p_toupper(pDst[0]);
		switch(iChar)
		{
		case 'I':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CALL_ID, pCur);
			break;
		case 'M':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CONTACT, pCur);
			break;
		case 'L':
			_iContentLen = p_atoi(pCur, 10);
			break;
		case 'C':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CONTENT_TYPE, pCur);
			break;
		case 'F':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_FROM, pCur);
			break;
		case 'T':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_TO, pCur);
			break;
		case 'R':
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REFER_TO, pCur);
			break;
		case 'V':
			if (Sip_iRecvViaNum < SIP_MAX_RECV_VIA)
			{
				SdramSaveString((USHORT)(PROTOCOL_SDRAM_POS+SIP_RECV_VIA + Sip_iRecvViaNum), pCur);
				Sip_iRecvViaNum ++;
			}
			break;
		}
	}
	else
	{
		if (p_strcmp_nocase_c2x(pDst, _cCallId))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CALL_ID, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cContact))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CONTACT, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, Http_cContentLength))
		{
			_iContentLen = p_atoi(pCur, 10);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, Http_cContentType))
		{	
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CONTENT_TYPE, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cCSeq))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_CSEQ, pCur);
			pTemp = p_strchr_x(pCur, ' ');
			pTemp ++; // pass ' '
			Sip_iRecvMethod = SipGetMethod(pTemp);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cFrom))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_FROM, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cTo))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_TO, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cVia))
		{
			if (Sip_iRecvViaNum < SIP_MAX_RECV_VIA)
			{
				SdramSaveString((USHORT)(PROTOCOL_SDRAM_POS+SIP_RECV_VIA + Sip_iRecvViaNum), pCur);
				Sip_iRecvViaNum ++;
			}
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, Http_cWWWAuthenticate))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_WWW_AUTHENTICATE, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, Http_cProxyAuthenticate))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_PROXY_AUTHENTICATE, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cReferTo))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REFER_TO, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cRecordRoute))
		{
			p_line_backup();
			p_line_start((PXCHAR)Sdram_pDataCache);
			iLen = SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_RECORD_ROUTE);
			if (iLen)
			{
				p_line_update_len();
				p_line_add_comma();
			}
			p_line_add_x(pCur);
			SdramWriteString(PROTOCOL_SDRAM_POS+SIP_RECV_RECORD_ROUTE);
			p_line_restore();
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cReplaces))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REPLACES, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cMinExpires))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_MIN_EXPIRES, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cExpires))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_EXPIRES, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cRequire))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REQUIRE, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cRAck))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_RACK, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cRSeq))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_RSEQ, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cSupported))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_SUPPORTED, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cEvent))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_EVENT, pCur);
			return;
		}
		if (p_strcmp_nocase_c2x(pDst, _cReferredBy))
		{
			SdramSaveString(PROTOCOL_SDRAM_POS+SIP_RECV_REFERRED_BY, pCur);
			return;
		}
	}
}

void _SaveContent()
{
	if (_iRecvLen && (Sip_iBodyLines < SIP_MAX_BODY_LINE))
	{
		SdramSaveData((USHORT)(PROTOCOL_SDRAM_POS+SIP_RECV_BODY + Sip_iBodyLines), _pRecvPacket, _iRecvLen);
		Sip_iBodyLines ++;
	}
}

void _ProcessMsg()
{
	SipGetTag(SIP_RECV_FROM_TAG, SIP_RECV_FROM);
	SipGetTag(SIP_RECV_TO_TAG, SIP_RECV_TO);
	SipGetViaBranch(_bRecvRequest);

	if (_bRecvRequest)
	{
		if (Sip_iRecvMethod == SIP_REQ_ACK)
		{
			SipTUHandleReq(Sip_iRecvMethod);
		}
		else
		{
			SipStRecvReq(Sip_iRecvMethod);
		}
	}
	else
	{
		if (Sip_iRecvViaNum == 1)
		{
			SipCtRecvResp(Sip_iRecvMethod, _iRecvMsgCode);
		}
	}
}

void SipRunData()
{
	DCHAR iNewLine;
	DSHORT iIndex;

	iIndex = 0;
	while (iIndex < Adapter_iReceiveLen)
	{
		iNewLine = p_IsNewLine((PXCHAR)(Adapter_pReceiveUdpData+iIndex));
		if (iNewLine)
		{
			iIndex += iNewLine;
			if (iIndex < Adapter_iReceiveLen && (X_VAL(Adapter_pReceiveUdpData, iIndex) == ' ' || X_VAL(Adapter_pReceiveUdpData, iIndex) == '\t'))
			{
				continue;
			}

			_pRecvPacket[_iRecvLen] = 0;
			if (_iState == SIP_STATE_INIT)
			{
				if (!_ParseFirstLine())
				{
					break;
				}
			}
			else if (_iState == SIP_STATE_HEADER_BEGIN)
			{
				if (_iRecvLen)
				{
					_ParseHeader();
				}
				else 
				{
					if (_iContentLen)
					{
						_iState = SIP_STATE_HEADER_END;
					}
					else
					{
						_ProcessMsg();
						break;
					}
				}
			}
			else if (_iState == SIP_STATE_HEADER_END)
			{
				_SaveContent();
				if (_iContentLen <= iNewLine)
				{
					_iContentLen = 0;
				}
				else
				{
					_iContentLen -= iNewLine;
				}
				if (!_iContentLen)	
				{
					_ProcessMsg();
					break;
				}
			}
			_iRecvLen = 0;
		}
		else
		{
			if (_iRecvLen < MAX_RECV_LEN)
			{
				_pRecvPacket[_iRecvLen] = X_VAL(Adapter_pReceiveUdpData, iIndex);
				_iRecvLen ++;
			}
			iIndex ++;
			if (_iState == SIP_STATE_HEADER_END)
			{
				_iContentLen --;
				if (!_iContentLen)
				{
					_SaveContent();
					_ProcessMsg();
					break;
				}
			}
		}
	}

	SipInitRecv();
}

/**********************************************************************************
****** SIP API functions
***********************************************************************************/
void SipInitDomainName()
{
//	PXCHAR_D pTemp;

	if (!p_strlen_x(Sys_pServiceID))
	{
		p_strcpy_x2x(Sys_pServiceID, Sys_pServiceAddr);
//		pTemp = p_strchr_x(Sys_pServiceID, ':');
//		if (pTemp)
//		{
//			pTemp[0] = 0;
//		}
	}
}

PXCHAR SipGetLocalIP()
{
	if (Sys_iNatTraversal == NAT_TRAVERSAL_DISABLE)
	{
		return Local_pIPAddress;
	}
	else
	{
		return Sys_pProxyIP;
	}
}


 void SipStartup()
{
	Sys_iProtocol = PROTOCOL_SIP;
	Sip_iConnMode = SIP_MODE_SENDRECV;
	Sip_iRegisterPort = Sys_iRegisterPort;
	Sip_iRtpPort = Sys_iRtpPort;

	SipInitDomainName();
	SipTspStartup();
	SipRxStartup();
	SipTransStartup();
	SipInitialize();
	SipInitRecv();
}

 void SipInitialize()
{
	SipSetCallContext(1);
	SipInitCall();
	SipSetCallContext(0);
	SipInitCall();
	Sip_iCurCall = 0;
}

 void SipHandleTimer()
{
	SipCtHandleTimer();
	SipStHandleTimer();
	SipRegHandleTimer();
}

