#include	<stdlib.h>
#include	<stdio.h>

#include    "../include/ppsm.h"
#include    "../include/ramdata.h"
#include    "../include/param.h"
#include	 "../include/mfunc.h"

#include    "../include/plat_inc.h"
#include    "../include/mfunc.h"
#include    "../include/precard.h"
#include    "../include/report.h"
#include    "../include/restapi.h"
/*----------------------------------------*/

extern _ram_data			*ramshm_ptr;
extern _state_machine		*smshm_ptr;
extern int					logMsgFlag;
extern char				logMsisdn[];
extern struct				timeval tvnow;
/*----------------------------------------*/
/*----------------------------------------*/
extern int smppEncodeSM();
extern int DebugMsg();
extern int pps_send_map_opr();

#ifdef OCS_USE_REDIS_DB
extern int RedisGetTariffInfo(u_short portid, char *service_nbr, int service_type, char *called_num);
extern int RedisUpdateUsedBundle(char *service_nbr, int service_type, int rr_id, unsigned long long used_bundle_this_time);
#endif

//extern int map_get_comdata_struct();
//extern int map_com_stof();

extern int pps_send_map_openrsp();

extern int ppsBcdToAsciiR();
extern int GetAccountPos();
extern int GetAccountCosID();
extern int GetAccountCUG();
extern int AccountLatchFlagCheck();
extern int CheckWetherValidRechargeCard();
extern int RechargeRequestProc();
extern int pps_send_map_open();
extern 	void 	StringCut(char *str, int c);
extern 	int 	SendAccountInfoBySMPP();
extern 	int		ppsAsciiToBcdR();
extern	int 	transferAccountUSSDProc(u_short portid);
extern int ppsSendUSSDStatistics(_state_data *shmp);
extern void pps_send_update_subs_status_to_crm(_prepaid_info *user_ptr, int update_flag);
extern	PPSParamStruct	ppsParam;


/*----------------------------------------*/

	
int GetUSSDOperationType(char *ussd_data)
{
	//char	ussd_format[128];
	
	return 1;
}


int ppsGetUssdParameter(char *ussd_data, char *ussd_sc, char *ussd_param, char *ussd_param1)
{
    int i, len, index=0, type=0;

    len = strlen(ussd_data);
    
    ussd_param[0] = '\0'; /* clear ussd parameter */
    ussd_param1[0]= '\0';
	
    for(i=0;i<len;i++)
    {
        if(ussd_data[i] != '*' && ussd_data[i] != '#')
        {
            if(type == 0)
            {
                ussd_sc[index++] = ussd_data[i];
            }
            else             
	    {
	    	  if(type == 1)
                	ussd_param[index++] = ussd_data[i];
		  else if(type==2)
                	ussd_param1[index++] = ussd_data[i];
            }
        }
        else 
        {
           if( ussd_data[i] == '#')
		   	return 1;
		   
            if(index>0)
            {
               type++;
               index = 0;
            }
        }
    }
    return 1;
}

int  GetUSSDRequest(u_short portid, char *ussd_data)
{
	int					retval = 0,len;
	u_char				data_flow[256];
       MapOprSrv_struct		opr_srv;
		
    	struct MapPUSSR_Arg	*pussr_arg;
        	
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);

	if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
	{
    		return retval;
	}

	if((data_flow[9] != ProcUnstrctSSReq) || data_flow[1]<14)
	{	
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid: %d ,did: %d, wait PSSDR but %d received\33[0m",
				portid,shmp->context_info.map_did,data_flow[9]);
		}

		pps_send_map_close(portid);
		return -1;
	}
		
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, Get Map opr,type:<%d>, PUSSR  ",
			portid,shmp->context_info.map_did,
			data_flow[9]);			
		pps_debug_map_msg(data_flow,0);
	}
				
	opr_srv.version = shmp->context_info.map_acn_ver;	
	opr_srv.message_type = data_flow[9];
	opr_srv.message_flag = data_flow[10];
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
	
	if(extract_mapparam(&opr_srv,
		data_flow[9],
		data_flow[10],
		data_flow[14]*256+data_flow[15],
		&data_flow[16])<=0)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31mportid: %d ,did: %d, decode PUSSR failed \33[0m",
				portid,shmp->context_info.map_did);
		}
		ppsSendUSSDStatistics(shmp);
		return -1;
	}
	shmp->context_info.invoke_id = data_flow[11]; //opr_srv.invoke_id;
		
	pussr_arg = &opr_srv.msg_list.pussr_arg;
	if(pussr_arg->param_flag != 0x01)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
					"\n\33[31mportid: %d ,did: %d, decode PUSSR failed \33[0m",
					portid,shmp->context_info.map_did);
		}
		ppsSendUSSDStatistics(shmp);
		return -1;
	}				

	len = pussr_arg->ussd_arg.ussd_string.string_len;
	if(len > 24) len = 24;
	
	switch(pussr_arg->ussd_arg.ussd_scheme & 0x0f)
	{
		case 0x00:
		case 0x0f: /* 7bit */
			smppDecodeSM((char *)pussr_arg->ussd_arg.ussd_string.ussd_data,
						 ussd_data,
						 len); 
		break;
		case 0x04: /* 8bit  */
		default:
			memcpy(ussd_data,
					pussr_arg->ussd_arg.ussd_string.ussd_data,
					len);	
		break;
	}
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"\nportid: %d ,did: %d, USSD data: \r\n\%s  ",
				portid,shmp->context_info.map_did,
				ussd_data);								
	}

	return 1;
}

int	SendUSSDRequest(u_short portid, char *ussd_info)
{
	int					len;
	u_char				buf[256];
	MapOprSrv_struct    opr_srv;
	MapOprData_struct	opr_data;
	struct MapUSSR_Arg  *ussr_arg;
	
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	shmp->context_info.map_iid = 
		map_get_invokeid(shmp->context_info.map_did);
	
	opr_srv.invoke_id = shmp->context_info.map_iid;
	opr_srv.version = shmp->context_info.map_acn_ver;	
	opr_srv.message_type = UnstrctSSReq;
	opr_srv.message_flag = MAP_REQUEST;
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
				
	ussr_arg = &opr_srv.msg_list.ussr_arg;
	ussr_arg->param_flag = 0x01;
	ussr_arg->ussd_arg.param_flag = 0x03;
//	ussr_arg->ussd_arg.ussd_scheme = 0x04; /* 8bit */
	ussr_arg->ussd_arg.ussd_scheme = 0x0f; /* 7bit */
	
	len = smppEncodeSM(ussd_info,buf);
	
	ussr_arg->ussd_arg.ussd_string.string_len = len;//strlen(ussd_info);
	memcpy(ussr_arg->ussd_arg.ussd_string.ussd_data,
			buf,
			ussr_arg->ussd_arg.ussd_string.string_len);
								 
	opr_data.port_id = portid;
	opr_data.dialogue_id = opr_srv.dialogue_id;
	opr_data.invoke_id = opr_srv.invoke_id;
	opr_data.message_type = opr_srv.message_type;
	opr_data.message_flag = opr_srv.message_flag;
	opr_data.param_flag = 0x1f;
	
	len = build_mapparam(&opr_srv,opr_data.param);
	if(len<=0 || len>MAX_MAPPOPR_LEN)
	{
		return 0;
	}
	opr_data.param_len = len;
	opr_data.param_flag |= 0x20;
			
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"portid: %d ,did: %d, Send Map USSD_Req.  @ %ld.%ld",
			portid,shmp->context_info.map_did,
			tvnow.tv_sec,tvnow.tv_usec);
		
	}		
	pps_send_map_opr(&opr_data, 1);
	
	return 1;
}

int SendUSSDNotify(u_short portid, char *ussd_info)
{
	int					len;
	u_char				buf[256];
	MapOprSrv_struct    opr_srv;
    MapOprData_struct	opr_data;
	struct MapUSSN_Arg  *ussn_arg;
	
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	shmp->context_info.map_iid = 
			map_get_invokeid(shmp->context_info.map_did);

	opr_srv.invoke_id = shmp->context_info.map_iid;
	opr_srv.version = shmp->context_info.map_acn_ver;	
	opr_srv.message_type = UnstrctSSNoti;
	opr_srv.message_flag = MAP_REQUEST;
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
				
	ussn_arg = &opr_srv.msg_list.ussn_arg;
	ussn_arg->param_flag = 0x01;
	ussn_arg->ussd_arg.param_flag = 0x03;
	//ussn_arg->ussd_arg.ussd_scheme = 0x04; /* 8bit */
	ussn_arg->ussd_arg.ussd_scheme = 0x0f; /* 7bit */
	
    len = smppEncodeSM(ussd_info,buf);
	ussn_arg->ussd_arg.ussd_string.string_len = len; //strlen(ussd_info);
	memcpy(ussn_arg->ussd_arg.ussd_string.ussd_data,
			buf,
			ussn_arg->ussd_arg.ussd_string.string_len);
								 
	opr_data.port_id = portid;
	opr_data.dialogue_id = opr_srv.dialogue_id;
	opr_data.invoke_id = opr_srv.invoke_id;
	opr_data.message_type = opr_srv.message_type;
	opr_data.message_flag = opr_srv.message_flag;
	opr_data.param_flag = 0x1f;
	
	len = build_mapparam(&opr_srv,opr_data.param);
	if(len<=0 || len>MAX_MAPPOPR_LEN)
	{
		return 0;
	}
	opr_data.param_len = len;
	opr_data.param_flag |= 0x20;
			
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"portid: %d ,did: %d, Send Map USSD_Notify.  @ %ld.%ld",
			portid,shmp->context_info.map_did,
			tvnow.tv_sec,tvnow.tv_usec);
		
	}		
	pps_send_map_opr(&opr_data, 1);		
	return 1;
}

int SendPSSRResponse(u_short portid)
{
	int					len;
	u_char				buf[256];
	MapOprSrv_struct    opr_srv;
    MapOprData_struct	opr_data;
	struct MapPUSSR_Res  *pussr_res;

	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);
	
	opr_srv.invoke_id = shmp->context_info.invoke_id;
	opr_srv.version = shmp->context_info.map_acn_ver;	
	opr_srv.message_type = ProcUnstrctSSReq;
	opr_srv.message_flag = MAP_RESPONSE;
	opr_srv.port_id = portid;
	opr_srv.dialogue_id = shmp->context_info.map_did;		
				
	pussr_res = &opr_srv.msg_list.pussr_res;
	pussr_res->param_flag = 0x01;
	pussr_res->ussd_res.param_flag = 0x03;
	pussr_res->ussd_res.ussd_scheme = 0x0f; /* 7bit */

       switch(shmp->process_info.u_error)
       {
           case CAP_ERR_MISSING_CUSTOMER_RECORD:
               len = smppEncodeSM(getSmsSentenceNative(0,SMS_NOT_REGISTER_PREPAID_USER),buf);
           break;
           case _PPS_ERR_SERVICE_NOT_APPLIED:
           	 len = smppEncodeSM(getSmsSentenceNative(0,SMS_SERVICE_NOT_APPLIED),buf);
           break;
           default:
               len = smppEncodeSM(getSmsSentenceNative(0,SMS_USSD_COMPLETED),buf);
           break;
       }		
	
	pussr_res->ussd_res.ussd_string.string_len = len;//strlen(ussd_info);
	memcpy(pussr_res->ussd_res.ussd_string.ussd_data,
			buf,
			pussr_res->ussd_res.ussd_string.string_len);
								 
	opr_data.port_id = portid;
	opr_data.dialogue_id = opr_srv.dialogue_id;
	opr_data.invoke_id = opr_srv.invoke_id;
	opr_data.message_type = opr_srv.message_type;
	opr_data.message_flag = opr_srv.message_flag;
	opr_data.param_flag = 0x1f;	
	
	len = build_mapparam(&opr_srv,opr_data.param);
	if(len<=0 || len>MAX_MAPPOPR_LEN)
	{
		return 0;
	}
	opr_data.param_len = len;
	opr_data.param_flag |= 0x20;
			
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
			"portid: %d ,did: %d, Send Map PUSSR_Ack.  @ %ld.%ld",
			portid,shmp->context_info.map_did,
			tvnow.tv_sec,tvnow.tv_usec);
		
	}		
	pps_send_map_opr(&opr_data, 0);
	
	return 1;
}




int SendPSSREnd(u_short portid,char *ussd_info)

{

	int					len;

	u_char				buf[256];

	MapOprSrv_struct    opr_srv;

    MapOprData_struct	opr_data;

	struct MapPUSSR_Res  *pussr_res;



	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    



	if(portid>=MAX_FSM_PROCESS)

	{

		return -1;

	}

	

	shmp += (portid);

	

	opr_srv.invoke_id = shmp->context_info.invoke_id;

	opr_srv.version = shmp->context_info.map_acn_ver;	

	opr_srv.message_type = ProcUnstrctSSReq;

	opr_srv.message_flag = MAP_RESPONSE;

	opr_srv.port_id = portid;

	opr_srv.dialogue_id = shmp->context_info.map_did;		

				

	pussr_res = &opr_srv.msg_list.pussr_res;

	pussr_res->param_flag = 0x01;

	pussr_res->ussd_res.param_flag = 0x03;

	pussr_res->ussd_res.ussd_scheme = 0x0f; /* 7bit */



	len = smppEncodeSM(ussd_info,buf);

	

	pussr_res->ussd_res.ussd_string.string_len = len;//strlen(ussd_info);

	memcpy(pussr_res->ussd_res.ussd_string.ussd_data,

			buf,

			pussr_res->ussd_res.ussd_string.string_len);

								 

	opr_data.port_id = portid;

	opr_data.dialogue_id = opr_srv.dialogue_id;

	opr_data.invoke_id = opr_srv.invoke_id;

	opr_data.message_type = opr_srv.message_type;

	opr_data.message_flag = opr_srv.message_flag;

	opr_data.param_flag = 0x1f;

	

	len = build_mapparam(&opr_srv,opr_data.param);

	if(len<=0 || len>MAX_MAPPOPR_LEN)

	{

		return 0;

	}

	opr_data.param_len = len;

	opr_data.param_flag |= 0x20;

			

	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)

	{

		DebugMsg(debugmib.display.asciiOut,

			"portid: %d ,did: %d, Send Map PUSSR_Ack.  @ %ld.%ld",

			portid,shmp->context_info.map_did,

			tvnow.tv_sec,tvnow.tv_usec);

		

	}		

	pps_send_map_opr(&opr_data, 0);

	

	return 1;

}

int SendUSSDTellMeNumberInfo(u_short portid)
{
	char				ussd_info[256];	
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	
	sprintf(ussd_info, "%s %s", getSmsSentenceNative(0,SMS_TELL_ME_NUMBER), shmp->caller_info.number);	
	
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[36m portid: %d ,did: %d, USSD Tell Me Number notify\n %s\33[0m",
				portid,shmp->context_info.map_did,
				ussd_info);								
	}
	SendPSSREnd(portid,ussd_info);
	return 1;	
}

int GetAccountRestInfo(u_short portid, char *prompt_info)
{
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	long	balance, promotion=0;
	char	expire_date[64]={0},promotion_expire_date[64]={0};
   	char	buf[2*MAX_SMS_LEN]="",buf2[4*MAX_SMS_LEN]="";
	int	len,totalLen, tmp_len=0;

	PutLogFunID("GetAccountRestInfo");

	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	memset(buf,0,MAX_SMS_LEN*2);
	memset(buf2,0,MAX_SMS_LEN*4);
	
	AsciiTime(expire_date,shmp->process_info.rest_if.mo_expiry_date);		
	balance = shmp->process_info.rest_if.balance;
		
 	/******************** balance **************************************/
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_
    if(strstr(getSmsSentenceNative(0,SMS_ACCOUNT_BALANCE), "%s") == NULL)
    {
	sprintf(buf,"%s",getSmsSentenceNative(0,SMS_ACCOUNT_BALANCE));
    }
    else
    {
    sprintf(buf, (char *)getSmsSentenceNative(0, SMS_ACCOUNT_BALANCE),
        (char *)shmp->caller_info.number);
    }
#else
	sprintf(buf,"Your balance for %s is ", (char *)shmp->caller_info.number);
#endif
	len = strlen(buf);
	
	strcpy(buf2,buf);
	totalLen = len;

	memset(buf,0,MAX_SMS_LEN*2);
	len = fillMoneyAndDate(balance,expire_date,0,0, (u_char *)buf);
	strcat(buf2,buf);
	totalLen += len;

	tmp_len = totalLen;
	/******************** balance **************************************/

	/******************** promotion **************************************/
	if(promotion > 0)
	{
		memset(buf,0,MAX_SMS_LEN*2);
		sprintf(buf,"%s",getSmsSentenceNative(0,SMS_ACCOUNT_PROMOTION));
		len = strlen(buf);

		strcat(buf2,buf);
		totalLen += len;
			
		memset(buf,0,MAX_SMS_LEN*2);
		len = fillMoneyAndDate(promotion,promotion_expire_date,0,0, (u_char *)buf);
		strcat(buf2,buf);
		totalLen += len;
	}
	memcpy(prompt_info,buf2,240);
	prompt_info[240]=0;

	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[36m portid: %d ,did: %d, USSD inquiry notify\n %s\33[0m",
				portid,shmp->context_info.map_did,
				prompt_info);								
	}

	
	/******************** promotion **************************************/
    return tmp_len;
}

int SendUSSDInqiuryInfo(u_short portid)
{
	char				ussd_info[256];	
	int len;
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	
	len = GetAccountPromptInfo(&shmp->caller_info,ussd_info)%256;	
	ussd_info[len] = 0;
	
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[36m portid: %d ,did: %d, USSD inquiry notify\n %s\33[0m",
				portid,shmp->context_info.map_did,
				ussd_info);								
	}
	//SendUSSDNotify(portid,ussd_info);
	SendPSSREnd(portid,ussd_info);
	return 1;	
}

int SendLowBalanceUSSDNotify(u_short portid)
{
	SendUSSDNotify(portid, (char *)getSmsSentenceNative(0,SMS_LOW_BALANCE_NOTIFY));
	
	return 1;	
}

int SendUSSDRechargeRequest(u_short portid)
{
	SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_RECHARGE_INPUT_PIN));
	return 1;
}

int SendUSSDRechargeRequestAgain(u_short portid)
{
	SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_RECHARGE_INPUT_PIN_AGAIN));
	return 1;
}


int	UssdInquiryProcess(u_short portid)
{
	int			caller_status;
	//int			 instance;
	_state_data	*shmp = (_state_data *) smshm_ptr->state_data;    
      COSTable        *cosTableItem;
      
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	
	if(pps_get_adaptor_flag())
	{
		shmp->process_info.sub_state = S_MAP_REST_QUERY;
		shmp->process_info.sub_state_2 = 0;	
		shmp->process_info.rest_if.rest_oc = 0;
		shmp->process_info.rest_if.rest_src = 0;			
		
		return 0;
	}
	
	shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;

	shmp->process_info.serviceKey = 1;
	shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;

	caller_status = GetAccountStatus(&shmp->caller_info);

	cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
       if(caller_status == T_FRESH)
	{
		if(cosTableItem->accountValidity[0].activiationByInquiryIs)
		{
			int instance;

			UpdateAccountStatus(shmp->caller_info.head,
				shmp->caller_info.tail,
				T_NORMAL);
			UpdateAccountFirstUsedDate(
				shmp->caller_info.head,
				shmp->caller_info.tail);

			UpdateExpirationFirstInquiry(
				&shmp->caller_info,
				cosTableItem->accountValidity[0].validiDaysActivatedByInquiringAccountWithZeroBalance);

			instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT 
						+ shmp->caller_info.tail;

			SendAccountRealSync(instance,0.0,0.0,OMC_OCODE_EDIT);	
			smppSendActivicationInfo(&shmp->caller_info,
				(char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number);  

			caller_status = T_NORMAL;
		}
	}
	
	if(caller_status == T_NORMAL) 
	{
		if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenInquiry)
		{
				SendAccountInfoBySMPP(&shmp->caller_info,
						ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number);  
		}
	}		

	SendUSSDInqiuryInfo(portid);
					
	return 1;
}

