#include "p_apps.h"
#include "p_mgcp.h"
#include "v_task.h"
#include "my_mgcp.h"

#define MGCP_MAX_SEND_LEN		(1024 - UDP_DATA)
#define MGCP_REG_TTL	60

#define MGCP_STATE_INIT				0
#define MGCP_STATE_HEADER_BEGIN		1
#define MGCP_STATE_HEADER_END		2

#define MGCP_ACTION_NOTIF		1
#define MGCP_ACTION_ACCUM		2
#define MGCP_ACTION_ACCDI		4
#define MGCP_ACTION_KESIA		8
#define MGCP_ACTION_EMBNO		16
#define MGCP_ACTION_IGNOR		32
#define MGCP_ACTION_SWAP		64

#define MGCP_DOMAIN_NAME_LEN	32
#define MGCP_CALL_ID_LEN		32
#define MGCP_CONN_ID_LEN		32
#define MGCP_REQ_EVENT_NUM		22
#define MGCP_ACCDI_BUF_SIZE		32
#define MGCP_ACCUM_BUF_SIZE		64
#define MGCP_REQ_INFO_NUM		24

 DCHAR Mgcp_iConnMode;

DSHORT Mgcp_iSendLen;
XSHORT Mgcp_iRecvMsgType;

//static XCHAR _pDomainName[MGCP_DOMAIN_NAME_LEN+1];
#define Sys_pDomainName	Sys_pPin

static XCHAR _pReqEventList[MGCP_REQ_EVENT_NUM];
static DCHAR _iAccDigitNum;
static XCHAR _pAccDigitBuf[MGCP_ACCDI_BUF_SIZE];

static XSHORT _iRegTimer;
static XSHORT _iNatTimer;
static DCHAR _iRecvSdpNum;
static XSHORT _iDigitMapLen;
static XLONG _lRecvTransId;
static XLONG _lLocalTransId;
static BOOLEAN _bRecvDigitMap;
static BOOLEAN _bWildCarded;
static BOOLEAN _bHookUp;

DSHORT _iCncHbTTL;

#define VERB_LABEL_LEN		4
static CCHAR _cVerb[MGCP_VERB_NUM][VERB_LABEL_LEN + 1] = 
{
	"EPCF", "CRCX", "MDCX", "DLCX", "RQNT",
	"NTFY", "AUEP", "AUCX", "RSIP"
};

static CCHAR _cRsipMethod[][16] = 
{
	"graceful", "forced", "restart", "disconnected", "cancel-graceful"
};

#define CONN_MODE_LEN	8
static CCHAR _cConnMode[MGCP_MODE_UNKNOWN][CONN_MODE_LEN + 1] = 
{
	"sendonly", "recvonly", "sendrecv", "confrnce",
	"inactive", "loopback", "conttest", "netwloop",
	"netwtest"
};

static CCHAR _cReqEvent[MGCP_REQ_EVENT_NUM][5] = 
{
	"D/0", "D/1", "D/2", "D/3", "D/4", "D/5", "D/6", "D/7", 
	"D/8", "D/9", "D/*", "D/#", "D/T", "D/A", "D/B", "D/C", 
	"D/D", "D/L", "L/HD", "L/HU", "L/HF", "L/OC"
};

/**************************************************************************
****** accesary functions *************************************************
***************************************************************************/
void _InsertEndpointId(BOOLEAN bWildCard)
{
	if (bWildCard)
		p_line_add_char('*');
	else
		p_line_add_x(Sys_pAccount);
	if (p_strlen_x(Sys_pDomainName))
	{
		p_line_add_char('@');
		p_line_add_x(Sys_pDomainName);
	}
}

void _IncLocalTransId()
{
	_lLocalTransId ++;
	if (_lLocalTransId > 999999999)
		_lLocalTransId = 1;
}

void _EmptyReqEventList()
{
	DCHAR i;

	for (i = 0; i < MGCP_REQ_EVENT_NUM; i ++)
	{
		_pReqEventList[i] = MGCP_ACTION_IGNOR;
	}
}
/******************************************************************
 **** functions to send out messages ******************************
 ******************************************************************/

void MgcpCommandLine(UCHAR iCode, BOOLEAN bWildCard)
{
	p_line_start((PXCHAR)Adapter_pSendUdpData);
	p_line_add_c(_cVerb[iCode]);
	p_line_add_space();
	p_line_add_long(_lLocalTransId);
	p_line_add_space();
	_InsertEndpointId(bWildCard);
	p_line_add_c((PCCHAR)" MGCP 1.0");
	p_line_add_newline();
}

void _ResponseLine(USHORT iCode, PCCHAR pComment)
{
	p_line_start((PXCHAR)Adapter_pSendUdpData);
	p_line_add_val(iCode);
	p_line_add_space();
	p_line_add_long(_lRecvTransId);
	p_line_add_space();
	p_line_add_c(pComment);
	p_line_add_newline();
}

void _SpecificEndpointId()
{
	p_line_add_char('Z');
	p_line_add_colon();
	_InsertEndpointId(FALSE);
	p_line_add_newline();
}

void _ConnectionId()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_I);
	if (iLen)
	{
		SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_I_BACKUP, iLen);
	}
	p_line_backup();
	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_char('I');
	p_line_add_colon();
	_NewToken(p_line_get_buf(), 16);	//	MGCP_CONN_ID_LEN
	p_line_update_len();
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_I);
	p_line_restore();

	p_line_add_x((PXCHAR)Sdram_pDataCache);
	p_line_add_newline();
}

void _ConnectionMode()
{
	p_line_add_char('M');
	p_line_add_colon();
	p_line_add_c(_cConnMode[Mgcp_iConnMode]);
	p_line_add_newline();
}

void _RestartMethod(UCHAR iMethod)
{
	if (iMethod == MGCP_RSIP_CNC_SPECIAL)
	{
		p_line_add_c((PCCHAR)"RM: hb ");
		p_line_add_ip(Local_pIPAddress);
		p_line_add_space();
		p_line_add_val(Sys_iRegisterPort);
		p_line_add_newline();
	}
	else
	{
		p_strcpy_c2x((PXCHAR)Sdram_pDataCache, (PCCHAR)"RM: ");
		p_strcat_c2x((PXCHAR)Sdram_pDataCache, _cRsipMethod[iMethod]);
		SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_RM);
		p_line_add_x((PXCHAR)Sdram_pDataCache);
		p_line_add_newline();
	}
}

void _EventState()
{
	p_line_add_c((PCCHAR)"ES: ");
	if (_bHookUp)
	{
		p_line_add_c((PCCHAR)"L/hu");
	}
	else
	{
		p_line_add_c((PCCHAR)"L/hd");
	}
	p_line_add_newline();
}

void _ObservedEvents()
{
	DCHAR i, iNum, iEvent;

	p_line_add_char('O');
	p_line_add_colon();
	iNum = SdramReadData(PROTOCOL_SDRAM_POS+MGCP_ACCUM_EVENTS);
	if (iNum)
	{
		for (i = 0; i < (UCHAR)(iNum - 1); i ++)
		{
			iEvent = X_VAL(Sdram_pDataCache, i);
			p_line_add_c(_cReqEvent[iEvent]);
			p_line_add_comma();
		}
		iEvent = X_VAL(Sdram_pDataCache, i);
		p_line_add_c(_cReqEvent[iEvent]);
	}
	p_line_add_newline();
}

// Packets sent, Octets sent, Packets received, Octets received,
// Packets lost, Jitter, Average latency
void _ConnectionParam()
{
	p_line_add_c((PCCHAR)"P: PS=");
	p_line_add_long(Rtp_lSendPackets);
	p_line_add_comma();

	p_line_add_c((PCCHAR)"OS=");
	p_line_add_long(Rtp_lSendBytes);
	p_line_add_comma();

	p_line_add_c((PCCHAR)"PR=");
	p_line_add_long(Rtp_lRecvPackets);
	p_line_add_comma();

	p_line_add_c((PCCHAR)"OR=");
	p_line_add_long(Rtp_lRecvBytes);
	p_line_add_comma();

	p_line_add_c((PCCHAR)"PL=0, JI=0, LA=0");
	p_line_add_newline();
}

void MgcpSendReq(UCHAR iRequest)
{
	MgcpTransSendReq(_lLocalTransId, iRequest);
	_IncLocalTransId();
}

void MgcpSendRSIP(UCHAR iMethod)
{
	DCHAR iVal;

	iVal = iMethod;
	if (iVal == MGCP_RSIP_CNC_SPECIAL)
	{
		MgcpCommandLine(MGCP_VERB_RSIP, TRUE);
	}
	else
	{
		MgcpCommandLine(MGCP_VERB_RSIP, FALSE);
	}
	_RestartMethod(iVal);
	MgcpSendReq(MGCP_VERB_RSIP);
}

