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

/**********************************************************************************
***********************************************************************************/
void _AckFinalResp(USHORT iResp)
{
	SipNewTag(SIP_TEMP_BUF);
	SipFillFinalResp(iResp, SIP_TEMP_BUF);
	SipAckFinalResp();
}

/**********************************************************************************
***** RFC3262   100rel ************************************************************
***********************************************************************************/
void SipUasInit100rel(UCHAR iRSeqIndex)
{
	DLONG lCSeq, lRSeq;

	lRSeq = (ULONG)p_rand();
	SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_CSEQ);
	lCSeq = p_atol((PXCHAR)Sdram_pDataCache, 10);
	ULONG2PUCHAR(lRSeq, (PUCHAR)(PXCHAR)Sdram_pDataCache);
	ULONG2PUCHAR(lCSeq, (PUCHAR)((PXCHAR)Sdram_pDataCache+REL100_DATA_CSEQ));
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO), REL100_DATA_LEN);

	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_c(_cRSeq);
	p_line_add_long(lRSeq);
	p_line_add_newline();
	SdramWriteString((USHORT)(PROTOCOL_SDRAM_POS+iRSeqIndex));
}

BOOLEAN SipUasCmp100rel()
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DLONG lRSeq, lCSeq;

	if (!SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO)))
		return FALSE;
	lRSeq = PXCHAR2ULONG((PXCHAR)Sdram_pDataCache);
	lCSeq = PXCHAR2ULONG((PXCHAR)(Sdram_pDataCache+REL100_DATA_CSEQ));

	if (!SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_RACK))
		return FALSE;

	// Compare response-num
	pCur = (PXCHAR)Sdram_pDataCache;
	pTemp = p_strchr_x(pCur, ' ');
	if (pTemp)	pTemp[0] = 0;
	else		return FALSE;
	if (p_atol(pCur, 10) != lRSeq)
		return FALSE;
	// Compare CSeq num
	pCur = pTemp;
	pCur ++;
	pCur += p_count_space(pCur);
	if (p_atol(pCur, 10) != lCSeq)
		return FALSE;
	return TRUE;
}

void SipUacInit100rel()
{
	DLONG lCSeq, lRSeq;

	SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_RSEQ);
	lRSeq = p_atol((PXCHAR)Sdram_pDataCache, 10);
	SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_CSEQ);
	lCSeq = p_atol((PXCHAR)Sdram_pDataCache, 10);
	ULONG2PUCHAR(lRSeq, (PUCHAR)(PXCHAR)Sdram_pDataCache);
	ULONG2PUCHAR(lCSeq, (PUCHAR)((PXCHAR)Sdram_pDataCache+REL100_DATA_CSEQ));
	SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO), REL100_DATA_LEN);
}

BOOLEAN SipUacCmp100rel()
{
	DLONG lRSeq, lCSeq;

	SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_RSEQ);
	lRSeq = p_atol((PXCHAR)Sdram_pDataCache, 10);
	SdramReadString(PROTOCOL_SDRAM_POS+SIP_RECV_CSEQ);
	lCSeq = p_atol((PXCHAR)Sdram_pDataCache, 10);

	SdramReadData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO));
	if (lCSeq == PXCHAR2ULONG((PXCHAR)(Sdram_pDataCache+REL100_DATA_CSEQ)) && lRSeq == (ULONG)(PXCHAR2ULONG((PXCHAR)Sdram_pDataCache) + 1))
	{
		ULONG2PUCHAR(lRSeq, (PUCHAR)(PXCHAR)Sdram_pDataCache);
		SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+Sip_iBaseIndex + SIP_CALL_100REL_INFO), REL100_DATA_LEN);
		return TRUE;
	}
	return FALSE;
}
/**********************************************************************************
***********************************************************************************/
void SipTUHandleTxError(UCHAR iMethod, UCHAR iTransNo)
{
	DCHAR iCallIndex;

	OutputString(IDS_SIP_RETRANS_FAILED);
	DebugCString(_cMethod[iMethod]);
	switch (iMethod)
	{
	case SIP_REQ_REGISTER:
		SipRegHandleTxError();
		break;

	case SIP_REQ_INVITE:
		iCallIndex = SipMatchInvTrans(iTransNo);
		if (iCallIndex < 2)	
		{
			SipSetCallContext(iCallIndex);
			SipCallEnd(SIP_SIGNAL_BUSY);
			SipTransferNotify(503);
			SipTransfertoClear();
		}
		break;

	case SIP_REQ_BYE:
		SipCallEnd(SIP_SIGNAL_BUSY);
		break;

	case SIP_REQ_CANCEL:
		SipCallEnd(SIP_SIGNAL_BUSY);
		break;

	case SIP_REQ_REFER:
		SipCallEnd(SIP_SIGNAL_BUSY);
		break;

	case SIP_REQ_NOTIFY:
		SipCallEnd(SIP_SIGNAL_BUSY);
		break;
	}
}