int SendUSSDRechargeSuccessInfo(u_short portid)
{
	char ussd_info[256],account_info[250];
	
	_state_data         *shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	
	GetAccountPromptInfo(&shmp->caller_info,account_info);
	sprintf(ussd_info,"%s %s",getSmsSentenceNative(0,SMS_GPRS_RECHARGE_SUCCESS),account_info);
	if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
	{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[36m portid: %d ,did: %d, USSD recharge notify\n %s\33[0m ",
				portid,shmp->context_info.map_did,
				ussd_info);								
	}
	//SendUSSDNotify(portid,ussd_info);

	SendPSSREnd(portid,ussd_info);
	return 1;
}


int SendUSSDFavortieInfo(u_short portid, int type)
{
    char ussd_info[256], buf[128];
    int i, head, tail, cos_id, plan_id, free_sms, free_call_duration;
    int send_request_flag = 0, retval = 1,counter=0;
    _prepaid_info                  *user_ptr=NULL;
    CosFriendFamilyControl   *friendFamilyControl;	
    _state_data                    *shmp = (_state_data *) smshm_ptr->state_data;    
    char *buf_ptr[8],tmp_buf[8][32];

    if(portid>=MAX_FSM_PROCESS)
    {
        return -1;
    }
	
    shmp += (portid);

    head = shmp->caller_info.head;
    tail = shmp->caller_info.tail;
    user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];        	

    for(i=0;i<8;i++)
        buf_ptr[i] = tmp_buf[i];
           
    switch(type)
    {
        case 0:  /* not register F&F service */
            sprintf(ussd_info,"%s",getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NOT_REGISTERED) );
        break;
        case 1:  /* not F&F plan user */
            sprintf(tmp_buf[0], "%d", user_ptr->favorite_numbers);
            counter = 1;
            for(i=0;i<MAX_FAVORITE_NUMBERS;i++)
            {
                if(user_ptr->favorite_number[i][MAX_MSISDN_BLEN-1]>3)
                {   
                    sprintf(tmp_buf[counter], "#%d: ", i);
                    MsisdnToAscii(buf, user_ptr->favorite_number[i]);
                    strcat(tmp_buf[counter++], buf);
                }
            }
            if(counter>2)
            {
               sprintf(ussd_info,"%s ...", ppsParseSentence((char *)getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NOT_PLAN), 2, buf_ptr));
               sendPPSNotificationMessage(head, tail, SMS_FRIEND_FAMILY_QUERY);
            }
            else
            {
                sprintf(ussd_info,"%s", ppsParseSentence((char *)getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NOT_PLAN), counter, buf_ptr));
            }
        break;
        case 2: /* F&F plan service is suspened */
	    cos_id = user_ptr->cos_id;
	    plan_id = user_ptr->favorite_plan_id;
	    friendFamilyControl = &ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0];
	    if(friendFamilyControl->friendFamilyPlan[plan_id-1].rentCharge > GetAccountBalance(head, tail))
	    {
	        sprintf(ussd_info, "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_SUSPENDT));
	    }
	    else
	    {
	        sprintf(ussd_info, "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_SUSPEND_REAC));
	        send_request_flag = 1;
	        retval = 0;
	    }
        break;
        case 3: /* F&F plan service is OK */
	    cos_id = user_ptr->cos_id;
	    plan_id = user_ptr->favorite_plan_id-1;
	    friendFamilyControl = &ppsParam.ppsTables.cosTable[cos_id].friendFamilyControl[0];
           free_sms = friendFamilyControl->friendFamilyPlan[plan_id].freeSMS;
           free_call_duration = friendFamilyControl->friendFamilyPlan[plan_id].freeCallDuration*60;

           sprintf(tmp_buf[0], "%d", user_ptr->favorite_numbers);
          if(free_call_duration>0)
               sprintf(tmp_buf[1], "%lu", user_ptr->free_favorite_call>free_call_duration ? 0: ((free_call_duration- user_ptr->free_favorite_call)/60));
           else
	        sprintf(tmp_buf[1], "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NO_LIMIT));           
           if(free_sms >0)
	        sprintf(tmp_buf[2], "%lu", user_ptr->free_favorite_sms> free_sms ? 0: free_sms-user_ptr->free_favorite_sms);
           else
           	 sprintf(tmp_buf[2], "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY_NO_LIMIT));
         

           sprintf(ussd_info, "%s ", ppsParseSentence((char *)getSmsSentenceNative(0,SMS_FRIEND_FAMILY_QUERY), 3, buf_ptr));
        
/*                
            for(i=0;i<MAX_FAVORITE_NUMBERS;i++)
            {
                if(user_ptr->favorite_number[i][MAX_MSISDN_BLEN-1]>3)
                {   
                    sprintf(buf, "#%d: ", i);
                    strcat(ussd_info, buf);
                    MsisdnToAscii(buf, user_ptr->favorite_number[i]);
                    strcat(ussd_info, buf);
                }
            }
 */       
        default:
        break;
    }
//	GetAccountPromptInfo(&shmp->caller_info,account_info);
//	sprintf(ussd_info,"%s,%s",getSmsSentenceNative(0,SMS_GPRS_RECHARGE_SUCCESS),account_info);
    if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
    {
        DebugMsg(debugmib.display.asciiOut,
                "\n\33[36m portid: %d ,did: %d, USSD Friends & Family info:\n %s\33[0m ",
                portid,shmp->context_info.map_did, ussd_info);								
    }

    if(send_request_flag == 0)
    	 SendPSSREnd(portid,ussd_info);
    else
    	SendUSSDRequest(portid, ussd_info);

    return retval;
}


int reactivateFaviroteSericeUssdProc(u_short portid)
{
    int				retval = 0,len, head ,tail,charge=0;
    u_char				data_flow[256];
    char				ussd_data[256],ussd_info[256];
    MapOprSrv_struct		opr_srv;
     CosFriendFamilyControl   *friendFamilyControl;
		
    //struct MapPUSSR_Arg	*pussr_arg;
    struct MapUSSR_Res  	*ussr_ack;

    _prepaid_info                  *user_ptr=NULL;
    
    _state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

    if(portid>=MAX_FSM_PROCESS)
    {
        return 1;
    }

    shmp += portid;
    
    if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    {
        return retval;
    }
    if((data_flow[9] != UnstrctSSReq) || data_flow[1]<14)
    {	
        if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
        {
            DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d ,did: %d, wait USSDR_ACK but %d received\33[0m",
						portid,shmp->context_info.map_did,data_flow[9]);
        }		
        ppsSendUSSDStatistics(shmp);

        return 1;
    }
			
    if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
    {
        DebugMsg(debugmib.display.asciiOut,
            "\nportid: %d ,did: %d, Get Map opr,type:<%d>, USSR  ",
            portid,shmp->context_info.map_did,
           data_flow[9]);			
        pps_debug_map_msg(data_flow,0);
    }
					
    opr_srv.version = shmp->context_info.map_acn_ver;	
    opr_srv.message_type = data_flow[9];
    opr_srv.message_flag = data_flow[10];
    opr_srv.port_id = portid;
    opr_srv.dialogue_id = shmp->context_info.map_did;		
			
    if(extract_mapparam(&opr_srv,
        data_flow[9],
        data_flow[10],
        data_flow[14]*256+data_flow[15],
        &data_flow[16])<=0)
    {
        if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
        {
            DebugMsg(debugmib.display.asciiOut,
                "\n\33[31mportid: %d ,did: %d, decode USSR_ACK failed \33[0m",
                portid,shmp->context_info.map_did);
        }
        ppsSendUSSDStatistics(shmp);
        return -1;
    }
			
    ussr_ack = &opr_srv.msg_list.ussr_res;
			
    if(ussr_ack->param_flag != 0x01)
    {
        if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
				"\n\33[31mportid: %d ,did: %d, USSR error received \33[0m",
				portid,shmp->context_info.map_did);
	}		
	return -1;
    }				

    retval = 1;
    head = shmp->caller_info.head;
    tail = shmp->caller_info.tail;
    user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];        	
    
    switch(ussr_ack->ussd_res.ussd_scheme & 0x0f)
    {
	case 0x00:
	case 0x0f: /* 7bit */
		smppDecodeSM((char *)ussr_ack->ussd_res.ussd_string.ussd_data,
			ussd_data,
			ussr_ack->ussd_res.ussd_string.string_len); 
	break;
	case 0x04: /* 8bit */
	default:
		memcpy(ussd_data,
			ussr_ack->ussd_res.ussd_string.ussd_data,
			ussr_ack->ussd_res.ussd_string.string_len);	
	break;
    }

    if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
    {
        DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, USSD data: %s",
					portid,shmp->context_info.map_did,
					ussd_data);								
    }

    len = strlen(ussd_data);
    if(len>16)
    {
        ussd_data[16] = 0;
        len = 16;
    }
			
    if(ussd_data[0] == '1') /* check response here */
    {
      
    }
    user_ptr->favorite_plan_state = 0;
    user_ptr->free_favorite_call = 0;
    user_ptr->free_favorite_sms = 0;
    user_ptr->fav_change_counter = 0;
    friendFamilyControl = &ppsParam.ppsTables.cosTable[user_ptr->cos_id].friendFamilyControl[0];    
    charge = friendFamilyControl->friendFamilyPlan[user_ptr->favorite_plan_id-1].rentCharge;

    shmp->caller_info.charge  = charge;
    user_ptr->balance = user_ptr->balance - charge;
    //UpdateAccountBalance( head, tail, -charge );    
   // SendOperatorRechargeCDR(head,tail, -charge);   
    SendPPSGeneralCDR(head, tail, -charge, CT_FF_ACTIVATION);
    SendAccountRealSync(head*UNIT_STORE_ACCOUNT+tail,-charge,0,2);

    if(ppsParam.ppsTables.cosTable[user_ptr->cos_id].smsNotificationInquiry[0].smsNotificationWhenFriendFamilyServiceReg)
        sendPPSNotificationMessage(head, tail, SMS_FRIEND_FAMILY_REG);
    
    sprintf(ussd_info, "%s", getSmsSentenceNative(0,SMS_FRIEND_FAMILY_SERIVCE_REACTIVATE));

    SendPSSREnd(portid,ussd_info);
    //SendUSSDNotify(portid,ussd_info);

    return retval;
    
}
int favoriteNumberUssdProc(u_short portid)
{
    int retval = SERVICE_KEEP_STATE;
    int head,tail;
    _state_data    *shmp = (_state_data *) smshm_ptr->state_data;    
   _prepaid_info   *user_ptr=NULL;
   
    if(portid>=MAX_FSM_PROCESS)
    {
        return -1;
    }
    shmp += (portid);

    switch(shmp->process_info.sub_state_2)    	
    {
        case 0:
        	head = shmp->caller_info.head;
        	tail = shmp->caller_info.tail;
        	user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];
        	if(user_ptr->favorite_plan_id<1 && user_ptr->favorite_numbers<=0)
        	{
                  shmp->process_info.sub_state_2 = 1;
        	}
        	else
        	{
        	    if(user_ptr->favorite_plan_id<1)
        	    {
        	        shmp->process_info.sub_state_2 = 2;
        	    }
        	    else
        	    {
        	        if(user_ptr->favorite_plan_state>0)
        	        {
        	            shmp->process_info.sub_state_2 = 3;
        	        }
        	        else
        	        {
        	            shmp->process_info.sub_state_2 = 4;
        	        }
        	    }
        	}
        break;
        case 1:
  	     SendUSSDFavortieInfo(portid,0);/* not register F&F service */
      	     return SERVICE_EXIT_PPS;        	
        break;
        case 2:
            SendUSSDFavortieInfo(portid, 1); /* not F&F plan user */ 
            return SERVICE_EXIT_PPS;                              	
        break;
        case 3:
        	if( SendUSSDFavortieInfo(portid, 2)== 0)  /* F&F plan service is suspended */
  	    	 shmp->process_info.sub_state_2 = 5;
  	    else
               return SERVICE_EXIT_PPS;
        break;
        case 4:
            SendUSSDFavortieInfo(portid, 3); /* F&F plan service is OK */
            return SERVICE_EXIT_PPS;
        break;
        case 5:
            if(reactivateFaviroteSericeUssdProc(portid))
            {
                return SERVICE_EXIT_PPS; //SERVICE_RETURN_TO_PARENT;
            }
        break;
        default:
            return SERVICE_EXIT_PPS;        	
        break;
    }

    return retval;
}

static int pps_send_rest_msg(u8 *msg_buf, int len)
{
	message_list	iptr_msg;

	iptr_msg.msgSrcPort = REST_PROXY_PORT;
	iptr_msg.msgDstPort = 4900;
	iptr_msg.msgDstIP =   GetLocalIP();
	iptr_msg.msgLength = len;
	memcpy(iptr_msg.msgContent, msg_buf, len);
	iptrPutMessage(iptr_msg);

	return 0;
}

int pps_send_rest_query_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_QUERY;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.query.msisdn, (char *)shmp->caller_info.number);

	len = encode_rest_query(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

extern _prepaid_info	*getPrepaidInfo(_account_info *account);
static int pps_handle_send_authcode_req(_rest_msg_s *rest_req)
{
	_rest_send_authcode_req *pReq = &rest_req->msg.send_authcode_req;
	_rest_msg_s		rest_rsp;
	_rest_send_authcode_rsp *pRsp = &rest_rsp.msg.send_authcode_rsp;
	u8 msg_buf[256];
	int len;

	PutLogFunID("pps_handle_send_authcode_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_send_authcode_req(), msisdn[%s], sms[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn, pReq->sms_content);
	}

	// check log msisdn
	int flag_log_msisdn = 0;
	_account_info user_info;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	int err_code = ERR_REST_SUCCESS;
	if ((strlen(pReq->msisdn) == 0) || (strlen(pReq->sms_content) == 0))
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_send_authcode_req(), invalid param");
		}

		err_code = ERR_REST_INVALID_PARAMETER_VALUE;
		goto out;
	}

	// get user info
	GetAccountPos(&user_info);
	int status = GetAccountStatus(&user_info);
	if ((status != T_NORMAL) && (status != T_SUSPEND))
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_send_authcode_req(), msisdn[%s], err status[%d]", \
						pReq->msisdn, status);
		}
		err_code = ERR_REST_USER_UNKNOWN;
	}
	else
	{
		// send authcode
		smppSendMOSM((char *)user_info.number, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number, \
						(u_char *)pReq->sms_content, strlen(pReq->sms_content), 0);
	}

out:
	// send response msg================
	rest_rsp.msg_type = REST_SEND_AUTHCODE_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_TRANSFER_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_send_authcode_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_query_userdata_req(_rest_msg_s *rest_req)
{
	_rest_query_user_data_req *pReq = &rest_req->msg.query_user_data_req;

	PutLogFunID("pps_handle_query_userdata_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_query_userdata_req(), msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn);
	}

	int flag_log_msisdn = 0;
	_account_info user_info;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	int err_code = ERR_REST_SUCCESS;
	_prepaid_info *pUsrInfo = NULL;
	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_query_userdata_req(), msisdn[%s], not found", \
						pReq->msisdn);
		}
		err_code = ERR_REST_USER_UNKNOWN;// not found
	}

	// set message
	_rest_msg_s		rest_rsp;
	_rest_query_user_data_rsp *pRsp = &rest_rsp.msg.query_user_data_rsp;
	memset(pRsp, 0, sizeof(_rest_query_user_data_rsp));
	memcpy(pRsp->msisdn, pReq->msisdn, 24);
	if (pUsrInfo != NULL)
	{
		//usrGroupName
		int cos_id = GetAccountCosID(&user_info);
		strcpy(pRsp->usrGrpName, (char *)ppsParam.ppsTables.cosTable[cos_id].title);
		
		pRsp->status = pUsrInfo->status;
		pRsp->balance = (u32)pUsrInfo->balance;
		pRsp->mo_expiry = pUsrInfo->mo_expiration_date;
		pRsp->remain_mo_voc_min = pUsrInfo->bundle_info.mo_voice/60;
		pRsp->remain_mt_voc_min = pUsrInfo->bundle_info.mt_voice/60;
		pRsp->remain_sms_num = pUsrInfo->bundle_info.sms;
		pRsp->remain_data_vol = pUsrInfo->bundle_info.data/(1024*1024);
	}
	else
	{
		pRsp->status = T_EXTERNAL;
	}

	// send response msg================
	rest_rsp.msg_type = REST_QUERY_USERDATA_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_QUERY_USERDATA_RSP, result[%d]", err_code);
	}
	
	u8 msg_buf[256];
	int len = encode_rest_query_user_data_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_bundle_subs_req(_rest_msg_s *rest_req)
{
	_rest_bundle_subs_req *pReq = &rest_req->msg.bundle_subs_req;
	_rest_msg_s		rest_rsp;
	_rest_bundle_subs_rsp *pRsp = &rest_rsp.msg.bundle_subs_rsp;
	int len;

	PutLogFunID("pps_handle_bundle_subs_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_bundle_subs_req(), msisdn[%s], pay type[%d], charge[%d]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn, pReq->payType, pReq->charge);
		DebugMsg(debugmib.display.asciiOut,
			"mo[%dMin], mt[%dMin], data[%dMB], sms[%d], valid day[%d]", \
			pReq->moVoiceMinute, pReq->mtVoiceMinute, pReq->dataVolume, pReq->smsNum, pReq->validDays);
	}

	// log msisdn
	_account_info user_info;
	int flag_log_msisdn = 0;
	memset(pRsp, 0, sizeof(_rest_bundle_subs_rsp));
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	// get user info
	int err_code = ERR_REST_SUCCESS;
	GetAccountPos(&user_info);
	user_info.status = GetAccountStatus(&user_info);
	user_info.expired_flag = (u_char)isAccountExpired(&user_info);
	if ((user_info.status != T_NORMAL) || user_info.expired_flag)
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_bundle_subs_req(), msisdn[%s], error, status[%d], expired[%d]", \
					pReq->msisdn, user_info.status, user_info.expired_flag);
		err_code = ERR_REST_USER_UNKNOWN;// not found
		goto out;
	}

	int sms_len = 0;
	char	sms_msg[256] = {0};
	float charge = 0.0;
	if (pReq->payType == 1)// pay by balance
	{
		charge = (float)pReq->charge;
		float balance = GetAccountBalance(user_info.head, user_info.tail);
		
		if(balance < charge)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_bundle_subs_req(), msisdn[%s], balance[%.4f] < request[%.4f]", \
						pReq->msisdn, balance, charge);
			err_code = ERR_REST_CREDIT_LIMIT;// not acceptable
			
			sprintf(sms_msg, "%s", getSmsSentenceNative(0, SMS_BUNDLE_PLAN_SUBSCRIBE_NOK));
			goto out;
		}
		
		// update balance
		UpdateAccountBalance(user_info.head, user_info.tail, -charge);
	}

	// update bundle info
	long	ret_value[10];
	ret_value[0] = 0 - (long)charge;
	ret_value[1] = pReq->dataVolume;
	ret_value[2] = pReq->moVoiceMinute;
	ret_value[3] = pReq->mtVoiceMinute;
	ret_value[4] = pReq->smsNum;
	ret_value[5] = pReq->validDays;
	ret_value[6] = 0;
	UpdateAccountBundlePlanInfo(&user_info, ret_value);
	//

	// sync
	int instance = user_info.head*UNIT_STORE_ACCOUNT + user_info.tail;
	SendAccountRealSync(instance, -charge, 0, OMC_OCODE_EDIT);
	//

	// send cdr===========================================
	SendSelfcareBundleSubCDR(&user_info, (int)charge, pReq->dataVolume*1024, pReq->moVoiceMinute*60);
	//

	// set sms string
	char		expire_date[64];
	char msg_buf[256] = {0};
	GetAccountBundlePlanInfo(&user_info, ret_value);
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "new bundle, data [%ld]MB, mo [%ld]Min, mt [%ld]Min, sms[%ld]", \
					ret_value[0], ret_value[1], ret_value[2], ret_value[3]);
	}
	
	AsciiTimeYMD(expire_date, ret_value[4]);
	sprintf(sms_msg, "%s", getSmsSentenceNative(0, SMS_BUNDLE_PLAN_SUBSCRIBE_OK));
	if(ret_value[1]>0 || ret_value[3]>0)
	{
		sprintf(msg_buf, (char *)getSmsSentenceNative(0, SMS_BUNDLE_PLAN_QUERY),
			ret_value[0],
			ret_value[1],
			// ret_value[2],// disable MT voice
			ret_value[3],
			expire_date);
	}
	else
	{
		sprintf(msg_buf, (char *)getSmsSentenceNative(0, SMS_BUNDLE_PLAN_QUERY_DATA),
			ret_value[0],
			expire_date);
	}
	
	strcat(sms_msg, msg_buf);
	//

out:
	// send sms
	sms_len = strlen(sms_msg);
	if (sms_len > 0)
	{
		smppSendMOSM(pReq->msisdn, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number, (u_char *)sms_msg, sms_len, 0);
	}
	//

	// send response msg================
	rest_rsp.msg_type = REST_BUNDLE_SUBS_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_BUNDLE_SUBS_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_bundle_subs_rsp(&rest_rsp, (u8 *)msg_buf);
	pps_send_rest_msg((u8 *)msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_bundle_usage_req(_rest_msg_s *rest_req)
{
	_rest_bundle_usage_req *pReq = &rest_req->msg.bundle_usage_req;

	PutLogFunID("pps_handle_bundle_usage_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_bundle_usage_req(), msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn);
	}

	_account_info user_info;
	int flag_log_msisdn = 0;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	int err_code = ERR_REST_SUCCESS;
	_prepaid_info *pUsrInfo = NULL;
	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_bundle_usage_req(), msisdn[%s], not found", \
					pReq->msisdn);
		err_code = ERR_REST_USER_UNKNOWN;// not found
	}

	// set msg
	_rest_msg_s		rest_rsp;
	_rest_bundle_usage_rsp *pRsp = &rest_rsp.msg.bundle_usage_rsp;
	memset(pRsp, 0, sizeof(_rest_bundle_usage_rsp));
	if (pUsrInfo != NULL)
	{
		pRsp->moVoiceInSec = pUsrInfo->bundle_info.mo_voice;
		pRsp->mtVoiceInSec = pUsrInfo->bundle_info.mt_voice;
		pRsp->smsNum = pUsrInfo->bundle_info.sms;
		pRsp->dataVolInKB = pUsrInfo->bundle_info.data/1024;
		pRsp->expiredTime = pUsrInfo->bundle_info.validity_date;
	}
	//

	// send response msg================
	rest_rsp.msg_type = REST_BUNDLE_USAGE_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_BUNDLE_USAGE_RSP, result[%d], data[%d]KB, mo[%d]sec, mt[%d]sec, sms[%d]", 
					err_code, pRsp->dataVolInKB, pRsp->moVoiceInSec, pRsp->mtVoiceInSec, pRsp->smsNum);
	}
	
	u8 msg_buf[256];
	int len = encode_rest_bundle_usage_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_recharge_req(_rest_msg_s *rest_req)
{
	_rest_recharge_req *pReq = &rest_req->msg.recharge_req;
	int len;
	int op_type = CT_ASSISTED_UP;
	u8 msg_buf[256];
	int flag_log_msisdn = 0;
	_account_info user_info;
	int err_code = ERR_REST_SUCCESS;

	char	sms_msg[256] = {0};
	int balance;
	float recharge;
	_prepaid_info	*pUserInfo = NULL;

	_rest_msg_s		rest_rsp;
	_rest_recharge_rsp *pRsp = &rest_rsp.msg.recharge_rsp;


	PutLogFunID("pps_handle_recharge_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_recharge_req(), op_type=%d, msisdn[%s], amount[%d]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->op_type, pReq->msisdn, pReq->amount);
	}

	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}
	
	GetAccountPos(&user_info);
	user_info.status = GetAccountStatus(&user_info);
	user_info.expired_flag = (u_char)isAccountExpired(&user_info);
	user_info.cos_id = (u_char)GetCosIDByAccount(&user_info);
	if ((user_info.status != T_NORMAL && user_info.status != T_FRESH && user_info.status != T_SUSPEND && user_info.status != T_DISABLE))
//	if ((user_info.status != T_NORMAL && user_info.status != T_FRESH && user_info.status != T_SUSPEND) || user_info.expired_flag)
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_req(), msisdn[%s], error, status[%d], expired[%d]", \
					pReq->msisdn, user_info.status, user_info.expired_flag);
		err_code = ERR_REST_USER_UNKNOWN;// not found
		goto out;
	}

	memset(pRsp, 0, sizeof(_rest_recharge_rsp));

	balance = (int)GetAccountBalance(user_info.head, user_info.tail);

	if(pReq->op_type == 0)
	{
		if (balance < pReq->amount )
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_req(), msisdn[%s], balance[%d] exceed maximum[%d]", \
						pReq->msisdn, (balance + pReq->amount), ppsParam.serviceControl.maxBalance);
			err_code = ERR_REST_CREDIT_LIMIT;
			sprintf(sms_msg, "%s", "Recharge failed, you have exceeded your maximum balance.");
			smppSendMOSM(pReq->msisdn, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number, (u_char *)sms_msg, strlen(sms_msg), 0);
			goto out;
		}
		op_type = CT_ASSISTED_DOWN;
		recharge = (-1)*(float)pReq->amount;
		
	}
	else if(pReq->op_type == 1)
	{
		if ((balance + pReq->amount) >= ppsParam.serviceControl.maxBalance)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_req(), msisdn[%s], balance[%d] exceed maximum[%d]", \
						pReq->msisdn, (balance + pReq->amount), ppsParam.serviceControl.maxBalance);
			err_code = ERR_REST_INVALID_PARAMETER_VALUE;
			sprintf(sms_msg, "%s", "Recharge failed, you have exceeded your maximum balance.");
			smppSendMOSM(pReq->msisdn, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number, (u_char *)sms_msg, strlen(sms_msg), 0);
			goto out;
		}
		op_type = CT_ASSISTED_UP;
		recharge = (float)pReq->amount;

	}
	else
	{
			err_code = ERR_REST_INVALID_PARAMETER_VALUE;
			sprintf(sms_msg, "%s", "Recharge failed, wrong op_type.");
			goto out;
	}
	
	// update balance
	//UpdateAccountBalance(user_info.head, user_info.tail, pReq->amount);
	UpdateAccountBalance(user_info.head, user_info.tail, recharge);

	pUserInfo = getPrepaidInfo(&user_info);

	// send cdr=====================================================
	
	SendSelfcareRechargeCDR(&user_info, "", op_type, (int)pReq->amount);

	// update status
	COSTable *cosTableItem = &ppsParam.ppsTables.cosTable[user_info.cos_id];
	if (T_FRESH == user_info.status) 
	{
		// update first used date
		//int index;
		//int mo_valid_time = 30, mt_valid_time = 30;
		/*
		_prepaid_data *shmp = &ramshm_ptr->prepaid_data;
		if((index=GetCardSystemParamByNearestValue(user_info.cos_id, (u_short)pReq->amount))>=0){
			mo_valid_time = cosTableItem->rechargeCardValidity[index].moValidity;
			mt_valid_time = cosTableItem->rechargeCardValidity[index].mtValidity;
		}
		*/
		/*
		mo_valid_time = mt_valid_time = pReq->valid_days;
		if(mo_valid_time<=0)
			mo_valid_time = mt_valid_time = 1;
		
		shmp->prepaid_info[user_info.head][user_info.tail].mo_expiration_date = 
			mo_valid_time*24*60*60 + tvnow.tv_sec;
		shmp->prepaid_info[user_info.head][user_info.tail].mt_expiration_date = 
			mt_valid_time*24*60*60 + tvnow.tv_sec;
		*/
		UpdateAccountFirstUsedDate(user_info.head, user_info.tail);
		UpdateExpirationForRechargeCard(&user_info, pReq->valid_days, (u_short)pReq->amount);
		UpdateAccountStatus(user_info.head, user_info.tail, T_NORMAL);
	}
	else
	{
		if(op_type == CT_ASSISTED_UP)
		{
			int old_status=0x00;
			
			old_status = GetAccountStatus(&user_info);
				
			UpdateExpirationForRechargeCard(&user_info, pReq->valid_days, (u_short)pReq->amount);
			UpdateAccountStatus(user_info.head, user_info.tail, T_NORMAL);

			if(old_status != T_NORMAL && old_status != T_FRESH)
				pps_send_update_subs_status_to_crm(pUserInfo, 1);	//update status to CRM , may then invoke procedures towards HLR/HSS
		}
	}
	//

	// Sync
	u32 instance = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
	SendAccountRealSync(instance, recharge, 0.0, OMC_OCODE_EDIT);

	// send notification sms
	if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenRecharge) 
	{
		SendAccountInfoBySMPP(&user_info, ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number);
	}

	// set respons msg
	pRsp->status = GetAccountStatus(&user_info);
	pRsp->balance = GetBalance(&user_info);
	pRsp->expiredTime = (u64)GetExpiration(&user_info);


	if(pUserInfo->cug_id>0 && pUserInfo->crm_info.vas_cug_state>0)
	{
		pps_send_rent_charge_to_crm(user_info.head, user_info.tail);
	}