void MgcpWaygoingHeartbeat()
{
	MgcpCommandLine(MGCP_VERB_RSIP, FALSE);
	_RestartMethod(MGCP_RSIP_RESTART);
	p_line_add_c((PCCHAR)"x-heartbeat:keepalive");
	p_line_add_newline();
	MgcpSendReq(MGCP_VERB_RSIP);
}

void MgcpSendNTFY()
{
	MgcpCommandLine(MGCP_VERB_NTFY, FALSE);
	if (SdramReadData(PROTOCOL_SDRAM_POS+MGCP_PARAM_X))
	{
		MgcpCopyFromSdram(MGCP_PARAM_X);
	}
	else
	{
		p_line_add_c((PCCHAR)"X: 0");
		p_line_add_newline();
	}
	_ObservedEvents();
	MgcpSendReq(MGCP_VERB_NTFY);
	_iAccDigitNum = 0;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_ACCUM_EVENTS, 0);
//	_EmptyReqEventList();
}

void MgcpSendResp(USHORT iCode)
{
	PCCHAR_D pComment;

	switch (iCode)
	{
	case 200:
	case 250:
		pComment = (PCCHAR)"OK";
		break;
	case 401:
		pComment = (PCCHAR)"already off hook";
		break;
	case 402:
		pComment = (PCCHAR)"already on hook";
		break;
	case 500:
		pComment = (PCCHAR)"endpoint unknown";
		break;
	case 501:
		pComment = (PCCHAR)"endpoint not ready";
		break;
	case 504:
		pComment = (PCCHAR)"Unknown command";
		break;
	case 505:
		pComment = (PCCHAR)"Unsupported RemoteConnectionDescriptor";
		break;
	case 510:
		pComment = (PCCHAR)"protocol error detected";
		break;
	case 511:
		pComment = (PCCHAR)"unrecognized extension";
		break;
	case 512:
		pComment = (PCCHAR)"can't detect one of the requested events";
		break;
	case 513:
		pComment = (PCCHAR)"can't generate one of the requested signals";
		break;
	case 515:
		pComment = (PCCHAR)"invalid conn Id";
		break;
	case 516:
		pComment = (PCCHAR)"unknown call Id";
		break;
	case 517:
		pComment = (PCCHAR)"unsupported mode";
		break;
	case 518:
		pComment = (PCCHAR)"unsupported package";
		break;
	case 522:
		pComment = (PCCHAR)"no such event";
		break;
	case 525:
		pComment = (PCCHAR)"Unknown extension in LocalConnectionOptions";
		break;
	case 527:
		pComment = (PCCHAR)"Missing RemoteConnectionDescriptor";
		break;
	case 528:
		pComment = (PCCHAR)"Incompatible version";
		break;
	case 533:
		pComment = (PCCHAR)"Response too large";
		break;
	case 541:
		pComment = (PCCHAR)"Invalid LocalConnectionDescriptor";
		break;
	}

	_ResponseLine(iCode, pComment);
	MgcpTransSendResp(_lRecvTransId);
}

void _ResponseLine200OK()
{
	_ResponseLine(200, (PCCHAR)"OK");
}

void MgcpRespAuditAll()
{
	_ResponseLine200OK();
	_SpecificEndpointId();
	MgcpTransSendResp(_lRecvTransId);
}

void MgcpRespAudit(PXCHAR pReqInfo, UCHAR iNumber)
{
	DCHAR i;
	BOOLEAN bReqLC;
	BOOLEAN bReqRC;

	bReqRC = FALSE;
	bReqLC = FALSE;
	_ResponseLine200OK();
	for (i = 0; i < iNumber; i ++)
	{
		if (pReqInfo[i] == MGCP_PARAM_ES)
		{
			_EventState();
		}
		else if (pReqInfo[i] == MGCP_PARAM_O)
		{
			_ObservedEvents();
		}
		else if (pReqInfo[i] == MGCP_PARAM_M)
		{
			_ConnectionMode();
		}
		else if (pReqInfo[i] == MGCP_PARAM_P)
		{
			_ConnectionParam();
		}
		else if (pReqInfo[i] == MGCP_PARAM_LC)
		{
			bReqLC = TRUE;
		}
		else if (pReqInfo[i] == MGCP_PARAM_RC)
		{
			bReqRC = TRUE;
		}
		else if (pReqInfo[i] == MGCP_PARAM_D)
		{
			if (_iDigitMapLen)
			{
				SdramCopyEthernetFrame(PROTOCOL_SDRAM_POS+MGCP_PARAM_D, p_line_get_buf(), _iDigitMapLen);
				p_line_set_len((USHORT)(p_line_get_len() + _iDigitMapLen));
				p_line_add_newline();
			}
		}
		else
		{
			MgcpCopyFromSdram(pReqInfo[i]);
		}
		if (p_line_get_len() > MGCP_MAX_SEND_LEN)
		{
			MgcpSendResp(533);
			return;
		}
	}
	if (bReqLC)
	{
		p_line_add_newline();
		p_line_add_p(PROTOCOL_SDRAM_POS+MGCP_PARAM_LC);
		if (p_line_get_len() > MGCP_MAX_SEND_LEN)
		{
			MgcpSendResp(533);
			return;
		}
	}
	if (bReqRC)
	{
		p_line_add_newline();
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_RC))
		{
			p_line_add_x((PXCHAR)Sdram_pDataCache);
		}
		else
		{
			p_line_add_c(Sdp_cV0);
			p_line_add_newline();
		}
		if (p_line_get_len() > MGCP_MAX_SEND_LEN)
		{
			MgcpSendResp(533);
			return;
		}
	}

	MgcpTransSendResp(_lRecvTransId);
}

void MgcpRespCrcx()
{
	_ResponseLine200OK();
	_ConnectionId();
	p_line_add_newline();
	if (_iRecvSdpNum)
	{
		MgcpSdpMsg(FALSE);
	}
	else
	{
		MgcpSdpMsg(TRUE);
	}
//	p_line_add_x((PXCHAR)Sdram_pDataCache);
	MgcpTransSendResp(_lRecvTransId);
}


void MgcpRespMdcx()
{
	_ResponseLine200OK();
	if (_iRecvSdpNum)
	{
		p_line_add_newline();
		MgcpSdpMsg(FALSE);
//		p_line_add_x((PXCHAR)Sdram_pDataCache);
	}
	MgcpTransSendResp(_lRecvTransId);
}

void MgcpRespDlcx()
{
	_ResponseLine(250, (PCCHAR)"Connection deleted");
	_ConnectionParam();
	MgcpTransSendResp(_lRecvTransId);
}
/******************************************************************
 **** accesary functions to handle received parameters ************
 ******************************************************************/
UCHAR _GetCommandType(PXCHAR pData)
{
	DCHAR i;

	for (i = 0; i < MGCP_VERB_NUM; i ++)
	{
		if (p_memcmp_nocase_c2x(pData, _cVerb[i], VERB_LABEL_LEN))
		{
			return i;
		}
	}
	return MGCP_VERB_UNKNOWN;
}

UCHAR _GetReqInfo(PXCHAR pData)
{
	DCHAR iChar, iChar1;

	iChar = p_toupper(pData[0]);
	iChar1 = p_toupper(pData[1]);
	if (iChar1)
	{
		if (iChar == 'R' && iChar1 == 'C')
			return MGCP_PARAM_RC;
		if (iChar == 'L' && iChar1 == 'C')
			return MGCP_PARAM_LC;
		if (iChar == 'E' && iChar1 == 'S')
			return MGCP_PARAM_ES;
		if (iChar == 'R' && iChar1 == 'M')
			return MGCP_PARAM_RM;
		if (iChar == 'R' && iChar1 == 'D')
			return MGCP_PARAM_RD;
		if (iChar == 'P' && iChar1 == 'L')
			return MGCP_PARAM_PL;
		if (iChar == 'M' && iChar1 == 'D')
			return MGCP_PARAM_MD;
		return 0;
	}
	else
	{
		switch (iChar)
		{
		case 'B':
			return MGCP_PARAM_B;
		case 'C':
			return MGCP_PARAM_C;
		case 'I':
			return MGCP_PARAM_I;
		case 'N':
			return MGCP_PARAM_N;
		case 'X':
			return MGCP_PARAM_X;
		case 'L':
			return MGCP_PARAM_L;
		case 'M':
			return MGCP_PARAM_M;
		case 'R':
			return MGCP_PARAM_R;
		case 'S':
			return MGCP_PARAM_S;
		case 'D':
			return MGCP_PARAM_D;
		case 'O':
			return MGCP_PARAM_O;
		case 'P':
			return MGCP_PARAM_P;
		case 'E':
			return MGCP_PARAM_E;
		case 'Z':
			return MGCP_PARAM_Z;
		case 'Q':
			return MGCP_PARAM_Q;
		case 'T':
			return MGCP_PARAM_T;
		case 'A':
			return MGCP_PARAM_A;
		default:
			return 0;
		}
	}
}

