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

#define SIP_CALL_ID_LEN		16
#define SIP_TAG_LEN			16
#define SIP_BRANCH_LEN		16

CCHAR _cMethod[][9] = 
{
	"INVITE", "ACK", "OPTIONS", "BYE", "CANCEL", "REGISTER", "REFER", "NOTIFY", "INFO", "PRACK", "UPDATE", "MESSAGE"
};

CCHAR _cMethodLen[] = 
{
	6, 3, 7, 3, 6, 8, 5, 6, 4, 5, 6, 7
};

CCHAR Sip_cContentType[][23] = {
	"application/sdp", "message/sipfrag", "application/dtmf-relay"
};

#define RESERVED_CHAR_NUM	10
static CCHAR _cReserved[RESERVED_CHAR_NUM] = {';', '/', '?', ':', '@', '&', '=', '+', '$', ','};

#define BRANCH_LABEL_LEN	14
static CCHAR _cBranch[] = "branch=z9hG4bK";

CCHAR _cEventRefer[] = "refer";
CCHAR _cEventMessage[] = "message-summary";
/*************************************************************************
*************************************************************************/
UCHAR SipGetMethod(PXCHAR pData)
{
	DCHAR i;

	for (i = SIP_REQ_INVITE; i < SIP_REQ_NUMBER; i ++)
	{
		if (!p_memcmp_c2x(pData, _cMethod[i], _cMethodLen[i]))
		{
			return i;
		}
	}
	return SIP_REQ_UNKNOWN;
}

PCCHAR SipGetRespCode(USHORT iResp)
{
	switch (iResp)
	{
	case 100:
		return (PCCHAR)("Trying");
	case 180:
		return (PCCHAR)("Ringing");
	case 181:
		return (PCCHAR)("Call Is Being Forwarded");
	case 182:
		return (PCCHAR)("Queued");
	case 183:
		return (PCCHAR)("Session Progress");
	case 200:
		return (PCCHAR)("OK");
	case 202:
		return (PCCHAR)("Accepted");
	case 300:
		return (PCCHAR)("Multiple Choices");
	case 301:
		return (PCCHAR)("Moved Permanently");
	case 302:
		return (PCCHAR)("Moved Temporarily");
	case 305:
		return (PCCHAR)("Use Proxy");
	case 380:
		return (PCCHAR)("Alternative Service");
	case 400:
		return (PCCHAR)("Bad Request");
	case 401:
		return (PCCHAR)("Unauthorized");
	case 402:
		return (PCCHAR)("Payment Required");
	case 403:
		return (PCCHAR)("Forbidden");
	case 404:
		return (PCCHAR)("Not Found");
	case 405:
		return (PCCHAR)("Method Not Allowed");
	case 406:
		return (PCCHAR)("Not Acceptable");
	case 407:
		return (PCCHAR)("Proxy Authentication Required");
	case 408:
		return (PCCHAR)("Request Timeout");
	case 410:
		return (PCCHAR)("Gone");
	case 413:
		return (PCCHAR)("Request Entity Too Large");
	case 414:
		return (PCCHAR)("Request URI Too Long");
	case 415:
		return (PCCHAR)("Unsupported Media Type");
	case 416:
		return (PCCHAR)("Unsupported URI Scheme");
	case 420:
		return (PCCHAR)("Bad Extension");
	case 421:
		return (PCCHAR)("Extension Required");
	case 423:
		return (PCCHAR)("Interval Too Brief");
	case 480:
		return (PCCHAR)("Temporarily Unavailable");
	case 481:
		return (PCCHAR)("Call/Transaction Does Not Exist");
	case 482:
		return (PCCHAR)("Loop Detected");
	case 483:
		return (PCCHAR)("Too Many Hops");
	case 484:
		return (PCCHAR)("Address Incomplete");
	case 485:
		return (PCCHAR)("Ambiguous");
	case 486:
		return (PCCHAR)("Busy Here");
	case 487:
		return (PCCHAR)("Request Terminated");
	case 488:
		return (PCCHAR)("Not Acceptable Here");
	case 491:
		return (PCCHAR)("Request Pending");
	case 493:
		return (PCCHAR)("Undecipherable");
	case 500:
		return (PCCHAR)("Server Internal Error");
	case 501:
		return (PCCHAR)("Not Implemented");
	case 502:
		return (PCCHAR)("Bad Gateway");
	case 503:
		return (PCCHAR)("Service Unavailable");
	case 504:
		return (PCCHAR)("Server Timeout");
	case 505:
		return (PCCHAR)("Version Not Supported");
	case 513:
		return (PCCHAR)("Message Too Large");
	case 600:
		return (PCCHAR)("Busy Everywhere");
	case 603:
		return (PCCHAR)("Decline");
	case 604:
		return (PCCHAR)("Does Not Exist Anywhere");
	case 606:
		return (PCCHAR)("Not Acceptable");
	default:
		return (PCCHAR)("Unknown Response Code");
	}
}