out:
	// send response msg================
	rest_rsp.msg_type = REST_RECHARGE_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_RECHARGE_RSP, result[%d], balance[%d]", err_code, pRsp->balance);
	}
	
	len = encode_rest_recharge_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

extern int isChildTransferAllowed(_prepaid_info *prepaidInfo);
extern int checkTransferedPartialFee(_account_info *callerInfo, float feeTransfered);

static int pps_handle_transfer_req(_rest_msg_s *rest_req)
{
	_rest_transfer_req *pReq = &rest_req->msg.transfer_req;
	int err_code = ERR_REST_SUCCESS, len;
	u8 msg_buf[256];
	u_char tmp[MAX_SMS_LEN*4] = {0};

	PutLogFunID("pps_handle_transfer_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_transfer_req(), transfer out[%s], in[%s], amount[%d]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->transferOutMsisdn, pReq->transferInMsisdn, pReq->amount);
	}

	_account_info user_info;
	strcpy((char *)user_info.number, pReq->transferOutMsisdn);

	// check log msisdn
	int flag_log_msisdn = 0;
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	// check param
	_rest_msg_s		rest_rsp;
	_rest_transfer_rsp *pRsp = &rest_rsp.msg.transfer_rsp;
	memset(pRsp, 0, sizeof(_rest_transfer_rsp));
	if ((pReq->amount == 0) || (strlen(pReq->transferOutMsisdn) == 0) || (strlen(pReq->transferInMsisdn) == 0))
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "pps_handle_transfer_req(), err param, transfer out msisdn[%s]", pReq->transferOutMsisdn);
		}
		goto out;
	}

	// check src number
	_prepaid_info *prepaidInfo = NULL;
	GetAccountPos(&user_info);
	if ((GetAccountStatus(&user_info) != T_NORMAL)\
		|| ((prepaidInfo = getPrepaidInfo(&user_info)) == NULL)\
		|| ((prepaidInfo->poolAccount.role == MASTER_SLAVE_CHILD)\
			&& (isChildTransferAllowed(prepaidInfo) == FALSE)))
	{
		strcpy((char *)tmp, (char *)getSmsSentenceNative(0, SMS_SERVICE_NOT_APPLIED));
		smppSendMsg((u_char *)pReq->transferOutMsisdn, tmp, FeeTransferPosition);

		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "src number[%s], SMS_SERVICE_NOT_APPLIED", pReq->transferOutMsisdn);
		}
		
		err_code = ERR_REST_USER_UNKNOWN;// not found
		goto out;
	}

	// check transfer fee
	float amount = (float)pReq->amount;
	int result = checkTransferedPartialFee(&user_info, amount);
	switch(result)
	{
	case CHECK_TRANSFERED_FEE_INSUFFIENT:
		strcpy((char *)tmp, (char *)getSmsSentenceNative(0, SMS_INSUFFICIENT_FEE));
		smppSendMsg((u_char *)pReq->transferOutMsisdn, tmp, FeeTransferPosition);
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "src number[%s], SMS_INSUFFICIENT_FEE", pReq->transferOutMsisdn);
		}
		
		err_code = ERR_REST_CREDIT_LIMIT;
		goto out;
		break;
	case CHECK_TRANSFERED_FEE_EXPIERED:
		strcpy((char *)tmp, (char *)getSmsSentenceNative(0, SMS_EXPIRED_ACCOUNT));
		smppSendMsg((u_char *)pReq->transferOutMsisdn, tmp, FeeTransferPosition);
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "src number[%s], SMS_EXPIRED_ACCOUNT", pReq->transferOutMsisdn);
		}
		
		err_code = ERR_REST_INVALID_USER_STATUS;
		goto out;
		break;
	default:
		break;
	}
	//

	// check dst number
	_account_info dst_user;
	strcpy((char *)dst_user.number, pReq->transferInMsisdn);
	int bDstAllowFlag = 0;
	if (GetAccountPos(&dst_user) == TRUE)
	{
		if (get_transfer_status_normal_flag())
		{
			int status = GetAccountStatus(&dst_user);
			if ((status == T_NORMAL) || (status == T_FRESH) || (status == T_SUSPEND))
			{
				bDstAllowFlag = 1;
			}
		}
		else
		{
			bDstAllowFlag = 1;
		}
	}

	if (!bDstAllowFlag)
	{
		strcpy((char *)tmp, (char *)getSmsSentenceNative(0, SMS_INVALID_NUMBER));
		smppSendMsg((u_char *)pReq->transferOutMsisdn, tmp, FeeTransferPosition);
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
		{
			DebugMsg(debugmib.display.asciiOut, "dst number[%s], SMS_INVALID_NUMBER", pReq->transferInMsisdn);
		}
		
		err_code = ERR_REST_DEST_USER_NOT_ALLOWED;
		goto out;
	}
	//

	// fee transfer
	poolTransferAccount(&user_info, &dst_user, amount);
	if(OCS_with_external_CRM() == 0)
	{
		notifyUserTransferResult_1(&user_info, &dst_user, (int)amount, NOTIFY_CALLER);
		notifyUserTransferResult_1(&user_info, &dst_user, (int)amount, NOTIFY_CALLED);
	}
	// send cdr
	float charge = (float)pReq->amount;
	SendSelfcareTransferCDR(&user_info, &dst_user, -charge);
	SendSelfcareTransferCDR(&dst_user, &user_info, charge);
	//

	// set response message
	pRsp->balance = (u32)GetAccountBalance(user_info.head, user_info.tail);

out:
	// send response msg================
	rest_rsp.msg_type = REST_TRANSFER_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_TRANSFER_RSP, result[%d], balance[%d]", err_code, pRsp->balance);
	}
	
	len = encode_rest_transfer_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

extern _climax_quence climaxQuence;
extern int GetClimaxQuenceStorePos(u_char *card_pwd,int start,int end);
extern int pps_real_update_card_file(int head, int tail);
static int pps_handle_recharge_card_req(_rest_msg_s *rest_req)
{
	_rest_recharge_card_req *pReq = &rest_req->msg.recharge_card_req;
	int err_code = ERR_REST_SUCCESS, len;
	u8 msg_buf[256];
	char	sms_msg[256] = {0};

	PutLogFunID("pps_handle_recharge_card_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_recharge_card_req(), msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn);
	}

	_account_info user_info;
	int flag_log_msisdn = 0;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	_rest_msg_s		rest_rsp;
	_rest_recharge_card_rsp *pRsp = &rest_rsp.msg.recharge_card_rsp;
	memset(pRsp, 0, sizeof(_rest_recharge_card_rsp));
	GetAccountPos(&user_info);
	user_info.status = GetAccountStatus(&user_info);
	user_info.expired_flag = isAccountExpired(&user_info);
	user_info.cos_id = GetCosIDByAccount(&user_info);
	if ((user_info.status != T_NORMAL && user_info.status != T_FRESH && user_info.status != T_SUSPEND) || user_info.expired_flag)
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], error status[%d] or expired[%d]", \
					pReq->msisdn, user_info.status, user_info.expired_flag);
		err_code = ERR_REST_USER_UNKNOWN;// not found
		goto out;
	}

	len = strlen(pReq->cardPwd);/* to judge length of pwd,6,8 */
	if(len <10 || len >16)
	{
		SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_FAIL, 0);
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], error pwd len[%d]", \
					pReq->msisdn, len);
		err_code = ERR_REST_INVALID_RECHARGE_PWD;
		goto fail;
	}

	if(OCS_with_external_CRM())
	{
		int proc_id = 0;
		_state_data 	*shmp;
		
		proc_id = AssignProcID(0);
		if(proc_id<0) return 0;
		
		shmp = (_state_data *)&smshm_ptr->state_data;
	   	shmp += proc_id;
	   	shmp->process_info.portid = proc_id;

		memcpy(&shmp->caller_info, &user_info, sizeof(_account_info));
		strcpy((char *)shmp->called_info.number, pReq->cardPwd);

		shmp->process_info.state = S_SMMP_RECHAGE_ACCOUNT;
		shmp->process_info.chargeFrom = 3;
		shmp->process_info.sub_state = 2;
		shmp->process_info.rest_if.src_ref = rest_req->header.src_ref;
		shmp->process_info.rest_if.dst_ref = proc_id;
		
		return 1;
	}
	

	char	card_pwd[64]="";
	int cardsqu = 0, cardtail = 0;
	_recharge_card_info	*cardshmp = NULL;
	EncryptCardHRN(pReq->cardPwd, (u_char *)card_pwd);
	if((cardsqu = GetClimaxQuenceStorePos((u_char *)card_pwd, 0, climaxQuence.counter)) < 0)
	{
		SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_FAIL, 0);
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], card not found", \
					pReq->msisdn);
		err_code = ERR_REST_INVALID_RECHARGE_PWD;
		goto fail;
	}
	cardtail = cardsqu % MAX_CARD_NUM_PSEG;
	cardsqu  = cardsqu / MAX_CARD_NUM_PSEG;
	
	cardshmp=&ramshm_ptr->card_data.prepaid_card[cardsqu][cardtail];
	if(memcmp(card_pwd, cardshmp->card_pwd, MAX_CARD_HRN_BLEN))
	{ /* error password */
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], error pwd", \
					pReq->msisdn);
		err_code = ERR_REST_INVALID_RECHARGE_PWD;
		goto fail;
   	}
   
	if(cardshmp->card_status != CARD_FRESH)
	{
		SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_FAIL, 0);
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], card already used", \
					pReq->msisdn);
		err_code = ERR_REST_INVALID_RECHARGE_PWD;
		goto fail;
	}
	
	if(cardshmp->expiry_date < time(NULL))
   	{
		SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_FAIL, 0);
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], card expired", \
					pReq->msisdn);
		err_code = ERR_REST_INVALID_RECHARGE_PWD;
		goto fail;
	}

	int balance = (int)GetAccountBalance(user_info.head, user_info.tail);
	if ((balance + cardshmp->face_value) >= ppsParam.serviceControl.maxBalance)
	{
		SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_FAIL, 0);
		DebugMsg(debugmib.display.asciiOut, "pps_handle_recharge_card_req(), msisdn[%s], balance[%d] exceed maximum[%d]", \
					pReq->msisdn, (balance + cardshmp->face_value), ppsParam.serviceControl.maxBalance);
		err_code = ERR_REST_UNABLE_TO_COMPLY;
		sprintf(sms_msg, "%s", "Recharge failed, you have exceeded your maximum balance.");
		smppSendMOSM(pReq->msisdn, (char *)ppsParam.ppsTables.serviceNumber[InquiryNumberPosition].number, (u_char *)sms_msg, strlen(sms_msg), 0);
		goto fail;
	}

	// update balance
	float amount = (float)cardshmp->face_value;
	UpdateAccountBalance(user_info.head, user_info.tail, amount);

	// update card
	cardshmp->card_status = CARD_USED;
	cardshmp->updated_date = tvnow.tv_sec;
	strcpy(cardshmp->msisdn_used, pReq->msisdn);
	SendPrepaidCardRealSync(cardsqu*MAX_CARD_NUM_PSEG+cardtail, 5);//delete
	pps_real_update_card_file(cardsqu, cardtail);
	//

	// send cdr=====================================================
	SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_SUCCESS, (int)cardshmp->face_value);

	// update status
	COSTable *cosTableItem = &ppsParam.ppsTables.cosTable[user_info.cos_id];
	if (T_FRESH == user_info.status) 
	{
		// update first used date
		int index;
		int mo_valid_time = cardshmp->valid_time, mt_valid_time = cardshmp->valid_time;
		_prepaid_data *shmp = &ramshm_ptr->prepaid_data;
		if((index=GetCardSystemParam(user_info.cos_id, (u_short)cardshmp->face_value))>=0){
			mo_valid_time = cosTableItem->rechargeCardValidity[index].moValidity;
			mt_valid_time = cosTableItem->rechargeCardValidity[index].mtValidity;
		}

		shmp->prepaid_info[user_info.head][user_info.tail].mo_expiration_date = 
			mo_valid_time*24*60*60 + tvnow.tv_sec;
		shmp->prepaid_info[user_info.head][user_info.tail].mt_expiration_date = 
			mt_valid_time*24*60*60 + tvnow.tv_sec;
		//
		
		UpdateAccountFirstUsedDate(user_info.head, user_info.tail);
		UpdateAccountStatus(user_info.head, user_info.tail, T_NORMAL);
	}
	else
	{
		UpdateExpirationForRechargeCard(&user_info, cardshmp->valid_time, (u_short)cardshmp->face_value);
		UpdateAccountStatus(user_info.head, user_info.tail, T_NORMAL);
	}
	//

	// promotion 
	int promo_balance = 0;
	if(IsPromotionTime(cosTableItem, tvnow))
	{
		int promo_balance = GetPromotionAmount(cosTableItem, (int)cardshmp->face_value);
		if(promo_balance !=0)
		{
			UpdateAccountPromotionBalance(user_info.head, user_info.tail, (float)promo_balance);
			UpdateAccountPromotionExpiryDay(user_info.head, user_info.tail, GetPromotionDay(cosTableItem, cardshmp->face_value));

			// send cdr==========================================================================
			//shmp->cdr_info.answertime = tvnow.tv_sec + 1;
			SendSelfcareRechargeCDR(&user_info, pReq->cardPwd, CT_RECHARGE_SUCCESS, promo_balance);
		}
	}
	//

	// Sync
	u32 instance = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
	ResetAccountRechargeFail(user_info.head, user_info.tail);
	resetCMBTimes(&user_info);
	SendAccountRealSync(instance, amount, promo_balance, OMC_OCODE_EDIT);

	// send notification sms
	if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenRecharge) 
	{
		SendAccountInfoBySMPP(&user_info, ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number);
	}

	// set respons msg
	pRsp->balance = GetBalance(&user_info);
	pRsp->rechargeAmount = (u32)cardshmp->face_value;
	pRsp->expiredTime = (u64)GetExpiration(&user_info);

	goto out;

fail:
	// send cdr==========================================================
	//SendRechargeCDR(proc_id, CT_RECHARGE_FAIL, 0);
	UpdateAccountRechargeFail(user_info.head, user_info.tail);
	int maxThreshold = GetParamRechargeAttemptLimit();
	if ((maxThreshold>0) && (maxThreshold < GetAccountRechargeFail(user_info.head, user_info.tail))) 
	{
	 	UpdateAccountStatus(user_info.head, user_info.tail, T_BLACKLIST);
		ResetAccountRechargeFail(user_info.head, user_info.tail);
	}
	instance = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
	SendAccountRealSync(instance, 0.0, 0.0, OMC_OCODE_EDIT);

out:
	// send response msg================
	rest_rsp.msg_type = REST_RECHARGE_CARD_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_RECHARGE_CARD_RSP, result[%d], recharge amount[%d], balance[%d]", \
					err_code, pRsp->rechargeAmount, pRsp->balance);
	}
	
	len = encode_rest_recharge_card_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_check_balance_req(_rest_msg_s *rest_req)
{
	_rest_check_balance_req *pReq = &rest_req->msg.check_balance_req;

	PutLogFunID("pps_handle_check_balance_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_check_balance_req(), msisdn[%s], amount[%d]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn, pReq->amount);
	}

	_account_info user_info;
	int flag_log_msisdn = 0;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	_prepaid_info *pUsrInfo = NULL;
	int err_code = ERR_REST_SUCCESS;
	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_check_balance_req(), msisdn[%s], not found", \
					pReq->msisdn);
		err_code = ERR_REST_USER_UNKNOWN;// not found
	}

	// set msg
	_rest_msg_s		rest_rsp;
	_rest_check_balance_rsp *pRsp = &rest_rsp.msg.check_balance_rsp;
	memset(pRsp, 0, sizeof(_rest_check_balance_rsp));
	if (pUsrInfo != NULL)
	{
		if ((pUsrInfo->status != T_NORMAL) || (pUsrInfo->balance < pReq->amount))
		{
			pRsp->available = 1;// not enough balance
		}
		else
		{
			pRsp->available = 0;// enough balance
		}
	}
	//

	// send response msg================
	rest_rsp.msg_type = REST_CHECK_BALANCE_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_CHECK_BALANCE_RSP, result[%d]", err_code);
	}
	
	u8 msg_buf[256];
	int len = encode_rest_check_balance_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

static int pps_handle_query_balance_req(_rest_msg_s *rest_req)
{
	_rest_query_balance_req *pReq = &rest_req->msg.query_balance_req;

	PutLogFunID("pps_handle_query_balance_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  pps_handle_query_balance_req(), msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, pReq->msisdn);
	}

	int flag_log_msisdn = 0;
	_account_info user_info;
	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			flag_log_msisdn = 1;
		}
	}

	_prepaid_info *pUsrInfo = NULL;
	int err_code = ERR_REST_SUCCESS;
	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_query_balance_req(), msisdn[%s], not found", \
					pReq->msisdn);
		err_code = ERR_REST_USER_UNKNOWN;// not found
	}

	// set msg
	_rest_msg_s		rest_rsp;
	_rest_query_balance_rsp *pRsp = &rest_rsp.msg.query_balance_rsp;
	memset(pRsp, 0, sizeof(_rest_query_balance_rsp));
	if (pUsrInfo != NULL)
	{
		if(pUsrInfo->status == T_NORMAL )
		{
			UpdateAccountStatusFromNormalToSuspendedforExpiration(pUsrInfo, user_info.head, user_info.tail);
		}
		
		//if (pUsrInfo->status == T_NORMAL)
		{
			pRsp->status   = pUsrInfo->status;
			pRsp->balance = (u32)pUsrInfo->balance;
			pRsp->mo_expiry = (u32)pUsrInfo->mo_expiration_date;
		}
	}
	//

	// send response msg================
	rest_rsp.msg_type = REST_QUERY_BALANCE_RSP;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) || flag_log_msisdn)
	{
		DebugMsg(debugmib.display.asciiOut, "reply REST_QUERY_BALANCE_RSP, result[%d]", err_code);
	}
	
	u8 msg_buf[256];
	int len = encode_rest_query_balance_rsp(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);
	//
	
	return 0;
}

int pps_handle_crm_sms_deliver_req(_rest_msg_s *rest_req)
{
	_rest_sms_deliver_req *pReq = &rest_req->msg.sms_deliver;

	int err_code = ERR_REST_SUCCESS;

	u8 msg_buf[256];
	int len;

	_rest_msg_s		rest_rsp;
	_rest_sms_deliver_res *pRsp = &rest_rsp.msg.sms_deliver_res;
		
	PutLogFunID("pps_handle_crm_sms_deliver_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  %s, msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pReq->msisdn);
	}

	
	// set msg
	memset(pRsp, 0, sizeof(_rest_sms_deliver_res));

	// send response msg================
	rest_rsp.msg_type = REST_CRM_SMS_DELIVER_RES;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsg(debugmib.display.asciiOut, "reply CRM_SMS_DELIVER_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_sms_deliver_res(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);

	len = strlen(pReq->sms_content);
	smppSendMOSM(pReq->msisdn, pps_get_service_number(HotLineNumberPosition), (u_char *)pReq->sms_content, len, 0);

	return 1;
}

int pps_handle_crm_create_account_req(_rest_msg_s *rest_req)
{
	_rest_create_acct_req *pReq = &rest_req->msg.create_acct;
	int err_code = ERR_REST_SUCCESS;
	u8 msg_buf[256];
	int len, user_index=0;	
	_account_info user_info;
	//int flag_log_msisdn = 0;
	int ocode=OMC_OCODE_EDIT;
	
	_prepaid_info *pUsrInfo = NULL;
	int dif_balance = 0;
	_prepaid_info		*shmp=NULL,tmpSubsData;
	
	_rest_msg_s		rest_rsp;
	_rest_create_acct_res *pRsp = &rest_rsp.msg.create_acct_res;
		
	PutLogFunID("pps_handle_crm_create_account_req");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  %s, msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pReq->msisdn);
	}

	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			//flag_log_msisdn = 1;
		}
	}

	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{

		//create it, check license

		if(debugmib.measurement.usernumber>=ppsParam.serviceControl.licenseduser)
		{
			DebugMsg(debugmib.display.asciiOut,		
				 "pps_handle_crm_create_account_req(), exist users %d >= licensed user(%ld)!" ,
				debugmib.measurement.usernumber,
				ppsParam.serviceControl.licenseduser);

			err_code = ERR_REST_NO_LICENSE;
			goto ret_err;

		}	
		
		shmp = &tmpSubsData;
		memset(shmp, 0x00, sizeof(_prepaid_info));
		len = strlen(pReq->msisdn);
		shmp->msisdn[MAX_MSISDN_BLEN-1] = len;
		AsciiToBcd(shmp->msisdn, pReq->msisdn, (len+1)/2*2);
		strcpy(shmp->pin, "123456");
		shmp->balance = pReq->balance;
		shmp->mo_expiration_date = shmp->mt_expiration_date = pReq->expiry_date;
		shmp->crm_info.customer_id = pReq->customer_id;
		shmp->crm_info.account_id = pReq->account_id;		
		shmp->crm_info.product_id = pReq->product_id;
		shmp->crm_info.base_plan_id = pReq->plan_id;
		shmp->crm_info.user_class = pReq->user_class;
		shmp->crm_info.birthday = pReq->birthday;
		shmp->crm_info.rent_charge = pReq->rent_charge;
		shmp->cug_id = pReq->cug_id;
		shmp->status = T_NORMAL;
		dif_balance = pReq->balance;

		user_index = AddPPSSubsData(shmp);

		ocode =	OMC_OCODE_ADD;
		
		DebugMsg(debugmib.display.asciiOut, "pps_handle_crm_create_account_req(), msisdn[%s], not found", \
					pReq->msisdn);
		
		
	}
	else
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_crm_create_account_req(), msisdn[%s], already exsits", \
					pReq->msisdn);
		//update
		dif_balance = pReq->balance - pUsrInfo->balance;

		pps_update_user_info_for_crm_create_account(pUsrInfo, 
				pReq->customer_id,
				pReq->account_id,
				pReq->product_id,
				pReq->plan_id,
				pReq->balance,
				pReq->expiry_date,
				pReq->rent_charge,
				pReq->birthday,
				pReq->cug_id);
		user_index = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
		ocode = OMC_OCODE_EDIT;
		
	}

	//sync...
	if(1)
	{
		int head = user_index / UNIT_STORE_ACCOUNT;
		int tail = user_index % UNIT_STORE_ACCOUNT;

		if(dif_balance != 0)
		{
			SendOperatorRechargeCDR(head,tail,dif_balance);
			AccountLatchFlagCheck(head,tail);
			pps_real_update_user_file(head, tail);
		}
		
		SendAccountRealSync(user_index,dif_balance,0,ocode); 
	}

ret_err:	
	// set msg
	memset(pRsp, 0, sizeof(_rest_create_acct_res));

	// send response msg================
	rest_rsp.msg_type = REST_CRM_CREATE_ACCT_RES;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsg(debugmib.display.asciiOut, "reply CRM_CREATE_ACCOUNT_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_create_account_res(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);


	if(0)//CRM should send a Welcome message to new created user
	{
		char sms_content[256];
		strcpy(sms_content, (char *)getSmsSentenceNative(0,SMS_ACTIVATION_NOTIFY));
		len = strlen(sms_content);
		smppSendMOSM(pReq->msisdn, pps_get_service_number(HotLineNumberPosition), (u_char *)sms_content, len, 0);
	}


	return 1;
}