void _AddReqEvent(UCHAR iEvent, UCHAR iAction)
{
	if (iEvent != MGCP_EVENT_UNKNOWN)
	{
		_pReqEventList[iEvent] = iAction;
	}
}

BOOLEAN _GetReqBaseEvent(PXCHAR pBuf)
{
	DCHAR iLen;
	PXCHAR_D pData;

	pData = pBuf;
	iLen = p_strlen_x(pData);
	if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"enf", 3))	return TRUE;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"oef", 3))	return TRUE;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"qbo", 3))	return TRUE;
	}
	return FALSE;
}

BOOLEAN _GetReqRtpEvent(PXCHAR pBuf)
{
	DCHAR iLen, iChar, iChar1;
	PXCHAR_D pData;

	pData = pBuf;
	iLen = p_strlen_x(pData);
	if (iLen == 2)
	{
		iChar = p_toupper(pData[0]);
		iChar1 = p_toupper(pData[1]);
		if (iChar == 'U' && iChar1 == 'C')	return TRUE;
		if (iChar == 'S' && iChar1 == 'R')	return TRUE;
		if (iChar == 'J' && iChar1 == 'I')	return TRUE;
		if (iChar == 'P' && iChar1 == 'L')	return TRUE;
		if (iChar == 'Q' && iChar1 == 'A')	return TRUE;
		if (iChar == 'O' && iChar1 == 'F')	return TRUE;
	}
	else if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"co1", 3))	return TRUE;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"co2", 3))	return TRUE;
	}
	return FALSE;
}

BOOLEAN _GetReqGenEvent(PXCHAR pBuf)
{
	DCHAR iLen, iChar, iChar1;
	PXCHAR_D pData;

	pData = pBuf;
	iLen = p_strlen_x(pData);
	if (iLen == 2)
	{
		iChar = p_toupper(pData[0]);
		iChar1 = p_toupper(pData[1]);
		if (iChar == 'M' && iChar1 == 'T')	return TRUE;
		if (iChar == 'F' && iChar1 == 'T')	return TRUE;
		if (iChar == 'L' && iChar1 == 'D')	return TRUE;
		if (iChar == 'O' && iChar1 == 'F')	return TRUE;
	}
	else if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"pat", 3))	return TRUE;
	}
	return FALSE;
}

BOOLEAN _GetReqLineEvent(PXCHAR pBuf, UCHAR iVal)
{
	DCHAR iLen, iChar, iChar1, iAction;
	PXCHAR_D pData;

	pData = pBuf;
	iAction = iVal;

	iLen = p_strlen_x(pData);
	if (iLen == 1)
	{
		iChar = p_toupper(pData[0]);
		if (iChar == 'P')	return TRUE;
		if (iChar == 'E')	return TRUE;
		if (iChar == 'S')	return TRUE;
	}
	else if (iLen == 2)
	{
		iChar = p_toupper(pData[0]);
		iChar1 = p_toupper(pData[1]);
		if (iChar == 'H' && iChar1 == 'D')
		{
			_AddReqEvent(MGCP_EVENT_LINE_HD, iAction);
			return TRUE;
		}
		if (iChar == 'H' && iChar1 == 'U')
		{
			_AddReqEvent(MGCP_EVENT_LINE_HU, iAction);
			return TRUE;
		}
		if (iChar == 'H' && iChar1 == 'F')
		{
			_AddReqEvent(MGCP_EVENT_LINE_HF, iAction);
			return TRUE;
		}
		if (iChar == 'O' && iChar1 == 'C')
		{
			_AddReqEvent(MGCP_EVENT_LINE_OC, iAction);
			return TRUE;
		}
		if (iChar == 'A' && iChar1 == 'W')	return TRUE;
		if (iChar == 'O' && iChar1 == 'F')	return TRUE;
	}
	else if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"nbz", 3))	return TRUE;
	}

	return FALSE;
}

UCHAR _Char2DtmfEvent(UCHAR iVal)
{
	DCHAR iChar;

	iChar = iVal;
	if (iChar >= '0' && iChar <= '9')		return (UCHAR)(MGCP_EVENT_DTMF_0 + iChar - '0');
	if (iChar >= 'A' && iChar <= 'D')		return (UCHAR)(MGCP_EVENT_DTMF_A + iChar - 'A');
	if (iChar == '#')		return MGCP_EVENT_DTMF_POUND;
	if (iChar == '*')		return MGCP_EVENT_DTMF_STAR;
	if (iChar == 'T')		return MGCP_EVENT_DTMF_T;
	if (iChar == 'L')		return MGCP_EVENT_DTMF_L;

	return MGCP_EVENT_UNKNOWN;
}

BOOLEAN _AddDtmfEvent(UCHAR iDtmf, UCHAR iAction)
{
	DCHAR i, iChar;

	iChar = p_toupper(iDtmf);
	if (iChar == 'X')
	{
		for (i = MGCP_EVENT_DTMF_0; i <= MGCP_EVENT_DTMF_9; i ++)
		{
			_AddReqEvent(i, iAction);
		}
	}
	else
	{
		i = _Char2DtmfEvent(iChar);
		if (i == MGCP_EVENT_UNKNOWN)		return FALSE;
		_AddReqEvent(i, iAction);
	}

	return TRUE;
}

BOOLEAN _GetReqDtmfEvent(PXCHAR pData, UCHAR iAction)
{
	PXCHAR_D pCur;
	DCHAR i;

	pCur = pData;
	if (pCur[0] == '[')
	{
		pCur ++;
		while (pCur[0] != ']' && pCur[0] != 0)
		{
			if (pCur[1] == '-')
			{
				for (i = pCur[0]; i <= pCur[2]; i ++)
				{
					_AddDtmfEvent(i, iAction);
				}
				pCur += 3;
			}
			else
			{
				_AddDtmfEvent(pCur[0], iAction);
				pCur ++;
			}
		}
		return TRUE;
	}
	else
	{
		i = p_strlen_x(pCur);
		if (i == 1)		
		{
			return _AddDtmfEvent(pCur[0], iAction);
		}
		else if (i == 2)
		{
			if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"of", 2))
				return TRUE;
		}
	}

	return FALSE;
}

UCHAR _GetAction(PXCHAR pData)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iAction;

	iAction = 0;
	pCur = pData;
	pTemp = p_strchr_x(pCur, ')');
	if (pTemp)	pTemp[0] = 0;
	do
	{
		pTemp = p_strchr_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		switch (p_toupper(pCur[0]))
		{
		case 'N':
			iAction |= MGCP_ACTION_NOTIF;
			break;
		case 'A':
			iAction |= MGCP_ACTION_ACCUM;
			break;
		case 'D':
			iAction |= MGCP_ACTION_ACCDI;
			break;
		case 'K':
			iAction |= MGCP_ACTION_KESIA;
			break;
		case 'E':
			iAction |= MGCP_ACTION_EMBNO;
			break;
		case 'I':
			iAction |= MGCP_ACTION_IGNOR;
			break;
		case 'S':
			iAction |= MGCP_ACTION_SWAP;
			break;
		}
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++;
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	return iAction;
}

void _GetReqEvent(PXCHAR pData)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iTemp, iAction;

	pCur = pData;
	pTemp = p_strchr_x(pCur, '(');
	if (pTemp)
	{
		pTemp[0] = 0;
		pTemp ++;
		iAction = _GetAction(pTemp);
	}
	else
	{
		iAction = MGCP_ACTION_NOTIF;
	}

	pTemp = p_strchr_x(pCur, '/');
	if (pTemp)
	{
		pTemp[0] = 0;
		if (p_strlen_x(pCur) == 1)
		{
			iTemp = p_toupper(pCur[0]);
			pCur = pTemp;
			pCur ++;
			if (iTemp == 'L' || iTemp == 'H')
			{
				_GetReqLineEvent(pCur, iAction);
			}
			else if (iTemp == 'D')
			{
				_GetReqDtmfEvent(pCur, iAction);
			}
		}
		else if (!p_strcmp_c2x(pCur, (PCCHAR)"auth"))
		{
			if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
			{
				pCur = pTemp;
				pCur ++;
				if (!p_strcmp_c2x(pCur, (PCCHAR)"authoc"))
				{
					Cnc_bReqAuthoc = TRUE;
				}
			}
		}
	}
	else
	{
		if (_GetReqLineEvent(pCur, iAction))	return;
		if (_GetReqDtmfEvent(pCur, iAction))	return;
		if (_GetReqGenEvent(pCur))				return;
		if (_GetReqBaseEvent(pCur))				return;
		if (_GetReqRtpEvent(pCur))				return;
	}
}