void SipAppendTag(UCHAR iTagIndex)
{
	DCHAR iLen;

	iLen = SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iTagIndex));
	if (iLen)
	{
		p_line_add_char(';');
		p_line_add_x((PXCHAR)Sdram_pDataCache);
	}
}

BOOLEAN _IsReservedChar(UCHAR iVal)
{
	DCHAR i;

	for (i = 0; i < RESERVED_CHAR_NUM; i ++)
	{
		if (iVal == _cReserved[i])
		{
			return TRUE;
		}
	}
	return FALSE;
}

void SipEscapeStr(PXCHAR pDstStr, PXCHAR pSrcStr)
{
	PXCHAR_D pDst;
	PXCHAR_D pSrc;
	DCHAR iVal;
	XCHAR pEscaped[4];

	pSrc = pSrcStr;
	pDst = pDstStr;
	pDst[0] = 0;
	pEscaped[0] = '%';
	pEscaped[3] = 0;

	while (*pSrc)
	{
		iVal = *pSrc;
		if (_IsReservedChar(iVal))
		{
			pEscaped[1] = p_char2asc((UCHAR)(iVal >> 4), FALSE);
			pEscaped[2] = p_char2asc(iVal, FALSE);
			p_strcat_x2x(pDst, pEscaped);
		}
		else
		{
			p_strcat_char2x(pDst, iVal);
		}
		pSrc ++;
	}
}

PXCHAR SipGetLocalUser()
{
	if (Sys_iServiceType == SIP_SERVICE_TYPE_CALLSERVE)
	{
		return Sys_pAccount;
	}
	else
	{
		return Sys_pLocalNumber;
	}
}
/*************************************************************************
*************************************************************************/
void SipNewNameUri(PXCHAR pDst, PXCHAR pNumber, PXCHAR pName)
{
	p_line_backup();
	p_line_start(pDst);
	if (pName && p_strlen_x(pName))
	{
		p_line_add_char('"');
		p_line_add_x(pName);
		p_line_add_char('"');
		p_line_add_space();
	}
	p_line_add_char('<');
	p_line_add_c(_cSipColon);
	p_line_add_x(pNumber);
	p_line_add_char('@');
	p_line_add_x(Sys_pServiceID);
	p_line_add_char('>');
	p_line_restore();
}

void SipNewIPUri(PXCHAR pDst, PXCHAR pIP, PXCHAR pNumber)
{
	p_line_backup();
	p_line_start(pDst);
	p_line_add_char('<');
	p_line_add_c(_cSipColon);
	if (pNumber && p_strlen_x(pNumber))
	{
		p_line_add_x(pNumber);
		p_line_add_char('@');
	}
	p_line_add_ip(pIP);
	p_line_add_char('>');
	p_line_restore();
}

void SipNewReqNameUri(PXCHAR pDst, PXCHAR pNumber)
{
	p_line_backup();
	p_line_start(pDst);
	p_line_add_c(_cSipColon);
	p_line_add_x(pNumber);
	p_line_add_char('@');
	p_line_add_x(Sys_pServiceID);
	p_line_restore();
}

/*
void SipNewReqIPUri(PXCHAR pDst, PXCHAR pIP)
{
	p_line_backup();
	p_line_start(pDst);
	p_line_add_c(_cSipColon);
	p_line_add_ip(pIP);
	p_line_restore();
}
*/
void SipNewBranch(UCHAR iIndexLow)
{
	p_strcpy_c2x((PXCHAR)Sdram_pDataCache, _cBranch);
	SipNewToken((PXCHAR)(Sdram_pDataCache + BRANCH_LABEL_LEN), SIP_BRANCH_LEN);
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iIndexLow), (UCHAR)(BRANCH_LABEL_LEN + SIP_BRANCH_LEN));
}

void SipNewTag(UCHAR iIndexLow)
{
	p_strcpy_c2x((PXCHAR)Sdram_pDataCache, _cTag);
	SipNewToken((PXCHAR)(Sdram_pDataCache + TAG_LABEL_LEN), SIP_TAG_LEN);
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+iIndexLow), (UCHAR)(TAG_LABEL_LEN + SIP_TAG_LEN));
}