int pps_handle_crm_query_tariff_res(_rest_msg_s *rest_res)
{
	int	portid;

	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    
	
	_rest_query_tariff_res *pRes = &rest_res->msg.query_tariff_res;
		
	PutLogFunID("pps_handle_crm_query_tariff_res");

	portid = rest_res->header.dst_ref;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += portid;

	if(shmp->process_info.rest_if.query_tariff_status != 1)
	{
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		{
			DebugMsg(debugmib.display.asciiOut,
				"    TS: %ld.%03d,  %s, port[%d] is not waiting for query tariff result", \
				tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, portid);
		}
	
		return -1;
	}

	if(pRes->result != 0)
	{
		shmp->process_info.rest_if.query_tariff_status = 3; //not found

		// log message
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		{
			DebugMsg(debugmib.display.asciiOut,
				"    TS: %ld.%03d,  %s, no data tariff errcode[%d]", \
				tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pRes->error_code);
		}
		
		return 0;
	}
	
	{
		shmp->process_info.rest_if.query_tariff_status = 2; //succeed

		/*
		shmp->process_info.tariff.unit_time = pRes->unit_time;
		shmp->process_info.tariff.tierRating.tierNumber = 0;
		shmp->process_info.tariff.tierRating.rating[0].base_fee = pRes->unit_charge;
		*/
		
		shmp->process_info.rest_if.unit  = pRes->unit_time;
		shmp->process_info.rest_if.unit_charge = pRes->unit_charge*1.0/100.0; //in CRM, the unit is *100 for better precision
		shmp->process_info.rest_if.tariff_discount = pRes->discount;
		shmp->process_info.rest_if.plan_id = pRes->plan_id;
		shmp->process_info.rest_if.bundle_plan_id = pRes->bundle_plan_id;		
		shmp->process_info.rest_if.total_plan_value = pRes->total_plan_value;
		shmp->process_info.rest_if.used_plan_value = pRes->used_plan_value;
		
		if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
		{
			DebugMsg(debugmib.display.asciiOut,
				"    TS: %ld.%03d,  %s, port[%d] tariff: %d*%6.3f * %d, %lld-%lld", \
				tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, portid,
				pRes->unit_time, shmp->process_info.rest_if.unit_charge, pRes->discount,
				pRes->total_plan_value, pRes->used_plan_value);
		}
	
		
	}
		
	return 1;
}

int pps_handle_crm_update_subs(_rest_msg_s *rest_req)
{
	_rest_update_subs_req *pReq = &rest_req->msg.update_subs;
	int err_code = ERR_REST_SUCCESS;
	u8 msg_buf[256];
	int len, user_index=0;	
	_account_info user_info;
	//int flag_log_msisdn = 0;
	int ocode=OMC_OCODE_EDIT;
	
	_prepaid_info *pUsrInfo = NULL;
	int dif_balance = 0;
	//_prepaid_info		*shmp=NULL;//,tmpSubsData;
	
	_rest_msg_s		rest_rsp;
	_rest_update_subs_res *pRsp = &rest_rsp.msg.update_subs_res;
		
	PutLogFunID("pps_handle_crm_update_subs");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  %s, msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pReq->msisdn);
	}

	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			//flag_log_msisdn = 1;
		}
	}

	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{


		DebugMsg(debugmib.display.asciiOut, "pps_handle_crm_update_subs(), msisdn[%s], not found", \
					pReq->msisdn);
		err_code = ERR_REST_USER_UNKNOWN;
		goto ret_err;
		
		
	}
	else
	{
		DebugMsg(debugmib.display.asciiOut, "pps_handle_crm_update_subs(), msisdn[%s]", \
					pReq->msisdn);

		if((pReq->optional_flag & 0x01) == 0x01)
			pUsrInfo->status = pReq->status;  //check if valid status
		if((pReq->optional_flag & 0x02) == 0x02)
		{
			pUsrInfo->balance = pReq->balance;
			dif_balance = pReq->balance - pUsrInfo->balance;
		}
		if((pReq->optional_flag & 0x04) == 0x04)
			pUsrInfo->mo_expiration_date = pUsrInfo->mt_expiration_date = pReq->balance_expiry_date;
		if((pReq->optional_flag & 0x08) == 0x08)
			pUsrInfo->crm_info.new_plan_id = pReq->basic_plan_id;
		if((pReq->optional_flag & 0x10) == 0x10)
			pUsrInfo->crm_info.new_rent_charge = pReq->basic_plan_rent;
		if((pReq->optional_flag & 0x20) == 0x20)
			pUsrInfo->crm_info.vas_cug_state = pReq->vas_cug_status;
		
		user_index = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
		ocode = OMC_OCODE_EDIT;
		
	}

	//sync...
	if(1)
	{
		int head = user_index / UNIT_STORE_ACCOUNT;
		int tail = user_index % UNIT_STORE_ACCOUNT;

		if(dif_balance != 0)
		{
			SendOperatorRechargeCDR(head,tail,dif_balance);
			AccountLatchFlagCheck(head,tail);
			pps_real_update_user_file(head, tail);
		}
		
		SendAccountRealSync(user_index,dif_balance,0,ocode); 
	}

ret_err:	
	// set msg
	memset(pRsp, 0, sizeof(_rest_update_subs_res));

	// send response msg================
	rest_rsp.msg_type = REST_CRM_UPDATE_SUBS_RES;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsg(debugmib.display.asciiOut, "reply CRM_UPDATE_SUBS_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_update_subs_res(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);

	return 1;
}

int pps_handle_crm_delete_subs(_rest_msg_s *rest_req)
{
	_rest_delete_subs_req *pReq = &rest_req->msg.delete_subs;
	int err_code = ERR_REST_SUCCESS;
	u8 msg_buf[256];
	int len, user_index=0;	
	_account_info user_info;
	//int flag_log_msisdn = 0;
	int ocode=OMC_OCODE_DEL;
	
	_prepaid_info *pUsrInfo = NULL;
	int dif_balance = 0;
	
	_rest_msg_s		rest_rsp;
	_rest_delete_subs_res *pRsp = &rest_rsp.msg.delete_subs_res;
		
	PutLogFunID("pps_handle_crm_delete_subs");

	// log message
	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  %s, msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pReq->msisdn);
	}

	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			//flag_log_msisdn = 1;
		}
	}

	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{


		DebugMsg(debugmib.display.asciiOut, "%s, msisdn[%s], not found", __FUNCTION__,  pReq->msisdn);
		err_code = ERR_REST_USER_UNKNOWN;
		goto ret_err;
		
		
	}
	else
	{
		DebugMsg(debugmib.display.asciiOut, "%s, msisdn[%s], found", __FUNCTION__,  pReq->msisdn);

		dif_balance = pUsrInfo->balance;
		
		user_index = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;
		ocode = OMC_OCODE_DEL;	
	}

	//sync...
	if(1)
	{
		int head = user_index / UNIT_STORE_ACCOUNT;
		int tail = user_index % UNIT_STORE_ACCOUNT;

		if(dif_balance != 0)
		{
			SendOperatorRechargeCDR(head, tail, 0-dif_balance);
	//		pps_real_update_user_file(head, tail);
		}
		
		SendAccountRealSync(user_index, 0-dif_balance, 0, ocode); 

		DeletePPSSubsData(pUsrInfo);
		
	}

ret_err:	
	// set msg
	memset(pRsp, 0, sizeof(_rest_delete_subs_res));

	// send response msg================
	rest_rsp.msg_type = REST_CRM_UPDATE_SUBS_RES;
	rest_rsp.header.dst_ref = rest_req->header.src_ref;
	rest_rsp.header.src_ref = rest_req->header.dst_ref;
	pRsp->error_code = err_code;
	if (err_code != ERR_REST_SUCCESS)
	{
		pRsp->result = RES_FAILED;
	}
	else
	{
		pRsp->result = RES_SUCCEED;
	}

	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
	{
		DebugMsg(debugmib.display.asciiOut, "reply CRM_DELETE_SUBS_RSP, result[%d]", err_code);
	}
	
	len = encode_rest_delete_subs_res(&rest_rsp, msg_buf);
	pps_send_rest_msg(msg_buf, len);

	return 1;
}

int pps_handle_crm_rent_charge(_rest_msg_s *rest_req)
{
	_rest_rent_charge_req *pReq = &rest_req->msg.rent_charge;

	int user_index=0;	
	_account_info user_info;
	//int flag_log_msisdn = 0;
	int charge;
	
	_prepaid_info *pUsrInfo = NULL;

	PutLogFunID("pps_handle_crm_rent_charge");


	if((logMsgFlag & 0x04) || (logMsgFlag & 0x02))
	{
		DebugMsg(debugmib.display.asciiOut,
			"    TS: %ld.%03d,  %s, msisdn[%s]", \
			tvnow.tv_sec, tvnow.tv_usec/1000, __FUNCTION__, pReq->msisdn);
	}

	strcpy((char *)user_info.number, pReq->msisdn);
	if(logMsgFlag & 0x08)
	{
		if(strstr((char *)user_info.number, logMsisdn))
		{
			//flag_log_msisdn = 1;
		}
	}

	if ((GetAccountPos(&user_info) == FALSE)
		|| ((pUsrInfo = getPrepaidInfo(&user_info)) == NULL))
	{


		DebugMsg(debugmib.display.asciiOut, "%s, msisdn[%s], not found", __FUNCTION__,  pReq->msisdn);
		return 0;
		
	}
	else
	{

		charge = pReq->rent_charge;
		
		user_index = user_info.head * UNIT_STORE_ACCOUNT + user_info.tail;

		DebugMsg(debugmib.display.asciiOut, "%s, msisdn[%s], found, charge=%d", __FUNCTION__,  pReq->msisdn, charge);
	}

	//sync...
	if(1)
	{
		int head = user_index / UNIT_STORE_ACCOUNT;
		int tail = user_index % UNIT_STORE_ACCOUNT;

		UpdateAccountCUGStatus(pUsrInfo, 0);
              UpdateAccountBalance(head, tail, -charge);
              SendAccountRealSync(user_index,-charge, 0.0, OMC_OCODE_EDIT);
              SendPeriodicChargeCDR(head,tail, charge, CT_RENT_CHARGE_TYPE0);
		
	}

	return 1;
}

/*----------------------------------------------------------*/

int pps_rest_recv_proxy()
{
	int loop, retval, portid=0;
	message_list msgGet;
	_rest_msg_s		rest_msg;
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	for(loop = 0; loop<5; loop++)
	{
		if(iptrGetMessage( &msgGet, REST_PROXY_PORT) <=0 )
			return 0;

		retval = decode_rest_api_msg( msgGet.msgContent, 
			msgGet.msgLength, 
			&rest_msg);

		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m Get RestProxy API: type=%d, retval=%d, dst ref=%d\33[0m",
				rest_msg.msg_type, retval, rest_msg.header.dst_ref);
		}		
		
		if(retval <= 0)
		{
			continue;
		}

		if ((rest_msg.msg_type == REST_QUERY) || (rest_msg.msg_type == REST_TOPUP)
			|| (rest_msg.msg_type == REST_TRANSFER) || (rest_msg.msg_type == REST_ORDER) 
			|| (rest_msg.msg_type == REST_FREE_RESOURCE) || (rest_msg.msg_type == REST_CHANNEL) 
			|| (rest_msg.msg_type == REST_POINT_QUERY) || (rest_msg.msg_type == REST_POINT_TRANSFER)
			)// Alepo
		{
			portid = rest_msg.header.dst_ref;
			if ((portid < 0) || (portid >= MAX_FSM_PROCESS))
				continue;
			shmp = (_state_data *) smshm_ptr->state_data;
			shmp += portid;
			shmp->process_info.rest_if.recv_cmd = 1;
			if(rest_msg.msg_type == REST_QUERY)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.query_res.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.query_res.error_code;
				if ((rest_msg.msg.query_res.balance & 0x80000000) != 0)
				{
					shmp->process_info.rest_if.balance = rest_msg.msg.query_res.balance & 0x7fffffff;
					shmp->process_info.rest_if.balance = -shmp->process_info.rest_if.balance;
				}
				else
				{
					shmp->process_info.rest_if.balance = rest_msg.msg.query_res.balance;
				}
				shmp->process_info.rest_if.mo_expiry_date = rest_msg.msg.query_res.mo_expiry;
				shmp->process_info.rest_if.mt_expiry_date = rest_msg.msg.query_res.mt_expiry;
			}
			else if(rest_msg.msg_type == REST_TOPUP)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.topup_res.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.topup_res.error_code;
				shmp->process_info.rest_if.balance = rest_msg.msg.topup_res.balance;
				shmp->process_info.rest_if.mo_expiry_date = rest_msg.msg.topup_res.mo_expiry;
				shmp->process_info.rest_if.mt_expiry_date = rest_msg.msg.topup_res.mt_expiry;
			}
			else if(rest_msg.msg_type == REST_TRANSFER)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.transfer_rsp.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.transfer_rsp.error_code;
			}
			else if(rest_msg.msg_type == REST_CHANNEL)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.chnl_res.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.chnl_res.error_code;
				shmp->process_info.ppsService.chnl_info.sess_state = rest_msg.msg.chnl_res.sess_state;
				strcpy(shmp->process_info.ppsService.chnl_info.prompt, rest_msg.msg.chnl_res.prompt);
			}
			else if(rest_msg.msg_type == REST_POINT_QUERY)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.queryPoint_res.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.queryPoint_res.error_code;
				shmp->process_info.rest_if.unit = rest_msg.msg.queryPoint_res.amount;
				shmp->process_info.rest_if.balance = rest_msg.msg.queryPoint_res.airtime_amount;
			}
			else if(rest_msg.msg_type == REST_POINT_TRANSFER)
			{
				shmp->process_info.rest_if.result = rest_msg.msg.queryPoint_res.result;
				shmp->process_info.rest_if.error_code = rest_msg.msg.queryPoint_res.error_code;
			}
		}
		else// Selfcare
		{
			switch (rest_msg.msg_type)
			{
			case REST_SEND_AUTHCODE_REQ:
				pps_handle_send_authcode_req(&rest_msg);
				break;
			case REST_QUERY_USERDATA_REQ:
				pps_handle_query_userdata_req(&rest_msg);
				break;
			case REST_BUNDLE_SUBS_REQ:
				pps_handle_bundle_subs_req(&rest_msg);
				break;
			case REST_BUNDLE_USAGE_REQ:
				pps_handle_bundle_usage_req(&rest_msg);
				break;
			case REST_RECHARGE_REQ:
				pps_handle_recharge_req(&rest_msg);
				break;
			case REST_TRANSFER_REQ:
				pps_handle_transfer_req(&rest_msg);
				break;
			case REST_RECHARGE_CARD_REQ:
				pps_handle_recharge_card_req(&rest_msg);
				break;
			case REST_CHECK_BALANCE_REQ:
				pps_handle_check_balance_req(&rest_msg);
				break;
			case REST_QUERY_BALANCE_REQ:
				pps_handle_query_balance_req(&rest_msg);
				break;
			case REST_CRM_SMS_DELIVER_REQ:
				pps_handle_crm_sms_deliver_req(&rest_msg);
				break;
			case REST_CRM_CREATE_ACCT_REQ:
				pps_handle_crm_create_account_req(&rest_msg);
				break;
			case REST_CRM_QUERY_TARIFF_RES:
				pps_handle_crm_query_tariff_res(&rest_msg);
				break;
			case REST_CRM_UPDATE_SUBS_REQ:
				pps_handle_crm_update_subs(&rest_msg);
				break;
			case REST_CRM_DELETE_SUBS_REQ:
				pps_handle_crm_delete_subs(&rest_msg);
				break;
			case REST_CRM_RENT_CHARGE:
				pps_handle_crm_rent_charge(&rest_msg);
				break;
			default:
				break;
			}
		}
	}

	return 1;
}

int pps_rest_query_process(u_short portid)
{
	int					retval = 0 ,result;
	char					ussd_data[256];        	
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);

	if(shmp->process_info.rest_if.timer ++ > 20*CYCLE_STATE_INTERVAL)
	{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
		pps_update_ussd_code_state(USSDCODE_QUERY_CODE_STR, USSDCODE_TYPE_QUERY, USSDCODE_STAT_ERR_TIMEOUT, 0);
#endif
		return -1;
	}
	
	switch(shmp->process_info.sub_state_2)
	{
		case 0:
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
			pps_update_ussd_code_state(USSDCODE_QUERY_CODE_STR, USSDCODE_TYPE_QUERY, USSDCODE_STAT_REQ, 0);
#endif
			pps_send_rest_query_req(portid);
			shmp->process_info.rest_if.timer = 0;
			shmp->process_info.rest_if.recv_cmd = 0;
			shmp->process_info.sub_state_2 = 1;			
		break;
		case 1:
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			result = shmp->process_info.rest_if.result;
			if(result == 0)
			{
				retval = 1;

				if(shmp->process_info.rest_if.rest_oc == 1) //recharge and query
				{
					char tmp_ussd_data[256];
					
					GetAccountRestInfo(portid, tmp_ussd_data);					
					sprintf(ussd_data, "Refill succeed. %s", tmp_ussd_data);
				
				}
				else
				{
					GetAccountRestInfo(portid, ussd_data);
				}
			}
			else
			{
				retval = -1;

				sprintf(ussd_data, "Operation failed, the number %s is not a prepaid subscriber.", shmp->caller_info.number);
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv query_res, result=%d\33[0m",
					portid, result);
			}		
			if(shmp->process_info.rest_if.rest_src == 0) //from USSD
			{
				SendPSSREnd(portid, ussd_data);			
			}
			else if(shmp->process_info.rest_if.rest_src == 1 ) //from SMPP
			{
				smppSendMOSM((char *)shmp->caller_info.number, (char *)shmp->origin_info.number, (u_char *)ussd_data, strlen(ussd_data), 0);

			}
			else if(shmp->process_info.rest_if.rest_src == 2) //from voice
			{
				//SendPSSREnd(portid, ussd_data);
			}
			
		break;
		default:
			retval = -1;
		break;
		
	}
	
	return retval;
}