// ci(time, number, name)
void _GetCIParam(PXCHAR pData)
{
	PXCHAR_D pTemp;
	PXCHAR_D pCur;
	DCHAR iLen;

//	Sys_pRemoteNumber[0] = 0;
	pTemp = p_strchr_x(pData, ',');
	if (!pTemp)		return;
	pCur = pTemp;
	pCur ++; // pass','
	pCur += p_count_space(pCur);
	pTemp = p_strchr_x(pCur, ',');
	if (!pTemp)		return;
	pTemp[0] = 0;
	if (pCur[0] == '"')
	{
		pCur ++;
		pTemp = p_strchr_x(pCur, '"');
		if (pTemp)	pTemp[0] = 0;
	}
	iLen = p_strlen_x(pCur);
	if (iLen > DIALED_MAX_LEN)
	{
		iLen = DIALED_MAX_LEN;
	}
	p_memcpy_x2x_0(Sys_pPeerDisplay, pCur, iLen);
}

UCHAR _GetSigLineEvent(PXCHAR pBuf, UCHAR iOption)
{
	DCHAR iLen, iChar, iChar1;
	PXCHAR_D pData;

	pData = pBuf;
	iLen = p_strlen_x(pData);

	if (iLen == 1)
	{
		iChar = p_toupper(pData[0]);
		if (iChar == 'E')	return MGCP_EVENT_LINE_E;
		if (iChar == 'P')	return MGCP_EVENT_LINE_P;
		if (iChar == 'V')	return MGCP_EVENT_LINE_V;
		if (iChar == 'Y')	return MGCP_EVENT_LINE_Y;
		if (iChar == 'Z')	
		{
			if (iOption == 0)
				return MGCP_EVENT_LINE_Z_POS;
			else if (iOption == 1)
				return MGCP_EVENT_LINE_Z_NEG;
			else
				return MGCP_EVENT_LINE_Z;
		}
		if (iChar == 'S')	return MGCP_EVENT_LINE_S;
	}
	else if (iLen == 2)
	{
		iChar = p_toupper(pData[0]);
		iChar1 = p_toupper(pData[1]);
		if (iChar == 'H' && iChar1 == 'D')		return MGCP_EVENT_LINE_HD;
		if (iChar == 'H' && iChar1 == 'U')		return MGCP_EVENT_LINE_HU;
		if (iChar == 'A' && iChar1 == 'W')		return MGCP_EVENT_LINE_AW;
		if (iChar == 'D' && iChar1 == 'L')		return MGCP_EVENT_LINE_DL;
		if (iChar == 'B' && iChar1 == 'Z')		return MGCP_EVENT_LINE_BZ;
		if (iChar == 'W' && iChar1 == 'T')		return MGCP_EVENT_LINE_WT;
		if (iChar == 'S' && iChar1 == 'L')		return MGCP_EVENT_LINE_SL;
		if (iChar == 'O' && iChar1 == 'T')		return MGCP_EVENT_LINE_OT;
		if (iChar == 'C' && iChar1 == 'I')		return MGCP_EVENT_LINE_CI;
		if (iChar == 'R')
		{
			if (iChar1 == 'G' || (iChar1 >= '0' && iChar1 <= '7'))		return MGCP_EVENT_LINE_RG;
			if (iChar1 == 'S')		return MGCP_EVENT_LINE_RS;
			if (iChar1 == 'O')		return MGCP_EVENT_LINE_RO;
			if (iChar1 == 'T')		return MGCP_EVENT_LINE_RT;
		}
	}
	else if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"mwi", 3))
			return MGCP_EVENT_LINE_MWI;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"nbz", 3))
			return MGCP_EVENT_LINE_NBZ;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"wt", 2) && pData[2] >= '1' && pData[2] <= '4')
			return MGCP_EVENT_LINE_WT;
	}
	else if (iLen == 4)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"adsi", 4))
			return MGCP_EVENT_LINE_ADSI;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"vmwi", 4))
			return MGCP_EVENT_LINE_VMWI;
	}
	return MGCP_EVENT_UNKNOWN;
}

UCHAR _GetSigGenericEvent(PXCHAR pBuf)
{
	DCHAR iLen, iChar, iChar1;
	PXCHAR_D pData;

	pData = pBuf;
	iLen = p_strlen_x(pData);

	if (iLen == 2)
	{
		iChar = p_toupper(pData[0]);
		iChar1 = p_toupper(pData[1]);
		if (iChar == 'R' && iChar1 == 'T')		return MGCP_EVENT_GENERIC_RT;
		if (iChar == 'C' && iChar1 == 'F')		return MGCP_EVENT_GENERIC_CF;
		if (iChar == 'C' && iChar1 == 'G')		return MGCP_EVENT_GENERIC_CG;
		if (iChar == 'I' && iChar1 == 'T')		return MGCP_EVENT_GENERIC_IT;
		if (iChar == 'P' && iChar1 == 'T')		return MGCP_EVENT_GENERIC_PT;
	}
	else if (iLen == 3)
	{
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"rbk", 3))
			return MGCP_EVENT_GENERIC_RBK;
		if (p_memcmp_nocase_c2x(pData, (PCCHAR)"pat", 3))
			return MGCP_EVENT_GENERIC_PAT;
	}
	return MGCP_EVENT_UNKNOWN;
}

UCHAR _GetSigDtmfEvent(PXCHAR pData)
{
	return _Char2DtmfEvent(pData[0]);
}

UCHAR _GetSigEvent(PXCHAR pData)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	PXCHAR_D pParam;
	DCHAR iTemp, iEvent, iOption;

	iOption = 2;
	pCur = pData;
	pParam = p_strchr_x(pCur, '(');
	if (pParam)		
	{
		if (pParam[1] == '+')
		{
			iOption = 0;
		}
		else if (pParam[1] == '-')
		{
			iOption = 1;
		}
		pParam[0] = 0;
	}

	iEvent = MGCP_EVENT_UNKNOWN;
	pTemp = p_strchr_x(pCur, '/');
	if (pTemp)
	{
		pTemp[0] = 0;
		if (p_strlen_x(pCur) != 1)	
			return MGCP_EVENT_UNKNOWN;
		iTemp = p_toupper(pCur[0]);
		pCur = pTemp;
		pCur ++; // pass '/'
		if (iTemp == 'L' || iTemp == 'H')
		{
			iEvent = _GetSigLineEvent(pCur, iOption);
			goto End;
		}
		if (iTemp == 'G')
		{
			iEvent = _GetSigGenericEvent(pCur);
			goto End;
		}
		if (iTemp == 'D')
		{
			iEvent = _GetSigDtmfEvent(pCur);
			goto End;
		}
	}
	else
	{
		iEvent = _GetSigLineEvent(pCur, iOption);
		if (iEvent != MGCP_EVENT_UNKNOWN)
			goto End;
		iEvent = _GetSigGenericEvent(pCur);
		if (iEvent != MGCP_EVENT_UNKNOWN)
			goto End;
		iEvent = _GetSigDtmfEvent(pCur);
		if (iEvent != MGCP_EVENT_UNKNOWN)
			goto End;
	}

End:
	if (pParam)
	{
		pParam ++;
		if (iEvent == MGCP_EVENT_LINE_CI)
		{
			_GetCIParam(pParam);
		}
	}

	return iEvent;
}

/******************************************************************
 **** functions to handle received parameters *********************
 ******************************************************************/
void MgcpHandleB()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_B_LO);
	if (!iLen)	return;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_B, iLen);
}

void MgcpHandleE()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_E_LO);
	if (!iLen)	return;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_E, iLen);
}

BOOLEAN MgcpHandleC()
{
	PXCHAR_D pCur;
	DCHAR iTemp;
	XCHAR pBuf[MGCP_CALL_ID_LEN + 1];
	
	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_C_LO);
	if (!iTemp)		goto End;

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);
	if (p_strlen_x(pCur) <= MGCP_CALL_ID_LEN)		
		p_strcpy_x2x(pBuf, pCur);
	else 		
		goto End;

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_C);
	if (!iTemp)		goto End;
	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);
	if (p_strcmp_nocase_x2x(pCur, pBuf))
		return TRUE;

End:
	MgcpSendResp(516);
	return FALSE;
}

BOOLEAN MgcpHandleI()
{
	PXCHAR_D pCur;
	DCHAR iTemp;
	XCHAR pBuf[MGCP_CONN_ID_LEN + 1];
	
	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_I_LO);
	if (!iTemp)		goto End;

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);
	if (p_strlen_x(pCur) <= MGCP_CONN_ID_LEN)		
		p_strcpy_x2x(pBuf, pCur);
	else	
		goto End;

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_I);
	if (!iTemp)		goto End;
	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);
	if (p_strcmp_nocase_x2x(pCur, pBuf))
		return TRUE;
