#include <stdio.h>
#include <sys/types.h>

#include "../include/public.h"  
#include "../include/ppsm.h"
#include "../include/message.h"
#include "../include/param.h"

#include "../include/plat_inc.h"

/*
#include "../../../../plat/public/src/include/includes.h"
#include "../../../../plat/public/src/include/function.h"
#include "../../../../plat/xapp/src/mapp/map_code.h"
#include "../../../../plat/xapp/src/ixap.h"
*/
#include "../../../../plat/scf/src/include/scfmsg.h"
#include "../../../../plat/scf/src/include/scfdef.h"
//#include "../../../../plat/xapp/src/capp/cap_head.h"
//#include "../../../../plat/xapp/src/capp/cap_public.h"


/*----------------------------------------- */
extern int SetLocationInfo(u_char *cgi,u_short portid);
extern void DebugMsgDelimiter();
extern void DebugMsg();
extern void ppsBcdToAsciiR();
extern void SetRoamingFlag();
/*------------------------------------------------*/
int transferIddBillingPrefix(char *number);
void capMessageProc();
int  decode_initialDP(_state_data *shmp, u_short portid,CapArg capArg);
void tcap_change_local_ssn(u32 proc,u8 src_ssn,u8 dst_ssn);
int  StuffCapMessage(CapArg capArg,PCAP_Message pcapmsg);
/*----------------------------------------- */
extern _state_machine     	*smshm_ptr;
extern _ram_data          	*ramshm_ptr;
extern int		  			logMsgFlag;
extern struct            	timeval tvnow;
/*----------------------------------------- */
extern int   	AssignProcID(int gy_flag);
extern int     	CutUnknownPrefix(char *number);
extern int     	AddInterPrefix(char *number);
extern int     	AddCC(char *number);
extern int     	AddNationalPrefix(char *number);
extern void		PutLogFunID(char *funName);
extern void 	StringCut(char *str, int c);
/*----------------------------------------- */
void capMessageProc()
{
	int			loop, portid,dlgid;
	CAP_Message	capmsg;
	u_char		msg_flow[256];
    _state_data	*shmp=NULL;

	PutLogFunID("capMessageProc");
	for(loop=0;loop<64;loop++)
	{
		if(!GetScfOpen(&capmsg)) // 从Open队列中读取消息，定期调用
			break;
		if(capmsg.msgLength[0]==0 && capmsg.msgLength[1]==0) {// 检查长度域是否> 0
			debugmib.display.proc_begin[6] ++;	     
			continue;
		}
		portid = AssignProcID(0);// 分配处理端口
		if( portid< MAX_FSM_PROCESS && portid>=0 )
		{
			AddPPSStatistics(MIBPPS_CAPOPEN,0);
	   		shmp=(_state_data *) &smshm_ptr->state_data;
		    	shmp += portid;

			shmp->process_info.portid = portid;
			
		    	dlgid =  capmsg.dialogue_id[0]*256 + capmsg.dialogue_id[1];
			shmp->context_info.mtype  = CAP_O_OPEN;
	        	shmp->context_info.dialogue_id = dlgid;
	        	shmp->context_info.new_flag = YES;
	        	shmp->context_info.acn = capmsg.msgContent[0];
	        	shmp->context_info.acn_ver = capmsg.msgContent[1];

			tcap_change_local_ssn(dlgid, SSN_SCF, 0x92);

			if(0)
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
			{  	    	
	    		DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,"[%04d] did=%d cap open received! ACN=[%d.%d]  @(%ld.%ld)",
					portid,dlgid,
					shmp->context_info.acn,
					shmp->context_info.acn_ver,
					tvnow.tv_sec,tvnow.tv_usec);
			}				        
		}
	}
	for(loop=0;loop<10;loop++)
	{
		if(!map_get_open(msg_flow,0x99))
			break;
					
		portid = AssignProcID(0);
		if( portid< MAX_FSM_PROCESS && portid>=0 )
		{
			//AddPPSStatistics(MIBPPS_CAPOPEN,0);
	   		shmp=(_state_data *) &smshm_ptr->state_data;
			shmp += portid;

			shmp->process_info.portid = portid;
			dlgid =  msg_flow[6]*256 + msg_flow[7];
			shmp->context_info.mtype  = 0x80;
			shmp->context_info.map_did = dlgid;
			shmp->context_info.new_flag = YES;
			shmp->context_info.map_acn = msg_flow[11];
			shmp->context_info.map_acn_ver = msg_flow[12];
			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
			{  	    	
	    		DebugMsgDelimiter();
				DebugMsg(debugmib.display.asciiOut,"[%04d] did=%d map open received! (%ld.%ld)",
					portid,dlgid,tvnow.tv_sec,tvnow.tv_usec);
			}				        
		}
	}
}


int
StuffCapMessage(CapArg capArg, PCAP_Message pcap_message)
{
   int msglen, offset=0, len;
   
   PutLogFunID("StuffCapMessage");

//   memset(pcap_message,0,sizeof(CAP_Message));
   pcap_message->msgServiceCode  = CAP_MSG_TYPE;
   pcap_message->dialogue_id[0]  = capArg.dialogue_id>>8;
   pcap_message->dialogue_id[1]  = capArg.dialogue_id;
   pcap_message->dialogue_id[2]  = 0x00;
   pcap_message->port_id[0]      = capArg.port_id>>8;
   pcap_message->port_id[1]      = capArg.port_id;
   pcap_message->port_id[2]      = 0x00;
   pcap_message->msgOperaCode    = capArg.ocode;
   pcap_message->msgOperaType	 = 0x01;
   pcap_message->msgContent[offset++] = capArg.invoke_id;
   pcap_message->msgContent[offset++] = 0x01; //optional point
   pcap_message->msgContent[offset++] = 0x01; //cap msg tag
   len = encode_capmsg(capArg,
					   &pcap_message->msgContent[offset+2],
						234);
   if(len<0 || len>240) return 0;
   pcap_message->msgContent[offset++] = len>>8;
   pcap_message->msgContent[offset++] = len; //cap msg length
   offset += len; 

   if(capArg.ocode != CAP_OC_ReleaseCall && capArg.ocode !=CAP_OC_ReleaseSMS)
   {
	   pcap_message->msgContent[offset++] = 0x10; //delimiter
	   pcap_message->msgContent[offset++] = 0x00;
   }

   pcap_message->msgContent[offset++] = 0x00; //end tag
   msglen  = 9;
   msglen += offset;
   pcap_message->msgLength[0] = msglen>>8;
   pcap_message->msgLength[1] = msglen;
   return msglen;
}