int pps_send_rest_topup_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_TOPUP;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.topup.msisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.topup.username, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.topup.password, (char *)shmp->called_info.number);
	strcpy(rest_msg.msg.topup.pincode, (char *)shmp->process_info.tmpNumber);

	len = encode_rest_topup(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_channel_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *)smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_CHANNEL;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.chnl.msisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.chnl.input, (char *)shmp->process_info.ppsService.chnl_info.input);
	strncpy(rest_msg.msg.chnl.sc_url, (char *)shmp->process_info.ppsService.chnl_info.scUrl, 127);
	strncpy(rest_msg.msg.chnl.sess_id, (char *)shmp->process_info.ppsService.chnl_info.sessId, 63);

	len = encode_rest_channel(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_order_req(u_short portid, u32 busicode)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_ORDER;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;//portid;
    rest_msg.msg.order.busicode = busicode;// recharge: 1000, order: 1001, cancel: 1002
    rest_msg.msg.order.offer_id = shmp->process_info.rest_if.bundle_plan_id;
    rest_msg.msg.order.paymethod = shmp->process_info.rest_if.plan_id | (shmp->process_info.rest_if.unit << 8);
    
	rest_msg.msg.order.pincode[0] = '\0';
	rest_msg.msg.order.callerMsisdn[0] = '\0';
    if (shmp->process_info.routing_number[0] != '\0')
    {
        strcpy(rest_msg.msg.order.msisdn, (char *)shmp->process_info.routing_number);
        strcpy(rest_msg.msg.order.payMsisdn, (char *)shmp->caller_info.number);
		if (busicode == 1000)// recharge airtime, buy for other
		{
			strcpy(rest_msg.msg.order.callerMsisdn, (char *)shmp->caller_info.number);
		}
    }
    else
    {
        strcpy(rest_msg.msg.order.msisdn, (char *)shmp->caller_info.number);
        rest_msg.msg.order.payMsisdn[0] = '\0';
    }
    if (shmp->process_info.rest_if.plan_id == 10)// mobile money
    {
        strcpy(rest_msg.msg.order.payMsisdn, shmp->process_info.tmpDigits);
    }
	rest_msg.msg.order.balance = (u32)shmp->process_info.rest_if.balance;

	len = encode_rest_order(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_free_resource_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_FREE_RESOURCE;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;//portid;
	strcpy(rest_msg.msg.free_resource.msisdn, (char *)shmp->caller_info.number);

	len = encode_rest_free_resource(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_download_app_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_DOWNLOAD_APP;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;//portid;
	strcpy(rest_msg.msg.downloadApp.msisdn, (char *)shmp->caller_info.number);

	len = encode_rest_downloadApp(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_offer_change_req(u_short portid, u8 flag_opt_out)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_OFFER_CHANGE;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;//portid;
	strcpy(rest_msg.msg.offerChange.msisdn, (char *)shmp->caller_info.number);
	rest_msg.msg.offerChange.opt_out = flag_opt_out;

	len = encode_rest_offerChange(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_point_query_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_POINT_QUERY;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.queryPoint.msisdn, (char *)shmp->caller_info.number);

	len = encode_rest_queryPoint(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_rest_point_transfer_req(u_short portid, u32 busicode)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data     *shmp = (_state_data *) smshm_ptr->state_data;

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_POINT_TRANSFER;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;//0xffff;
	strcpy(rest_msg.msg.transferPoint.msisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.transferPoint.target_msisdn, (char *)shmp->process_info.routing_number);
	rest_msg.msg.transferPoint.amount = shmp->process_info.rest_if.unit;
	rest_msg.msg.transferPoint.busicode = busicode;

	len = encode_rest_transferPoint(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_send_selfcare_topup_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_UPDATE_RECHARGE_CARD_REQ;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.topup.msisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.topup.username, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.topup.password, (char *)shmp->called_info.number);
	if(1)
	{
		rest_msg.msg.topup.optional_flag = 0x03;
		rest_msg.msg.topup.account_id = 10024;
		rest_msg.msg.topup.balance = GetAccountBalance(shmp->caller_info.head, shmp->caller_info.tail);

	}

	len = encode_rest_topup(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;
}

int pps_rest_topup_process(u_short portid)
{
	int					retval = 0, /*len, error_input = 0, */result;
	//u_char				data_flow[256], service_type=0;
	char					ussd_data[256];//, ussd_sc[256], ussd_param[256];
	//MapComSrv_struct		com_data;
       //MapOprSrv_struct		opr_srv;
	//COSTable                     *cosTableItem;
		
	//struct MapPUSSR_Arg	*pussr_arg;
	//struct MapUSSR_Res  	*ussr_ack;
        	
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);

	if(shmp->process_info.rest_if.timer ++ > 20*CYCLE_STATE_INTERVAL)
	{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
		pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_ERR_TIMEOUT, 0);
#endif
		return -1;
	}
	
	switch(shmp->process_info.sub_state_2)
	{
		case 0:
			pps_send_rest_topup_req(portid);
			shmp->process_info.rest_if.timer = 0;
			shmp->process_info.rest_if.recv_cmd = 0;
			shmp->process_info.sub_state_2 = 1;
		break;
		case 1:
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			result = shmp->process_info.rest_if.result;
			if(result == 0)
			{
				//char tmp_ussd_data[256];
				if(0)
				{
					shmp->process_info.sub_state_2 = 2;
					shmp->process_info.wait_timer = 0;
					return 0;
				}
				//GetAccountRestInfo(portid, tmp_ussd_data);
				//sprintf(ussd_data, "You successfully ");
				sprintf(ussd_data, "%s", getSmsSentenceNative(0, SMS_GPRS_RECHARGE_SUCCESS));

			}
			else
			{
				//sprintf(ussd_data, "Operation failed, wrong password, please check and try again!");
				sprintf(ussd_data, "%s", getSmsSentenceNative(0, SMS_RECHARGE_FAILED_NO_CARD));
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv topup_res, result=%d\33[0m",
					portid, result);
			}		
			
			if( shmp->process_info.rest_if.rest_src == 0) // recharge by USSD
			{
				SendPSSREnd(portid, ussd_data);
			}
			else if( shmp->process_info.rest_if.rest_src == 1) // recharge by SMPP
			{
				smppSendMOSM((char *)shmp->caller_info.number, (char *)shmp->origin_info.number, (u_char *)ussd_data, strlen(ussd_data), 0);
			}
			else if( shmp->process_info.rest_if.rest_src == 2) // recharge by Voice
			{
				//
			}

			retval = 1;
		break;
		case 2:
			if(shmp->process_info.wait_timer ++ >=  1*CYCLE_STATE_INTERVAL) //wait for 1second to send GET
			{
				shmp->process_info.rest_if.timer = 0;
				shmp->process_info.rest_if.recv_cmd = 0;
				if( shmp->process_info.rest_if.rest_src == 0) // recharge by USSD
				{
					shmp->process_info.sub_state = S_MAP_REST_QUERY;
				}
				else if( shmp->process_info.rest_if.rest_src == 1) // recharge by SMPP
				{
					shmp->process_info.sub_state = S_SMPP_REST_QUERY;
				}
				else			//recharge by voice
					shmp->process_info.sub_state = S_MAP_REST_QUERY;
				
				shmp->process_info.sub_state_2 = 0;
				shmp->process_info.wait_timer = 0;		
				shmp->process_info.rest_if.rest_oc = 1;				
			}
			break;
		default:
			retval = -1;
		break;
	}
	
	
	return retval;

}


int pps_send_rest_transfer_req(u_short portid)
{
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_TRANSFER;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	strcpy(rest_msg.msg.transfer_req.transferOutMsisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.transfer_req.transferInMsisdn, (char *)shmp->process_info.ppsService.feeTransfer.account.number);
	rest_msg.msg.transfer_req.amount = shmp->process_info.ppsService.feeTransfer.fee;;
	
	len = encode_rest_transfer_req(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}

int pps_rest_transfer_process(u_short portid)
{
	int			retval = 0, result;
	int			op_src = 0;	
       char			ussd_data[256];  
	_state_data	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);

	if(shmp->process_info.rest_if.timer ++ > 20*CYCLE_STATE_INTERVAL)
	{
		return -1;
	}
	
	switch(shmp->process_info.sub_state_2)
	{
		case 0:
			pps_send_rest_transfer_req(portid);
			shmp->process_info.rest_if.timer = 0;
			shmp->process_info.rest_if.recv_cmd = 0;
			shmp->process_info.sub_state_2 = 1;
		break;
		case 1:
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			result = shmp->process_info.rest_if.result;
			op_src = shmp->process_info.rest_if.rest_src;


			if(result == 0)
			{

				SendTransferSuccessRequest(portid, op_src);

			}
			else
			{
				sprintf(ussd_data, "Operation failed, please check and try again!");

				if(op_src  == 0)
					SendPSSREnd(portid, (char *)ussd_data);
				else
					smppSendMsg(shmp->caller_info.number, (u_char *)ussd_data, FeeTransferPosition);
				
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv transfer_res, result=%d\33[0m",
					portid, result);
			}		
	
			retval = 1;
		break;
		default:
			retval = -1;
		break;
	}
	
	
	return retval;

}

int RechargeSucceedwithCRM(u_short portid)
{
    int                    retval = S_IDLE,promo_balance=0;
    DWORD            instance=0;
    //_account_info   tmp_info;
    _state_data     *shmp;
    COSTable        *cosTableItem;
	    
    if(portid>=MAX_FSM_PROCESS) return 0;

    PutLogFunID("RechargeRequestProc");

    shmp=(_state_data *)&smshm_ptr->state_data;
    shmp += portid;
    retval = shmp->process_info.state;

   
    UpdateBalanceForRecharge(&shmp->caller_info, shmp->process_info.rest_if.balance);

    SendRechargeCDR( portid, CT_RECHARGE_SUCCESS, shmp->process_info.rest_if.balance);

    if(T_FRESH == GetAccountStatus(&shmp->caller_info) ) 
    {
        UpdateAccountFirstUsedDate(shmp->caller_info.head, shmp->caller_info.tail);
    }
    UpdateAccountStatus(shmp->caller_info.head, shmp->caller_info.tail, T_NORMAL);
    UpdateAccountExpiration(shmp->caller_info.head, shmp->caller_info.tail, shmp->process_info.rest_if.balance, shmp->process_info.rest_if.mo_expiry_date);

    // promotion 
    cosTableItem = &ppsParam.ppsTables.cosTable[shmp->caller_info.cos_id];
    if(IsPromotionTime(cosTableItem,tvnow))
    {
        promo_balance = GetPromotionAmount(cosTableItem,shmp->process_info.rest_if.balance);
        if(promo_balance !=0)
        {
            shmp->cdr_info.answertime = tvnow.tv_sec + 1;
            UpdateAccountPromotionBalance(shmp->caller_info.head, shmp->caller_info.tail, (float)promo_balance);
            UpdateAccountPromotionExpiryDay(
                        shmp->caller_info.head,
                        shmp->caller_info.tail,
                        GetPromotionDay(cosTableItem,shmp->process_info.rest_if.balance)
            );
            SendRechargeCDR( portid, CT_RECHARGE_SUCCESS, GetPromotionAmount(cosTableItem,shmp->process_info.rest_if.balance));
        }
    }
	
    instance = shmp->caller_info.head * UNIT_STORE_ACCOUNT + shmp->caller_info.tail;	
    ResetAccountRechargeFail(shmp->caller_info.head, shmp->caller_info.tail);
    resetCMBTimes(&shmp->caller_info);
    SendAccountRealSync(instance,shmp->process_info.rest_if.balance,promo_balance,OMC_OCODE_EDIT);
	
    if(cosTableItem->smsNotificationInquiry[0].smsNotificationWhenRecharge) 
    {
        if(shmp->process_info.serviceType == SRV_RECHARGE_ONE_INPUT)
            SendAccountInfoBySMPP(&shmp->caller_info,
                    ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number);   
        else
            SendAccountInfoBySMPP(&shmp->caller_info,
                    ppsParam.ppsTables.serviceNumber[ScratchCardRechargeNumberPosition].number);   
    }
    
    return retval;
}

int pps_bundle_plan_process(u_short portid)
{
	char	ussd_data[1024];
	int retval = 0, result=0;
       int key_input;
	//int	cos_bundle_control=0;

	   
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);

	if(shmp->process_info.funnel ++ > 50*CYCLE_STATE_INTERVAL)
	{
		return -1;
	}

	switch(shmp->process_info.sub_state_2 )
	{
		case 0:			
			subscribe_bundle_plan(shmp, shmp->process_info.tmpDigits, 1, ussd_data);		
			ussd_data[160] = 0;
			if(strlen(ussd_data) <= 160)
			{
				if(1)
				{
					SendPSSREnd(portid, ussd_data);
					retval = 1;
				}
				else
				{
					SendUSSDRequest(portid, ussd_data);
					shmp->process_info.sub_state_2 = 1;
					shmp->process_info.funnel = 0;
					retval = 0;
				}
			}
		break;
		case 1:
			retval = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(retval >= 1)
			{
				subscribe_bundle_plan(shmp, shmp->process_info.tmpDigits, 1, ussd_data);		
				ussd_data[160] = 0;
				SendPSSREnd(portid, ussd_data);	
			}
		break;
		case 2:
			result = ocs_bundle_plan_query(shmp, shmp->process_info.tmpDigits, 1, ussd_data);		
			ussd_data[160] = 0;
			if(1)
			//if(result == 0)
			{
				SendPSSREnd(portid, ussd_data);
				retval = 1;
			}
			else
			{
				SendUSSDRequest(portid, ussd_data);
				shmp->process_info.sub_state_2 = 1;
				shmp->process_info.funnel = 0;
				retval = 0;
			}
		break;
		case 5://send sub-menu of bundle plan
			//cos_bundle_control = get_cos_bundle_control(shmp->caller_info.cos_id);
			if(shmp->process_info.serviceKey == 6)// data plan only
				sprintf(ussd_data, "%s", getSmsSentenceNative(0,SMS_BUNDLE_PLAN_USSD_MENU));
			else
				sprintf(ussd_data, "%s", getSmsSentenceNative(0,SMS_BUNDLE_PLAN_USSD_MENU1));
			
			if(shmp->process_info.serviceInput ++ > 3)
			{
				SendPSSRResponse(portid);
				return 1;
			}
			SendUSSDRequest(portid, ussd_data);		
			shmp->process_info.sub_state_2 = 6;		
			shmp->process_info.funnel = 0;
		break;
		case 6:
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					shmp->process_info.sub_state_2 = 5;		
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					shmp->process_info.sub_state_2 = 5;		
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
							shmp->process_info.sub_state_2 = 7;					//inquiry	
						break;
						case 2:
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 8;					//subscribe	
						break;
						case 0:
						default:
							SendPSSRResponse(portid);
							retval = 1;
						break;
					}
				}
			}
			else if(result == -1)
			{
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;
		case 7:
			result = ocs_bundle_plan_query(shmp, shmp->process_info.tmpDigits, 1, ussd_data);		
			ussd_data[160] = 0;
			if(result == 0)
			{
				SendPSSREnd(portid, ussd_data);
				retval = 1;
			}
			else
			{
				sprintf(ussd_data, "%s", getSmsSentenceNative(0,SMS_BUNDLE_PLAN_NOT_APPLIED));
				SendPSSREnd(portid, ussd_data);
				retval = 1;
			}
		break;
		case 8:// ussd adaptor enter here
			if(shmp->process_info.serviceInput ++ > 3)
			{
				SendPSSRResponse(portid);
				return 1;
			}
			subscribe_bundle_plan_query_info(shmp, 0, 2, ussd_data);
			SendUSSDRequest(portid, ussd_data);		
			shmp->process_info.sub_state_2 = 9;		
			shmp->process_info.funnel = 0;			
		break;
		case 9:
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 2)
				{
					shmp->process_info.sub_state_2 = 8;						
					shmp->process_info.funnel = 0;			
					break;
				}

                if (0)//(pps_get_adaptor_flag())
                {/*
                    pps_send_rest_order_req(portid);// send bundle subs req
                    shmp->process_info.funnel = 0;
                    shmp->process_info.rest_if.timer = 0;
                    shmp->process_info.rest_if.recv_cmd = 0;
                    shmp->process_info.sub_state_2 = 11;*/
                }
				else
				{
					result = subscribe_bundle_plan(shmp, shmp->process_info.tmpDigits, 2, ussd_data); 
					if(result == 1)
					{
						SendPSSREnd(portid, ussd_data);
						retval = 1;				
					}
					else
					{
						shmp->process_info.sub_state_2 = 8;		
						shmp->process_info.funnel = 0;			
					}
				}
			}
			else if(result == -1)
			{
				SendPSSRResponse(portid);
				retval = 1;
			}

		break;
		/*case 11:
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			result = shmp->process_info.rest_if.result;
			if(result == 0)
			{
				//char tmp_ussd_data[256];
				if(0)
				{
					shmp->process_info.sub_state_2 = 2;
					shmp->process_info.wait_timer = 0;
					return 0;
				}
				//GetAccountRestInfo(portid, tmp_ussd_data);
				//sprintf(ussd_data, "You successfully ");
				sprintf(ussd_data, "%s", getSmsSentenceNative(0, SMS_GPRS_RECHARGE_SUCCESS));

			}
			else
			{
				//sprintf(ussd_data, "Operation failed, wrong password, please check and try again!");
				sprintf(ussd_data, "%s", getSmsSentenceNative(0, SMS_RECHARGE_FAILED_NO_CARD));
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv topup_res, result=%d\33[0m",
					portid, result);
			}		
			
			//if( shmp->process_info.rest_if.rest_src == 0) // recharge by USSD
			//{
				SendPSSREnd(portid, ussd_data);
			//}
        break;*/
	}
	
	return retval;
}


int pps_send_query_tariff_req(u_short portid)
{
	char 			prefix[32], areaName[32] = "";
	int				service_type = 1; /*1=mo call, 2=sms, 3=data */
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_CRM_QUERY_TARIFF_REQ;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;
	
	 if(shmp->context_info.callType == CT_MO_CALL || shmp->context_info.callType == CT_MF_CALL)
		service_type = 1;
	else if(shmp->context_info.callType == CT_MT_CALL)
		service_type = 1;
	else if(shmp->context_info.callType == CT_MO_SM)
		service_type = 3;
	else//data
		service_type = 2;
	
	rest_msg.msg.query_tariff.service_type = service_type;

	if(service_type != 2)
	{
		if(ocs_get_charge_prefix( (char *)shmp->charge_info.number, prefix, areaName, &shmp->process_info.tariff.call_type) == 0)
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , ocs_get_charge_prefix() failed, charge_number=%s \33[0m",
					portid, shmp->charge_info.number);
			}		
		
			return 0;
		}
		strncpy(shmp->process_info.ppsService.areaName, areaName, 31);
	}
	else
	{//CRM bug, data billing must take a area_code...
		memcpy(prefix, shmp->caller_info.number, 5);
		prefix[5] = 0;
	}
	
	if(service_type == 1)
		shmp->process_info.call_type = shmp->process_info.tariff.call_type;

#ifdef OCS_USE_REDIS_DB// get tariff and bundle
	if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
				"[%04d], prefix[%s] caller=%s charge_number=%s, srv_type=%d",
				portid, prefix, shmp->caller_info.number, shmp->charge_info.number, service_type);
	}
	
	RedisGetTariffInfo(portid, (char *)shmp->caller_info.number, 
					service_type, prefix);
	return 1;
#endif
	shmp->process_info.rest_if.query_tariff_status = 1; //wait for result
	
	strcpy(rest_msg.msg.query_tariff.msisdn, (char *)shmp->caller_info.number);
	strcpy(rest_msg.msg.query_tariff.called_number, prefix);
	
	len = encode_rest_query_tariff(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);

	if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid: %d , ocs_get_charge_prefix() caller=%s charge_number=%s , srv_type=%d\33[0m",
				portid, shmp->caller_info.number, shmp->charge_info.number, service_type);
	}		
	
	return 1;

}