End:
	MgcpSendResp(515);
	return FALSE;
}

BOOLEAN MgcpHandleM()			
{
	DCHAR iTemp;
	PXCHAR_D pCur;

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_M_LO);
	if (!iTemp)		goto End;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_M, iTemp);

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);
	for (iTemp = 0; iTemp < MGCP_MODE_UNKNOWN; iTemp ++)
	{
		if (p_memcmp_nocase_c2x(pCur, _cConnMode[iTemp], CONN_MODE_LEN))
		{
			Mgcp_iConnMode = iTemp;
			if (Mgcp_iConnMode > MGCP_MODE_INACTIVE)
				goto End;
			if (!_iRecvSdpNum)
			{
				if (Mgcp_iConnMode == MGCP_MODE_SENDRECV || Mgcp_iConnMode == MGCP_MODE_SENDONLY || Mgcp_iConnMode == MGCP_MODE_CONFRNCE)
				{
					MgcpSendResp(200);
					return FALSE;
				}
			}
			return TRUE;
		}
	}

End:
	Mgcp_iConnMode = MGCP_MODE_UNKNOWN;
	MgcpSendResp(517);
	return FALSE;
}

void _GetAudioFrames(USHORT iVal)
{
	DSHORT iPTime;

	iPTime = iVal;
	if (Sys_iAudioType == CODEC_NULL || !iPTime)	
		return;

	if (Sys_iAudioType == CODEC_G7231)
	{
		if (iPTime % 30 == 0 && iPTime >= 30 && iPTime <= 240)
		{
			Sys_iAudioFrames = iPTime / 30;
		}
	}
	else if (Sys_iAudioType == CODEC_GSM610)
	{
		if (iPTime >= 20 && iPTime <= 160)
		{
			Sys_iAudioFrames = iPTime / 20;
		}
	}
	else
	{
		if (iPTime >= 10 && iPTime <= 80)
		{
			Sys_iAudioFrames = iPTime / 10;
		}
	}
}

BOOLEAN MgcpHandleL()
{
	DCHAR iTemp, iCodec;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DSHORT iPTime;
	BOOLEAN bEcho, bSilence;

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_L_LO);
	if (!iTemp)	return TRUE;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_L, iTemp);

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);

	iPTime = 0;
	bEcho = TRUE;
	bSilence = TRUE;
	iCodec = CODEC_NULL;
	do 
	{
		pTemp = p_strchr_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		if (pCur[1] == ':')
		{
			iTemp = p_toupper(pCur[0]);
			pCur += 2;
			switch (iTemp)
			{
			case 'P':
				iPTime = p_atoi(pCur, 10);
				break;
			case 'A':
				if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"PCMU", 4))
					iCodec = CODEC_G711U;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"PCMA", 4))
					iCodec = CODEC_G711A;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"G723", 4) || p_memcmp_nocase_c2x(pCur, (PCCHAR)"G.723", 5))
					iCodec = CODEC_G7231;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"G729", 4) || p_memcmp_nocase_c2x(pCur, (PCCHAR)"G.729", 5))
					iCodec = CODEC_G729;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"GSM", 3))
					iCodec = CODEC_GSM610;
				else
					iCodec = CODEC_NULL;
				break;
			case 'E':
				if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"on", 2))
					bEcho = TRUE;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"off", 3))
					bEcho = FALSE;
				break;
			case 'S':
				if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"on", 2))
					bSilence = TRUE;
				else if (p_memcmp_nocase_c2x(pCur, (PCCHAR)"off", 3))
					bSilence = FALSE;
				break;
			}
		}
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++;
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	iCodec = SdpAudioMatch(iCodec);
	if (iCodec != CODEC_NULL)
	{
		Sys_iAudioType = iCodec;
	}
	_GetAudioFrames(iPTime);

/*	if (bEcho)	Dsp_iOptions |= USE_AEC_OR; 
	else		Dsp_iOptions &= USE_AEC_AND; 

	if (bSilence) 	Dsp_iOptions |= USE_VAD_OR; 
	else			Dsp_iOptions &= USE_VAD_AND; 
*/
	return TRUE;
}

void MgcpHandleT()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_T_LO);
	if (!iLen)	return;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_T, iLen);
}

void MgcpHandleQ()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_Q_LO);
	if (!iLen)	return;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_Q, iLen);
}

/*
BOOLEAN MgcpHandleN()
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	XCHAR pIP[IP_ALEN];
	DSHORT iPort;

	if (!SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_N_LO))
		return FALSE;
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_N);

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);

	iPort = Sys_iServicePort;
	pTemp = p_strchr_x(pCur, ':');
	if (pTemp)
	{
		pTemp[0] = 0;
		pTemp ++;
		iPort = p_atoi(pTemp, 10);
	}

	if (p_String2IP(pCur, pIP))
	{
		if (!p_memcmp_ip(pIP, Sys_pServiceIP) && iPort == Sys_iServicePort)
		{
			return FALSE;
		}
	}
	else
	{
		if (!p_strcmp_x2x(pCur, Sys_pServiceAddr) && iPort == Sys_iServicePort)
		{
			return FALSE;
		}
	}

	p_strcpy_x2x(Sys_pServiceAddr, pCur);
	Sys_iServicePort = iPort;
	return TRUE;
}
*/

BOOLEAN MgcpHandleR()
{
	DCHAR iTemp;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	XCHAR pBuf[256];

	if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
	{
		Cnc_bReqAuthoc = FALSE;
	}
	_EmptyReqEventList();
	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO);
	if (!iTemp)		return TRUE;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_R, iTemp);

	p_memcpy_x2x_0(pBuf, (PXCHAR)Sdram_pDataCache, iTemp);
	pCur = (PXCHAR)(pBuf + 2);
	pCur += p_count_space(pCur);

	do
	{
		pTemp = _StrchrBrkt_x(pCur, ',');
		if (pTemp) pTemp[0] = 0;
		_GetReqEvent(pCur);
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++; // pass ','
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	if (_pReqEventList[MGCP_EVENT_LINE_HU] != MGCP_ACTION_IGNOR && _bHookUp)
	{
		MgcpSendResp(402);
		return FALSE;
	}
	if (_pReqEventList[MGCP_EVENT_LINE_HD] != MGCP_ACTION_IGNOR && !_bHookUp)
	{
		MgcpSendResp(401);
		return FALSE;
	}
	return TRUE;	
}

BOOLEAN MgcpHandleS()
{
	DCHAR iTemp, iEventNum;
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iRgIndex, iCiIndex;
	XCHAR pBuf[256];
	XCHAR pEvent[8];
	
	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_S_LO);
	if (!iTemp)		return TRUE;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_S, iTemp);

	p_memcpy_x2x_0(pBuf, (PXCHAR)Sdram_pDataCache, iTemp);
	pCur = (PXCHAR)(pBuf + 2);
	pCur += p_count_space(pCur);

	if (!pCur[0])
	{
		TaskSignalMsg(MGCP_STOP_SIGNAL);
		return TRUE;
	}

	iEventNum = 0;
	iRgIndex = 0;
	iCiIndex = 0;
	do
	{
		pTemp = _StrchrBrkt_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		iTemp = _GetSigEvent(pCur);
/*		if (iTemp == MGCP_EVENT_UNKNOWN)
		{
			MgcpSendResp(513);
			return FALSE;

		}
		else
*/
		if (iTemp != MGCP_EVENT_UNKNOWN)
		{
			if (iEventNum < 8)
			{
				if (iTemp == MGCP_EVENT_LINE_RG)
				{
					iRgIndex = iEventNum;
				}
				else if (iTemp == MGCP_EVENT_LINE_CI)
				{
					iCiIndex = iEventNum;
				}

				pEvent[iEventNum] = iTemp;
				iEventNum ++;
			}
		}
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++; // pass ','
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	if (iCiIndex > iRgIndex)		// Since we need CI before RG to make the CID display right, so we change the order here.
	{
		pEvent[iRgIndex] = MGCP_EVENT_LINE_CI;
		pEvent[iCiIndex] = MGCP_EVENT_LINE_RG;
	}

	for (iTemp = 0; iTemp < iEventNum; iTemp ++)
	{
		if (pEvent[iTemp] == MGCP_EVENT_LINE_HD)
		{
			TaskHandleData(MGCP_HANDSET_HD, (PXCHAR)0, 0);
		}
		else if (pEvent[iTemp] == MGCP_EVENT_LINE_HU)
		{
			TaskHandleData(MGCP_HANDSET_HU, (PXCHAR)0, 0);
		}
		else 		
		{
			TaskSignalMsg(pEvent[iTemp]);
		}
	}
	return TRUE;
}