int decode_initialDP_v1(_state_data *shmp,u_short portid,CapArg capArg)
{
	int 		flag,len,cause,unknwon_flag=0;
	int 		err_flag = 0x00;
	//int		mf_call_flag = 0;
	
	CapInitialDP *pInitialDP;

	PutLogFunID("decode_initialDP");
	
	cause = INVALID_MESSAGE;

  	pInitialDP = &capArg.msg_list.initialDPArg;

  	flag = pInitialDP->optional_flag;

	shmp->process_info.serviceKey = pInitialDP->serviceKey;

			
  	if(flag & 0x0400)
  	{ //EventTypeBCSM
  		if(pInitialDP->eventTypeBCSM == capp_termAttemptAuthorized )
  			shmp->context_info.callType = CT_MT_CALL;
  		else
  			shmp->context_info.callType = CT_MO_CALL;
  	}
  	else
  	{
     	DebugMsg(debugmib.display.asciiOut,"Error Msg: EventTypeBCSM missed");
     	err_flag = 0x01;
  	}
	
	if(flag & 0x2000)
	{ //IMSI
		len = pInitialDP->iMSI[0]%9;				
		memcpy(shmp->caller_info.IMSI,
			&pInitialDP->iMSI[1],
			len);
	}
	else
	{
		DebugMsg(debugmib.display.asciiOut,"Error Msg: IMSI missed!");
		//err_flag = 0x01;
	}

	if(flag & 0x040000)
	{ //MSC Address
		 len = pInitialDP->mscAddress[0];
		 if(len>11 || len<2) 
		 {
			DebugMsg(debugmib.display.asciiOut,"Wrong MSC Address!");
			return 0;
		 }
		ppsBcdToAsciiR(shmp->cdr_info.msc_addr, 
					&pInitialDP->mscAddress[2],
					(len-1)*2);
		StringCut(shmp->cdr_info.msc_addr,'F');		
	 
	}
	
    if(flag & 0x01)
    { //callled party number,mandatory
		len = pInitialDP->calledPartyNumber[0];
		if(len>11 || len<3)
		{
			DebugMsg(debugmib.display.asciiOut,"Wrong called party number!");
			return 0;
		}
		unknwon_flag = 0;
		switch(pInitialDP->calledPartyNumber[1])
		{
			case 0x81:  //subscriber
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //unknown
				unknwon_flag = 1;
	
			break;
			case 0x01:
				unknwon_flag = 1;
	
			break;
			case 0x82:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //unknown
				unknwon_flag = 1;
			break;
			case 0x02:
				unknwon_flag = 1;
			break;
			case 0x83:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ; //national
			case 0x03:
				unknwon_flag = 2;
			break;
			case 0x84:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //international 
			case 0x04:
			break;
		}

		if(unknwon_flag == 0)
	              shmp->called_info.nai = 0x91;     
		else if(unknwon_flag == 1)
	              shmp->called_info.nai = 0x81;     
		else
	              shmp->called_info.nai = 0xa1;     

		memcpy(shmp->cdr_info.called,
			&pInitialDP->calledPartyNumber[3],
			len-2); 
		shmp->cdr_info.called[len-2]=0xFF;
		ppsBcdToAsciiR(shmp->called_info.number, 
			&pInitialDP->calledPartyNumber[3], 
			(len-2)*2);
		
		StringCut((char *)shmp->called_info.number, 'F');
                  
		strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);
		
		if(unknwon_flag == 0)
		{
			AddInterPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 1)
		{
	//		CutUnknownPrefix(shmp->called_info.number);
			if(transferIddBillingPrefix((char *)shmp->charge_info.number))
				CutUnknownPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 2)
		{
			AddNationalPrefix((char *)shmp->charge_info.number);
			AddCC((char *)shmp->called_info.number);
		}
		
		CutUnknownPrefix((char *)shmp->called_info.number);
	}
	else
	{
		//DebugMsg(debugmib.display.asciiOut,"Called party number missed!");
		//err_flag = 0x01;	  
   		if(1)//flag & 0x100000)
	  	{ //callled partyBCD number
			len = pInitialDP->calledPartyBCDNumber[0];
			if(len>13 || len<1)
			{
				    	DebugMsg(debugmib.display.asciiOut,"Wrong called partyBCD number!");
						return 0;
			}
		 //81 or 91
		 	unknwon_flag = 0;
		 	switch(pInitialDP->calledPartyBCDNumber[1])
			{
		  		case 0x80:
				case 0xc0:
				 	unknwon_flag = 1;
			 	break;
		   		case 0x81:
				case 0xc1:
				 //check prefix , here
					 unknwon_flag = 1;
            			break;
		   		case 0x90: /*international */
		   		break;
		   		case 0x91:
		   		break;
		  		case 0xa0: /*national */
			 		unknwon_flag = 2;
		   		break;
		   		case 0xa1:
			 		unknwon_flag = 2;
		   		break;
		   		default:
		   		break;
		 	}
			if(unknwon_flag == 0)
	              	shmp->called_info.nai = 0x91;     
			else if(unknwon_flag == 1)
		              shmp->called_info.nai = 0x81;     
			else
	              	shmp->called_info.nai = 0xa1;     

		    memcpy(shmp->cdr_info.called,
  				    &pInitialDP->calledPartyBCDNumber[2],
			    	len-1);          
         		shmp->cdr_info.called[len-1]=0xFF;
		 	ppsBcdToAsciiR(shmp->called_info.number, 
                    &pInitialDP->calledPartyBCDNumber[2], 
                    (len-1)*2);
         		StringCut((char *)shmp->called_info.number, 'F');
         				         	
			strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);

			if(unknwon_flag == 0)
			{
				AddInterPrefix((char *)shmp->charge_info.number);
	//			AddInterPrefix(shmp->called_info.number);
		//		CutUnknownPrefix(shmp->called_info.number);
			}
		 	else if(unknwon_flag == 1)
		 	{
		   		//CutUnknownPrefix(shmp->called_info.number);
		   		if(transferIddBillingPrefix((char *)shmp->charge_info.number))
					CutUnknownPrefix((char *)shmp->charge_info.number);
		 	}
		 	else if(unknwon_flag == 2)
			{
				AddNationalPrefix((char *)shmp->charge_info.number);
		   		AddCC((char *)shmp->called_info.number);
		 	}
			CutUnknownPrefix((char *)shmp->called_info.number);
	  	}
		else
		{
			DebugMsg(debugmib.display.asciiOut,"Warning: Neigther 'Called party number' nor 'Called Party BCD Number' is presented...");
			err_flag = 0x01;	  			
		}
		
	}
	
	if((flag & 0x400000)||(flag & 0x800))
	{ //MF
		shmp->context_info.callType = CT_MF_CALL;
	 	//mf_call_flag = 1;
		
		len = pInitialDP->redirectingPartyID[0];
		if(len>11 || len<3) {
			DebugMsg(debugmib.display.asciiOut,"Wrong redirectingPartyID!");
			return 0;
		}
		unknwon_flag = 0;
		switch(pInitialDP->redirectingPartyID[1] & 0x0F)
		{
			case 1:
			case 2:
				unknwon_flag = 1;
			break;
			case 3:
				unknwon_flag = 2;
			break;
			case 4:
				unknwon_flag = 0;
			break;
		}
		if(pInitialDP->redirectingPartyID[1] & 0x80){
		   //odd number digits, last digit is filler 
			pInitialDP->redirectingPartyID[len] = 
			pInitialDP->redirectingPartyID[len] | 0xF0 ;
		}

		if(unknwon_flag == 0)
	              shmp->caller_info.nai = 0x91;     
		else if(unknwon_flag == 1)
	              shmp->caller_info.nai = 0x81;     
		else
	              shmp->caller_info.nai = 0xa1;     
		
		memcpy(shmp->cdr_info.caller,
			&pInitialDP->redirectingPartyID[3], 
			len-2);
		shmp->cdr_info.caller[len-2]=0xFF;

		ppsBcdToAsciiR(shmp->caller_info.number, 
			&pInitialDP->redirectingPartyID[3], 
			(len-2)*2);
		StringCut((char *)shmp->caller_info.number, 'F');

		if(unknwon_flag == 2)
		{
			AddCC((char *)shmp->caller_info.number);
		}
		CutUnknownPrefix((char *)shmp->caller_info.number);
	}	

	if(flag & 0x02 )
	{ /* calling party number */
		len = pInitialDP->callingPartyNumber[0];
		if(len>11 || len<3)
		{
			DebugMsg(debugmib.display.asciiOut,"Wrong calling party number!");
			return 0;
		}
		unknwon_flag = 0;
		switch(pInitialDP->callingPartyNumber[1])
		{
			case 0x02:
			case 0x82:
				unknwon_flag = 1;
			break;
			case 0x03:
			case 0x83:
				unknwon_flag = 2;
			break;
		}

		if(pInitialDP->callingPartyNumber[1] & 0x80)
		{
			/* odd number digits, last digit is filler  */
			pInitialDP->callingPartyNumber[len] = 
				pInitialDP->callingPartyNumber[len] | 0xF0 ;
		}

		if(shmp->context_info.callType != CT_MF_CALL)
		{
			memcpy(shmp->cdr_info.caller,
				&pInitialDP->callingPartyNumber[3], 
				len-2);
			shmp->cdr_info.caller[len-2]=0xFF;

			if(unknwon_flag == 0)
		              shmp->caller_info.nai = 0x91;     
			else if(unknwon_flag == 1)
		              shmp->caller_info.nai = 0x81;     
			else
		              shmp->caller_info.nai = 0xa1;     
	
	
			ppsBcdToAsciiR(shmp->caller_info.number, 
				&pInitialDP->callingPartyNumber[3], 
				(len-2)*2);
			
			StringCut((char *)shmp->caller_info.number, 'F');

		
			if(unknwon_flag == 0)
			{
				//AddInterPrefix(shmp->charge_info.number);
			}
			else if(unknwon_flag == 1) //unknown
			{
				CutUnknownPrefix((char *)shmp->caller_info.number);
		//		if(transferIddBillingPrefix(shmp->charge_info.number))
			//		CutUnknownPrefix(shmp->charge_info.number);
			}
			else if(unknwon_flag == 2)//national 
			{
		//		AddNationalPrefix(shmp->charge_info.number);
				AddCC((char *)shmp->caller_info.number);
			}

			if(shmp->context_info.callType == CT_MT_CALL)
				strcpy((char *)shmp->charge_info.number, (char *)shmp->caller_info.number);
		}
		else
		{
			if(unknwon_flag == 0)
		              shmp->origin_info.nai = 0x91;     
			else if(unknwon_flag == 1)
		              shmp->origin_info.nai = 0x81;     
			else
		              shmp->origin_info.nai = 0xa1;     
	
	
			ppsBcdToAsciiR(shmp->origin_info.number, 
				&pInitialDP->callingPartyNumber[3], 
				(len-2)*2);
			
			StringCut((char *)shmp->origin_info.number, 'F');
		
			if(unknwon_flag == 0)
			{
			}
			else if(unknwon_flag == 1) //unknown
			{
				CutUnknownPrefix((char *)shmp->origin_info.number);
			}
			else if(unknwon_flag == 2)//national 
			{
				AddCC((char *)shmp->origin_info.number);
			}
		
		}
	}
    	else
	{
		DebugMsg(debugmib.display.asciiOut,"Error Msg: calling party number missed!");
		err_flag = 0x01;
	}
          
	if(flag & 0x8000)
	{//location information
		if(shmp->context_info.callType == CT_MO_CALL)
		{
			if(pInitialDP->locationInformation.cellIdOrLAI_ch==0)
			{
				SetLocationInfo(
					&pInitialDP->locationInformation.cellIdOrLAI.cellIdFixedLength[1],
					portid);
			}
			else
			{
				DebugMsg(debugmib.display.asciiOut,"Location Info. missed for MO Call!");
				return 0;
			}
		}
	//	else if(shmp->context_info.callType == CT_MT_CALL)
		{
			len = pInitialDP->locationInformation.vlr_number[0];
			if(len<2 || len>11)
			{
				DebugMsg(debugmib.display.asciiOut,"Wrong vlr number!");
				return 1; /* roaming not */
			}
			ppsBcdToAsciiR(shmp->cdr_info.locationNumber, 
				&pInitialDP->locationInformation.vlr_number[2],
				(len-1)*2);
			StringCut(shmp->cdr_info.locationNumber,'F');
			SetRoamingFlag(shmp);
		}
	}
	else 
	{
		if(shmp->context_info.callType  == CT_MO_CALL)
		{
			DebugMsg(debugmib.display.asciiOut,"Location Info. missed for MO Call!");
			return 0;
		}
	}

	if(err_flag){
		cause = INVALID_MESSAGE;
		memcpy(&shmp->process_info.tcos ,&cause,2) ;
		return 0;
	}
	return 1;
}