int pps_send_update_plan_value_req(u_short portid)
{
	int				service_type = 1; /*1=mo call, 2=sms, 3=data */
	int				len = 0;
	u_char			data_flow[256];
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	_rest_msg_s		rest_msg;
	
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	shmp += (portid);

	rest_msg.msg_type = REST_CRM_UPDATE_PLAN_INFO_REQ;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = portid;

	 if(shmp->context_info.callType == CT_MO_CALL || shmp->context_info.callType == CT_MF_CALL)
		service_type = 1;
	else if(shmp->context_info.callType == CT_MT_CALL)
		service_type = 1;
	else if(shmp->context_info.callType == CT_MO_SM)
		service_type = 3;
	else//data
		service_type = 2;
	/*	
	 if(shmp->process_info.call_type == CT_MO_CALL || shmp->process_info.call_type == CT_MF_CALL)
		service_type = 0;
	else if(shmp->process_info.call_type == CT_MT_CALL)
		service_type = 1;
	else if(shmp->process_info.call_type == CT_MO_SM)
		service_type = 3;
	else//data
		service_type = 2;
	*/
#ifdef OCS_USE_REDIS_DB
	if ((shmp->process_info.rest_if.plan_value_add_this_time & 0x8000000000000000) == 0)// not refund
	{
	RedisUpdateUsedBundle((char *)shmp->caller_info.number, service_type, shmp->process_info.rest_if.bundle_plan_id, 
						shmp->process_info.rest_if.plan_value_add_this_time);
	}
#endif
	
	strcpy(rest_msg.msg.update_plan_info.msisdn, (char *)shmp->caller_info.number);
	rest_msg.msg.update_plan_info.service_type = service_type;
	rest_msg.msg.update_plan_info.account_id = GetAccountID(&shmp->caller_info);
	rest_msg.msg.update_plan_info.plan_id = shmp->process_info.rest_if.plan_id;	
	rest_msg.msg.update_plan_info.bundle_id = shmp->process_info.rest_if.bundle_plan_id;
	rest_msg.msg.update_plan_info.plan_total_value = shmp->process_info.rest_if.total_plan_value;
	rest_msg.msg.update_plan_info.plan_used_value = shmp->process_info.rest_if.used_plan_value;
	rest_msg.msg.update_plan_info.sess_update_times = shmp->process_info.rest_if.sess_update_times++;
	rest_msg.msg.update_plan_info.this_time_add_value = shmp->process_info.rest_if.plan_value_add_this_time;
	
	if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
	{
		DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid[%04d], update_plan_value_req() caller=%s, ID[%d], total-used[%llu-%llu], this[0x%llx], srv_type=%d\33[0m",
				portid, shmp->caller_info.number, shmp->process_info.rest_if.bundle_plan_id, shmp->process_info.rest_if.total_plan_value, 
				shmp->process_info.rest_if.used_plan_value, shmp->process_info.rest_if.plan_value_add_this_time, service_type);
	}
	len = encode_rest_update_plan_info(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
	
	return 1;

}
int query_tariff_test(u_char call_type)
{
	int portid = AssignProcID(0);
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    
	
	shmp += (portid);
	sprintf((char *)shmp->caller_info.number, "%s", "672350004");
	sprintf((char *)shmp->called_info.number, "%s", "008675512345678");
	shmp->process_info.call_type = call_type;
	shmp->process_info.state = S_CRM_QUERY_TARIFF_TEST;
	
	pps_send_query_tariff_req(portid);
	
	return 1;
}



int pps_crm_query_tariff_test_proc(u_short portid)
{
	int					retval = 0;

	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	
	if(shmp->process_info.funnel ++ > SSHORT_DELAY_TIMER)
	{
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid: %d  wait query tariff result timeout\33[0m", portid);
		}		
		return -1;			
	}

	if(shmp->process_info.rest_if.query_tariff_status == 2)
	{
		retval =  1;
	}

	return retval;
}


void pps_send_update_subs_status_to_crm(/*int head, int tail*/_prepaid_info *user_ptr, int update_flag)
{
	int				len = 0;
	u_char			data_flow[256];
	_rest_msg_s		rest_msg;
	//_prepaid_info		*user_ptr=NULL;
	char				msisdn[32];
	
	//user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];	

	rest_msg.msg_type = REST_CRM_UPDATE_SUBS_REQ;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;
			
	if (update_flag == 1)
		rest_msg.msg.update_subs.optional_flag = 0x01;
	else if (update_flag == 2)
		rest_msg.msg.update_subs.optional_flag = 0x04 | 0x08;

	len = user_ptr->msisdn[MAX_MSISDN_BLEN-1];

	if(len<MIN_MSISDN_ALEN || len>MAX_MSISDN_ALEN)
	{
		return;
	}
	BcdToAscii(msisdn,user_ptr->msisdn,(MAX_MSISDN_BLEN-1)*2);
	msisdn[len] = 0;
	strcpy(rest_msg.msg.update_subs.msisdn, msisdn);
	
	rest_msg.msg.update_subs.account_id = user_ptr->crm_info.account_id;	
	rest_msg.msg.update_subs.status = user_ptr->status;
	rest_msg.msg.update_subs.basic_plan_id = user_ptr->crm_info.base_plan_id;
	rest_msg.msg.update_subs.balance_expiry_date = user_ptr->mo_expiration_date;
	
	len = encode_rest_update_subs(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
}

/*
rent charge to CRM, if succeed then CRM sends payment request to OCS
if failed, CRM sends update account status with CUG status (crm_info.vas_cug_state = 1
*/
void pps_send_rent_charge_to_crm(int head, int tail)
{
	int				len = 0;
	u_char			data_flow[256];
	_rest_msg_s		rest_msg;
	_prepaid_info		*user_ptr=NULL;
	char				msisdn[32];
	
	user_ptr = &ramshm_ptr->prepaid_data.prepaid_info[head][tail];	

	rest_msg.msg_type = REST_CRM_RENT_CHARGE;
	rest_msg.header.dst_ref = 0x0000;
	rest_msg.header.src_ref = 0xffff;
			
	rest_msg.msg.rent_charge.optional_flag = 0x01;

	len = user_ptr->msisdn[MAX_MSISDN_BLEN-1];

	if(len<MIN_MSISDN_ALEN || len>MAX_MSISDN_ALEN)
	{
			return;
	}
	BcdToAscii(msisdn,user_ptr->msisdn,(MAX_MSISDN_BLEN-1)*2);
	msisdn[len] = 0;
	strcpy(rest_msg.msg.rent_charge.msisdn, msisdn);
	
	rest_msg.msg.rent_charge.balance = user_ptr->balance;
	
	len = encode_rest_rent_charge(&rest_msg, data_flow);

	pps_send_rest_msg(data_flow, len);
}

/*---------------------------------------------------------*/

int ppsMapState(u_short portid)
{
	int					retval = 0,len, error_input = 0, result;
	u_char				data_flow[256], service_type=0;
	char					ussd_data[256], ussd_sc[64], ussd_param[256], ussd_param1[256];
	MapComSrv_struct		com_data;
       MapOprSrv_struct		opr_srv;
	//COSTable                     *cosTableItem;
		
    	struct MapPUSSR_Arg	*pussr_arg;
    	struct MapUSSR_Res  	*ussr_ack;

	int	cos_bundle_control=0;
      	
	_state_data         	*shmp = (_state_data *) smshm_ptr->state_data;    

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	shmp->process_info.duration ++;
	
	if(shmp->process_info.funnel ++ > USSD_DELAY_TIMER)
	{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
		if(pps_get_adaptor_flag())
		{
			if (shmp->process_info.sub_state == S_MAP_RECHARGE_WAIT_PIN)
			{
				pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_ERR_TIMEOUT, shmp->process_info.duration);
			}
		}
#endif
		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\n\33[31m portid: %d ,did: %d, wait pussdr request timeout\33[0m",
				portid,shmp->context_info.map_did);
		}		
		ppsSendUSSDStatistics(shmp);
		pps_send_map_close(portid);
		return -1;			
	}
	
	if(map_get_comdata_struct(&com_data,shmp->context_info.map_did))
	{		
		if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\nportid: %d ,did: %d, Get Map com, type: %d @ %ld.%ld",
				portid,shmp->context_info.map_did,
				com_data.message_type,
				tvnow.tv_sec,tvnow.tv_usec);
			map_com_stof(&com_data,data_flow,0);
			pps_debug_map_msg(data_flow,0);
		}	
		if(com_data.message_type != MAP_DELIMITER)
		{
			ppsSendUSSDStatistics(shmp);
			return (retval = 1);
		}
	}
	
    switch(shmp->process_info.sub_state)
    {
    	case S_MAP_SEND_OPENRSP:
		if(shmp->context_info.map_acn == AC_networkUnstructuredSs)
		{  		
    			pps_send_map_openrsp(portid, OpenResultAccept);
    		}
    		else
    		{
    			pps_send_map_openrsp(portid,OpenResultRefuse);
    		}
    		shmp->process_info.funnel = 0;
    		shmp->process_info.sub_state = S_MAP_GET_PUSSDR;
    	break;
    	case S_MAP_GET_PUSSDR:
    		if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    		{
    			break;
    		}
		if((data_flow[9] != ProcUnstrctSSReq) || data_flow[1]<14)
		{	
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d ,did: %d, wait PSSDR but %d received\33[0m",
					portid,shmp->context_info.map_did,data_flow[9]);
			}
			ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);
			return -1;
		}
		
		if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\nportid: %d ,did: %d, Get Map opr,type:<%d>, PUSSR  ",
				portid,shmp->context_info.map_did,
				data_flow[9]);			
			pps_debug_map_msg(data_flow,0);
		}
				
		opr_srv.version = shmp->context_info.map_acn_ver;	
		opr_srv.message_type = data_flow[9];
		opr_srv.message_flag = data_flow[10];
		opr_srv.port_id = portid;
		opr_srv.dialogue_id = shmp->context_info.map_did;		
		
		if(extract_mapparam(&opr_srv,
			data_flow[9],
			data_flow[10],
			data_flow[14]*256+data_flow[15],
			&data_flow[16])<=0)
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31mportid: %d ,did: %d, decode PUSSR failed \33[0m",
					portid,shmp->context_info.map_did);
			}
			ppsSendUSSDStatistics(shmp);
			return -1;
		}
		shmp->context_info.invoke_id = data_flow[11]; //opr_srv.invoke_id;
		
		pussr_arg = &opr_srv.msg_list.pussr_arg;
		if(pussr_arg->param_flag != 0x01)
		{
			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
						"\n\33[31mportid: %d ,did: %d, decode PUSSR failed \33[0m",
						portid,shmp->context_info.map_did);
			}
			ppsSendUSSDStatistics(shmp);
			return -1;
		}				
		
		switch(pussr_arg->ussd_arg.ussd_scheme & 0x0f)
		{
			case 0x00:
			case 0x0f: /* 7bit */
				smppDecodeSM((char *)pussr_arg->ussd_arg.ussd_string.ussd_data,
							 ussd_data,
							 pussr_arg->ussd_arg.ussd_string.string_len); 
			break;
			case 0x04: /* 8bit  */
			default:
				memcpy(ussd_data,
						pussr_arg->ussd_arg.ussd_string.ussd_data,
						pussr_arg->ussd_arg.ussd_string.string_len);	
			break;
		}
		if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
				"\nportid: %d ,did: %d, USSD data: \r\n\%s  ",
					portid,shmp->context_info.map_did,
					ussd_data);								
		}
		
		len = pussr_arg->ussd_arg.msisdn[0];
		if(len<3 || len>11)
		{
		    if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		    {
		        DebugMsg(debugmib.display.asciiOut,
		            "\n\33[31mportid: %d ,did: %d, decode PUSSR failed, error MSISDN length: %d\33[0m",
		            portid,shmp->context_info.map_did,len);
		    }		
		    shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
		    return retval;
		}
		ppsBcdToAsciiR(shmp->caller_info.number, 
				&pussr_arg->ussd_arg.msisdn[2],
				(len-1)*2);					
		StringCut((char *)shmp->caller_info.number, 'F');
		GetAccountPos(&shmp->caller_info);
		memset(shmp->cdr_info.caller,0xFF,8);
		memcpy(shmp->cdr_info.caller,&pussr_arg->ussd_arg.msisdn[2],(len-1));
		memset(shmp->caller_info.IMSI, 0xFF, 8);

		if(logMsgFlag & 0x08)
		{
			if(strstr((char *)shmp->caller_info.number, logMsisdn)){
				shmp->process_info.logMsisdn = 0x01;
			}
		}

		if(pps_get_adaptor_flag())
		{
			shmp->caller_info.cos_id = 0;
			shmp->caller_info.cug_id = 0;
			shmp->caller_info.head = 0;
			shmp->caller_info.tail = 0;
		}
		else
		{
			if(shmp->caller_info.head<MSISDN_HEAD_NUM)
			{
				shmp->caller_info.cos_id = GetAccountCosID(&shmp->caller_info);
				shmp->caller_info.cug_id = GetAccountCUG(&shmp->caller_info); 
				shmp->caller_info.status = GetAccountStatus(&shmp->caller_info);

				if(shmp->caller_info.status == T_BLACKLIST ||
					shmp->caller_info.status == T_RELEASED)
				{
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
					shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
					return retval;

				}
			}
			else
			{		
				/* send error info */
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31mportid: %d ,did: %d, PUSSR, msisdn=%s not prepaid subs. \33[0m",
						portid,shmp->context_info.map_did,
						shmp->caller_info.number);								
				}
				shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
				shmp->process_info.u_error = CAP_ERR_MISSING_CUSTOMER_RECORD;
				return retval;
			}
		}
		
		memset(ussd_sc, 0x00, 24);
		memset(ussd_param, 0x00, 24);
		memset(ussd_param1, 0x00, 24);
		ppsGetUssdParameter(ussd_data, ussd_sc, ussd_param, ussd_param1);
		ussd_sc[23] = 0;
		ussd_param[23] = 0;
		ussd_param1[23] = 0;
		
		strcpy((char *)shmp->called_info.number, ussd_sc);
		
		service_type = GetUssdServiceType(shmp);

		if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
		{
			DebugMsg(debugmib.display.asciiOut,
						"\n\33[32mportid: %d ,USSD Service Code:<%s>, service type=%d , Param: %s \33[0m",
						portid,
						ussd_sc,
						service_type,
						ussd_param);								
		}

		shmp->process_info.funnel = 0;
    		shmp->process_info.serviceKey = 0;
		shmp->process_info.sub_state_2 = 0;
		
		memset(shmp->process_info.tmpDigits, 0x00, MAX_ASCII_NUMBER_LEN);
		if(strlen(ussd_param) < MAX_ASCII_NUMBER_LEN)
			strcpy(shmp->process_info.tmpDigits, ussd_param);
		else
		{
			memcpy(shmp->process_info.tmpDigits, ussd_param, MAX_ASCII_NUMBER_LEN - 1);			
		}
		
		switch(service_type)
		{
		    case SRV_INQUIRY:
		    	shmp->process_info.serviceKey = 1;
		    	UssdInquiryProcess(portid);
		    break;
		    case SRV_SCRATCH_CARD_RECHARGE:
		    case SRV_RECHARGE_2TYPES:
		    	len = strlen(ussd_param);
		    	if(len>=8)// (len>=10)
		    	{
                         memset(shmp->cdr_info.called,0xFF,10);
			    ppsAsciiToBcdR(shmp->cdr_info.called,
					ussd_param,
					(len+1)/2*2);

		           if(len%2)
			        shmp->cdr_info.called[(len+1)/2] |= 0xF0;
		           strcpy((char *)shmp->called_info.number, ussd_param);
                   strcpy((char *)shmp->process_info.tmpNumber, ussd_param1);
			    if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			   {
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[32mportid: %d ,did: %d, PUSSR, msisdn=%s [ all-in-one input  ]. \33[0m",
					portid,shmp->context_info.map_did,
					shmp->caller_info.number);
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[32 Service code:%s, recharge card password:%s. \33[0m",ussd_sc,ussd_param);								
			   }			
    		           shmp->process_info.funnel = 0;
		           shmp->process_info.sub_state = S_MAP_CHECK_USSD_INPUT_CARD_VALIDITY;    			    	
		    	}
		    	else
		    	{
		    	    SendUSSDRechargeRequest(portid);
			    shmp->process_info.serviceInput = 0;
			    shmp->process_info.sub_state = S_MAP_RECHARGE_WAIT_PIN;
			    shmp->process_info.serviceKey = 2;		    	
		    	}
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_REQ, 0);
#endif
		    break;
		    case SRV_FEE_TRANSFER:

			if(!pps_get_adaptor_flag())
			{
				if(shmp->caller_info.status == T_FRESH ||
					shmp->caller_info.status == T_SUSPEND)
				{
						shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
						shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
						return retval;

				}
			}
			if(strlen(ussd_param) > 2 && strlen(ussd_param1)>0)
			{
				shmp->process_info.ussd_transfer_one_input_flag = 1;
				strcpy((char *)shmp->process_info.ppsService.feeTransfer.account.number, ussd_param);
				shmp->process_info.ppsService.feeTransfer.fee = atoi(ussd_param1);
			    if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			   {
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[32mportid: %d ,did: %d, PUSSR, msisdn=%s [ ussd balance transfer all-in-one  ]. \33[0m",
					portid,shmp->context_info.map_did,
					shmp->caller_info.number);
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[32 received number :%s, balance to be transferred:%d. \33[0m",ussd_param,
						shmp->process_info.ppsService.feeTransfer.fee);								
			   }			

			}
			else
				shmp->process_info.ussd_transfer_one_input_flag = 0;	
		    	shmp->process_info.sub_state = S_MAP_FEE_TRANSFER;
			shmp->process_info.serviceKey = 3;
		    break;
		    case SRV_CALL_ME_BACK:
		    	clearCMBInfo(portid);
			shmp->process_info.sub_state = S_MAP_CALL_ME_BACK;					
			shmp->process_info.serviceKey = 4;
		    break;
		    case SRV_TELL_ME_NUMBER:
		    	shmp->process_info.sub_state = S_MAP_TELL_ME_NUMBER;					
			shmp->process_info.serviceKey = 5;
		    break;
		    case SRV_FAVORITE_NUMBER:
		    	shmp->process_info.sub_state = S_MAP_FAVORITE_NUMBER;					
			shmp->process_info.serviceKey = 6;
		    break;
		    case SRV_BUNDLE_PLAN:
			if(shmp->caller_info.status == T_FRESH ||
				shmp->caller_info.status == T_SUSPEND)
			{
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
					shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
					return retval;

			}

			if(1)
			{
				char called_buf[32];
				strcpy((char *)shmp->called_info.number, ussd_sc);
				len = strlen((char *)shmp->called_info.number);
				strcpy(called_buf, (char *)shmp->called_info.number);
				if(len %2 ==1){
					strcat(called_buf,"F");
					len ++;
				}
				strcat(called_buf,"FF");
				ppsAsciiToBcdR(shmp->cdr_info.called, called_buf, len+2);
			}	

		    	shmp->process_info.sub_state = S_MAP_BUNDLE_PLAN;					
			shmp->process_info.serviceKey = 7;
		    break;
		    case SRV_BUNDLE_QUERY:
			if(shmp->caller_info.status == T_FRESH ||
				shmp->caller_info.status == T_SUSPEND)
			{
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
					shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
					return retval;

			}

		    	shmp->process_info.sub_state = S_MAP_BUNDLE_PLAN;	
			shmp->process_info.sub_state_2 = 2;				
			shmp->process_info.serviceKey = 8;
		    break;		    
		    case SRV_CALL_HOTLINE:
		    default:
             if(pps_get_adaptor_flag())
             {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_
                if (match_channel_info(ussd_sc, shmp->process_info.ppsService.chnl_info.scUrl) > 0)
                {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
					pps_update_ussd_code_state(ussd_sc, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_REQ, 0);
#endif
                    shmp->process_info.sub_state = S_MAP_THIRD_PARTY_CHANNEL;
                    shmp->process_info.sub_state_2 = 1;
                    break;
                }
                else if (memcmp(ussd_sc, "117", 3) == 0)
                {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
					pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_REQ, 0);
#endif
                    shmp->process_info.sub_state = S_MAP_THIRD_PARTY_HOTLINE;
                    shmp->process_info.sub_state_2 = 1;
                    break;
                }
                else
#endif
                {
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
					shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
					return retval;
                }
             }
			 cos_bundle_control = get_cos_bundle_control(shmp->caller_info.cos_id);
			 if(cos_bundle_control == 1)// data plan only
		    	 	SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_MENU));	
			 else
			 	SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_MENU1));
   		        shmp->process_info.sub_state = S_MAP_GET_USSDACK;	
		    break;
		}
		
    	break;
    	case S_MAP_GET_USSDACK:    		
    		if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    		{
    			break;
    		}
			if((data_flow[9] != UnstrctSSReq) || data_flow[1]<14)
			{	
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d ,did: %d, wait USSDR_ACK but %d received\33[0m",
						portid,shmp->context_info.map_did,data_flow[9]);
				}
				ppsSendUSSDStatistics(shmp);
				pps_send_map_close(portid);
				return -1;
			}
			
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, Get Map opr,type:<%d>, USSR  ",
					portid,shmp->context_info.map_did,
					data_flow[9]);			
				pps_debug_map_msg(data_flow,0);
			}
					
			opr_srv.version = shmp->context_info.acn_ver;	
			opr_srv.message_type = data_flow[9];
			opr_srv.message_flag = data_flow[10];
			opr_srv.port_id = portid;
			opr_srv.dialogue_id = shmp->context_info.map_did;		
			
			if(extract_mapparam(&opr_srv,
				data_flow[9],
				data_flow[10],
				data_flow[14]*256+data_flow[15],
				&data_flow[16])<=0)
			{
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31mportid: %d ,did: %d, decode USSR_ACK failed \33[0m",
						portid,shmp->context_info.map_did);
				}
				ppsSendUSSDStatistics(shmp);
				return -1;
			}
			
			ussr_ack = &opr_srv.msg_list.ussr_res;
			
			if(ussr_ack->param_flag != 0x01)
			{
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
							"\n\33[31mportid: %d ,did: %d, USSR error received \33[0m",
							portid,shmp->context_info.map_did);
				}
				ppsSendUSSDStatistics(shmp);
				return -1;
			}				
			
			switch(ussr_ack->ussd_res.ussd_scheme & 0x0f)
			{
				case 0x00:
				case 0x0f: /* 7bit */
					smppDecodeSM((char *)ussr_ack->ussd_res.ussd_string.ussd_data,
								 ussd_data,
								 ussr_ack->ussd_res.ussd_string.string_len); 
				break;
				case 0x04: /* 8bit */
				default:
					memcpy(ussd_data,
							ussr_ack->ussd_res.ussd_string.ussd_data,
							ussr_ack->ussd_res.ussd_string.string_len);	
				break;
			}
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, USSD data: \r\n\%s  ",
					portid,shmp->context_info.map_did,
					ussd_data);								
			}
			
			cos_bundle_control = get_cos_bundle_control(shmp->caller_info.cos_id);
			if(ussr_ack->ussd_res.ussd_string.string_len == 1)
			{
			       unsigned char key;

			       if(ussd_data[0]>=0x30 && ussd_data[0]<=0x39)
			       	ussd_data[0] -= 0x30; /* 0-9 */
			       else if(ussd_data[0]>=0x61 )
			       	ussd_data[0] -= 0x61; /* a- z */
			       else if(ussd_data[0] >=0x41 )
			       	ussd_data[0] -= 0x41; /* A-Z */
			       /* change ascii to digits */
			       
			       key = GetUssdServiceKey(ussd_data[0]);
			       
			       switch(key)
			       {			           
			           case USSD_OC_INQUIRY:
			           	UssdInquiryProcess(portid);
			           break;
			           case USSD_OC_RECHARGE:
			           	SendUSSDRechargeRequest(portid);
					shmp->process_info.serviceInput = 0;
					shmp->process_info.sub_state = S_MAP_RECHARGE_WAIT_PIN;
					shmp->process_info.serviceKey = 2;
			           break;
			           case USSD_OC_FEE_TRANSFER:
					if(shmp->caller_info.status == T_FRESH ||
						shmp->caller_info.status == T_SUSPEND)
					{
							shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
							shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
							return retval;

					}
					
			           	shmp->process_info.sub_state = S_MAP_FEE_TRANSFER;
					shmp->process_info.serviceKey = 3;
			           break;
			           case USSD_OC_CALL_ME_BACK:
			           	clearCMBInfo(portid);
					shmp->process_info.sub_state = S_MAP_CALL_ME_BACK;					
					shmp->process_info.serviceKey = 4;
			           break;
			           case USSD_OC_TELL_ME_NUMBER:
			           	shmp->process_info.sub_state = S_MAP_TELL_ME_NUMBER;					
					shmp->process_info.serviceKey = 5;
			           break;
			           case USSD_OC_FRIEND_FAMILY_QUERY:
			           	shmp->process_info.sub_state = S_MAP_FAVORITE_NUMBER;					
			           	shmp->process_info.sub_state_2 = 0;
					shmp->process_info.serviceKey = 6;
			           break;
			           case USSD_OC_EXIT:
			           case USSD_OC_HOTLINE:
			           	shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
					shmp->process_info.serviceKey = 7;
			           break;
				    case USSD_OC_BUNDLE_PLAN:
				    case USSD_OC_BUNDLE_PLAN_ALL:
					if(shmp->caller_info.status == T_FRESH ||
						shmp->caller_info.status == T_SUSPEND)
					{
							shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
							shmp->process_info.u_error = _PPS_ERR_SERVICE_NOT_APPLIED;
							return retval;

					}

					if((cos_bundle_control == 1) && (key == USSD_OC_BUNDLE_PLAN_ALL))// user has data plan only, not allow to request bundle plan!
					{
						error_input = 1;
						break;
					}
					
					if(1)
					{
						char called_buf[32];
						strcpy((char *)shmp->called_info.number, ussd_sc);
						len = strlen((char *)shmp->called_info.number);
						strcpy(called_buf, (char *)shmp->called_info.number);
						if(len %2 ==1){
							strcat(called_buf,"F");
							len ++;
						}
						strcat(called_buf,"FF");
						ppsAsciiToBcdR(shmp->cdr_info.called, called_buf, len+2);
					}	

			           	shmp->process_info.sub_state = S_MAP_BUNDLE_PLAN;					
			           	shmp->process_info.sub_state_2 = 5;
					if(key == USSD_OC_BUNDLE_PLAN_ALL)
						shmp->process_info.serviceKey = 7;
					else
						shmp->process_info.serviceKey = 6;
				    break;
				   
			           default:
			           	error_input = 1;
			           break;
			           
			       }
			}
			else
			{
				error_input = 1;
			}
			/* error input */
			if(error_input)
			{
				if(shmp->process_info.serviceInput++>=3)
				{
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
				}
				else
				{
					if (cos_bundle_control == 0)// user has bundle plan, no suitable sentance, so has to repeat it
					{
						SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_MENU1));// repeat this menu
					}
					else
					{
						SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_ERROR_INPUT));
					}
				}
			}
    		shmp->process_info.funnel = 0;
    	break;
    	case S_MAP_RECHARGE_WAIT_PIN:
    		if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    		{
    			break;
    		}
			if((data_flow[9] != UnstrctSSReq) || data_flow[1]<14)
			{	
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_ERR_SYSTEM, shmp->process_info.duration);
#endif
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d ,did: %d, wait USSDR_ACK but %d received\33[0m",
						portid,shmp->context_info.map_did,data_flow[9]);
				}		
				ppsSendUSSDStatistics(shmp);
				pps_send_map_close(portid);
				return -1;
			}
			
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, Get Map opr,type:<%d>, USSR  ",
					portid,shmp->context_info.map_did,
					data_flow[9]);			
				pps_debug_map_msg(data_flow,0);
			}
					
			opr_srv.version = shmp->context_info.acn_ver;	
			opr_srv.message_type = data_flow[9];
			opr_srv.message_flag = data_flow[10];
			opr_srv.port_id = portid;
			opr_srv.dialogue_id = shmp->context_info.map_did;		
			
			if(extract_mapparam(&opr_srv,
				data_flow[9],
				data_flow[10],
				data_flow[14]*256+data_flow[15],
				&data_flow[16])<=0)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_ERR_MSG, shmp->process_info.duration);
#endif
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31mportid: %d ,did: %d, decode USSR_ACK failed \33[0m",
						portid,shmp->context_info.map_did);
				}
				ppsSendUSSDStatistics(shmp);
				return -1;
			}
			
			ussr_ack = &opr_srv.msg_list.ussr_res;
			
			if(ussr_ack->param_flag != 0x01)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_ERR_MSG, shmp->process_info.duration);
#endif
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
							"\n\33[31mportid: %d ,did: %d, USSR error received \33[0m",
							portid,shmp->context_info.map_did);
				}		
				return -1;
			}				
			
			switch(ussr_ack->ussd_res.ussd_scheme & 0x0f)
			{
				case 0x00:
				case 0x0f: /* 7bit */
					smppDecodeSM((char *)ussr_ack->ussd_res.ussd_string.ussd_data,
						ussd_data,
						ussr_ack->ussd_res.ussd_string.string_len); 
				break;
				case 0x04: /* 8bit */
				default:
					memcpy(ussd_data,
						ussr_ack->ussd_res.ussd_string.ussd_data,
						ussr_ack->ussd_res.ussd_string.string_len);	
				break;
			}
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, USSD data: %s",
					portid,shmp->context_info.map_did,
					ussd_data);								
			}
			len = strlen(ussd_data);
			if(len>16)
			{
				ussd_data[16] = 0;
				len = 16;
			}
			
			memset(shmp->cdr_info.called,0xFF,10);

			ppsAsciiToBcdR(shmp->cdr_info.called,
					ussd_data,
					(len+1)/2*2);

		if(len%2)
			shmp->cdr_info.called[(strlen(ussd_data)+1)/2] |= 0xF0;
		strcpy((char *)shmp->called_info.number, ussd_data);
			
    		shmp->process_info.funnel = 0;
		shmp->process_info.sub_state = S_MAP_CHECK_USSD_INPUT_CARD_VALIDITY;    		
    	break;
    	case S_MAP_CHECK_USSD_INPUT_CARD_VALIDITY:
    		if(UseExternalVC())
    		{
    			shmp->process_info.sub_state_2 = 0;
    			shmp->process_info.sub_state = S_MAP_USSD_CHECK_CARD_DATA_RCM;
    			return retval;
    		}
		if(OCS_with_external_CRM())
		{
    			shmp->process_info.sub_state_2 = 0;
    			shmp->process_info.sub_state = S_MAP_USSD_CHECK_CARD_DATA_CRM;
    			return retval;
		
		}
		
		if(pps_get_adaptor_flag())
		{
    			shmp->process_info.sub_state = S_MAP_REST_TOPUP;
    			shmp->process_info.sub_state_2 = 0;
			return retval;
		}
    		if(CheckWetherValidRechargeCard(portid,shmp->called_info.number, &result)==0)
    		{
    			if(result == 5 )
    			{
    				shmp->process_info.u_error = 0xee;
				shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
    			}
    			else
    			{
        			shmp->process_info.sub_state = S_MAP_USSD_INPUT_CARD_PWD_AGAIN;
    			}
    			return retval;
    		}
    		RechargeRequestProc(portid);
		SendUSSDRechargeSuccessInfo(portid);
		//shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK_SEND_USSN;

		if(1)
		{
	    		ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);    		
	    		shmp->process_info.sub_state = S_IDLE;
	    		retval = 1;

		}

		
    	break;
    	case S_MAP_USSD_INPUT_CARD_PWD_AGAIN:
    		if(shmp->process_info.serviceInput++>3)
    		{
      		       shmp->process_info.u_error = 0xee;
			shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
    			return retval;
    		}
    		SendUSSDRechargeRequestAgain(portid);
		shmp->process_info.sub_state = S_MAP_RECHARGE_WAIT_PIN;
    	break;
    	case S_MAP_USSD_CHECK_CARD_DATA_RCM:
             switch(shmp->process_info.sub_state_2 )
             {
                   case 0:
                        send_scf_update_card_data(portid);
                        shmp->process_info.sub_state_2 = 1;
                        shmp->process_info.funnel = 0;
                        shmp->process_info.update_card_ack = 0;
                   break;
      	            case 1:
            	  	  if(!shmp->process_info.update_card_ack)
            	  	  {
            	  	        return retval;
            	  	  }
            	  	  if(shmp->process_info.funnel>SSHORT_DELAY_TIMER)
            	  	  {
            	  	       shmp->process_info.u_error = 0xee;
  			       shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
    			       return retval;
            	  	  }
            	  	  if(shmp->process_info.update_card_result != OC_RESULT_OK)
            	  	  {
            	  	        RechargeFailedUpdateAccountData(portid);
				 shmp->process_info.sub_state = S_MAP_USSD_INPUT_CARD_PWD_AGAIN;
            	  	        return retval;
            	  	   }
            	  	   RechargeRequestProc(portid);
			   SendUSSDRechargeSuccessInfo(portid);
		          shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK_SEND_USSN;
            	     break;
		     default:
			  shmp->process_info.u_error = 0xee;
			  shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
            	     break;
             	}
            	 break;
	case S_MAP_USSD_CHECK_CARD_DATA_CRM:
            switch(shmp->process_info.sub_state_2 )
             {
                   case 0:
                        pps_send_selfcare_topup_req(portid);
                        shmp->process_info.sub_state_2 = 1;
                        shmp->process_info.funnel = 0;
			     shmp->process_info.rest_if.recv_cmd = 0;
			break;
      	            case 1:
            	  	  if(shmp->process_info.rest_if.recv_cmd == 0)
            	  	  {
            	  	        return retval;
            	  	  }
            	  	  if(shmp->process_info.funnel>SSHORT_DELAY_TIMER)
            	  	  {
            	  	       shmp->process_info.u_error = 0xee;
  			       shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
    			       return retval;
            	  	  }
			  if(shmp->process_info.rest_if.result)
			  {
            	  	        RechargeFailedUpdateAccountData(portid);
				 shmp->process_info.sub_state = S_MAP_USSD_INPUT_CARD_PWD_AGAIN;
            	  	        return retval;
            	  	   }
            	  	   RechargeSucceedwithCRM(portid);
			   SendUSSDRechargeSuccessInfo(portid);
		          shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK_SEND_USSN;
            	     break;
		     default:
			  shmp->process_info.u_error = 0xee;
			  shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
            	     break;
             	}
		break;
    	case S_MAP_SEND_PUSSR_ACK:
    		SendPSSRResponse(portid);
    		ppsSendUSSDStatistics(shmp);
		pps_send_map_close(portid);    			
    		shmp->process_info.sub_state = S_IDLE;
    		return 1;
    	break;
    	case S_MAP_SEND_PUSSR_ACK_SEND_USSN:
    		if(!map_get_oprdata(data_flow,shmp->context_info.map_did))
    		{
    			break;
    		}


			if((data_flow[9] != UnstrctSSNoti) || data_flow[1]<10)
			{	
				if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
				{
					DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d ,did: %d, wait USSDN_ACK but %d received\33[0m",
						portid,shmp->context_info.map_did,data_flow[9]);
				}
				ppsSendUSSDStatistics(shmp);
				pps_send_map_close(portid);
				return -1;
			}
			
			if((logMsgFlag == 0xff) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\nportid: %d ,did: %d, Get Map opr < USSN_ACK >  ",
					portid,shmp->context_info.map_did);			
				pps_debug_map_msg(data_flow,0);
			}
			
    			SendPSSRResponse(portid);
    			ppsSendUSSDStatistics(shmp);
    			pps_send_map_close(portid);
			shmp->process_info.sub_state = S_IDLE;
			shmp->process_info.funnel = 0;

			return 1;
			break;
    	case S_MAP_WAIT_USSN_ACK:
    		ppsSendUSSDStatistics(shmp);
		pps_send_map_close(portid);    		
    		shmp->process_info.sub_state = S_IDLE;
    		retval = 1;
    	break;		
		case S_MAP_FEE_TRANSFER:
			result = transferAccountUSSDProc(portid);
			switch(result)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_MENU));											
		    		shmp->process_info.funnel = 0;
					shmp->process_info.sub_state = S_MAP_GET_USSDACK;	
				break;
				case SERVICE_EXIT_PPS:
				default:
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
				break;
			}
		break;
		case S_MAP_CALL_ME_BACK:
			result = callMebackUSSDProc(portid);
			switch(result)
			{
				case SERVICE_KEEP_STATE:
				break;
				case SERVICE_RETURN_TO_PARENT:
					SendUSSDRequest(portid, (char *)getSmsSentenceNative(0,SMS_USSD_MENU));											
		    		shmp->process_info.funnel = 0;
					shmp->process_info.sub_state = S_MAP_GET_USSDACK;	
				break;
				case SERVICE_EXIT_PPS:
				default:
					shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
				break;
			}
		break;
		case S_MAP_TELL_ME_NUMBER:
			SendUSSDTellMeNumberInfo(portid);			
			shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;
		break;
		case S_MAP_FAVORITE_NUMBER:
			result = favoriteNumberUssdProc(portid);
			switch(result)
			{
			    case SERVICE_KEEP_STATE:
			    break;
   			    case SERVICE_EXIT_PPS:
			        shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;
			    break;
			    case SERVICE_RETURN_TO_PARENT:
			    default:
			    	 shmp->process_info.sub_state = S_MAP_SEND_PUSSR_ACK;
			    break;
			}
		break;
	case S_MAP_REST_QUERY:
		retval = pps_rest_query_process(portid);
		if(retval != 0)
		{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
			pps_update_ussd_code_state(USSDCODE_QUERY_CODE_STR, USSDCODE_TYPE_QUERY, USSDCODE_STAT_DUR, shmp->process_info.duration);
#endif
	    		ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);    		
	    		shmp->process_info.sub_state = S_IDLE;
	    		retval = 1;