UCHAR MgcpHandleF(PXCHAR pDst)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iTemp, iNum;

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_F_LO);
	if (!iTemp)	return 0;

	pCur = (PXCHAR)(Sdram_pDataCache + 2);
	pCur += p_count_space(pCur);	
	iNum = 0;

	do
	{
		pTemp = p_strchr_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		iTemp = _GetReqInfo(pCur);
		if (iTemp)
		{
			if (iNum < MGCP_REQ_INFO_NUM)
			{
				pDst[iNum] = iTemp;
				iNum ++;
			}
		}
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++; // pass ','
			pCur += p_count_space(pCur);
		}
	}while (pTemp);

	return iNum;
}

void MgcpHandleX()
{
	DCHAR iLen;

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_X_LO);
	if (!iLen)	return;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_X, iLen);
}

void _UpdateTrans(PXCHAR pBuf)
{
	PXCHAR_D pTemp;
	PXCHAR_D pData;
	DLONG iLower, iUpper;

	pData = pBuf;
	pTemp = p_strchr_x(pData, '-');
	if (pTemp)
	{
		pTemp[0] = 0;
		pTemp ++;
		iLower = p_atol(pData, 10);
		iUpper = p_atol(pTemp, 10);
		for (; iLower <= iUpper; iLower ++)
		{
			MgcpTransFree(iLower);
		}
	}
	else
	{
		iLower = p_atol(pData, 10);
		MgcpTransFree(iLower);
	}
}

void MgcpHandleK()
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iLen;
	XCHAR pBuf[256];

	iLen = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_K_LO);
	if (!iLen)		return;

	p_strcpy_x2x(pBuf, (PXCHAR)Sdram_pDataCache);
	pCur = (PXCHAR)(pBuf + 2);
	pCur += p_count_space(pCur);
	
	do
	{
		pTemp = p_strchr_x(pCur, ',');
		if (pTemp)	pTemp[0] = 0;
		_UpdateTrans(pCur);
		if (pTemp)
		{
			pCur = pTemp;
			pCur ++; // pass ','
			pCur += p_count_space(pCur);
		}
	}while (pTemp);
}


void MgcpHandleD()
{
	PXCHAR_D pCur;
	DCHAR iLen;
	XCHAR pEntry[MAP_ENTRY_LEN+1];

	if (!_bRecvDigitMap)	return;

	SdramCopyEthernetFrame(PROTOCOL_SDRAM_POS+MGCP_RECV_D_LO, (PXCHAR)Adapter_pReceivePacket, _iDigitMapLen);
	SdramSaveEthernetFrame(PROTOCOL_SDRAM_POS+MGCP_PARAM_D, (PXCHAR)Adapter_pReceivePacket, _iDigitMapLen);
	Sys_iDigitMapNum = 0;
	X_VAL(Adapter_pReceivePacket, _iDigitMapLen) = 0;

	pCur = (PXCHAR)(Adapter_pReceivePacket + 2);
	pCur += p_count_space(pCur);
	iLen = 0;
	if (*pCur == '(')
	{
		pCur ++;
		while (*pCur != ')')
		{
			if (*pCur == '|')
			{
				pEntry[iLen] = 0;
				MgcpMapAddEntry(pEntry);
				iLen = 0;
				pCur ++;
			}
			else
			{
				pEntry[iLen] = *pCur;
				iLen ++;
				pCur ++;
			}
		}
		if (iLen)
		{
			pEntry[iLen] = 0;
			MgcpMapAddEntry(pEntry);
		}
	}
	else
	{
		pCur[MAP_ENTRY_LEN] = 0;
		MgcpMapAddEntry(pCur);
	}
}

void MgcpHandleRC()
{
	DCHAR i;

	X_VAL(Sdram_pDataCache2, 0) = 0;
	for (i = 0; i < _iRecvSdpNum; i ++)
	{
		SdramReadString((USHORT)(PROTOCOL_SDRAM_POS+MGCP_RECV_SDP_LO + i));
		p_strcat_x2x((PXCHAR)Sdram_pDataCache2, (PXCHAR)Sdram_pDataCache);
		p_strcat_c2x((PXCHAR)Sdram_pDataCache2, (PCCHAR)"\r\n");
	}
	p_strcpy_x2x((PXCHAR)Sdram_pDataCache, (PXCHAR)Sdram_pDataCache2);
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_RC);
}

/******************************************************************
 **** functions to handle received messages ***********************
 ******************************************************************/
void MgcpHandleTspError(UCHAR iMethod)
{
	OutputVal(iMethod, IDS_CHECK_POINT_0);
	if (iMethod == MGCP_VERB_RSIP)
	{
		if (Sys_iServiceType == MGCP_SERVICE_TYPE_UPTECH)
		{
			MgcpSendRSIP(MGCP_RSIP_GRACEFUL);
			_iRegTimer = 0;
		}
		else
		{
			_iRegTimer = 0;
			TaskLogonFailed(0);
		}
	}
}

void MgcpHandleReq()
{
	DCHAR iTemp;
	XCHAR pBuf[MGCP_REQ_INFO_NUM];

	switch ((UCHAR)Mgcp_iRecvMsgType)
	{
	case MGCP_VERB_EPCF:
		MgcpHandleB();
		MgcpHandleK();
		MgcpSendResp(200);
		break;

	case MGCP_VERB_CRCX:
		iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_C);
		if (iTemp)
		{
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_C_BACKUP, iTemp);
		}
		iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_C_LO);
		if (!iTemp)
		{
			MgcpSendResp(510);
			return;
		}
		SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_C, iTemp);

		if (!MgcpHandleM())	return;
		if (!MgcpHandleL())	return;
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO))
		{
			if (!MgcpHandleR())	return;
		}
		MgcpHandleK();
		MgcpHandleT();
		MgcpHandleD();
		MgcpHandleQ();
		MgcpHandleX();

		if (_iRecvSdpNum)
		{
			MgcpHandleRC();
			if (MgcpHandleSdp(_iRecvSdpNum))
			{
				MgcpRespCrcx();
			}
			else
			{
				MgcpSendResp(505);
				return;
			}
		}
		else
		{
			MgcpRespCrcx();
		}
		TaskStartRtp();
		TaskSignalMsg(MGCP_EVENT_CRCX);
		MgcpHandleS();
		break;

	case MGCP_VERB_MDCX:
		if (!MgcpHandleC())		return;
		if (!MgcpHandleI())		return;
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_M_LO))
		{
			if (!MgcpHandleM())	return;
		}	
		else
		{
			Mgcp_iConnMode = MGCP_MODE_SENDRECV;
		}
		if (!MgcpHandleL()) return;
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO))
		{
			if (!MgcpHandleR())	return;
		}
		MgcpHandleK();
		MgcpHandleT();
		MgcpHandleD();
		MgcpHandleQ();
		MgcpHandleX();
		if (_iRecvSdpNum)
		{
			MgcpHandleRC();
			if (MgcpHandleSdp(_iRecvSdpNum))
			{
				MgcpRespMdcx();	
			}
			else
			{
				MgcpSendResp(505);
				return;
			}
		}
		else
		{
			MgcpRespMdcx();	
		}
		TaskStartRtp();
		TaskSignalMsg(MGCP_CALL_CONNECTED);
		MgcpHandleS();
		break;

	case MGCP_VERB_DLCX:
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_C_LO))
		{
			if (!MgcpHandleC())		return;
		}
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_I_LO))
		{
			if (!MgcpHandleI())		return;
		}
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO))
		{
			if (!MgcpHandleR())	return;
		}
		MgcpHandleK();
		MgcpHandleT();
		MgcpHandleD();
		MgcpHandleQ();
		MgcpHandleX();
		MgcpHandleE();

		MgcpRespDlcx();
		MgcpInitConn();

		iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_C_BACKUP);
		if (iTemp)
		{
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_C, iTemp);
			iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_PARAM_I_BACKUP);
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_I, iTemp);
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_C_BACKUP, 0);
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_I_BACKUP, 0);
		}
		else
		{
			TaskSignalMsg(MGCP_EVENT_DLCX);
		}
		MgcpHandleS();
		break;

	case MGCP_VERB_RQNT:
		MgcpHandleX();
		MgcpHandleK();
		MgcpHandleT();
		MgcpHandleD();
		MgcpHandleQ();
		
		if (!MgcpHandleR())	return;
		if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
		{
			if (Cnc_bReqAuthoc)
			{
				CncHandleS();
				return;
			}
		}
		if (SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_Q_LO))	// looks like harbour system send a Q in RQNT when connected
		{
			if (p_strstr_nocase_c((PXCHAR)Sdram_pDataCache, (PCCHAR)"process"))
			{
				TaskSignalMsg(MGCP_CALL_CONNECTED);
			}
		}
		if (!SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_S_LO))
		{
			TaskSignalMsg(MGCP_STOP_SIGNAL);
		}
		else
		{
			if (!MgcpHandleS())	return;
		}

		MgcpSendResp(200);
		break;

	case MGCP_VERB_AUEP:
		MgcpHandleK();
		if (_bWildCarded)
		{
			MgcpRespAuditAll();
			return;
		}
		iTemp = MgcpHandleF(pBuf);
		if (iTemp)
		{
			MgcpRespAudit(pBuf, iTemp);
		}
		else
		{
			MgcpSendResp(200);
		}
		break;

	case MGCP_VERB_AUCX:
		if (!MgcpHandleI())	return;
		MgcpHandleK();
		iTemp = MgcpHandleF(pBuf);
		if (iTemp)
		{
			MgcpRespAudit(pBuf, iTemp);
		}
		else
		{
			MgcpSendResp(200);
		}
		break;
	}
}

