/*	MAP dialogue PDU coding/decoding c file	*/
/*	Written by Liu Zhiguo 2003-08-25		*/
/*	Version: 1.0							*/
/*	--------------------------------------	*/

#include "map_includes.h"
#include "../../../tcap/src/include/tcap_head.h"
#include "../../../tcap/src/include/tcap_public.h"
#include "../../../tcap/src/include/tcap_struct.h"
#include "../xap_interfunc.h"
#include "map_dlgpdu.h"


static u8	MAPP_Dlgpdu[7] = {0x04,0x00,0x00,0x01,0x01,0x01,0x01};

u8 build_mapdlg(struct MapDlg_struct *dlg_ptr,u8 *data_buf)	// build user information portion
{
	struct	MapDlgOpen_struct	*map_open;
	struct	MapDlgUAbort_struct	*map_uabort;
	ASN_BUF	asn_buf;
	u8		temp_buf[256],temp_data[256];
	int		len=0,len1=0;

	asn_encode(temp_buf,&asn_buf);
	switch (dlg_ptr->dlg_type)
	{
		case MAPDLG_OPEN:
			map_open = (MapDlgOpen_struct *) &dlg_ptr->map_dlg.map_open;
			if ((map_open->param_flag & 0x01))
				len1 = add_tlv("0.0",map_open->peer_ref[0],map_open->peer_ref+1,0x80,&asn_buf);
			if ((map_open->param_flag & 0x02))
				len1 = add_tlv("0.1",map_open->local_ref[0],map_open->local_ref+1,0x80,&asn_buf);
			break;
		case MAPDLG_ACCEPT:
			len1 = add_tlv("1",0,&dlg_ptr->dlg_type,0x80,&asn_buf);
			break;
		case MAPDLG_CLOSE:
			len1 = add_tlv("2",0,&dlg_ptr->dlg_type,0x80,&asn_buf);
			break;
		case MAPDLG_REFUSE:
			temp_data[0] = dlg_ptr->map_dlg.map_refuse.reason;
			len1 = add_tlv("3.10",1,temp_data,0x00,&asn_buf);
			break;
		case MAPDLG_UABORT:
			map_uabort = (MapDlgUAbort_struct *) &dlg_ptr->map_dlg.map_uabort;
			switch (map_uabort->choice_flag)
			{
				case 0:
					len1 = add_null("4.0",0x00,&asn_buf);
					break;
				case 1:
					len1 = add_null("4.1",0x00,&asn_buf);
					break;
				case 2:
					temp_data[0] = map_uabort->choice.resunavi;
					len1 = add_tlv("4.2.10",1,temp_data,0x00,&asn_buf);
					break;
				case 3:
					temp_data[0] = map_uabort->choice.appproccancel;
					len1 = add_tlv("4.3.10",1,temp_data,0x00,&asn_buf);
					break;
				default:
					break;
			}
			break;
		case MAPDLG_PABORT:
			temp_data[0] = dlg_ptr->map_dlg.map_pabort.reason;
			len1 = add_tlv("5.10",1,temp_data,0x00,&asn_buf);
			break;
		default:
			break;
	}
	asn_encode(data_buf,&asn_buf);
	len = add_tlv("8",0,temp_data,0x20,&asn_buf);
	len = add_tlv("8.6-1",7,MAPP_Dlgpdu,0x00,&asn_buf);
	len = add_tlv("8.0-2",len1,temp_buf,0xa0,&asn_buf);
	return len;
}