int
decode_initialDP(_state_data *shmp,u_short portid,CapArg capArg)
{
	int 		flag,len,cause,unknwon_flag=0;
	int 		err_flag = 0x00;

	CapInitialDP *pInitialDP;

	PutLogFunID("decode_initialDP");

  	pInitialDP = &capArg.msg_list.initialDPArg;

  	flag = pInitialDP->optional_flag;

	shmp->process_info.serviceKey = pInitialDP->serviceKey;

	if(shmp->context_info.acn_ver == 0)
		return decode_initialDP_v1(shmp,portid,capArg);

	if(pInitialDP->eventTypeBCSM == capp_termAttemptAuthorized)
		shmp->context_info.callType = CT_MT_CALL;
		
	if(flag & 0x040000){ //MSC Address
		 len = pInitialDP->mscAddress[0];
		 if(len>11 || len<2) 
		 {
			DebugMsg(debugmib.display.asciiOut,"Wrong MSC Address!");
			return 0;
		 }
		ppsBcdToAsciiR(shmp->cdr_info.msc_addr, 
					&pInitialDP->mscAddress[2],
					(len-1)*2);
		StringCut(shmp->cdr_info.msc_addr,'F');		
	 
	}else{
		DebugMsg(debugmib.display.asciiOut,"\nError Msg: MSC Address missed");
		err_flag = 0x01;
  	}

  	if(flag & 0x0400){ //EventTypeBCSM
  	}else{
     	DebugMsg(debugmib.display.asciiOut,"Error Msg: EventTypeBCSM missed");
     	err_flag = 0x01;
  	}

  	if(flag & 0x100000){ //Time and timezone
  	}else{
     	DebugMsg(debugmib.display.asciiOut,"Error Msg: Time&timezone missed");
	    err_flag = 0x01;
  	}

	/*
	if(flag & 0x02 )
	{ // calling party number 
         	len = pInitialDP->callingPartyNumber[0];
		 	if(len>11 || len<3)
		 	{
				DebugMsg(debugmib.display.asciiOut,"Wrong calling party number!");
				return 0;
		 	}
			unknwon_flag = 0;
			switch(pInitialDP->callingPartyNumber[1])
			{
				case 0x02:
				case 0x82:
					unknwon_flag = 1;
				break;
				case 0x03:
				case 0x83:
					unknwon_flag = 2;
				break;
			}
		 	if(pInitialDP->callingPartyNumber[1] & 0x80)
		 	{
		   		// odd number digits, last digit is filler  
		   		pInitialDP->callingPartyNumber[len] = 
		   				pInitialDP->callingPartyNumber[len] | 0xF0 ;
		 	}
	}
	*/

  	if(!(flag & 0x01))
	{
    	 	shmp->context_info.callType = CT_MO_CALL;
	 	 if(flag & 0x2000){ //IMSI
			len = pInitialDP->iMSI[0]%9;				
		 	memcpy(shmp->caller_info.IMSI,
				&pInitialDP->iMSI[1],
				len);
	  	}
	  	else{
			DebugMsg(debugmib.display.asciiOut,"Error Msg: IMSI missed!");
			//err_flag = 0x01;
	  	}

		if(flag & 0x02 )
	  	{ /* calling party number */
         		len = pInitialDP->callingPartyNumber[0];
		 	if(len>11 || len<3)
		 	{
				DebugMsg(debugmib.display.asciiOut,"Wrong calling party number!");
				return 0;
		 	}
			unknwon_flag = 0;
	              shmp->caller_info.nai = 0x91;     

			switch(pInitialDP->callingPartyNumber[1])
			{
				case 0x02:
				case 0x82:
					unknwon_flag = 1;
			              shmp->caller_info.nai = 0x81;     

				break;
				case 0x03:
				case 0x83:
					unknwon_flag = 2;
			              shmp->caller_info.nai = 0xa1;     
		
				break;
			}
		 	if(pInitialDP->callingPartyNumber[1] & 0x80)
		 	{
		   		/* odd number digits, last digit is filler  */
		   		pInitialDP->callingPartyNumber[len] = 
		   				pInitialDP->callingPartyNumber[len] | 0xF0 ;
		 	}
	         	memcpy(shmp->cdr_info.caller,
			    	 	&pInitialDP->callingPartyNumber[3], 
				    	len-2);
	         	shmp->cdr_info.caller[len-2]=0xFF;
	         	ppsBcdToAsciiR(shmp->caller_info.number, 
	            	        &pInitialDP->callingPartyNumber[3], 
	                	    (len-2)*2);
		        StringCut((char *)shmp->caller_info.number, 'F');
			
			strcpy((char *)shmp->charge_info.number, (char *)shmp->caller_info.number);
			if(unknwon_flag == 0)
			{
				AddInterPrefix((char *)shmp->charge_info.number);
			}
			else if(unknwon_flag == 1) //unknown
			{
				CutUnknownPrefix((char *)shmp->caller_info.number);
			}
			else if(unknwon_flag == 2)//national 
			{
				AddNationalPrefix((char *)shmp->charge_info.number);
		   		AddCC((char *)shmp->caller_info.number);
			}
    	}
     	else
	  	{
	    	DebugMsg(debugmib.display.asciiOut,"Error Msg: calling party number missed!");
	    	err_flag = 0x01;
      	}

        if(flag & 0x100000)
	  	{ //callled partyBCD number
        	 len = pInitialDP->calledPartyBCDNumber[0];
		 	if(len>13 || len<1)
		 	{
		    	DebugMsg(debugmib.display.asciiOut,"Wrong called partyBCD number!");
				return 0;
			 }
		 //81 or 91
		 	unknwon_flag = 0;
		 	switch(pInitialDP->calledPartyBCDNumber[1])
			{
		  		case 0x80:
				case 0xc0:
				 	unknwon_flag = 1;
			              shmp->called_info.nai = 0x81;     
			
			 	break;
		   		case 0x81:
				case 0xc1:
				 //check prefix , here
					 unknwon_flag = 1;
			              shmp->called_info.nai = 0x81;     

            			break;
		   		case 0x90: /*international */
		   		case 0x91:
			              shmp->called_info.nai = 0x91;     

		   		break;
		  		case 0xa0: /*national */
		   		case 0xa1:
			 		unknwon_flag = 2;
			              shmp->called_info.nai = 0xa1;     

		   		break;
		   		default:
		   		break;
		 	}
		    	memcpy(shmp->cdr_info.called,
  				    &pInitialDP->calledPartyBCDNumber[2],
			    	len-1);          
	         	shmp->cdr_info.called[len-1]=0xFF;
		 	ppsBcdToAsciiR(shmp->called_info.number, 
                    &pInitialDP->calledPartyBCDNumber[2], 
                    (len-1)*2);

			StringCut((char *)shmp->called_info.number, 'F');
			shmp->called_info.nai = pInitialDP->calledPartyBCDNumber[1];
				
			strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);

			if(unknwon_flag == 0)
			{
				AddInterPrefix((char *)shmp->charge_info.number);
	//			AddInterPrefix(shmp->called_info.number);
		//		CutUnknownPrefix(shmp->called_info.number);
	/*	   		if(transferIddBillingPrefix(shmp->charge_info.number))
					CutUnknownPrefix(shmp->charge_info.number);
		*/
			}
		 	else if(unknwon_flag == 1)
		 	{
		   		//CutUnknownPrefix(shmp->called_info.number);
		   		if(transferIddBillingPrefix((char *)shmp->charge_info.number))
					CutUnknownPrefix((char *)shmp->charge_info.number);
		 	}
		 	else if(unknwon_flag == 2)
			{
				AddNationalPrefix((char *)shmp->charge_info.number);
		   		AddCC((char *)shmp->called_info.number);
		 	}
			CutUnknownPrefix((char *)shmp->called_info.number);
	  	}
	  	else
	  	{
		    	DebugMsg(debugmib.display.asciiOut,"Error Msg: called party bcd number missed!");
		    	err_flag = 0x01;
	  	}

	  	if(flag & 0x8000)
	  	{/* location information */
			if(pInitialDP->locationInformation.cellIdOrLAI_ch==0)
			{
			/*both cellid and lac are known */
           		SetLocationInfo(
					&pInitialDP->locationInformation.cellIdOrLAI.cellIdFixedLength[1],portid);
			}else
			{/*only lac is known*/
			}

			len = pInitialDP->locationInformation.vlr_number[0];
			if(len<2 || len>11 ) return 0;
			ppsBcdToAsciiR(shmp->cdr_info.locationNumber, 
						&pInitialDP->locationInformation.vlr_number[2],
						(len-1)*2);
			StringCut(shmp->cdr_info.locationNumber,'F');
	  } 
	  else{
	    err_flag = 0x01;
	  }
  }
  else
  { // MT/MF CALL
	shmp->process_info.dir = 1;
	unknwon_flag = 0;
	if(flag & 0x2000){ //IMSI
		len = pInitialDP->iMSI[0]%9;
		memcpy(shmp->called_info.IMSI,
			&pInitialDP->iMSI[1],
			len);
	}
	else{
		 DebugMsg(debugmib.display.asciiOut,"Error Msg: IMSI missed!");
		 //err_flag = 0x01;
	}

	if(flag & 0x01){ //callled party number,mandatory
		len = pInitialDP->calledPartyNumber[0];
		if(len>11 || len<3)
		{
		    DebugMsg(debugmib.display.asciiOut,"Wrong called party number!");
			return 0;
		}
	 	unknwon_flag = 0;
              shmp->called_info.nai = 0x81;     

		switch(pInitialDP->calledPartyNumber[1])
		{
			case 0x81:  //subscriber
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //unknown
				unknwon_flag = 1;
			break;
			case 0x01:
				unknwon_flag = 1;
			break;
			case 0x82:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //unknown
				unknwon_flag = 1;
			break;
			case 0x02:
				unknwon_flag = 1;
			break;
			case 0x83:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ; //national
			case 0x03:
				unknwon_flag = 2;
		              shmp->called_info.nai = 0xa1;     

			break;
			case 0x84:
				pInitialDP->calledPartyNumber[len] = 
				pInitialDP->calledPartyNumber[len] | 0xF0 ;  //international 

			case 0x04:
		              shmp->called_info.nai = 0x91;     
			break;
		}

		memcpy(shmp->cdr_info.called,
			&pInitialDP->calledPartyNumber[3],
			len-2); 
		shmp->cdr_info.called[len-2]=0xFF;
		ppsBcdToAsciiR(shmp->called_info.number, 
			&pInitialDP->calledPartyNumber[3], 
			(len-2)*2);
		StringCut((char *)shmp->called_info.number, 'F');
		strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);
		
		if(unknwon_flag == 0)
		{
			AddInterPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 1)
		{
	//		CutUnknownPrefix(shmp->called_info.number);
			if(transferIddBillingPrefix((char *)shmp->charge_info.number))
				CutUnknownPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 2)
		{
			AddNationalPrefix((char *)shmp->charge_info.number);
		   	AddCC((char *)shmp->called_info.number);
		 }
		CutUnknownPrefix((char *)shmp->called_info.number);
	}
	else
	{
		err_flag = 0x01;	  
	}

	if(shmp->context_info.callType != CT_MT_CALL)
	{
		if((flag & 0x400000)||(flag & 0x800))
		{ //MF
				
			shmp->context_info.callType = CT_MF_CALL;
			if(flag & 0x2000){ //IMSI
				len = pInitialDP->iMSI[0]%9;
				memcpy(shmp->caller_info.IMSI,
						&pInitialDP->iMSI[1],
						len);
			}
			else{
				DebugMsg(debugmib.display.asciiOut,"Error Msg: IMSI missed!");
				err_flag = 0x01;
			}

			len = pInitialDP->redirectingPartyID[0];
			if(len>11 || len<3) {
				DebugMsg(debugmib.display.asciiOut,"Wrong redirectingPartyID!");
				return 0;
			}
			unknwon_flag = 0;
			switch(pInitialDP->redirectingPartyID[1] & 0x0F)
			{
				case 1:
				case 2:
			    	unknwon_flag = 1;
		              shmp->caller_info.nai = 0x81;     
				break;
				case 3:
			    	unknwon_flag = 2;
		              shmp->caller_info.nai = 0xa1;     
				break;
				case 4:
			    	unknwon_flag = 0;
		              shmp->caller_info.nai = 0x91;     
				break;
			}
			 if(pInitialDP->redirectingPartyID[1] & 0x80){
			   //odd number digits, last digit is filler 
			    pInitialDP->redirectingPartyID[len] = 
			   	pInitialDP->redirectingPartyID[len] | 0xF0 ;
			 }
		         memcpy(shmp->cdr_info.caller,
			     	&pInitialDP->redirectingPartyID[3], 
				    len-2);
	       	  shmp->cdr_info.caller[len-2]=0xFF;


	        	 ppsBcdToAsciiR(shmp->caller_info.number, 
	                    &pInitialDP->redirectingPartyID[3], 
	                    (len-2)*2);
	         	StringCut((char *)shmp->caller_info.number, 'F');

			if(unknwon_flag == 2)
			{
			   	AddCC((char *)shmp->caller_info.number);
			 }
			CutUnknownPrefix((char *)shmp->caller_info.number);
		}
		else
		{  //MT
			//shmp->context_info.callType = CT_MT_CALL;
		}
	}
	
	{
		if(flag & 0x02)
		{
			len = pInitialDP->callingPartyNumber[0];
			if(len>11 || len<2)
			{
				DebugMsg(debugmib.display.asciiOut,"Wrong calling party number!");
				return 0;
		   	}
			unknwon_flag = 0;
	
			switch(pInitialDP->callingPartyNumber[1])
			{
				case 0x02:
				case 0x82:
					unknwon_flag = 1;
			              shmp->caller_info.nai = 0x81;     

				break;
				case 0x03:
				case 0x83:
					unknwon_flag = 2;
			              shmp->caller_info.nai = 0xa1;     

				break;
			}
		
			if(pInitialDP->callingPartyNumber[1] & 0x80)
			{
			   //odd number digits, last digit is filler 
				pInitialDP->callingPartyNumber[len] = 
				pInitialDP->callingPartyNumber[len] | 0xF0 ;
			}
			if(shmp->context_info.callType == CT_MT_CALL)
			{
				if(unknwon_flag == 0)
			              shmp->caller_info.nai = 0x91;     
				else if(unknwon_flag == 1)
		       	       shmp->caller_info.nai = 0x81;     
				else
		              	shmp->caller_info.nai = 0xa1;     

				memcpy(shmp->cdr_info.caller,
				     	&pInitialDP->callingPartyNumber[3], 
					len-2);
				shmp->cdr_info.caller[len-2]=0xFF;
				ppsBcdToAsciiR(shmp->caller_info.number, 
		                    &pInitialDP->callingPartyNumber[3], 
		                    (len-2)*2);
				StringCut((char *)shmp->caller_info.number, 'F');

				strcpy((char *)shmp->charge_info.number, (char *)shmp->caller_info.number);
				if(unknwon_flag == 0)
				{
					AddInterPrefix((char *)shmp->charge_info.number);
				}
				else if(unknwon_flag == 1) //unknown
				{
					CutUnknownPrefix((char *)shmp->caller_info.number);
				}
				else if(unknwon_flag == 2)//national 
				{
					AddNationalPrefix((char *)shmp->charge_info.number);
			   		AddCC((char *)shmp->caller_info.number);
				}	
			}
			else if(shmp->context_info.callType == CT_MF_CALL)
			{
				if(unknwon_flag == 0)
			              shmp->origin_info.nai = 0x91;     
				else if(unknwon_flag == 1)
		       	       shmp->origin_info.nai = 0x81;     
				else
		              	shmp->origin_info.nai = 0xa1;     

				ppsBcdToAsciiR(shmp->origin_info.number, 
		                    &pInitialDP->callingPartyNumber[3], 
		                    (len-2)*2);
				StringCut((char *)shmp->origin_info.number, 'F');

			}
		}
      }
		
	if(flag & 0x8000){//location information
		len = pInitialDP->locationInformation.vlr_number[0];
		if(len<2 || len>11)
		{
			DebugMsg(debugmib.display.asciiOut,"Wrong vlr number!");
			return 0;
		}
		ppsBcdToAsciiR(shmp->cdr_info.locationNumber, 
				&pInitialDP->locationInformation.vlr_number[2],
				(len-1)*2);
		StringCut(shmp->cdr_info.locationNumber,'F');

		if(pInitialDP->locationInformation.cellIdOrLAI_ch==0)
		{
			SetLocationInfo(
				&pInitialDP->locationInformation.cellIdOrLAI.cellIdFixedLength[1],
				portid);
		}
		else
		{
			SetRoamingFlag(shmp);
		}
	}
  }

  if(err_flag){
     cause = INVALID_MESSAGE;
     memcpy(&shmp->process_info.tcos ,&cause,2) ;
     return 0;
  }
  return 1;
}