//			shmp->process_info.serviceKey = 1;
//			shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;		
		}
	break;
	case S_MAP_REST_TOPUP:
		retval = pps_rest_topup_process(portid);
		if(retval != 0)
		{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
			pps_update_ussd_code_state(USSDCODE_TOPUP_CODE_STR, USSDCODE_TYPE_TOPUP, USSDCODE_STAT_DUR, shmp->process_info.duration);
#endif
	    		ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);    		
	    		shmp->process_info.sub_state = S_IDLE;
	    		retval = 1;

//			shmp->process_info.serviceKey = 2;
//			shmp->process_info.sub_state = S_MAP_WAIT_USSN_ACK;		
		}
	break;

	case S_MAP_BUNDLE_PLAN:
		retval = pps_bundle_plan_process(portid);
		if(retval != 0)
		{
	    		ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);    		
	    		shmp->process_info.sub_state = S_IDLE;
	    		retval = 1;
		}
	break;
	case S_MAP_THIRD_PARTY_HOTLINE:
		retval = pps_third_party_plan_process(portid);
		if(retval != 0)
		{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
			pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_DUR, shmp->process_info.duration);
#endif
			ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);
			shmp->process_info.sub_state = S_IDLE;
			retval = 1;
		}
	break;
	case S_MAP_THIRD_PARTY_CHANNEL:
		retval = pps_third_party_channel_process(portid);
		if(retval != 0)
		{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
			pps_update_ussd_code_state(shmp->process_info.ppsService.chnl_info.scUrl, USSDCODE_TYPE_CHANNEL, USSDCODE_STAT_DUR, shmp->process_info.duration);
#endif
			ppsSendUSSDStatistics(shmp);
			pps_send_map_close(portid);
			shmp->process_info.sub_state = S_IDLE;
			retval = 1;
		}
	break;
	default:
    		retval = 1;
    	break;
    }	
	return retval;		
}

int pps_rest_test_process(int flag)
{
	int portid;
	_state_data *shmp=(_state_data *) &smshm_ptr->state_data;
	
	portid = AssignProcID(0);
	if( portid< MAX_FSM_PROCESS && portid>=0 )
	{
		shmp += portid;
		memset(shmp, 0x00, sizeof(_state_data));

		DebugMsg(debugmib.display.asciiOut,
						"\n\33[31m portid: %d , %s , flag=%d\33[0m",
						portid, __FUNCTION__, flag);

		shmp->process_info.state = S_MAP_STATE;
		if(flag == 0)
		{
			shmp->process_info.sub_state = S_MAP_REST_QUERY;	
		}
		else
		{
			shmp->process_info.sub_state = S_MAP_REST_TOPUP;	
			strcpy((char *)shmp->called_info.number, "123456789012");

		}
		
		strcpy((char *)shmp->caller_info.number, "86755900123");
	}
	
	return 1;
}


int SmppRechargeProc(u_short portid)
{
    _state_data *shmp;
    int retval=0;
    int error_code = ERR_REST_SUCCESS;
	
    PutLogFunID("SnmpRechargeProc");

    shmp = (_state_data *)&smshm_ptr->state_data;

    if(portid>=MAX_FSM_PROCESS)
        return -1;
    shmp += portid;

    if(shmp->process_info.funnel ++>SSHORT_DELAY_TIMER)
    {
        sendSMSRechargeNegativeResponse(shmp, OC_RESULT_SYSTEM_FAILURE);
        return -1;
    }
    switch(shmp->process_info.sub_state)
    {
        case 0:
            send_scf_update_card_data(portid);
            shmp->process_info.sub_state = 1;
            shmp->process_info.funnel = 0;
            shmp->process_info.update_card_ack = 0;
        break;
        case 1:
            if(!shmp->process_info.update_card_ack)
            {
                return retval;
            }
            if(shmp->process_info.update_card_result != OC_RESULT_OK)
            {
                RechargeFailedUpdateAccountData(portid);
                sendSMSRechargeNegativeResponse(shmp, shmp->process_info.update_card_result );
                return (retval = -1);
            }
            RechargeRequestProc(portid);
            retval = 1;
        break;
	  case 2:
            pps_send_selfcare_topup_req(portid);
            shmp->process_info.funnel = 0;
            shmp->process_info.rest_if.recv_cmd = 0;	 
	      if(shmp->process_info.chargeFrom == 3)
	      	{
	            shmp->process_info.sub_state = 4;
	      	}
	      else
	            shmp->process_info.sub_state = 3;
			
	  break;
	  case 3:
   	  	if(shmp->process_info.rest_if.recv_cmd == 0)
            {
     	  	      return retval;
            }
            if(shmp->process_info.funnel>SSHORT_DELAY_TIMER)
           {
                return (retval = -1);
           }
	     if(shmp->process_info.rest_if.result)
            {
                RechargeFailedUpdateAccountData(portid);
                sendSMSRechargeNegativeResponse(shmp, shmp->process_info.rest_if.result );
                return (retval = -1);
            }
            RechargeSucceedwithCRM(portid);
	      retval = 1;  	
	  break;
	  case 4:
   	  	if(shmp->process_info.rest_if.recv_cmd == 0)
            {
     	  	      return retval;
            }
            if(shmp->process_info.funnel>SSHORT_DELAY_TIMER)
           {
           		error_code = ERR_REST_UNABLE_TO_COMPLY;
           }
	     if(shmp->process_info.rest_if.result)
            {
            		switch(shmp->process_info.rest_if.result == 1)
            		{
            			case 1:
		           		error_code = ERR_REST_INVALID_RECHARGE_PWD;
				break;
				case 2: //error status
		           		error_code = ERR_REST_INVALID_PARAMETER_VALUE;
				break;
				case 3: //expired
				default:
		           		error_code = ERR_REST_INVALID_PARAMETER_VALUE;				
				break;
            		}
            }

		if(1)
		{
			int len;
			char	msg_buf[256];
			_rest_msg_s		rest_rsp;
			_rest_recharge_card_rsp *pRsp = &rest_rsp.msg.recharge_card_rsp;
			
			memset(pRsp, 0, sizeof(_rest_recharge_card_rsp));

			rest_rsp.msg_type = REST_RECHARGE_CARD_RSP;
			rest_rsp.header.dst_ref = shmp->process_info.rest_if.src_ref; 
			rest_rsp.header.src_ref = shmp->process_info.rest_if.dst_ref;
			pRsp->error_code = error_code;
			if (error_code != ERR_REST_SUCCESS)
			{
				pRsp->result = RES_FAILED;
				pRsp->rechargeAmount = 0;

			}
			else
			{
				pRsp->result = RES_SUCCEED;

		            RechargeSucceedwithCRM(portid);
				pRsp->rechargeAmount = shmp->process_info.rest_if.balance;
			}

			pRsp->balance = GetBalance(&shmp->caller_info);
			pRsp->expiredTime = (u64)GetExpiration(&shmp->caller_info);

			if((logMsgFlag & 0x04) || (logMsgFlag & 0x02) )
			{
				DebugMsg(debugmib.display.asciiOut, "reply REST_RECHARGE_CARD_RSP, result[%d], recharge amount[%d], balance[%d]", \
							error_code, pRsp->rechargeAmount, pRsp->balance);
			}
			
			len = encode_rest_recharge_card_rsp(&rest_rsp, (u8 *)msg_buf);
			pps_send_rest_msg((u8 *)msg_buf, len);
		}
		
	      retval = 1;  	

	  break;
	  default:
	  	retval = 1;
	  break;
    }
    return retval;
}

// for restproxy(zmobile) =========================================
char yx_ussd_menu[YX_USSD_MENU_NUM_MAX][512]= {
    /*0main*/"Welcome to the Ultimate DATA experience - zedmobile!\n1. UNLIMITED zedmobile calls and Data @ an Unbelievable K20 for 30 days\n2. zedDATA\n3. zedVOICE\n4. zedMIFI & Router\n5. Buy for Other\n6. Balance Check",
    /*1k20*/"Try our  K20 UNLIMITED Calls & Data\n1. Yes\n0. To return to main menu",
    /*2data*/"1. 24 Hrs\n2. 7 days\n3. 30 days\n0. To return to main menu",
    /*3voice*/"1. Daily\n2. Weekly\n3. Monthly\n0. To return to main menu",
    /*4mifi*/"Welcome to the ULTIMATE DATA experience - zedmobile!\n1. K50 = 6 GB for 30 days\n2. K100 = 15GB for 30 days\n3. K200 = 40GB for 30 days\n4. K500 = 65GB +5GBDaily  for 30 days + Unlimited netflix\n5. K700 = 80 GB + 6 GB daily for 30 days + Unlimited Netflix + Youtube\n6. K1000 = 100 GB +8Gb Daily + Unlimited netflix  + Youtube\n0. To return to main menu",
    /*5buy4Other*/"Share the ULTIMATE DATA experience - zedmobile!\nKindly enter the number you wish to share a zedmobile bundle with.(098X xxxxxx)",
    /*6balanceCheck*/"Dear Customer, your balance is processed. You will receive a confirmation message shortly",
    /*7*/"",
    /*8*/"",
    /*9*/"",
    /*10data 24Hrs*/"1. K2= 100 MB for 24Hrs\n2. K5= 350 MB for 24Hrs\n3. K10= 1.5 GB for 24Hrs\n0. To return to main menu",
    /*11data 7days*/"1. K5= 500 MB for 7 days\n2. K10= 1 GB for 7 days\n3. K20= 2 GB for 7 days\n4. K50= 7.5 GB for 7 days\n0. To return to main menu",
    /*12data 30days*/"1. K50= 5 GB for 30 days\n2. K100= 10 GB for 30 days\n3. K200= 30 GB for 30 days\n0. To return to main menu",
    /*13voic Daily*/"Press\n1 . K2= 8 min allnet + 20MB + 50 SMS\n2. K5= 26 min allnet + 40MB + 100 SMS\n3. K10= 40 Min allnet + 70MB + 100 SMS\n0. To return to main menu",
    /*14voic Weekly*/"Press\n1. K5= 17 min allnet + 100MB + 50 SMS\n2. K10= 45 min allnet + 300 MB + 100 SMS\n3. K20= 120min allnet + 400MB +100 SMS\n4. K50= 350 min allnet + 500MB + 100 SMS\n0. To return to main menu",
    /*15voic Monthly*/"Press\n1. K50= 200 min allnet + 1 GB + 500 SMS\n2. K100= 725min allnet + 3GB + 500 SMS\n3. K200= 1750 min allnet + 5GB + 500 SMS\n4. K250= 800min allnet + 15GB + 500 SMS\n0. To return to main menu",
    /*16MIFI*/"",
    /*17otherMenu*/"1. ZedLife na K20\n2. zedDATA\n3. zedVoice\n4. zedMIFI & Router\n0. To return to main menu",
    /*18thirdParty*/"1. Airtel\n2. MTN",
    /*19enterPhone*/"Enter mobile number",
    /*20payMethod*/"1. Main account\n2. Mobile money",
    /*21Paid*/"Your transaction is being processed. You will receive a confirmation SMS soon. For the ULTIMATE experience use My zedLife  App ( selfcare)\n1. Download zedLife App and don’t miss out on anything.\n0. To return to the main menu",
    /*22enterPin*/"Enter pin to confirm",
    /*23complete*/"Thank you. You will soon receive the link via text message.",
    /*24cancel auto renewal*/"Are you certain about canceling auto renewal?\n1. No\n2. Yes\n0. To return to main menu",
};
char yx_chnl_info[YX_USSD_CHNL_NUM_MAX][128]= {
};
char yx_momo_info[YX_MOBILE_MONEY_MAX][32]= {"Airtel Money", "MTN MoMo", "Zamtel Kwacha", ""};
int yx_offerIds[YX_OFFER_TYPE_MAX][YX_OFFER_PER_TYPE];
char yx_offerStrs[YX_OFFER_TYPE_MAX][YX_OFFER_PER_TYPE][128]= {};
int yx_ussd_daily_report = 0;
extern int time_now[7];
int match_channel_info(char *sc, char *url)
{
    int i;
	if (strlen(sc) < 3)
	{
		return 0;
	}
    for (i=0; i<YX_USSD_CHNL_NUM_MAX; i++)
    {
        if ((strlen(yx_chnl_info[i]) > 12) && (strncmp(sc, yx_chnl_info[i], 3) == 0))
        {
            strcpy(url, yx_chnl_info[i]);
            return 1;
        }
    }
    return 0;
}