void MgcpHandleResp(UCHAR iMethod)
{
//	BOOLEAN bRedirect;

	switch (iMethod)
	{
	case MGCP_VERB_RSIP:
//		bRedirect = MgcpHandleN();
//		if (bRedirect)
//		{
//			TaskLogon();
//		}
//		else
		{
			if (Mgcp_iRecvMsgType == 200)
			{
				if (!Task_bLogoned)
				{
					TaskLogonCompleted();
				}
			}
			else if (Mgcp_iRecvMsgType >= 400)
			{
				TaskLogonFailed(0);
			}
		}
		break;
	case MGCP_VERB_NTFY:
		break;
	}
}

BOOLEAN _CheckEndpointId(PXCHAR pData)
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iLen;

	pCur = pData;
	pTemp = p_strchr_x(pCur, '@');
	if (!pTemp)	return FALSE;

	pTemp[0] = 0;
	pTemp ++;
	if (!p_strcmp_nocase_x2x(pTemp, Sys_pDomainName))
		return FALSE;
	
	if (p_strcmp_nocase_x2x(pCur, Sys_pAccount))
		return TRUE;

	if (pCur[0] == '*' && pCur[1] == 0)
	{
		_bWildCarded = TRUE;
		return TRUE;
	}

	iLen = p_strlen_x(pCur);
	iLen --;
	if (pCur[iLen] == '*' && p_memcmp_nocase_x2x(pCur, Sys_pAccount, iLen))
	{
		_bWildCarded = TRUE;
		return TRUE;
	}

	return FALSE;
}

void MgcpProcessData()
{
	PXCHAR_D pCur;
	PXCHAR_D pTemp;
	DCHAR iTemp;
	XCHAR pBuf[256];

	iTemp = SdramReadString(PROTOCOL_SDRAM_POS+MGCP_RECV_FIRST_LINE);
	if (!iTemp)		return;
	p_strcpy_x2x(pBuf, (PXCHAR)Sdram_pDataCache);
	pCur = pBuf;

	if (pCur[4] == ' ')
	{
		Mgcp_iRecvMsgType = _GetCommandType(pCur);
		pCur += 4;
		pCur += p_count_space(pCur);
		pTemp = p_strchr_x(pCur, ' ');
		if (!pTemp)		return;
		_lRecvTransId = p_atol(pCur, 10);
		pCur = pTemp;
		pCur += p_count_space(pCur);

		// this request has been received before, transaction layer will resend the response
		if (MgcpTransRecvReq(_lRecvTransId))	return;

		if (Mgcp_iRecvMsgType == MGCP_VERB_UNKNOWN || Mgcp_iRecvMsgType == MGCP_VERB_NTFY || Mgcp_iRecvMsgType == MGCP_VERB_RSIP)
		{
			MgcpSendResp(504);
			return;
		}

		pTemp = p_strchr_x(pCur, ' ');
		if (!pTemp)
		{
			MgcpSendResp(510);
			return;
		}
		pTemp[0] = 0;
		if (!_CheckEndpointId(pCur))
		{
			MgcpSendResp(500);
			return;
		}

		MgcpHandleReq();
	}
	else if (pCur[3] == ' ')
	{
		Mgcp_iRecvMsgType = p_atoi(pCur, 10);
		pCur += 4;
		_lRecvTransId = p_atol(pCur, 10);
		iTemp = MgcpTransRecvResp(_lRecvTransId);
		// this response has no corresponding request, just ignore it
		if (iTemp == MGCP_VERB_UNKNOWN)
			return;

		MgcpHandleResp(iTemp);
	}
	else
	{
		MgcpSendResp(501);
	}
	_iNatTimer = 0;
}

void MgcpSaveHeader(UCHAR iLength)
{
	DCHAR iLen, iChar;
	PXCHAR_D pData;

	iLen = iLength;
	pData = (PXCHAR)Sdram_pDataCache;
	
	if (pData[1] == ':')
	{
		iChar = p_toupper(pData[0]);
		switch (iChar)
		{
		case 'B':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_B_LO, iLen);
			break;
		case 'C':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_C_LO, iLen);
			break;
		case 'I':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_I_LO, iLen);
			break;
		case 'M':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_M_LO, iLen);
			break;
		case 'T':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_T_LO, iLen);
			break;
		case 'L':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_L_LO, iLen);
			break;
		case 'N':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_N_LO, iLen);
			break;
		case 'Q':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_Q_LO, iLen);
			break;
		case 'E':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_E_LO, iLen);
			break;
		case 'R':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO, iLen);
			break;
		case 'F':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_F_LO, iLen);
			break;
		case 'X':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_X_LO, iLen);
			break;
		case 'K':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_K_LO, iLen);
			break;
		case 'S':
			SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_S_LO, iLen);
			break;
		}
	}
	else if (p_memcmp_nocase_c2x(pData, (PCCHAR)"Xhb:", 4))
	{
		if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
		{
			pData += 4;
			pData += p_count_space(pData);
			_iCncHbTTL = p_atoi(pData, 10);
		}
	}
}

void MgcpRunData(PXCHAR pBuf)
{
	DSHORT iRecvLen, iOldIndex, iNewIndex;
	DCHAR iNewLine, iState;
	PXCHAR_D pData;

	pData = pBuf;
	iOldIndex = 0;
	iNewIndex = 0;
	iRecvLen = 0;
	iState = MGCP_STATE_INIT;

	while (iNewIndex < Adapter_iReceiveLen)
	{
		iNewLine = p_IsNewLine((PXCHAR)(pData+iNewIndex));
		if (iNewLine)
		{
			iNewIndex += iNewLine;
			if (iState == MGCP_STATE_INIT)
			{
				if (iRecvLen > 255)		iRecvLen = 255;
				if (iRecvLen)
				{
					p_memcpy_x2x((PXCHAR)Sdram_pDataCache, (PXCHAR)(pData+iOldIndex), (UCHAR)iRecvLen);
					SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_FIRST_LINE, (UCHAR)iRecvLen);
					iState = MGCP_STATE_HEADER_BEGIN;
				}
			}
			else if (iState == MGCP_STATE_HEADER_BEGIN)
			{
				if (iRecvLen)
				{
					if (p_toupper(pData[iOldIndex]) == 'D' && pData[iOldIndex + 1] == ':')
					{
						_bRecvDigitMap = TRUE;
						_iDigitMapLen = iRecvLen;
						SdramSaveEthernetFrame(PROTOCOL_SDRAM_POS+MGCP_RECV_D_LO, (PXCHAR)(pData+iOldIndex), iRecvLen);
					}
					else
					{
						if (iRecvLen > 255)		iRecvLen = 255;
						p_memcpy_x2x((PXCHAR)Sdram_pDataCache, (PXCHAR)(pData+iOldIndex), (UCHAR)iRecvLen);
						MgcpSaveHeader((UCHAR)iRecvLen);
					}
				}
				else 
				{
					iState = MGCP_STATE_HEADER_END;
				}
			}
			else if (iState == MGCP_STATE_HEADER_END)
			{
				if (_iRecvSdpNum < MGCP_MAX_RECV_SDP && iRecvLen)
				{
					if (iRecvLen > 255)		iRecvLen = 255;
					p_memcpy_x2x((PXCHAR)Sdram_pDataCache, (PXCHAR)(pData+iOldIndex), (UCHAR)iRecvLen);
					SdramWriteData((USHORT)(PROTOCOL_SDRAM_POS+MGCP_RECV_SDP_LO + _iRecvSdpNum), (UCHAR)iRecvLen);
					_iRecvSdpNum ++;
				}
			}
			iRecvLen = 0;
			iOldIndex = iNewIndex;
		}
		else
		{

			iRecvLen ++;
			iNewIndex ++;
		}
	}
}

