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

static XCHAR _pViaNum[2];
static CCHAR _cBaseIndex[2][5] = 
{
	{SIP_INV0_VIA, SIP_INV0_FROM, SIP_INV0_TO, SIP_INV0_CALL_ID, SIP_INV0_CSEQ},
	{SIP_INV1_VIA, SIP_INV1_FROM, SIP_INV1_TO, SIP_INV1_CALL_ID, SIP_INV1_CSEQ}
};

void SipSaveInv(UCHAR iInv)
{
	DCHAR i, iIndex;

	iIndex = iInv;
	_pViaNum[iIndex] = Sip_iRecvViaNum;
	for (i = 0; i < Sip_iRecvViaNum; i ++)
	{
		SipCpySdram((UCHAR)(_cBaseIndex[iIndex][0] + i), (UCHAR)(SIP_RECV_VIA + i));
	}
	SipCpySdram(_cBaseIndex[iIndex][1], SIP_RECV_FROM);
	SipCpySdram(_cBaseIndex[iIndex][2], SIP_RECV_TO);
	SipCpySdram(_cBaseIndex[iIndex][3], SIP_RECV_CALL_ID);
	SipCpySdram(_cBaseIndex[iIndex][4], SIP_RECV_CSEQ);
}

void SipLoadInv(UCHAR iInv)
{
	DCHAR i, iIndex;

	iIndex = iInv;
	Sip_iRecvViaNum = _pViaNum[iIndex];
	for (i = 0; i < Sip_iRecvViaNum; i ++)
	{
		SipCpySdram((UCHAR)(SIP_RECV_VIA + i), (UCHAR)(_cBaseIndex[iIndex][0] + i));
	}
	SipCpySdram(SIP_RECV_FROM, _cBaseIndex[iIndex][1]);
	SipCpySdram(SIP_RECV_TO, _cBaseIndex[iIndex][2]);
	SipCpySdram(SIP_RECV_CALL_ID, _cBaseIndex[iIndex][3]);
	SipCpySdram(SIP_RECV_CSEQ, _cBaseIndex[iIndex][4]);
	SdramWriteData(PROTOCOL_SDRAM_POS+SIP_RECV_TO_TAG, 0);
}

/*************************************************************************************
 *** Request  ************************************************************************
 ************************************************************************************/
void _FillHeaderFromSdram(PCCHAR pHeader, UCHAR iSrcIndex)
{
	if (SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iSrcIndex)))
	{
		p_line_add_c(pHeader);
		p_line_add_x((PXCHAR)Sdram_pDataCache);
		p_line_add_newline();
	}
}

void _FillCommonHeader()
{
	SipFillVia(SIP_CUR_BRANCH);
	_FillHeaderFromSdram(_cRoute, (UCHAR)(Sip_iBaseIndex + SIP_CALL_ROUTE_HEADER));
	SipFillMaxForwards();
	SipFillUserAgent();
	SipFillFrom((UCHAR)(Sip_iBaseIndex + SIP_CALL_LOCAL_URI), (UCHAR)(Sip_iBaseIndex + SIP_CALL_LOCAL_TAG));
	SipFillTo((UCHAR)(Sip_iBaseIndex + SIP_CALL_REMOTE_URI), (UCHAR)(Sip_iBaseIndex + SIP_CALL_REMOTE_TAG));
	SipFillCallId((UCHAR)(Sip_iBaseIndex + SIP_CALL_CALL_ID));
	SipFillContact();
	SipFillProxyRequire();
	SipFillAuth();
}

void _PrepareAuth(UCHAR iMethod)
{
	HttpClearAuth();
	if (SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_WWW_AUTH)))
	{
		SipGenAuth(iMethod, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI), (UCHAR)(Sip_iBaseIndex + SIP_CALL_WWW_AUTH), HTTP_AUTH_TYPE_WWW);
	}
	if (SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_PROXY_AUTH)))
	{
		SipGenAuth(iMethod, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI), (UCHAR)(Sip_iBaseIndex + SIP_CALL_PROXY_AUTH), HTTP_AUTH_TYPE_PROXY);
	}
}

void SipFillInv(BOOLEAN bReInvite)
{
	_PrepareAuth(SIP_REQ_INVITE);
	SipFillReqLine(SIP_REQ_INVITE, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));

	SipNewBranch(SIP_CUR_BRANCH);
	SipCpySdram((UCHAR)(Sip_iBaseIndex + SIP_CALL_INV_BRANCH), SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_INVITE);
	// CNC's bullshit system can't handle Allow header, so mark this out here