int
decode_initialDPSMS(_state_data *shmp,u_short portid,CapArg capArg)
{
	int flag,len,cause,unknwon_flag=0;
	int err_flag = 0x00;
	
	CapInitialDPSMS *pInitialDPSMS;

	PutLogFunID("decode_initialDPSMS");

	pInitialDPSMS = &capArg.msg_list.initialDPSMSArg;

	flag = pInitialDPSMS->optional_flag;

	shmp->context_info.callType = CT_MO_SM;

	shmp->process_info.serviceKey = pInitialDPSMS->serviceKey;

	if(flag & 0x01){ //calledPartyBCDNumber
		len = pInitialDPSMS->destinationSubscriberNumber[0];
		if(len>11 || len<2){
			return 0;
		}
		shmp->called_info.nai = 0x91;
		switch(pInitialDPSMS->destinationSubscriberNumber[1])
		{
			case 0x81:
			case 0x80:
				unknwon_flag = 1;
				shmp->called_info.nai = 0x81;
			break;
			case 0x91:
			case 0x90: //international number
			break;
			case 0xA1:
			case 0xA0: //national number
				unknwon_flag = 2;
				shmp->called_info.nai = 0xa1;
			break;
			default:
			break;
		}
		memcpy(shmp->cdr_info.called,
			  &pInitialDPSMS->destinationSubscriberNumber[2],
			  len-1);          
		shmp->cdr_info.called[len-1]=0xFF;

		ppsBcdToAsciiR(shmp->called_info.number, 
					&pInitialDPSMS->destinationSubscriberNumber[2], 
					(len-1)*2);
		StringCut((char *)shmp->called_info.number, 'F');	 
		StringCut((char *)shmp->called_info.number, 'E');	 
						
		strcpy((char *)shmp->charge_info.number, (char *)shmp->called_info.number);

		if(unknwon_flag == 0)
		{
			AddInterPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 1)
		{
			if(CutUnknownPrefix((char *)shmp->called_info.number) !=1)
			{
				cause = NO_ROUTE;
				memcpy(&shmp->process_info.tcos ,&cause,2) ;
				return 0;
			}
			if(transferIddBillingPrefix((char *)shmp->charge_info.number))
				CutUnknownPrefix((char *)shmp->charge_info.number);
		}
		else if(unknwon_flag == 2)
		{
			AddNationalPrefix((char *)shmp->charge_info.number);
			AddCC((char *)shmp->called_info.number);
		}
	}
	
	if(flag & 0x02)
	{ //calling
		len = pInitialDPSMS->callingPartyNumber[0];
		if(len>11 || len<3) return 0;
		memcpy(shmp->cdr_info.caller,
			   &pInitialDPSMS->callingPartyNumber[2], 
			   len-1);
		shmp->cdr_info.caller[len-1]=0xFF;
		ppsBcdToAsciiR(shmp->caller_info.number, 
					&pInitialDPSMS->callingPartyNumber[2], 
					(len-1)*2);
		StringCut((char *)shmp->caller_info.number, 'F');      
		StringCut((char *)shmp->caller_info.number, 'E');      

	}
	if(flag & 0x08)
	{ //imsi
		len = pInitialDPSMS->iMSI[0]%9;
		memcpy(shmp->caller_info.IMSI,
			   &pInitialDPSMS->iMSI[1],
			   len);
    
	}
	if(flag & 0x10)
	{/* location information */
		if(pInitialDPSMS->locationInformation.cellIdOrLAI_ch==0)
		{
		/*both cellid and lac are known */
			SetLocationInfo(
				&pInitialDPSMS->locationInformation.cellIdOrLAI.cellIdFixedLength[1],portid);
		}
		len = pInitialDPSMS->locationInformation.vlr_number[0];
		if(len<2 || len>11 ) return 0;
		ppsBcdToAsciiR(shmp->cdr_info.locationNumber, 
					&pInitialDPSMS->locationInformation.vlr_number[2],
					(len-1)*2);
		StringCut(shmp->cdr_info.locationNumber,'F');
	}

	
  	if(flag & 0x40)
  	{
		len = pInitialDPSMS->sMSCAddress[0];
		if(len<2 || len>11 ) return 0;
		ppsBcdToAsciiR(shmp->cdr_info.smsc_addr, 
					&pInitialDPSMS->sMSCAddress[2],
					(len-1)*2);
		StringCut(shmp->cdr_info.smsc_addr,'F');

  	}

	
	if(err_flag){
		cause = INVALID_MESSAGE;
		memcpy(&shmp->process_info.tcos ,&cause,2) ;
		return 0;
	}
	return 1;

}