BOOLEAN SipTUHandleResp(UCHAR iVal, USHORT iRespVal)
{
	DCHAR iMethod;
	DSHORT iResp;

	iMethod = iVal;
	iResp = iRespVal;

	if (iMethod == SIP_REQ_REGISTER)
	{
		SipRegHandleResp(iResp);
		return TRUE;
	}

	if (SipMatchCall(0))	
	{
		SipSetCallContext(0);
	}
	else if (SipMatchCall(1))
	{
		SipSetCallContext(1);
	}
	else
	{
		return FALSE;
	}

	switch(iMethod)
	{
	case SIP_REQ_INVITE:
		SipCallInvResp(iResp);
		break;
	case SIP_REQ_REFER:
		SipCallRefResp(iResp);
		break;
	case SIP_REQ_BYE:
		SipCallByeResp(iResp);
		break;
	case SIP_REQ_CANCEL:
		SipCallCancelResp(iResp);
		break;
	case SIP_REQ_PRACK:
		SipCallPrackResp(iResp);
		break;
	case SIP_REQ_NOTIFY:
		SipCallNotifyResp(iResp);
		break;
	}

	return TRUE;
}

void SipTUHandleReq(UCHAR iVal)
{
	DCHAR iCallIndex, iMethod;

	iMethod = iVal;
	if (iMethod == SIP_REQ_OPTIONS)
	{
		if (SipCallAllIdle())
		{
			SipOptionsResp(200);
		}
		else
		{
			SipOptionsResp(486);
		}
		return;
	}

	if (iMethod == SIP_REQ_NOTIFY)
	{
		SipNotifyReq();
		return;
	}

	if (iMethod == SIP_REQ_MESSAGE)
	{
		SipMessageReq();
		return;
	}

	if (SipMatchCall(0))		
	{
		iCallIndex = 0;
		SipSetCallContext(iCallIndex);
	}
	else if (SipMatchCall(1))	
	{
		iCallIndex = 1;
		SipSetCallContext(iCallIndex);
	}
	else
	{
		iCallIndex = 2;
	}

	switch(iMethod)
	{
	case SIP_REQ_INVITE:
		if (iCallIndex < 2)
		{
			SipCallReinvReq();
		}
		else
		{
			if (SipCallAllIdle())
			{
				Sip_iCurCall = 0;
				SipSetCallContext(0);
				SipCallInvReq();
			}
			else
			{
				if (SipCallIsIdle(0))
				{
					SipSetCallContext(0);
					SipCallInvReq();
				}
				else if (SipCallIsIdle(1))
				{
					SipSetCallContext(1);
					SipCallInvReq();
				}
				else
				{
					_AckFinalResp(486);
				}
			}
		}
		break;

	case SIP_REQ_ACK:
		if (iCallIndex < 2)
		{
			SipCallAckReq();
		}
		break;

	case SIP_REQ_BYE:
		if (iCallIndex < 2)
		{
			SipCallByeReq();
		}
		else
		{
			_AckFinalResp(481);
		}
		break;

	case SIP_REQ_CANCEL:
		if (iCallIndex < 2)
		{
			SipCallCanReq();
		}
		else
		{
			_AckFinalResp(481);
		}
		break;

	case SIP_REQ_REFER:
		if (iCallIndex < 2)
		{
			SipCallRefReq();
		}
		else
		{
			_AckFinalResp(488);
		}
		break;

	case SIP_REQ_INFO:
		if (iCallIndex < 2)
		{
			SipCallInfoReq();
		}
		else
		{
			_AckFinalResp(481);
		}
		break;

	case SIP_REQ_PRACK:
		if (iCallIndex < 2)
		{
			SipCallPrackReq();
		}
		else
		{
			_AckFinalResp(481);
		}
		break;

	case SIP_REQ_UPDATE:
		if (iCallIndex < 2)
		{
			SipCallUpdateReq();
		}
		else
		{
			_AckFinalResp(481);
		}
		break;
	}
}