//	SipFillAllow();
	SipFillSupported();
	if (bReInvite)
	{
		SipFillSdp(FALSE);
	}
	else
	{
		_FillHeaderFromSdram(_cReplaces, SIP_CALL_REPLACES);
		_FillHeaderFromSdram(_cReferredBy, SIP_CALL_REFERRED_BY);
		SipFillSdp(TRUE);
	}
}

void SipFillAck(BOOLEAN bSuccess)
{
	_PrepareAuth(SIP_REQ_ACK);
	if (bSuccess)
	{
		SipFillReqLine(SIP_REQ_ACK, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));
		SipNewBranch(SIP_CUR_BRANCH);
	}
	else
	{
		SipRemoveBracket(SIP_TEMP_BUF, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REMOTE_URI));
		SipFillReqLine(SIP_REQ_ACK, SIP_TEMP_BUF);
		SipCpySdram(SIP_CUR_BRANCH, (UCHAR)(Sip_iBaseIndex + SIP_CALL_INV_BRANCH));
	}
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_INV_SEQ], SIP_REQ_ACK);
	SipFillContentLength(0);
	p_line_add_newline();
}

void SipFillBye()
{
	_PrepareAuth(SIP_REQ_BYE);
	SipFillReqLine(SIP_REQ_BYE, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));

	SipNewBranch(SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_BYE);
	SipFillContentLength(0);
	p_line_add_newline();
}

void SipFillCancel()
{
	_PrepareAuth(SIP_REQ_CANCEL);
	SipRemoveBracket(SIP_TEMP_BUF, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REMOTE_URI));
	SipFillReqLine(SIP_REQ_CANCEL, SIP_TEMP_BUF);

	SipCpySdram(SIP_CUR_BRANCH, (UCHAR)(Sip_iBaseIndex + SIP_CALL_INV_BRANCH));
	SipFillVia(SIP_CUR_BRANCH);
	SipFillMaxForwards();
	SipFillUserAgent();
	SipFillFrom((UCHAR)(Sip_iBaseIndex + SIP_CALL_LOCAL_URI), (UCHAR)(Sip_iBaseIndex + SIP_CALL_LOCAL_TAG));
	SdramWriteData(PROTOCOL_SDRAM_POS+SIP_TEMP_BUF, 0);
	SipFillTo((UCHAR)(Sip_iBaseIndex + SIP_CALL_REMOTE_URI), SIP_TEMP_BUF);
	SipFillCallId((UCHAR)(Sip_iBaseIndex + SIP_CALL_CALL_ID));
	SipFillContact();
	SipFillAuth();
	SipFillCSeq(Sip_pCallData[CALL_INFO_INV_SEQ], SIP_REQ_CANCEL);
	SipFillContentLength(0);
	p_line_add_newline();
}

void SipFillRefer()
{
	_PrepareAuth(SIP_REQ_REFER);
	SipFillReqLine(SIP_REQ_REFER, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));

	SipNewBranch(SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_REFER);
	SipFillReferTo(SIP_CUR_REFER_TO);
	SipFillReferredBy();
	SipFillContentLength(0);
	p_line_add_newline();
}

UCHAR _NewDtmfRelay(UCHAR iKey, UCHAR iDstIndex)
{
	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_c((PCCHAR)"Signal=");
	p_line_add_char(iKey);
	p_line_add_newline();
	p_line_add_c((PCCHAR)"Duration=200");
	p_line_add_newline();
	return SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));
}

void SipFillInfo(UCHAR iKey)
{
	DCHAR iLen;

	_PrepareAuth(SIP_REQ_INFO);
	SipFillReqLine(SIP_REQ_INFO, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));
	SipNewBranch(SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_INFO);

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

	SipFillContentType(SIP_CTYPE_DTMF);
	SipFillContentLength(iLen);
	p_line_add_newline();
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_TEMP_BUF);
}

UCHAR _NewNotifyBody(USHORT iNotifyCode, UCHAR iDstIndex)
{
	DSHORT iCode;

	iCode = iNotifyCode;
	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_c(_cSipVer);
	p_line_add_space();
	p_line_add_val(iCode);
	p_line_add_space();
	p_line_add_c(SipGetRespCode(iCode));
	p_line_add_newline();
	return SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iDstIndex));
}