int 
ppsDebugCapMsg(CAP_Message *cap_message,int flag)
{
	int loop;
	char buf[1024]={""},buf1[256]={""};
	char capOC[256][40] =
	{
		" InitialDP",
		"",	"",	"",	"","",	"",	"",	"","",	"",	"",	"","",	"",	"",	
		" AssistRequestInstructions",
		" EstablishTemporaryConnection",
		" DisconnectForwardConnection",
		" ConnectToResource",
		" Connect",
		"",
		" ReleaseCall",
		" RequestReportBCSMEvent",
		" EventReportBCSM",
		"",		"",		"",		"",		"",		"",
		" Continue",
		"",
		" ResetTimer",
		" FurnishChargingInformation",
		" ApplyCharging",
		" ApplyChargingReport",
		"",		"",		"",		"",		"",		"",		"",	
		" CallInformationReport",
		" CallInformationRequest",
		" SendChargingInformation",
		" PlayAnnouncement",
		" PromptAndCollectUserInformation",
		" SpecializedResourceReport",
		"",		"",		"",
		" Cancel",
		"",
		" ActivityTest",
		"",		"",		"",		"",
		" InitialDPSMS",
		" FurnishChargingInformationSMS",
		" ConnectSMS",
		" RequestReportSMSEvent",
		" EventReportSMS",
		" ContinueSMS",
		" ReleaseSMS",
		" ResetTimerSMS",
	};

	PutLogFunID("ppsDebugCapMsg");
	DebugMsg(debugmib.display.asciiOut,"");
	if(!flag)
	{
		DebugMsg(debugmib.display.asciiOut,
					" \33[32m-- <P/DID=%04d/%04d> Rec. MSG @%ld.%ld\33[0m",
						cap_message->port_id[0]*256+cap_message->port_id[1],
						cap_message->dialogue_id[0]*256+cap_message->dialogue_id[1],
						tvnow.tv_sec,tvnow.tv_usec);
	}
	else
	{
		DebugMsg(debugmib.display.asciiOut,
					" \33[32m-- <P/DID=%04d/%04d> Snd. MSG @%ld.%ld\33[0m",
						cap_message->port_id[0]*256+cap_message->port_id[1],
						cap_message->dialogue_id[0]*256+cap_message->dialogue_id[1],
						tvnow.tv_sec,tvnow.tv_usec);
	}
	DebugMsg(debugmib.display.asciiOut,"\33[32m <ocode = %d> %s \33[0m",
			cap_message->msgOperaCode,
			capOC[cap_message->msgOperaCode]);

	DebugMsg(debugmib.display.asciiOut," ----------------- Message Flow  -----------------");
	sprintf(buf,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n",
			cap_message->msgLength[0],
			cap_message->msgLength[1],
			cap_message->msgServiceCode,
			cap_message->port_id[0],
			cap_message->port_id[1],
			cap_message->port_id[2],
			cap_message->dialogue_id[0],
			cap_message->dialogue_id[1],
			cap_message->dialogue_id[2],
			cap_message->msgOperaCode,
			cap_message->msgOperaType);

   for(loop=0;loop<cap_message->msgLength[1]-9;loop++)
   {
     sprintf(buf1,"%02X ",cap_message->msgContent[loop]);
     strcat(buf,buf1);
     if((loop+1)%16==0){
		sprintf(buf1,"\r\n");
		strcat(buf,buf1);
		}
   }
   DebugMsg(debugmib.display.asciiOut,"%s",buf);

   return 1;
}

char *GetCapError(char *error,int ocode)
{
	PutLogFunID("GetCapError");

   sprintf(error,"Unknown operation");
   switch(ocode){
     case CAP_O_END:
	   sprintf(error,"cap end");
	 break;
	 case CAP_O_UABORT:
	   sprintf(error,"cap uabort");
	 break;
	 case CAP_O_PABORT:
	   sprintf(error,"cap pabort");
	 break;
	 case CAP_O_ERROR:
	   sprintf(error,"cap error");
	 break;
	 default:
	 break;
   }
   return error;
}