void SipNewCallId(UCHAR iDstIndex)
{
	DCHAR iLen;

	SipNewToken((PXCHAR)Sdram_pDataCache, SIP_CALL_ID_LEN);
	iLen = SIP_CALL_ID_LEN;
	X_VAL(Sdram_pDataCache, iLen) = '@';
	iLen ++;
	p_IP2String(SipGetLocalIP(), (PXCHAR)(Sdram_pDataCache + iLen));
	SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));
}

void SipNewLocalUri(UCHAR iDstIndex)
{
	if (Sys_bUseService)
	{
		SipNewNameUri((PXCHAR)Sdram_pDataCache, SipGetLocalUser(), Sys_pLocalNumber);
	}
	else
	{
		SipNewIPUri((PXCHAR)Sdram_pDataCache, SipGetLocalIP(), SipGetLocalUser());
	}
	SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));
}

void SipFillReqLine(UCHAR iMethod, UCHAR iUriIndex)
{
//	Sip_iSendLen = 0;
	p_line_start(Sip_pDataOut);
	p_line_add_c(_cMethod[iMethod]);
	p_line_add_space();
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iUriIndex));
	p_line_add_space();
	p_line_add_c(_cSipVer);
	p_line_add_newline();
}

void SipFillStatusLine(USHORT iResp)
{
//	Sip_iSendLen = 0;
	p_line_start(Sip_pDataOut);
	p_line_add_c(_cSipVer);
	p_line_add_space();
	p_line_add_val(iResp);
	p_line_add_space();
	p_line_add_c(SipGetRespCode(iResp));
	p_line_add_newline();
}

void SipFillVia(UCHAR iBranchIndex)
{
	p_line_add_c(_cVia);
	p_line_add_c(_cSipVer);
	p_line_add_char('/');
	if (Sip_bUsingUdp)
	{
		p_line_add_c((PCCHAR)"UDP");
	}
	else
	{
		p_line_add_c((PCCHAR)"TCP");
	}
	p_line_add_space();

	p_line_add_ip(SipGetLocalIP());
	p_line_add_char(':');
	p_line_add_val(Sip_iRegisterPort);
	p_line_add_char(';');
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iBranchIndex));
	p_line_add_c((PCCHAR)";rport");
	p_line_add_newline();
}

void SipFillFrom(UCHAR iUriIndex, UCHAR iTagIndex)
{
	p_line_add_c(_cFrom);
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iUriIndex));
	SipAppendTag(iTagIndex);
	if (Sys_iServiceType == SIP_SERVICE_TYPE_MEDIARING)
	{
		p_line_add_c((PCCHAR)";auth=1");
	}
	p_line_add_newline();
}

void SipFillTo(UCHAR iUriIndex, UCHAR iTagIndex)
{
	p_line_add_c(_cTo);
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iUriIndex));
	SipAppendTag(iTagIndex);
	p_line_add_newline();
}

void SipFillReferTo(UCHAR iUriIndex)
{
	p_line_add_c(_cReferTo);
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iUriIndex));
	p_line_add_newline();
}

void SipFillReferredBy()
{
	p_line_add_c(_cReferredBy);
	p_line_add_char('<');
	p_line_add_c(_cSipColon);
	if (Sys_bUseService || IsValidIP(Sys_pGWIP))
	{
		p_line_add_x(SipGetLocalUser());
		p_line_add_char('@');
		p_line_add_x(Sys_pServiceID);
	}
	else
	{
		p_line_add_ip(SipGetLocalIP());
		p_line_add_char(':');
		p_line_add_val(Sip_iRegisterPort);
	}
		p_line_add_char('>');
	p_line_add_newline();
}

void SipFillCallId(UCHAR iCallIdIndex)
{
	p_line_add_c(_cCallId);
	p_line_add_p((USHORT)(PROTOCOL_SDRAM_POS+iCallIdIndex));
	p_line_add_newline();
}

void SipFillContact()
{
	p_line_add_c(_cContact);
	p_line_add_char('<');
	p_line_add_c(_cSipColon);
	if (Sys_bUseService || IsValidIP(Sys_pGWIP))
	{
		if (p_strlen_x(SipGetLocalUser()))
		{
			p_line_add_x(SipGetLocalUser());
			p_line_add_char('@');
		}
	}
	p_line_add_ip(SipGetLocalIP());
	p_line_add_char(':');
	p_line_add_val(Sip_iRegisterPort);
	p_line_add_char('>');
	p_line_add_newline();
}