void SipFillNotify(USHORT iCode)
{
	DCHAR iLen;

	_PrepareAuth(SIP_REQ_NOTIFY);
	SipFillReqLine(SIP_REQ_NOTIFY, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));
	SipNewBranch(SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_NOTIFY);
	SipFillEvent(SIP_EVENT_REFER);

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

	SipFillContentType(SIP_CTYPE_SIPFRAG);
	SipFillContentLength(iLen);
	p_line_add_newline();
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_TEMP_BUF);
}

void SipFillPrack()
{
	DLONG lRSeq, lCSeq;

	_PrepareAuth(SIP_REQ_PRACK);
	SipFillReqLine(SIP_REQ_PRACK, (UCHAR)(Sip_iBaseIndex + SIP_CALL_REQUEST_URI));

	SipNewBranch(SIP_CUR_BRANCH);
	_FillCommonHeader();
	SipFillCSeq(Sip_pCallData[CALL_INFO_CUR_SEQ], SIP_REQ_PRACK);

	SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO));
	lRSeq = PXCHAR2ULONG((PXCHAR)Sdram_pDataCache);
	lCSeq = PXCHAR2ULONG((PXCHAR)(Sdram_pDataCache+REL100_DATA_CSEQ));
	SipFillRAck(lRSeq, lCSeq);

	SipFillContentLength(0);
	p_line_add_newline();
}
/*************************************************************************************
 *** Response ************************************************************************
 ************************************************************************************/
void _FillRespTo(UCHAR iTagIndex)
{
	p_line_add_c(_cTo);
	p_line_add_p(PROTOCOL_SDRAM_POS+SIP_RECV_TO);
	if (!SdramReadData(PROTOCOL_SDRAM_POS+SIP_RECV_TO_TAG))
	{
		SipAppendTag(iTagIndex);
	}
	p_line_add_newline();
}

void _FillRespVia()
{
	DCHAR i;

	for (i = 0; i < Sip_iRecvViaNum; i ++)
	{
		_FillHeaderFromSdram(_cVia, (UCHAR)(i + SIP_RECV_VIA));
	}
}

void _FillRespCommonHeader()
{
	_FillRespVia();
	_FillHeaderFromSdram(_cRecordRoute, SIP_RECV_RECORD_ROUTE);
	_FillHeaderFromSdram(_cCallId, SIP_RECV_CALL_ID);
	_FillHeaderFromSdram(_cCSeq, SIP_RECV_CSEQ);
	_FillHeaderFromSdram(_cFrom, SIP_RECV_FROM);
}

void SipFill2xxSdp(BOOLEAN bOffer)
{
	SipFillStatusLine(200);
	_FillRespCommonHeader();
	_FillRespTo((UCHAR)(Sip_iBaseIndex + SIP_CALL_LOCAL_TAG));
	SipFillContact();
	SipFillAllow();
	SipFillSupported();
	SipFillSdp(bOffer);
}

/* Fill Final Response 2xx-6xx */
void SipFillFinalResp(USHORT iResp, UCHAR iTagIndex)
{
	SipFillStatusLine(iResp);
	_FillRespCommonHeader();
	_FillRespTo(iTagIndex);
	if(iResp == 302)
	{
		SipFillFwdContact();
	}
	else
	{
		SipFillContact();
	}
	SipFillContentLength(0);
	p_line_add_newline();
}

void SipFill180(UCHAR iTagIndex, UCHAR iRSeqIndex)
{
	SipFillStatusLine(180);
	_FillRespCommonHeader();
	_FillRespTo(iTagIndex);
	if (SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+iRSeqIndex)))
	{
		p_line_add_x((PXCHAR)Sdram_pDataCache);
		SipFillRequire();
	}
	SipFillContact();
	if (Sys_iServiceType == SIP_SERVICE_TYPE_ITALKBB)
	{
		SipFillSdp(FALSE);
	}
	else
	{
		SipFillContentLength(0);
		p_line_add_newline();
	}

//	SipFillSdp(FALSE);
}

void SipOptionsResp(USHORT iResp)
{
	OutputString(IDS_SIP_OPTION_REQ);

	SipFillStatusLine(iResp);
	_FillRespCommonHeader();
	SipNewTag(SIP_TEMP_BUF);
	_FillRespTo(SIP_TEMP_BUF);
	SipFillContact();
	SipFillAllow();
	SipFillAccept();
	SipFillSupported();
	SipFillSdp(TRUE);

	SipAckFinalResp();
}