int read_yx_ussd_param(void)
{
	//char	*temp_ptr;
	char	info_str[512];
	char	sysconf[]="/usr/local/ussdgw/bin/conf/yx_ussd.conf";
	FILE *fp = fopen(sysconf,"r");// read configure
	if (fp == NULL)
	{
		printf("can not open file %s!!\n",sysconf);
		return 0;
	}

    int i, ret;
	while (!feof(fp))
	{
		info_str[0] = '\n';
		ret = fgets(info_str, 250, fp);
		if (info_str[0] == '#' || info_str[0] == '\n')
			continue;

        i = 0;
        while (info_str[i] != '\0')
        {
            if (info_str[i] == '|')
            {
                info_str[i] = '\n';
            }
            i++;
        }
        
		if(!strncasecmp(info_str,"dailyreport=", 12))
		{
			yx_ussd_daily_report = atoi(&info_str[12]);
		}
		else if(!strncasecmp(info_str,"bundle11=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][0] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle12=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][1] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle13=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][2] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle14=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][3] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle15=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][4] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle16=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][5] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle17=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][6] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"bundle18=", 9))
		{
			yx_offerIds[YX_OFFER_TYPE_BUNDLE][7] = atoi(&info_str[9]);
		}
		else if(!strncasecmp(info_str,"data11=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_1][0] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data12=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_1][1] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data13=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_1][2] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data14=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_1][3] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data21=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_2][0] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data22=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_2][1] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data23=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_2][2] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data24=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_2][3] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data31=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_3][0] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data32=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_3][1] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data33=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_3][2] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"data34=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DATA_3][3] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"voice11=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_1][0] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice12=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_1][1] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice13=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_1][2] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice14=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_1][3] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice21=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_2][0] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice22=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_2][1] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice23=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_2][2] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice24=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_2][3] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice31=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_3][0] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice32=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_3][1] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice33=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_3][2] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"voice34=", 8))
		{
			yx_offerIds[YX_OFFER_TYPE_VOICE_3][3] = atoi(&info_str[8]);
		}
		else if(!strncasecmp(info_str,"mifi11=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][0] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi12=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][1] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi13=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][2] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi14=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][3] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi15=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][4] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi16=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][5] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"mifi17=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_MIFI_1][6] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"ama01=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][0] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama02=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][1] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama03=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][2] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama04=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][3] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama05=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][4] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama06=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][5] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"ama07=", 6))
		{
			yx_offerIds[YX_OFFER_TYPE_AMA_1][6] = atoi(&info_str[6]);
		}
		else if(!strncasecmp(info_str,"diba01=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][0] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba02=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][1] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba03=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][2] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba04=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][3] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba05=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][4] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba06=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][5] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba07=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][6] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba08=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][7] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba09=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][8] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba10=", 7))
		{
			yx_offerIds[YX_OFFER_TYPE_DIBA_1][9] = atoi(&info_str[7]);
		}
		else if(!strncasecmp(info_str,"diba01str=", 10))
		{
			snprintf(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][0], 127, "%s", &info_str[10]);//strncpy(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][0], &info_str[10], 127);
		}
		else if(!strncasecmp(info_str,"diba02str=", 10))
		{
			snprintf(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][1], 127, "%s", &info_str[10]);
		}
		else if(!strncasecmp(info_str,"diba03str=", 10))
		{
			snprintf(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][2], 127, "%s", &info_str[10]);
		}
		else if(!strncasecmp(info_str,"diba04str=", 10))
		{
			snprintf(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][3], 127, "%s", &info_str[10]);
		}
		else if(!strncasecmp(info_str,"diba05str=", 10))
		{
			snprintf(yx_offerStrs[YX_OFFER_TYPE_DIBA_1][4], 127, "%s", &info_str[10]);
		}
		else if(!strncasecmp(info_str,"0main=",6))
		{
            strcpy(yx_ussd_menu[0], &info_str[6]);
		}
		else if(!strncasecmp(info_str,"1k20=",5))
		{
            strcpy(yx_ussd_menu[1], &info_str[5]);
		}
		else if(!strncasecmp(info_str,"2data=",6))
		{
            strcpy(yx_ussd_menu[2], &info_str[6]);
		}
		else if(!strncasecmp(info_str,"3voice=",7))
		{
            strcpy(yx_ussd_menu[3], &info_str[7]);
		}
		else if(!strncasecmp(info_str,"4mifi=",6))
		{
            strcpy(yx_ussd_menu[4], &info_str[6]);
		}
		else if(!strncasecmp(info_str,"5buy4Other=",11))
		{
            strcpy(yx_ussd_menu[5], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"6balanceCheck=",14))
		{
            strcpy(yx_ussd_menu[6], &info_str[14]);
		}
		else if(!strncasecmp(info_str,"7ama=",5))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_PRESS_AMA], &info_str[5]);
		}
		else if(!strncasecmp(info_str,"8unlimited=",11))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_PRESS_UNLIMITED_BUNDLES], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"9airtime=",9))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_PRESS_PURCHASE_AIRTIME], &info_str[9]);
		}
		else if(!strncasecmp(info_str,"10data24Hrs=",12))
		{
            strcpy(yx_ussd_menu[10], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"11data7days=",12))
		{
            strcpy(yx_ussd_menu[11], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"12data30days=",13))
		{
            strcpy(yx_ussd_menu[12], &info_str[13]);
		}
		else if(!strncasecmp(info_str,"13voiceDaily=",13))
		{
            strcpy(yx_ussd_menu[13], &info_str[13]);
		}
		else if(!strncasecmp(info_str,"14voiceWeekly=",14))
		{
            strcpy(yx_ussd_menu[14], &info_str[14]);
		}
		else if(!strncasecmp(info_str,"15voiceMonthly=",15))
		{
            strcpy(yx_ussd_menu[15], &info_str[15]);
		}
		else if(!strncasecmp(info_str,"17otherMenu=",12))
		{
            strcpy(yx_ussd_menu[17], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"18thirdParty=",13))
		{
            strcpy(yx_ussd_menu[18], &info_str[13]);
			
			/* mobile moneys
			int i=0, offset;
			char *token;
			char delimiter[] = "|";
			char str[160]="";
			strncpy(str, yx_ussd_menu[18], 159);
			token = strtok(str, delimiter);
			while ((token != NULL) && (i < YX_MOBILE_MONEY_MAX)) {
				if (token[0]<'0' || token[0]>'9')
				{
					token = strtok(NULL, delimiter);
					continue;
				}
				offset = 2;
				if (token[2] == ' ')
				{
					offset = 3;
				}
				strncpy(yx_momo_info[i], &token[offset], 31);
				i++;
				token = strtok(NULL, delimiter);
			}*/
		}
		else if(!strncasecmp(info_str,"19enterPhone=",13))
		{
            strcpy(yx_ussd_menu[19], &info_str[13]);
		}
		else if(!strncasecmp(info_str,"20payMethod=",12))
		{
            strcpy(yx_ussd_menu[20], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"21Paid=",7))
		{
            strcpy(yx_ussd_menu[21], &info_str[7]);
		}
		else if(!strncasecmp(info_str,"22enterPin=",11))
		{
            strcpy(yx_ussd_menu[22], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"23complete=",11))
		{
            strcpy(yx_ussd_menu[23], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"24cancelrenewal=",16))
		{
            strcpy(yx_ussd_menu[24], &info_str[16]);
		}
		else if(!strncasecmp(info_str,"25enteramount=",14))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_AIRTIME_AMOUNT], &info_str[14]);
		}
		else if(!strncasecmp(info_str,"26airtimeno=",12))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_AIRTIME_NO], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"27dibaama=",10))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_DIBAAMA], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"28diba=",7))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_DIBA], &info_str[7]);
		}
		else if(!strncasecmp(info_str,"29momopin=",10))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_MOMO_PIN], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"30promo=",8))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_PROMO], &info_str[8]);
		}
		else if(!strncasecmp(info_str,"31querypoint=",13))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_QUERY_POINT], &info_str[13]);
		}
		else if(!strncasecmp(info_str,"32curpoint=",11))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_CUR_POINT], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"33point2num=",12))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_POINT2NUM], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"34offerchange=",14))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_OFFER_CHANGED], &info_str[14]);
		}
		else if(!strncasecmp(info_str,"35pointtrans=",13))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_POINT_TRANSFERED], &info_str[13]);
		}
		else if(!strncasecmp(info_str,"36pointlow=",11))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_POINT_LOW], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"37offerout=",11))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_OFFER_OUT], &info_str[11]);
		}
		else if(!strncasecmp(info_str,"38transfail=",12))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_POINT_TRANS_FAIL], &info_str[12]);
		}
		else if(!strncasecmp(info_str,"39shareno=",10))
		{
            strcpy(yx_ussd_menu[YX_USSD_MENU_SHARE_NBR], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel00=", 10))
		{
            strcpy(yx_chnl_info[0], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel01=", 10))
		{
            strcpy(yx_chnl_info[1], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel02=", 10))
		{
            strcpy(yx_chnl_info[2], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel03=", 10))
		{
            strcpy(yx_chnl_info[3], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel04=", 10))
		{
            strcpy(yx_chnl_info[4], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel05=", 10))
		{
            strcpy(yx_chnl_info[5], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel06=", 10))
		{
            strcpy(yx_chnl_info[6], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel07=", 10))
		{
            strcpy(yx_chnl_info[7], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel08=", 10))
		{
            strcpy(yx_chnl_info[8], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel09=", 10))
		{
            strcpy(yx_chnl_info[9], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel10=", 10))
		{
            strcpy(yx_chnl_info[10], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel11=", 10))
		{
            strcpy(yx_chnl_info[11], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel12=", 10))
		{
            strcpy(yx_chnl_info[12], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel13=", 10))
		{
            strcpy(yx_chnl_info[13], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel14=", 10))
		{
            strcpy(yx_chnl_info[14], &info_str[10]);
		}
		else if(!strncasecmp(info_str,"channel15=", 10))
		{
            strcpy(yx_chnl_info[15], &info_str[10]);
		}
	}

	fclose(fp);
	return 1;
}

int pps_third_party_plan_process(u_short portid)
{
	char	ussd_data[1024];
	int retval = 0, result=0;
	int key_input;

	_state_data *shmp = (_state_data *) smshm_ptr->state_data;
	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	if(shmp->process_info.funnel ++ > 100*CYCLE_STATE_INTERVAL)
	{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
		pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_TIMEOUT, 0);
#endif
		return -1;
	}

	switch(shmp->process_info.sub_state_2 )
	{
		case 1:
			if(shmp->process_info.serviceInput++ > 3)
			{
				SendPSSRResponse(portid);
				return 1;
			}
            shmp->process_info.funnel = 0;
            shmp->process_info.rest_if.plan_id = 0;
            shmp->process_info.rest_if.bundle_plan_id = 0;
            shmp->process_info.routing_number[0] = '\0';
            
            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_MAIN]);
            shmp->process_info.sub_state_2 = 2;
		break;
		case 2:
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					shmp->process_info.sub_state_2 = 1;
					shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					shmp->process_info.sub_state_2 = 1;
					shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_UNLIMITED_BUNDLES]);
                            shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 20;//1. UNLIMITED Data
						break;
						case 2:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_ZED_DATA]);
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 22;//zedDATA
						break;
						case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_ZED_VOICE]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 23;//zedVOICE
						break;
						case 4:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_MIFI_AND_ROUTER]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 24;//zedMifi & Router
						break;
						case 5:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_INPUT_NO]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 25;//Buy for Other
						break;
						case 6:
                            //SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_BALANCE_CHECK]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 26;//Balance Check, inform BOSS
						break;
						case 7:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_PURCHASE_AIRTIME]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 28;//Recharge Airtime
						break;
						case 8:// KaBoosta: redirect to 118
							if (match_channel_info("118", shmp->process_info.ppsService.chnl_info.scUrl) > 0)
							{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
								pps_update_ussd_code_state("118", USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_REQ, 0);
#endif
								shmp->process_info.sub_state = S_MAP_THIRD_PARTY_CHANNEL;
								shmp->process_info.sub_state_2 = 1;
								break;
							}
						break;
						case 0:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_DIBAAMA]);// YX_USSD_MENU_PRESS_AMA
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 15;//27;//diba & amaFive
						break;
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
		break;//
		case 3:
			if(shmp->process_info.serviceInput++ > 3)
			{
				SendPSSRResponse(portid);
				return 1;
			}
            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_BUY_FOR_OTHER]);// menu 1-4
            shmp->process_info.sub_state_2 = 4;
		break;
		case 4:// Buy for others, select menu 1-4
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					shmp->process_info.sub_state_2 = 3;
					shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					shmp->process_info.sub_state_2 = 3;
					shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_UNLIMITED_BUNDLES]);
                            shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 20;//1. UNLIMITED Data
						break;
						case 2:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_ZED_DATA]);
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 22;//zedDATA
						break;
						case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_ZED_VOICE]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 23;//zedVOICE
						break;
						case 4:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_MIFI_AND_ROUTER]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 24;//zedMifi & Router
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
		break;
		case 10:// Recharge Promo
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// Opt-in, send transfer Plan and return
							pps_send_rest_offer_change_req(portid, 0);
							SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_OFFER_CHANGED]);
							shmp->process_info.serviceInput = 0;
							retval = 1;
						break;
						case 2:// Query Bonus, send query points
							pps_send_rest_point_query_req(portid);
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 11;// query points
						break;
						case 3:// Transfer Gift
							//pps_send_rest_point_query_req(portid);
							SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_CUR_POINT]);
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 13;// transfer Gift
						break;
						case 4:// Opt-out, send transfer Plan and return
							pps_send_rest_offer_change_req(portid, 1);
							SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_OFFER_OUT]);
							shmp->process_info.serviceInput = 0;
							retval = 1;
						break;
						default:
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 1;
							shmp->process_info.funnel = 0;
						break;
					}
				}
			}
			else if(result == -1)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;//
		case 11:// query points
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			shmp->process_info.rest_if.recv_cmd = 0;
			result = shmp->process_info.rest_if.result;
			if(result == 0)
			{
				retval = 1;
				sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_QUERY_POINT], shmp->process_info.rest_if.unit, 
					shmp->process_info.rest_if.balance/100, shmp->process_info.rest_if.balance%100);
			}
			else
			{
				retval = -1;
				sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_QUERY_POINT], 0);
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv query_points_res, result=%d, point=%d\33[0m",
					portid, result, shmp->process_info.rest_if.unit);
			}		
			SendPSSREnd(portid, ussd_data);
		break;
		case 12:// current points
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			shmp->process_info.rest_if.recv_cmd = 0;
			result = shmp->process_info.rest_if.result;
			if(result == 0)
			{
				/*if (shmp->process_info.rest_if.unit <= 0)
				{
					retval = -1;
					sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_QUERY_POINT], 0);
					SendPSSREnd(portid, ussd_data);
				}
				else
				{
					sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_CUR_POINT], shmp->process_info.rest_if.unit);
					SendUSSDRequest(portid, ussd_data);
					shmp->process_info.serviceInput = 0;
					shmp->process_info.sub_state_2 = 13;// enter number that transfer Gift to
				}*/
				sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_POINT_TRANSFERED], shmp->process_info.rest_if.unit, shmp->process_info.routing_number);
				SendPSSREnd(portid, ussd_data);
				retval = 1;
			}
			else
			{
				retval = -1;
				sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_POINT_TRANS_FAIL], shmp->process_info.routing_number);
				SendPSSREnd(portid, ussd_data);
			}

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d , recv query_points_res, result=%d, point=%d\33[0m",
					portid, result, shmp->process_info.rest_if.unit);
			}		
		break;
		case 13:// input No. transfer Gift for
			result = getUssdACK(portid, (u_char *)shmp->process_info.routing_number);
			if(result >= 1)
			{
				sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_POINT2NUM], shmp->process_info.routing_number);
				SendUSSDRequest(portid, ussd_data);
				shmp->process_info.serviceInput = 0;
				shmp->process_info.sub_state_2 = 14;// =>Amount Input
				shmp->process_info.funnel = 0;
			}
			else if(result == -1)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;
		case 14:// Point Amount Input
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					if (key_input <= 0)
					{
						SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_POINT_LOW]);
						retval = 1;
					}
					else
					{
						shmp->process_info.rest_if.unit = key_input;
						pps_send_rest_point_transfer_req(portid, 1070);
						//sprintf(ussd_data, yx_ussd_menu[YX_USSD_MENU_POINT_TRANSFERED], shmp->process_info.rest_if.unit, shmp->process_info.routing_number);
						//SendPSSREnd(portid, ussd_data);
					}
					//retval = 1;
					shmp->process_info.serviceInput = 0;
					shmp->process_info.sub_state_2 = 12;// =>wait result
				}
			}
			else if(result == -1)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;
		case 15:
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 2:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_DIBA]);
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 16;//diba 5x
						break;
						case 1:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PROMO]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 10;//Recharge Promo
						break;
						case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_AMA]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 27;//amaFive
						break;
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
		break;//
		case 16:// 0, DIBA sub menu
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
						case 2:
						case 3:
						case 4:
						case 5:
						{
							char tmp_buf[160]="";
							snprintf(tmp_buf, 159, "%s\n%s", yx_offerStrs[YX_OFFER_TYPE_DIBA_1][key_input-1], 
								yx_ussd_menu[YX_USSD_MENU_UNLIMITED_ONCE_RECUR]);
							SendUSSDRequest(portid, tmp_buf);//yx_ussd_menu[YX_USSD_MENU_UNLIMITED_ONCE_RECUR]);
						}
							shmp->process_info.rest_if.bundle_plan_id = key_input -1;
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 17;//once, recur or cancel
							shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 17:// 0, diba: once, recur
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					int bundleId = shmp->process_info.rest_if.bundle_plan_id * 2;
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// once off
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DIBA_1][bundleId];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 2:// recur
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DIBA_1][bundleId + 1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 3:// cancel recur
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_CANCEL_RENEWAL]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DIBA_1][bundleId + 1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 36;//cancel auto renewal
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 18:// input No. share airtime with
			result = getUssdACK(portid, (u_char *)shmp->process_info.routing_number);
			if(result >= 1)
			{
				SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_AIRTIME_AMOUNT]);
				shmp->process_info.serviceInput = 0;
				shmp->process_info.sub_state_2 = 19;// =>Airtime Amount Input
				shmp->process_info.funnel = 0;
			}
			else if(result == -1)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;
		case 19:// Airtime Amount Input, share with
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);

					shmp->process_info.rest_if.unit = key_input;
					pps_send_rest_point_transfer_req(portid, 1069);
					SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_PAID_MONEY]);
					retval = 1;
				}
			}
			else if(result == -1)
			{
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
				SendPSSRResponse(portid);
				retval = 1;
			}
		break;
		case 20:// unlimited data
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// K20 Unlimited-24hrs
                            /*SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_UNLIMITED_ONCE_RECUR]);
                            shmp->process_info.rest_if.bundle_plan_id = 0;// yx_offerIds[YX_OFFER_TYPE_BUNDLE][0];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 21;//once, recur or cancel
                            shmp->process_info.funnel = 0;*/

							SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
							shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_BUNDLE][0];
							shmp->process_info.serviceInput = 0;
							shmp->process_info.sub_state_2 = 31;//select money
							shmp->process_info.funnel = 0;
						break;
						case 2:// K20 Unlimited-3 Days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_UNLIMITED_ONCE_RECUR]);
                            shmp->process_info.rest_if.bundle_plan_id = 1;// yx_offerIds[YX_OFFER_TYPE_BUNDLE][2];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 21;//once, recur or cancel
                            shmp->process_info.funnel = 0;
						break;
						case 3:// K100 Unlimited-7 Days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_UNLIMITED_ONCE_RECUR]);
                            shmp->process_info.rest_if.bundle_plan_id = 2;//yx_offerIds[YX_OFFER_TYPE_BUNDLE][3];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 21;//once, recur or cancel
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 21:// 1, k20 unlimited calls and data
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					int bundleId = shmp->process_info.rest_if.bundle_plan_id * 2;
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_BUNDLE][bundleId];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 2:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_BUNDLE][bundleId + 1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_CANCEL_RENEWAL]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_BUNDLE][bundleId + 1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 36;//cancel auto renewal
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 22:// 2, zed DATA
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// 24Hrs
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_DATA_24HRS]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 41;
                            shmp->process_info.funnel = 0;
						break;
						case 2:// 7 days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_DATA_7DAYS]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 42;
                            shmp->process_info.funnel = 0;
						break;
						case 3:// 30 days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_DATA_30DAYS]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 43;
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 23:// 3, zed VOICE
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// 24Hrs
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_VOICE_DAILY]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 51;
                            shmp->process_info.funnel = 0;
						break;
						case 2:// 7 days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_VOICE_WEEKLY]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 52;
                            shmp->process_info.funnel = 0;
						break;
						case 3:// 30 days
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_VOICE_MONTHLY]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 53;
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 24:// 4, MIFI sub menu
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_MIFI_1][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 25:// input No.
			result = getUssdACK(portid, (u_char *)shmp->process_info.routing_number);
			if(result >= 1)
			{
                //SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_BUY_FOR_OTHER]);// menu 1-4
                shmp->process_info.serviceInput = 0;
                shmp->process_info.sub_state_2 = 3;
                shmp->process_info.funnel = 0;
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 26:// Balance Check
		    if (1)
		    {
                pps_send_rest_free_resource_req(portid);// send free resource req, no need to handle rsp
		    }
            SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_PRESS_BALANCE_CHECK]);
            retval = 1;
        break;
		case 27:// 0, AMA sub menu
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_AMA_1][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 28:// 7. Recharge Airtime
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// Buy for self, order->msisdn = shmp->caller_info.number
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_AIRTIME_AMOUNT]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 30;//=>Airtime Amount Input
                            shmp->process_info.funnel = 0;
						break;
                        case 2:// Buy for other
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_AIRTIME_NO]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 29;//=>input No. buy airtime for
                            shmp->process_info.funnel = 0;
						break;
                        case 3:// Me2U
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SHARE_NBR]);
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 18;//=>input No. share airtime with
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 29:// input No. buy airtime for
			result = getUssdACK(portid, (u_char *)shmp->process_info.routing_number);
			if(result >= 1)
			{
				SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_AIRTIME_AMOUNT]);
                shmp->process_info.serviceInput = 0;
                shmp->process_info.sub_state_2 = 30;// =>Airtime Amount Input
                shmp->process_info.funnel = 0;
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 30:// Airtime Amount Input
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					shmp->process_info.rest_if.balance = (long)key_input;
					
					SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_PROVIDER]);
					shmp->process_info.rest_if.plan_id = 10;// mobile money
					shmp->process_info.rest_if.busicode = 1000;// busicode: recharge
					shmp->process_info.serviceInput = 0;
					shmp->process_info.sub_state_2 = 34;//select provider; 33;//enter pin
					shmp->process_info.funnel = 0;
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 41:// zed Data sub 24Hrs
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DATA_1][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 42:// zed Data sub 7 days
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                        case 4:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DATA_2][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 43:// zed Data sub 30 days
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_DATA_3][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 51:// zed VOICE sub daily
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_VOICE_1][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 52:// zed VOICE sub weekly
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                        case 4:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_VOICE_2][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 53:// zed VOICE sub monthly
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:
                        case 2:
                        case 3:
                        case 4:
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_MONEY]);
                            shmp->process_info.rest_if.bundle_plan_id = yx_offerIds[YX_OFFER_TYPE_VOICE_3][key_input-1];
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 31;//select money
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 31:// select money
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// pay by balance
                            shmp->process_info.rest_if.plan_id = 4;// balance
                            if (1)//(pps_get_adaptor_flag())
                            {
                                pps_send_rest_order_req(portid, 1001);// send bundle subs req
                                /*shmp->process_info.funnel = 0;
                                shmp->process_info.rest_if.timer = 0;
                                shmp->process_info.rest_if.recv_cmd = 0;
                                shmp->process_info.sub_state_2 = 11;*/
                            }
                            SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_PAID_MONEY]);// SendUSSDRequest
                            shmp->process_info.serviceInput = 0;
                            //shmp->process_info.sub_state_2 = 32;//paid money
                            retval = 1;
                            break;
						case 2:// pay by mobile money
                            SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_SELECT_PROVIDER]);
                            shmp->process_info.rest_if.plan_id = 10;// mobile money
							shmp->process_info.rest_if.busicode = 1001;// busicode: order
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 34;//select provider; 33;//enter pin
                            shmp->process_info.funnel = 0;
						break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 32:// paid
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// complete
						    // send download app req
						    pps_send_rest_download_app_req(portid);
						    
                            SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_SUBSCRIB_COMPLETE]);
                            retval = 1;
                            break;
						case 0:
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 33:// enter pin, not in used currently
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				// subscribe bundle
                if (1)//(pps_get_adaptor_flag())
                {
                    pps_send_rest_order_req(portid, 1001);// send bundle subs req
                    /*shmp->process_info.funnel = 0;
                    shmp->process_info.rest_if.timer = 0;
                    shmp->process_info.rest_if.recv_cmd = 0;
                    shmp->process_info.sub_state_2 = 11;*/
                }
                SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_PAID_MONEY]);//SendUSSDRequest
                shmp->process_info.serviceInput = 0;
                //shmp->process_info.sub_state_2 = 32;//paid money
                retval = 1;
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 34:// select provider
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 1:// Airtel
						case 2:// MTN
                        case 3:// Zemtel
                        case 4:// NULL
                        case 5:// NULL
                            shmp->process_info.rest_if.unit = key_input;// operator
                            if (strstr(yx_ussd_menu[YX_USSD_MENU_ENTER_PAY_NUMBER], "%s") != NULL)
                            {
								char tmp_buf[160]="";
								sprintf(tmp_buf, (char *)yx_ussd_menu[YX_USSD_MENU_ENTER_PAY_NUMBER],
									(char *)yx_momo_info[key_input-1]);
								SendUSSDRequest(portid, tmp_buf);
                            }
							else
							{
								SendUSSDRequest(portid, yx_ussd_menu[YX_USSD_MENU_ENTER_PAY_NUMBER]);
							}
                            shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 35;//enter pay number
						break;
						case 0:
						default:
							//shmp->process_info.serviceInput = 0;
                            //shmp->process_info.sub_state_2 = 1;
                            //shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 35:// enter pay number
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				// subscribe bundle
                if (1)//(pps_get_adaptor_flag())
                {
                    pps_send_rest_order_req(portid, shmp->process_info.rest_if.busicode);// send bundle subs req
                }
				if (strstr(yx_ussd_menu[YX_USSD_MENU_MOMO_PIN], "%s") != NULL)
				{
					char tmp_buf[160]="", tmp_nbr[64]="";
					sprintf(tmp_nbr, "%s %s", yx_momo_info[shmp->process_info.rest_if.unit-1], shmp->process_info.tmpDigits);
					sprintf(tmp_buf, (char *)yx_ussd_menu[YX_USSD_MENU_MOMO_PIN], tmp_nbr);
					SendPSSREnd(portid, tmp_buf);//SendUSSDRequest
				}
				else
				{
					SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_MOMO_PIN]);//SendUSSDRequest
				}
                shmp->process_info.serviceInput = 0;
                //shmp->process_info.sub_state_2 = 32;//paid money
                retval = 1;
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
		case 36:// cancel auto renewal
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
				if(strlen(shmp->process_info.tmpDigits) > 1)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}

				if(isdigit(shmp->process_info.tmpDigits[0]) == 0)
				{
					//shmp->process_info.sub_state_2 = 1;
					//shmp->process_info.funnel = 0;
					break;
				}
				else
				{
					key_input = atoi(shmp->process_info.tmpDigits);
					switch(key_input)
					{
						case 2:// Yes
							// send cancel auto renewal req
							shmp->process_info.rest_if.plan_id = 4;// balance
							pps_send_rest_order_req(portid, 1002);
                            SendPSSREnd(portid, yx_ussd_menu[YX_USSD_MENU_PAID_MONEY]);//SendUSSDRequest
                            shmp->process_info.serviceInput = 0;
                            //shmp->process_info.sub_state_2 = 32;//paid money
							retval = 1;
						break;
						case 0:
						case 1:// No
						default:
							shmp->process_info.serviceInput = 0;
                            shmp->process_info.sub_state_2 = 1;
                            shmp->process_info.funnel = 0;
						break;
					}
				}
			}
            else if(result == -1)
            {
#ifdef _ZED_NO_CALLER_NUM_AND_EXPIRY_DATE_ // ussd_code daily report
				pps_update_ussd_code_state(USSDCODE_HOTLINE_CODE_STR, USSDCODE_TYPE_HOTLINE, USSDCODE_STAT_ERR_MSG, 0);
#endif
                SendPSSRResponse(portid);
                retval = 1;
            }
        break;
	}
	
	return retval;
}

int pps_third_party_channel_process(u_short portid)
{
	int			retval = 0, result;
	int         key_input;
	char		ussd_data[256];
	_state_data  *shmp = (_state_data *) smshm_ptr->state_data;

	if(portid>=MAX_FSM_PROCESS)
	{
		return -1;
	}
	
	shmp += (portid);
	if(shmp->process_info.rest_if.timer ++ > 100*CYCLE_STATE_INTERVAL)
	{
		return -1;
	}
	
	switch(shmp->process_info.sub_state_2)
	{
		case 1:
            shmp->process_info.ppsService.chnl_info.input[0] = '\0';
            shmp->process_info.ppsService.chnl_info.prompt[0] = '\0';
            sprintf(shmp->process_info.ppsService.chnl_info.sessId,"%04d%02d%02d%02d%02d%02d%s",
             time_now[0],time_now[1],time_now[2],
             time_now[3],time_now[4],time_now[5], shmp->caller_info.number);
			pps_send_rest_channel_req(portid);// send channel req
			shmp->process_info.rest_if.timer = 0;
			shmp->process_info.rest_if.recv_cmd = 0;
			shmp->process_info.sub_state_2 = 2;
		break;
		case 2:
			if(shmp->process_info.rest_if.recv_cmd == 0)
				break;
			result = shmp->process_info.rest_if.result;

			if((logMsgFlag & 0x01) || shmp->process_info.logMsisdn)
			{
				DebugMsg(debugmib.display.asciiOut,
					"\n\33[31m portid: %d, recv channel_res, result=%d\33[0m",
					portid, result);
			}
            
			if(result != 0)// error
			{
                SendPSSRResponse(portid);
                retval = 1;
			}
			else
			{
    			if (shmp->process_info.ppsService.chnl_info.sess_state == 1)// continue
    			{
    				sprintf(ussd_data, "%s", shmp->process_info.ppsService.chnl_info.prompt);
                    SendUSSDRequest(portid, ussd_data);
                    shmp->process_info.funnel = 0;
                    shmp->process_info.rest_if.timer = 0;
                    shmp->process_info.serviceInput = 0;
                    shmp->process_info.sub_state_2 = 3;
    			}
                else// 0, terminate
                {
                    sprintf(ussd_data, "%s", shmp->process_info.ppsService.chnl_info.prompt);
                    SendPSSREnd(portid, ussd_data);
                    retval = 1;
                }
			}
		break;
		case 3:
			result = getUssdACK(portid, (u_char *)shmp->process_info.tmpDigits);
			if(result >= 1)
			{
                strncpy(shmp->process_info.ppsService.chnl_info.input, shmp->process_info.tmpDigits, MAX_ASCII_NUMBER_LEN-1);
                pps_send_rest_channel_req(portid);// send channel req
                shmp->process_info.funnel = 0;
                shmp->process_info.rest_if.timer = 0;
                shmp->process_info.rest_if.recv_cmd = 0;
                shmp->process_info.sub_state_2 = 2;
			}
            else if(result == -1)
            {
                SendPSSRResponse(portid);
                retval = 1;
            }
            break;
		default:
			retval = -1;
		break;
	}
	
	return retval;
}

//