/**********************************************************************************
****** MGCP Initialization functions **********************************************
***********************************************************************************/
void MgcpInitRecv()
{
	_bRecvDigitMap = FALSE;
	_bWildCarded = FALSE;
	_iRecvSdpNum = 0;
	
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_FIRST_LINE, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_B_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_C_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_I_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_M_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_T_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_L_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_N_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_Q_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_E_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_R_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_F_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_X_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_K_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_S_LO, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_RECV_RC_LO, 0);
}

void MgcpInitN()
{
	XCHAR pIP[IP_ALEN];

	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_char('N');
	p_line_add_colon();
	ParseDnsAddr(Sys_pServiceAddr, pIP, p_line_get_buf()); 
	p_line_update_len();
	if (IsValidIP(pIP))
	{
		p_line_add_char('[');
		p_line_add_ip(pIP);
		p_line_add_char(']');
	}
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_N);
}

void MgcpInitA()
{
	DCHAR iType;

	iType = Sys_iAudioType;
	if (iType == CODEC_NULL)
	{
		iType = CODEC_G729;
	}

	p_line_start((PXCHAR)Sdram_pDataCache);
	p_line_add_char('A');
	p_line_add_colon();
	p_line_add_char('a');
	p_line_add_char(':');
	p_line_add_c(Sdp_cAudioMap[iType]);
	p_line_add_comma();
	if (iType == CODEC_G7231)
	{
		p_line_add_c((PCCHAR)"p:30-240");
	}
	else
	{
		p_line_add_c((PCCHAR)"p:10-80");
	}
	p_line_add_comma();
	p_line_add_c((PCCHAR)"e:on, s:on, t:0, v:l;d;g, m:sendonly;recvonly;sendrecv;confrnce;inactive");
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_A);
}

void MgcpInitPL()
{
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_PL, 0);
}

void MgcpInitMD()
{
	p_strcpy_c2x((PXCHAR)Sdram_pDataCache, (PCCHAR)"MD: 1024");
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_MD);
}

void MgcpInitRD()
{
	p_strcpy_c2x((PXCHAR)Sdram_pDataCache, (PCCHAR)"RD: 0");
	SdramWriteString(PROTOCOL_SDRAM_POS+MGCP_PARAM_RD);
}

void MgcpInitConn()
{
	Mgcp_iConnMode = MGCP_MODE_INACTIVE;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_C, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_I, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_RC, 0);
}
/**********************************************************************************
****** MGCP API functions
***********************************************************************************/
 void	MgcpStartup()
{
	Sys_iProtocol = PROTOCOL_MGCP;

	if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
	{
		_iCncHbTTL = 60;
	}

	Sys_iDigitMapNum = 0;
	_iRegTimer = 0;
	_iNatTimer = 0;
	_iDigitMapLen = 0;
	_lLocalTransId = 1;
	_iAccDigitNum = 0;
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_ACCUM_EVENTS, 0);
	_bHookUp = TRUE;
	_EmptyReqEventList();

	MgcpInitN();
	MgcpInitA();
	MgcpInitPL();
	MgcpInitMD();
	MgcpInitRD();
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_B, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_T, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_L, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_Q, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_E, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_R, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_X, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_S, 0);
	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_RM, 0);

	SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_PARAM_LC, 0);
	MgcpTransInit();
	MgcpInitConn();
	MgcpInitRecv();
}

 void MgcpInitialize()
{
}

 void MgcpLogon()
{
	if (Task_bLogoned)	return;

	if (Sys_bUseService)
	{
		if (IsValidIP(Sys_pServiceIP))
		{
			UdpOpen(Sys_pServiceIP, Sys_iServicePort, Sys_iRegisterPort, MGCP_REQ_SDRAM_LO);
			// send RSIP
			if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
			{
				CncSendRSIP();
			}
			else
			{
				MgcpSendRSIP(MGCP_RSIP_RESTART);
			}
		}
		else
		{
			TaskLogonFailed(0);
		}
	}
	else
	{
		TaskLogonFailed(0);
	}
}

 void MgcpLogoff()
{
	if (!Task_bLogoned)		return;

	MgcpSendRSIP(MGCP_RSIP_GRACEFUL);
//	Task_bLogoned = FALSE;
	TaskLogoffCompleted();
}

 void MgcpHandleTimer()
{
	MgcpTransHandleTimer();

	if (!Task_bLogoned)
	{
		_iRegTimer ++;
		if (_iRegTimer >= MGCP_REG_TTL)
		{
			TaskLogon();
			_iRegTimer = 0;
		}
	}
	else
	{
		if (Sys_iServiceType == MGCP_SERVICE_TYPE_UPTECH)
		{
			_iRegTimer ++;
			if (_iRegTimer >= MGCP_REG_TTL)
			{
				MgcpSendRSIP(MGCP_RSIP_GRACEFUL);
				_iRegTimer = 0;
			}
		}
		else if (Sys_iLocalType == MGCP_LOCAL_TYPE_CNC_AUTH)
		{
			_iCncHbTTL --;
			if (!_iCncHbTTL)
			{
				_iCncHbTTL = 60;		// The correct Cnc Hb timer should be got from the response of this packet, 
				MgcpSendRSIP(MGCP_RSIP_CNC_SPECIAL);
			}
		}
		else if (Sys_iServiceType == MGCP_SERVICE_TYPE_WAYGOING)
		{
			_iRegTimer ++;
			if (_iRegTimer >= Sys_iRegisterTTL)
			{
				MgcpWaygoingHeartbeat();
				_iRegTimer = 0;
			}
		}
		else
		{
			if (IsFunctionMode() && Sys_iNatTTL)
			{
				_iNatTimer ++;
				if (_iNatTimer >= Sys_iNatTTL)
				{
					MgcpSendRSIP(MGCP_RSIP_RESTART);
					_iNatTimer = 0;
				}
			}
		}
	}
}

void _AccumEvents(UCHAR iEvent)
{
	DCHAR iNum;

	iNum = SdramReadData(PROTOCOL_SDRAM_POS+MGCP_ACCUM_EVENTS);
	if (iNum < MGCP_ACCUM_BUF_SIZE)
	{
		X_VAL(Sdram_pDataCache, iNum) = iEvent;
		iNum ++;
		SdramWriteData(PROTOCOL_SDRAM_POS+MGCP_ACCUM_EVENTS, iNum);
	}
}

void _ConvertDigits()
{
	DCHAR i, iLen;

	iLen = (_iAccDigitNum < DIALED_MAX_LEN)? _iAccDigitNum : DIALED_MAX_LEN;
	for (i = 0; i < iLen; i ++)
	{
		Sys_pRemoteNumber[i] = p_getAsciiKey(_pAccDigitBuf[i]);
	}
	Sys_pRemoteNumber[i] = 0;
}

 void	MgcpNotify(UCHAR iNotifyEvent)
{
	DCHAR iAction, iVal, iEvent;

	iEvent = iNotifyEvent;
	if (iEvent == MGCP_EVENT_LINE_HD || iEvent == MGCP_EVENT_LINE_HU)
	{
		if (iEvent == MGCP_EVENT_LINE_HU)		
			_bHookUp = TRUE;
		else	
			_bHookUp = FALSE;
		_AccumEvents(iEvent);
		MgcpSendNTFY();
		return;
	}

	iAction = _pReqEventList[iEvent];
	if (iAction & MGCP_ACTION_IGNOR)
	{
		if (iEvent <= MGCP_EVENT_DTMF_POUND && (IsInCall()))
		{
			TaskSignalMsg((UCHAR)(iEvent+MGCP_SEND_DTMF0));
		}
		return;
	}

	if (!(iAction & MGCP_ACTION_KESIA))
	{
		TaskSignalMsg(MGCP_STOP_SIGNAL);
	}

	if (iAction & MGCP_ACTION_NOTIF)
	{
		_AccumEvents(iEvent);
		MgcpSendNTFY();
		return;
	}

	if (iAction & MGCP_ACTION_ACCUM)
	{
		_AccumEvents(iEvent);
		return;
	}

	if (iAction & MGCP_ACTION_ACCDI)
	{
		_AccumEvents(iEvent);
		if (_iAccDigitNum < MGCP_ACCDI_BUF_SIZE)
		{
			_pAccDigitBuf[_iAccDigitNum] = iEvent;
			_iAccDigitNum ++;
		}
		iVal = MgcpMatchMap(_pAccDigitBuf, _iAccDigitNum);
		if (iVal == DIGITMAP_UNDERMATCH)
		{
			Map_iTimeOut = MAP_TIME_OUT_1;
		}
		else if (iVal == DIGITMAP_TOMATCH)
		{
			Map_iTimeOut = MAP_TIME_OUT_2;
		}
		else if (iVal == DIGITMAP_MATCH  || iVal == DIGITMAP_NOTMATCH)
		{
			if (!Task_bConnected)
			{
				_ConvertDigits();
				TaskSignalMsg(MGCP_START_CALL);
			}
			MgcpSendNTFY();
		}
		return;
	}
}