void SipFillFwdContact()
{
	p_line_add_c(_cContact);
	p_line_add_char('<');
	p_line_add_c(_cSipColon);
	if (Sys_bUseService || IsValidIP(Sys_pGWIP))
	{
		p_line_add_x(Sys_pForwardNumber);
		p_line_add_char('@');
		p_line_add_x(Sys_pServiceID);
	}
	else
	{
		p_line_add_x(Sys_pForwardNumber);
	}
	p_line_add_char('>');
	p_line_add_newline();
}

void SipFillCSeq(ULONG lSeq, UCHAR iMethod)
{
	p_line_add_c(_cCSeq);
	p_line_add_long(lSeq);
	p_line_add_space();
	p_line_add_c(_cMethod[iMethod]);
	p_line_add_newline();
}

void SipFillMaxForwards()
{
	p_line_add_c((PCCHAR)"Max-Forwards: 70");
	p_line_add_newline();
}

void SipFillExpires(USHORT iVal)
{
	p_line_add_c(_cExpires);
	p_line_add_val(iVal);
	p_line_add_newline();
}

void SipFillContentLength(USHORT iLen)
{
	p_line_add_c(Http_cContentLength);
	p_line_add_val(iLen);
	p_line_add_newline();
}

void SipFillContentType(UCHAR iType)
{
	p_line_add_c(Http_cContentType);
	p_line_add_c(Sip_cContentType[iType]);
	p_line_add_newline();
}

void SipFillAllow()
{
	DCHAR i;
	p_line_add_c(_cAllow);
	for (i = SIP_REQ_INVITE; i < SIP_REQ_NUMBER-1; i ++)
	{
		if (i != SIP_REQ_REGISTER)
		{
			p_line_add_c(_cMethod[i]);
			p_line_add_comma();
		}
	}
	p_line_add_c(_cMethod[i]);
	p_line_add_newline();
}

void SipFillUserAgent()
{
	p_line_add_c(Http_cUserAgent);
	p_line_add_colon();
	TaskUserData(SIP_USER_AGENT, p_line_get_buf());
	p_line_add_newline();
}

void SipFillAccept()
{
	p_line_add_c(Http_cAccept);
	p_line_add_colon();
	p_line_add_c(Sip_cContentType[SIP_CTYPE_SDP]);
	p_line_add_comma();
	p_line_add_c(Sip_cContentType[SIP_CTYPE_SIPFRAG]);
	p_line_add_comma();
	p_line_add_c(Sip_cContentType[SIP_CTYPE_DTMF]);
	p_line_add_newline();
}

void SipFillSupported()
{
	p_line_add_c(_cSupported);
	if (Sys_iCallType & SIP_PRACK_OR)
	{
		p_line_add_c(_c100rel);
		p_line_add_comma();
	}
	p_line_add_c((PCCHAR)"replaces");
	p_line_add_newline();
}

void SipFillRequire()
{
	p_line_add_c(_cRequire);
	p_line_add_c(_c100rel);
	p_line_add_newline();
}

void SipFillProxyRequire()
{
	if (Sys_iServiceType == SIP_SERVICE_TYPE_NORTEL)
	{
		p_line_add_c((PCCHAR)"Proxy-Require: com.nortelnetworks.firewall");
		p_line_add_newline();
	}
}

void SipFillRAck(ULONG lRSeq, ULONG lCSeq)
{
	p_line_add_c(_cRAck);
	p_line_add_long(lRSeq);
	p_line_add_space();
	p_line_add_long(lCSeq);
	p_line_add_space();
	p_line_add_c(_cMethod[SIP_REQ_INVITE]);
	p_line_add_newline();
}

void SipFillEvent(UCHAR iEventType)
{
	p_line_add_c((PCCHAR)_cEvent);
	switch (iEventType)
	{
	case SIP_EVENT_REFER:
		p_line_add_c(_cEventRefer);
		break;
	case SIP_EVENT_MESSAGE:
		p_line_add_c(_cEventMessage);
		break;
	}
	p_line_add_newline();
}

void SipFillSdp(BOOLEAN bOffer)
{
	DSHORT iLen;

	p_line_backup();			// backup because SipNewSdp will use p_line_xxxx functions
	iLen = SipNewSdp(SIP_TEMP_BUF, bOffer);
	p_line_restore();	// restore

	SipFillContentType(SIP_CTYPE_SDP);
	SipFillContentLength(iLen);
	p_line_add_newline();

	SdramReadAll(PROTOCOL_SDRAM_POS+SIP_TEMP_BUF);
	p_wmemcpy_x2x(p_line_get_buf(), (PXCHAR)Sdram_pDataCache, (USHORT)(iLen+1));
	p_line_inc_len(iLen);
}