u8 extract_mapdlg(struct MapDlg_struct *dlg_ptr,struct dlgport_struct *port_ptr)
{
	struct	MapDlgOpen_struct	*map_open;
	struct	MapDlgUAbort_struct	*map_uabort;
	ASN_BUF	asn_buf;
	u8		temp_buf[256],temp_data[256];
	int		len;

	dlg_ptr->dlg_type = 0xff;
	len = asn_decode(port_ptr->user_info,1,&asn_buf);
	if (len != port_ptr->user_info_len)
	{
		xap_send_error("MAPP extract user info error");
		return 0;
	}
	len = get_tlv("8",temp_buf,&asn_buf);	// get External tag
	if (len == -1)	// has nor external tag
	{
		xap_send_error("MAPP extract user info error");
		return 0;
	}
	len = get_tlv("8.6",temp_buf,&asn_buf);
	if (len == 7)	// get MAP dialgoue PDU
	{
		if (temp_buf[5] != 1 || temp_buf[6] != 1)
		{
			xap_send_error("MAPP extract user info error identifier");
			return 0;
		}
	}
	len = get_tlv("8.0",temp_buf,&asn_buf);	// get ASN.1 type
	if (len == -1)
	{
		xap_send_error("MAPP extract user info error ASN.1 type");
		return 0;
	}
	len = asn_decode(temp_buf,1,&asn_buf);
	len = get_tlv("0",temp_data,&asn_buf);	// MAP_OPEN info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_OPEN;
		map_open = (MapDlgOpen_struct *) &dlg_ptr->map_dlg.map_open;
		map_open->param_flag = 0;
		len = get_tlv("0.0",temp_data,&asn_buf);	// local reference
		if (len != -1)
		{
			map_open->param_flag |= 0x02;
			map_open->local_ref[0] = len;
			memcpy(map_open->local_ref+1,temp_data,len);
		}
		len = get_tlv("0.1",temp_data,&asn_buf);	// peer reference
		if (len != -1)
		{
			map_open->param_flag |= 0x01;
			map_open->peer_ref[0] = len;
			memcpy(map_open->peer_ref+1,temp_data,len);
		}
		return 1;
	}
	len = get_tlv("1",temp_data,&asn_buf);	// MAP_ACCEPT info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_ACCEPT;
		return 1;
	}
	len = get_tlv("2",temp_data,&asn_buf);	// MAP_CLOSE info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_CLOSE;
		return 1;
	}
	len = get_tlv("3",temp_data,&asn_buf);	// MAP_REFUSE info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_REFUSE;
		len = get_tlv("3.10",temp_data,&asn_buf);
		if (len != 1)
		{
			xap_send_error("MAPP extract user info refuse lack reason");
			return 0;
		}
		dlg_ptr->map_dlg.map_refuse.param_flag = 0x01;
		dlg_ptr->map_dlg.map_refuse.reason = temp_data[0];
		return 1;
	}
	len = get_tlv("4",temp_data,&asn_buf);	// MAP_UABORT info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_UABORT;
		map_uabort = (MapDlgUAbort_struct *) &dlg_ptr->map_dlg.map_uabort;
		len = get_tlv("4.0",temp_data,&asn_buf);	// user specific reason
		if (len != -1)
			map_uabort->choice_flag = 0;
		len = get_tlv("4.1",temp_data,&asn_buf);	// user resource limitation
		if (len != -1)
			map_uabort->choice_flag = 1;
		len = get_tlv("4.2",temp_data,&asn_buf);	// resource unabailable
		if (len != -1)
		{
			map_uabort->choice_flag = 2;
			len = get_tlv("4.2.10",temp_data,&asn_buf);
			if (len == -1)
				return 0;
			map_uabort->choice.resunavi = temp_data[0];
		}
		len = get_tlv("4.3",temp_data,&asn_buf);	// APC
		if (len != -1)
		{
			map_uabort->choice_flag = 3;
			len = get_tlv("4.3.10",temp_data,&asn_buf);
			if (len == -1)
				return 0;
			map_uabort->choice.appproccancel = temp_data[0];
		}
		return 1;
	}
	len = get_tlv("5",temp_data,&asn_buf);	// MAP_PAOBRT info
	if (len != -1)
	{
		dlg_ptr->dlg_type = MAPDLG_PABORT;
		len = get_tlv("5.10",temp_data,&asn_buf);
		if (len != 1)
			return 0;
		dlg_ptr->map_dlg.map_pabort.param_flag = 0x01;
		dlg_ptr->map_dlg.map_pabort.reason = temp_data[0];
		return 1;
	}
	xap_send_error("MAPP extract user info unknown type");
	return 0;
}
